Index: proj/include/ent.h
===================================================================
--- proj/include/ent.h	(revision 306)
+++ proj/include/ent.h	(revision 307)
@@ -71,6 +71,7 @@
 int    (map_collides_bullet)(const map_t *p, const bullet_t *bullet);
 int16_t (map_get_width)   (const map_t *p);
 int16_t (map_get_height)  (const map_t *p);
+int (map_make_dijkstra)(map_t *p, uint16_t x, uint16_t y);
 int (gunner_collides_bullet)(const gunner_t *shooter, const bullet_t *bull);
 int (gunner_collides_gunner)(const gunner_t *shooter1, const gunner_t *shooter2);
 void   (map_draw)(map_t *p);
Index: proj/include/proj_func.h
===================================================================
--- proj/include/proj_func.h	(revision 306)
+++ proj/include/proj_func.h	(revision 307)
@@ -29,7 +29,7 @@
 /**
  * @brief Updates movement variables.
  */
-void update_movement(const map_t *map, gunner_t *p, keys_t *keys, list_t *shooter_list);
+void update_movement(map_t *map, gunner_t *p, keys_t *keys, list_t *shooter_list);
 
 void update_mouse(struct packet *p);
 
@@ -39,7 +39,7 @@
 
 void (update_game_state)(const map_t *map, list_t *shooter_list, list_t *bullet_list);
 
-void (get_random_spawn)(const map_t *map, gunner_t *p);
+void (get_random_spawn)(const map_t *map, gunner_t *p, list_t *l);
 
 void update_scale(void);
 
Index: proj/include/proj_macros.h
===================================================================
--- proj/include/proj_macros.h	(revision 306)
+++ proj/include/proj_macros.h	(revision 307)
@@ -26,7 +26,7 @@
 #define HIGHLIGHT_COLOR         0x404040
 #define DELIMITER_COLOR         0x404040
 
-#define MELEE_RANGE    150
+#define MELEE_RANGE    80
 #define MELEE_DAMAGE   1
 
 #endif /* end of include guard: PROJ_MACROS_H_INCLUDED */
Index: proj/libs/graph/include/font.h
===================================================================
--- proj/libs/graph/include/font.h	(revision 306)
+++ proj/libs/graph/include/font.h	(revision 307)
@@ -18,6 +18,8 @@
 font_t* (font_ctor)(const char *s);
 void    (font_dtor)(font_t *p);
 
+font_t *consolas;
+
 struct text;
 typedef struct text text_t;
 text_t* (text_ctor)(const font_t *fnt, const char *txt);
Index: proj/libs/graph/include/graph.h
===================================================================
--- proj/libs/graph/include/graph.h	(revision 306)
+++ proj/libs/graph/include/graph.h	(revision 307)
@@ -11,9 +11,10 @@
 #define LINEAR_FRAME_BUFFER_MD  BIT(14)
 
 // Colors in RBG (8 bit)
-#define GRAPH_BLACK               0x000000
-#define GRAPH_WHITE               0xFFFFFF
-#define GRAPH_TRANSPARENT         0x00
+#define GRAPH_BLACK             0x000000
+#define GRAPH_WHITE             0xFFFFFF
+#define GRAPH_TRANSPARENT       0x00
+#define GRAPH_RED               0xFF0000
 
 // Alpha
 #define ALPHA_THRESHOLD     0x7F
Index: proj/libs/graph/src/font.c
===================================================================
--- proj/libs/graph/src/font.c	(revision 306)
+++ proj/libs/graph/src/font.c	(revision 307)
@@ -197,10 +197,14 @@
         }
     }
     // Draw text
-    for(int16_t newy = 0; newy < newH; ++newy){
+    for(int16_t x, y, newy = 0; newy < newH; ++newy){
+        y = inity+newy;
         for(int16_t newx = 0; newx < newW; ++newx){
+            x = initx+newx;
+            if(!(0 <= x && x < graph_get_XRes() &&
+                 0 <= y && y < graph_get_YRes())) continue;
             uint8_t a = *(alp_new_buf+newx+newy*newW);
-            if(a < 0x7F) graph_set_pixel(initx+newx,inity+newy,p->color);
+            if(a < ALPHA_THRESHOLD) graph_set_pixel(x,y,p->color);
         }
     }
     free(alp_new_buf);
Index: proj/src/ent.c
===================================================================
--- proj/src/ent.c	(revision 306)
+++ proj/src/ent.c	(revision 307)
@@ -5,8 +5,13 @@
 #include "graph.h"
 #include "utils.h"
 #include "rectangle.h"
+#include "font.h"
+#include "errors.h"
+#include "queue.h"
 #include <math.h>
 
+#define GREEN_HEALTH_COLOR      0x009900
+
 static double scale = 1.0;
 static int16_t x_origin = 0;
 static int16_t y_origin = 0;
@@ -23,6 +28,7 @@
     sprite_t *dude;
     sprite_t *weapon;
     double health, current_health;
+    text_t *txt;
     gunner_type type;
     int team;
 };
@@ -35,6 +41,7 @@
     ret->y = 0.0;
     ret->health = 100;
     ret->current_health = ret->health;
+    ret->txt = text_ctor(consolas, "");
     ret->type = type;
     ret->team = team;
     ret->dude   = sprite_ctor(dude  );
@@ -42,12 +49,18 @@
     if(ret->dude == NULL || ret->weapon == NULL){
         gunner_dtor(ret);
         return NULL;
-    } else return ret;
+    }
+    text_set_size(ret->txt, 15);
+    text_set_valign(ret->txt, text_valign_center);
+    text_set_halign(ret->txt, text_halign_center);
+    text_set_color(ret->txt, GRAPH_WHITE);
+    return ret;
 }
 void (gunner_dtor)(gunner_t *p){
     if(p == NULL) return;
     sprite_dtor(p->dude);
     sprite_dtor(p->weapon);
+    text_dtor(p->txt);
     free(p);
 }
 void (gunner_set_pos)  (gunner_t *p, double x, double y){ p->x = x; p->y = y; }
@@ -96,13 +109,18 @@
     double health = gunner_get_health(p);
     double perc = curr_health/health;
     rectangle_t *green_bar = rectangle_ctor(x, y, (int16_t)(w*perc), 10);
-    rectangle_set_fill_color(green_bar, 0x00FF00);
+    rectangle_set_fill_color(green_bar, GREEN_HEALTH_COLOR);
     rectangle_t *red_bar = rectangle_ctor(x+(int16_t)(w*perc), y, (int16_t)(w*(1-perc)), 10);
-    rectangle_set_fill_color(red_bar, 0xFF0000);
+    rectangle_set_fill_color(red_bar, GRAPH_RED);
+    char buf[20]; sprintf(buf, "%d/%d", (int)p->current_health, (int)p->health);
+    text_set_text(p->txt, buf);
+    text_set_pos(p->txt, x+w/2, y+10/2);
     rectangle_draw(green_bar);
     rectangle_draw(red_bar);
+    text_draw(p->txt);
     rectangle_dtor(green_bar);
     rectangle_dtor(red_bar);
+
 }
 
 double (gunner_distance)(const gunner_t *p1, const gunner_t *p2){
@@ -198,6 +216,8 @@
     basic_sprite_t *bsp_background;
     sprite_t *background;
     uint8_t *collide;
+    int *x_prev;
+    int *y_prev;
 };
 map_t* (map_ctor)(const char **background, const char **collide){
     map_t *ret = malloc(sizeof(map_t));
@@ -206,11 +226,13 @@
     ret->bsp_background = NULL;
     ret->background     = NULL;
     ret->collide        = NULL;
+    ret->x_prev         = NULL;
+    ret->y_prev         = NULL;
 
     ret->bsp_background = basic_sprite_ctor(background, 0, 0);
     ret->background     = sprite_ctor(ret->bsp_background);
     if(ret->bsp_background == NULL ||
-        ret->background     == NULL){ map_dtor(ret); return NULL; }
+       ret->background     == NULL){ map_dtor(ret); return NULL; }
 
     basic_sprite_t *bsp_collide = basic_sprite_ctor(collide, 0, 0);
     if(bsp_collide == NULL){ map_dtor(ret); return NULL; }
@@ -224,6 +246,13 @@
     }
     basic_sprite_dtor(bsp_collide);
 
+    ret->x_prev = malloc(W*H*sizeof(int));
+    ret->y_prev = malloc(W*H*sizeof(int));
+
+    if(ret->x_prev == NULL || ret->y_prev == NULL){
+        map_dtor(ret);
+        return NULL;
+    }
     return ret;
 }
 void (map_dtor)(map_t *p){
@@ -231,6 +260,8 @@
     sprite_dtor(p->background);
     basic_sprite_dtor(p->bsp_background);
     free(p->collide);
+    free(p->x_prev);
+    free(p->y_prev);
     free(p);
 }
 int16_t (map_get_x_screen)(const map_t *p){ return (-x_origin)*scale; }
@@ -244,7 +275,29 @@
     uint32_t pos = x_ + y_*w;
     return p->collide[pos];
 }
+int (map_make_dijkstra)(map_t *p, uint16_t x, uint16_t y){
+    const uint16_t W = basic_sprite_get_w(p->bsp_background),
+                   H = basic_sprite_get_h(p->bsp_background);
+    for(size_t i = 0; i < W*H; ++i)
+        p->x_prev[i] = p->y_prev[i] = -1;
+    /// ACTUAL DIJKSTRA
+    queue_t *q = queue_ctor();
+    int *ptr;
+    p->x_prev[y*W+x] = x; p->x_prev[y*W+x] = y;
+    ptr = malloc(sizeof(int)); *ptr = y*W+x; queue_push(q, ptr);
+    while(!queue_empty(q)){
+        int c = *(int*)list_node_val(queue_top(q)); free(queue_top(q)); queue_pop(q);
+        if(p->collide[c]){ p->x_prev[c] = p->y_prev[c] = -1; continue; }
+        uint16_t x = c%W, y = c/W;
+        if(0   <= x-1){ int pos = y*W+(x-1); if(p->x_prev[pos] == -1){ p->x_prev[pos] = x; p->y_prev[pos] = y; ptr = malloc(sizeof(int)); *ptr = pos; queue_push(q, ptr); }}
+        if(x+1 <  W  ){ int pos = y*W+(x+1); if(p->x_prev[pos] == -1){ p->x_prev[pos] = x; p->y_prev[pos] = y; ptr = malloc(sizeof(int)); *ptr = pos; queue_push(q, ptr); }}
+        if(0   <= y-1){ int pos = (y-1)*W+x; if(p->x_prev[pos] == -1){ p->x_prev[pos] = x; p->y_prev[pos] = y; ptr = malloc(sizeof(int)); *ptr = pos; queue_push(q, ptr); }}
+        if(y+1 <  H  ){ int pos = (y+1)*W+x; if(p->x_prev[pos] == -1){ p->x_prev[pos] = x; p->y_prev[pos] = y; ptr = malloc(sizeof(int)); *ptr = pos; queue_push(q, ptr); }}
+    }
+    return SUCCESS;
+}
 
+
 int (map_collides_gunner)(const map_t *p, const gunner_t *shooter) {
     double radius = max(sprite_get_w(shooter->dude), sprite_get_h(shooter->dude))/2.0;
     double shooter_x = gunner_get_x(shooter);
Index: proj/src/proj.c
===================================================================
--- proj/src/proj.c	(revision 306)
+++ proj/src/proj.c	(revision 307)
@@ -109,73 +109,55 @@
     keys_t *keys = get_key_presses();
 
     /// loop stuff
-    int ipc_status;
-    message msg;
-
     int click = 0;
-
+    uint32_t int_vector = 0;
     int good = true;
-
     while (good) {
         /* Get a request message. */
-        if ((r = driver_receive(ANY, &msg, &ipc_status)) != 0) {
-            printf("driver_receive failed with %d", r);
-            continue;
-        }
-        if (is_ipc_notify(ipc_status)) { /* received notification */
-            switch (_ENDPOINT_P(msg.m_source)) {
-                case HARDWARE: /* hardware interrupt notification */
-                for (uint32_t i = 0, n = 1; i < 32; i++, n <<= 1) {
-                    if (msg.m_notify.interrupts & n) {
-                        interrupt_handler(i);
-                        switch (i) {
-                            case TIMER0_IRQ:
+        if((r = get_interrupts_vector(&int_vector))) return r;
+        for (uint32_t i = 0, n = 1; i < 32; i++, n <<= 1) {
+            if (int_vector & n) {
+                interrupt_handler(i);
+                switch (i) {
+                    case TIMER0_IRQ:
 
-                            graph_clear_screen();
-                            switch(menu_update_state(main_menu, click)){
-                                case -1: break;
-                                case  0: singleplayer(); break; //campaign(); break;
-                                case  1: break;
-                                case  2: chat(); break;
-                                case  3: good = false; break;
-                            }
-                            menu_draw(main_menu);
+                    graph_clear_screen();
+                    switch(menu_update_state(main_menu, click)){
+                        case -1: break;
+                        case  0: singleplayer(); break; //campaign(); break;
+                        case  1: break;
+                        case  2: chat(); break;
+                        case  3: good = false; break;
+                    }
+                    menu_draw(main_menu);
 
-                            click = 0;
+                    click = 0;
 
-                            sprite_set_pos(sp_crosshair, *get_mouse_X(), *get_mouse_Y());
-                            sprite_draw(sp_crosshair);
-                            graph_draw();
+                    sprite_set_pos(sp_crosshair, *get_mouse_X(), *get_mouse_Y());
+                    sprite_draw(sp_crosshair);
+                    graph_draw();
 
-                            break;
-                            case KBC_IRQ:
-                            if ((scancode[0]) == ESC_BREAK_CODE) good = false;
-                            case MOUSE_IRQ:
-                            if (counter_mouse_ih >= 3) {
-                                mouse_parse_packet(packet_mouse_ih, &pp);
-                                update_mouse(&pp);
-                                if (!click) click = last_lb ^ keys->lb_pressed && keys->lb_pressed;
-                                last_lb = keys->lb_pressed;
-                                counter_mouse_ih = 0;
-                            }
-                            break;
-                            case COM1_IRQ: nctp_ih(); break;
-                        }
+                    break;
+                    case KBC_IRQ:
+                    if ((scancode[0]) == ESC_BREAK_CODE) good = false;
+                    case MOUSE_IRQ:
+                    if (counter_mouse_ih >= 3) {
+                        mouse_parse_packet(packet_mouse_ih, &pp);
+                        update_mouse(&pp);
+                        if (!click) click = last_lb ^ keys->lb_pressed && keys->lb_pressed;
+                        last_lb = keys->lb_pressed;
+                        counter_mouse_ih = 0;
                     }
+                    break;
+                    case COM1_IRQ: nctp_ih(); break;
                 }
-
-                break;
-                default:
-                break; /* no other notifications expected: do nothing */
             }
-        } else { /* received standart message, not a notification */
-            /* no standart message expected: do nothing */
         }
     }
 
     basic_sprite_dtor      (bsp_crosshair); bsp_crosshair = NULL;
     basic_sprite_dtor      (bsp_shooter  ); bsp_shooter   = NULL;
-    /*basic_sprite_dtor      (bsp_zombie   );*/ bsp_zombie    = NULL;
+    basic_sprite_dtor      (bsp_zombie   ); bsp_zombie    = NULL;
     sprite_dtor            (sp_crosshair ); sp_crosshair  = NULL;
     basic_sprite_dtor      (bsp_pistol   ); bsp_pistol    = NULL;
     basic_sprite_dtor      (bsp_nothing  ); bsp_nothing   = NULL;
@@ -339,7 +321,7 @@
                         list_node_t *it = list_begin(shooter_list);
                         while (it != list_end(shooter_list)) {
                             gunner_t *p = *(gunner_t**)list_node_val(it);
-                            get_random_spawn(map1, p);
+                            get_random_spawn(map1, p, shooter_list);
                             gunner_set_curr_health(p, gunner_get_health(p));
                             it = list_node_next(it);
                         }
@@ -425,9 +407,6 @@
                     case TIMER0_IRQ:
                     if (no_interrupts % 60 == 0) timer_update(in_game_timer);
 
-                    clock_t t1, t2;
-                    t1 = clock();
-
                     update_movement(map1, shooter1, keys, shooter_list);
 
                     update_game_state(map1, shooter_list, bullet_list);
@@ -449,7 +428,7 @@
                         gunner_set_health(zombie, health);
                         gunner_set_curr_health(zombie, health);
                         health *= ZOMBIE_HEALTH_FACTOR;
-                        get_random_spawn(map1, zombie);
+                        get_random_spawn(map1, zombie, shooter_list);
                         list_push_back(shooter_list, zombie);
                     }
 
@@ -464,26 +443,10 @@
                     sprite_draw(sp_crosshair);
                     graph_draw();
 
-                    t2 = clock();
-                    printf("%d microseconds\n", t2-t1);
-
                     break;
                     case KBC_IRQ:
                     if ((scancode[0]) == ESC_BREAK_CODE) {
                         good = false;
-                        // reset game
-                        while(list_size(bullet_list) > 0){
-                            bullet_t *p = (bullet_t*)list_erase(bullet_list, list_begin(bullet_list));
-                            bullet_dtor(p);
-                        }
-                        list_node_t *it = list_begin(shooter_list);
-                        while (it != list_end(shooter_list)) {
-                            gunner_t *p = *(gunner_t**)list_node_val(it);
-                            get_random_spawn(map1, p);
-                            gunner_set_curr_health(p, gunner_get_health(p));
-                            it = list_node_next(it);
-                        }
-                        timer_reset(in_game_timer);
                     }
                     break;
                     case MOUSE_IRQ:
Index: proj/src/proj_func.c
===================================================================
--- proj/src/proj_func.c	(revision 306)
+++ proj/src/proj_func.c	(revision 307)
@@ -48,7 +48,7 @@
     }
 }
 
-void update_movement(const map_t *map, gunner_t *p, keys_t *keys, list_t *shooter_list) {
+void update_movement(map_t *map, gunner_t *p, keys_t *keys, list_t *shooter_list) {
     int ver_mov = keys->s_pressed - keys->w_pressed;
     int hor_mov = keys->d_pressed - keys->a_pressed;
     double x = gunner_get_x(p);
@@ -81,6 +81,20 @@
             it = list_node_next(it);
         }
     }
+
+    // Update zombie positions
+    map_make_dijkstra(map, gunner_get_x(p), gunner_get_y(p));
+    list_node_t *it = list_begin(shooter_list);
+    while(it != list_end(shooter_list)){
+        gunner_t *g = *(gunner_t**)list_node_val(it);
+        if(gunner_get_type(g) & gunner_follow){
+            //float theta = 0.0;
+            //map_where_to_follow(map, &theta);
+            //float c = fm_cos(theta), s = fm_sin(theta);
+
+        }
+        it = list_node_next(it);
+    }
 }
 
 void (shoot_bullet)(const gunner_t *shooter, list_t *bullet_list, const basic_sprite_t *bsp_bullet) {
@@ -138,7 +152,8 @@
         list_node_t *it2 = list_begin(shooter_list);
         while(it2 != list_end(shooter_list)){
             gunner_t *s2 = *list_node_val(it2);
-            if(s1 != s2 && gunner_distance(s1, s2) < MELEE_RANGE)
+            if(gunner_get_team(s1) != gunner_get_team(s2) &&
+               gunner_distance(s1, s2) < MELEE_RANGE)
                 gunner_set_curr_health(s2, gunner_get_curr_health(s2) - MELEE_DAMAGE);
             if(gunner_get_curr_health(s2) <= 0){
                 list_node_t *aux = list_node_next(it2);
@@ -150,15 +165,26 @@
     }
 }
 
-void (get_random_spawn)(const map_t *map, gunner_t *p) {
+void (get_random_spawn)(const map_t *map, gunner_t *p, list_t *l) {
     uint16_t w = map_get_width(map), h = map_get_height(map);
     double x, y;
 
-    do {
+    while(true){
         x = rand() % w;
         y = rand() % h;
         gunner_set_pos(p, x, y);
-    } while (map_collides_gunner(map, p));
+        if(map_collides_gunner(map, p)) continue;
+        int collides = false;
+        list_node_t *it = list_begin(l);
+        while(it != list_end(l)){
+            if(gunner_collides_gunner(p, *list_node_val(it))){
+                collides = true;
+                break;
+            }
+            it = list_node_next(it);
+        }
+        if(!collides) return;
+    }
 }
 
 void update_scale(void) {
