Complete.Org: Mailing Lists: Archives: freeciv-dev: October 2004:
[Freeciv-Dev] (PR#10687) adding animation
Home

[Freeciv-Dev] (PR#10687) adding animation

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#10687) adding animation
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 22 Oct 2004 18:59:41 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=10687 >

> [jdorje - Sat Oct 23 01:25:50 2004]:
> 
> This patch adds animation!
> 
> Apply the patch, copy the warriors.png into data/misc, run with 
> civclient, and build lots of warriors.  There are four animated actions: 
> movement, attacking, dying, and fortifying.
> 
> There are bugs.  And it is incomplete.
> 
> The animation graphics are taken from the incoming directory, made by 
> Lukas Tonne using blender.

Oops, I forgot the "attack" animation!  Here's a new patch.

Also, you have to set smooth_unit_move_msec (a local client option) to
be non-zero for it to work.

jason

? warrior.png
? warrior_animation.README
? data/misc/warriors.png
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.158
diff -u -r1.158 mapview_common.c
--- client/mapview_common.c     20 Oct 2004 15:36:12 -0000      1.158
+++ client/mapview_common.c     23 Oct 2004 01:59:12 -0000
@@ -1819,6 +1819,36 @@
                    ABS(canvas_dy) + NORMAL_TILE_HEIGHT);
 }
 
+static void run_animation(struct tile *ptile, struct anim *anim)
+{
+  int canvas_x, canvas_y;
+
+  if (tile_to_canvas_pos(&canvas_x, &canvas_y, ptile)) {
+    int frame, w, h;
+    int x = canvas_x + NORMAL_TILE_WIDTH / 2 - anim_center_x;
+    int y = canvas_y + NORMAL_TILE_HEIGHT / 2 - anim_center_y;
+    
+    get_sprite_dimensions(anim->frame[0], &w, &h);
+
+    canvas_copy(mapview_canvas.tmp_store, mapview_canvas.store,
+               x, y, x, y, w, h);
+
+    for (frame = 0; frame < anim->count; frame++) {
+      canvas_put_sprite_full(mapview_canvas.store,
+                            x, y, anim->frame[frame]);
+      dirty_rect(x, y, w, h);
+      flush_dirty();
+      gui_flush();
+
+      myusleep(50000);
+
+      canvas_copy(mapview_canvas.store, mapview_canvas.tmp_store,
+                 x, y, x, y, w, h);
+    }
+    dirty_rect(x, y, w, h);
+  }
+}
+
 /****************************************************************************
   This function is called to decrease a unit's HP smoothly in battle
   when combat_animation is turned on.
@@ -1828,10 +1858,24 @@
 {
   static struct timer *anim_timer = NULL; 
   struct unit *losing_unit = (hp0 == 0 ? punit0 : punit1);
+  struct unit *winning_unit = (hp1 == 0 ? punit0 : punit1);
   int canvas_x, canvas_y, i;
+  enum direction8 dir = get_direction_for_step(losing_unit->tile,
+                                              winning_unit->tile);
+  struct anim *anim;
 
-  set_units_in_combat(punit0, punit1);
+  if (tile_to_canvas_pos(&canvas_x, &canvas_y, punit0->tile)) {
+    anim = &sprites.units[punit0->type].anim[ANIM_ATTACK][dir];
+
+    if (anim->count > 0) {
+      hidden_units_tile = punit0->tile;
+      refresh_tile_mapcanvas(punit0->tile, FALSE);
+      run_animation(punit0->tile, anim);
+      hidden_units_tile = NULL;
+    }
+  }
 
+  set_units_in_combat(punit0, punit1);
   while (punit0->hp > hp0 || punit1->hp > hp1) {
     const int diff0 = punit0->hp - hp0, diff1 = punit1->hp - hp1;
 
@@ -1850,46 +1894,71 @@
 
     usleep_since_timer_start(anim_timer, 10000);
   }
+  set_units_in_combat(NULL, NULL);
 
-  if (num_tiles_explode_unit > 0
-      && tile_to_canvas_pos(&canvas_x, &canvas_y,
-                          losing_unit->tile)) {
-    refresh_tile_mapcanvas(losing_unit->tile, FALSE);
-    canvas_copy(mapview_canvas.tmp_store, mapview_canvas.store,
-               canvas_x, canvas_y, canvas_x, canvas_y,
-               NORMAL_TILE_WIDTH, NORMAL_TILE_HEIGHT);
-
-    for (i = 0; i < num_tiles_explode_unit; i++) {
-      int w, h;
-
-      get_sprite_dimensions(sprites.explode.unit[i], &w, &h);
-      anim_timer = renew_timer_start(anim_timer, TIMER_USER, TIMER_ACTIVE);
-
-      /* We first draw the explosion onto the unit and draw draw the
-       * complete thing onto the map canvas window. This avoids
-       * flickering. */
-      canvas_copy(mapview_canvas.store, mapview_canvas.tmp_store,
+  if (tile_to_canvas_pos(&canvas_x, &canvas_y, losing_unit->tile)) {
+    anim = &sprites.units[losing_unit->type].anim[ANIM_DIE][dir];
+    if (anim->count > 0) {
+      hidden_units_tile = losing_unit->tile;
+      refresh_tile_mapcanvas(losing_unit->tile, FALSE);
+      run_animation(losing_unit->tile, anim);
+      hidden_units_tile = NULL;
+    } else if (num_tiles_explode_unit > 0) {
+      set_units_in_combat(punit0, punit1);
+      refresh_tile_mapcanvas(losing_unit->tile, FALSE);
+      canvas_copy(mapview_canvas.tmp_store, mapview_canvas.store,
                  canvas_x, canvas_y, canvas_x, canvas_y,
                  NORMAL_TILE_WIDTH, NORMAL_TILE_HEIGHT);
-      canvas_put_sprite_full(mapview_canvas.store,
-                            canvas_x + NORMAL_TILE_WIDTH / 2 - w / 2,
-                            canvas_y + NORMAL_TILE_HEIGHT / 2 - h / 2,
-                            sprites.explode.unit[i]);
-      dirty_rect(canvas_x, canvas_y, NORMAL_TILE_WIDTH, NORMAL_TILE_HEIGHT);
 
-      flush_dirty();
-      gui_flush();
+      for (i = 0; i < num_tiles_explode_unit; i++) {
+       int w, h;
 
-      usleep_since_timer_start(anim_timer, 20000);
+       get_sprite_dimensions(sprites.explode.unit[i], &w, &h);
+       anim_timer = renew_timer_start(anim_timer, TIMER_USER, TIMER_ACTIVE);
+
+       /* We first draw the explosion onto the unit and draw draw the
+        * complete thing onto the map canvas window. This avoids
+        * flickering. */
+       canvas_copy(mapview_canvas.store, mapview_canvas.tmp_store,
+                   canvas_x, canvas_y, canvas_x, canvas_y,
+                   NORMAL_TILE_WIDTH, NORMAL_TILE_HEIGHT);
+       canvas_put_sprite_full(mapview_canvas.store,
+                              canvas_x + NORMAL_TILE_WIDTH / 2 - w / 2,
+                              canvas_y + NORMAL_TILE_HEIGHT / 2 - h / 2,
+                              sprites.explode.unit[i]);
+       dirty_rect(canvas_x, canvas_y, NORMAL_TILE_WIDTH, NORMAL_TILE_HEIGHT);
+       
+       flush_dirty();
+       gui_flush();
+
+       usleep_since_timer_start(anim_timer, 20000);
+      }
+      set_units_in_combat(NULL, NULL);
     }
   }
 
-  set_units_in_combat(NULL, NULL);
   refresh_tile_mapcanvas(punit0->tile, FALSE);
   refresh_tile_mapcanvas(punit1->tile, FALSE);
 }
 
 /**************************************************************************
+  Do animations when changing activity.  punit->activity gives the
+  old activity; new_activity the new one.
+**************************************************************************/
+void animate_unit_change_activity(const struct unit *punit,
+                                 enum unit_activity new_activity)
+{
+  if (punit->activity == ACTIVITY_IDLE
+      && new_activity == ACTIVITY_FORTIFYING) {
+    struct anim *anim = &(sprites.units[punit->type].
+                         anim[ANIM_FORTIFY][punit->client.facing]);
+
+    refresh_tile_mapcanvas(punit->tile, FALSE);
+    run_animation(punit->tile, anim);
+  }
+}
+
+/**************************************************************************
   Animates punit's "smooth" move from (x0, y0) to (x0+dx, y0+dy).
   Note: Works only for adjacent-tile moves.
 **************************************************************************/
@@ -1899,6 +1968,7 @@
   static struct timer *anim_timer = NULL;
   struct tile *dest_tile;
   int dest_x, dest_y;
+  enum direction8 dir;
 
   /* only works for adjacent-square moves */
   if (dx < -1 || dx > 1 || dy < -1 || dy > 1 || (dx == 0 && dy == 0)) {
@@ -1919,54 +1989,86 @@
   if (!dest_tile) {
     return;
   }
+  dir = get_direction_for_step(src_tile, dest_tile);
 
   if (tile_visible_mapcanvas(src_tile)
       || tile_visible_mapcanvas(dest_tile)) {
     int start_x, start_y;
     int canvas_dx, canvas_dy;
     double timing_sec = (double)smooth_move_unit_msec / 1000.0, mytime;
+    struct anim *anim = &sprites.units[punit->type].anim[ANIM_MOVE][dir];
 
     assert(smooth_move_unit_msec > 0);
 
     map_to_gui_vector(&canvas_dx, &canvas_dy, dx, dy);
 
     tile_to_canvas_pos(&start_x, &start_y, src_tile);
-    if (is_isometric) {
-      start_y -= NORMAL_TILE_HEIGHT / 2;
-    }
 
     /* Flush before we start animating. */
     flush_dirty();
     gui_flush();
 
-    do {
-      int new_x, new_y;
+    if (anim->count > 0) {
+      int frame, width, height;
 
-      mytime = MIN(read_timer_seconds(anim_timer), timing_sec);
+      get_sprite_dimensions(anim->frame[0], &width, &height);
 
-      new_x = start_x + canvas_dx * (mytime / timing_sec);
-      new_y = start_y + canvas_dy * (mytime / timing_sec);
+      for (frame = 0; frame < anim->count; frame++) {
+       int x = start_x + canvas_dx * frame / anim->count
+         + NORMAL_TILE_WIDTH / 2 - anim_center_x;
+       int y = start_y + canvas_dy * frame / anim->count
+         + NORMAL_TILE_HEIGHT / 2 - anim_center_y;
+
+       canvas_copy(mapview_canvas.tmp_store, mapview_canvas.store,
+                   x, y, x, y, width, height);
+
+       canvas_put_sprite_full(mapview_canvas.store,
+                              x, y, anim->frame[frame]);
+       dirty_rect(x, y, width, height);
+       flush_dirty();
+       gui_flush();
+       myusleep(20000);
+
+       canvas_copy(mapview_canvas.store, mapview_canvas.tmp_store,
+                   x, y, x, y, width, height);
+       dirty_rect(x, y, width, height);
+      }
+    } else {
+      do {
+       int new_x, new_y;
 
-      /* Backup the canvas store to the temp store. */
-      canvas_copy(mapview_canvas.tmp_store, mapview_canvas.store,
-                 new_x, new_y, new_x, new_y,
-                 UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
+       if (is_isometric) {
+         start_y -= NORMAL_TILE_HEIGHT / 2;
+       }
 
-      /* Draw */
-      put_unit(punit, mapview_canvas.store, new_x, new_y);
-      dirty_rect(new_x, new_y, UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
+       mytime = MIN(read_timer_seconds(anim_timer), timing_sec);
 
-      /* Flush. */
-      flush_dirty();
-      gui_flush();
+       new_x = start_x + canvas_dx * (mytime / timing_sec);
+       new_y = start_y + canvas_dy * (mytime / timing_sec);
 
-      /* Restore the backup.  It won't take effect until the next flush. */
-      canvas_copy(mapview_canvas.store, mapview_canvas.tmp_store,
-                 new_x, new_y, new_x, new_y,
-                 UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
-      dirty_rect(new_x, new_y, UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
-    } while (mytime < timing_sec);
+       /* Backup the canvas store to the temp store. */
+       canvas_copy(mapview_canvas.tmp_store, mapview_canvas.store,
+                   new_x, new_y, new_x, new_y,
+                   UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
+
+       /* Draw */
+       put_unit(punit, mapview_canvas.store, new_x, new_y);
+       dirty_rect(new_x, new_y, UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
+
+       /* Flush. */
+       flush_dirty();
+       gui_flush();
+
+       /* Restore the backup.  It won't take effect until the next flush. */
+       canvas_copy(mapview_canvas.store, mapview_canvas.tmp_store,
+                   new_x, new_y, new_x, new_y,
+                   UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
+       dirty_rect(new_x, new_y, UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
+      } while (mytime < timing_sec);
+    }
   }
+
+  punit->client.facing = dir;
 }
 
 /**************************************************************************
Index: client/mapview_common.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.h,v
retrieving revision 1.80
diff -u -r1.80 mapview_common.h
--- client/mapview_common.h     17 Oct 2004 15:47:48 -0000      1.80
+++ client/mapview_common.h     23 Oct 2004 01:59:12 -0000
@@ -190,6 +190,8 @@
 
 void decrease_unit_hp_smooth(struct unit *punit0, int hp0, 
                             struct unit *punit1, int hp1);
+void animate_unit_change_activity(const struct unit *punit,
+                                 enum unit_activity new_activity);
 void move_unit_map_canvas(struct unit *punit,
                          struct tile *ptile, int dx, int dy);
 
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.411
diff -u -r1.411 packhand.c
--- client/packhand.c   21 Oct 2004 20:27:28 -0000      1.411
+++ client/packhand.c   23 Oct 2004 01:59:12 -0000
@@ -1006,6 +1006,7 @@
         }
       }
 
+      animate_unit_change_activity(punit, packet_unit->activity);
       punit->activity = packet_unit->activity;
       punit->activity_target = packet_unit->activity_target;
 
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.207
diff -u -r1.207 tilespec.c
--- client/tilespec.c   20 Oct 2004 05:12:32 -0000      1.207
+++ client/tilespec.c   23 Oct 2004 01:59:13 -0000
@@ -84,6 +84,7 @@
 
 static int roadstyle;
 static int flag_offset_x, flag_offset_y;
+int anim_center_x, anim_center_y;
 
 #define NUM_CORNER_DIRS 4
 #define TILES_PER_CORNER 4
@@ -193,6 +194,8 @@
 */
 static bool focus_unit_hidden = FALSE;
 
+struct tile *hidden_units_tile = NULL;
+
 static struct Sprite* lookup_sprite_tag_alt(const char *tag, const char *alt,
                                            bool required, const char *what,
                                            const char *name);
@@ -855,6 +858,11 @@
   flag_offset_y = secfile_lookup_int_default(file, 0,
                                             "tilespec.flag_offset_y");
 
+  anim_center_x = secfile_lookup_int_default(file, 0,
+                                            "tilespec.anim_center_x");
+  anim_center_y = secfile_lookup_int_default(file, 0,
+                                            "tilespec.anim_center_y");
+
   c = secfile_lookup_str_default(file, "10x20", "tilespec.city_names_font");
   city_names_font = mystrdup(c);
 
@@ -1546,12 +1554,51 @@
 void tilespec_setup_unit_type(int id)
 {
   struct unit_type *ut = get_unit_type(id);
-  
-  ut->sprite = lookup_sprite_tag_alt(ut->graphic_str, ut->graphic_alt,
-                                    unit_type_exists(id), "unit_type",
-                                    ut->name);
+  const char *anim_types[ANIM_COUNT] = {
+    "die", "attack", "fortify", "move", "stand"
+  };
+  int anim, dir_index;
+  const char *name = ut->graphic_str;
+
+  sprites.units[id].base = load_sprite(name);
+  if (!sprites.units[id].base) {
+    name = ut->graphic_alt;
+    sprites.units[id].base = load_sprite(name);
+  }
+  if (!sprites.units[id].base) {
+    /* Should we have a fallback sprite? */
+    /* This string matches the one in lookup_sprite_tag_alt. */
+    freelog(LOG_FATAL, _("Don't have graphicics tags %s or %s for %s %s"),
+           ut->graphic_str, ut->graphic_alt, _("unit"), ut->name);
+    exit(EXIT_FAILURE);
+  }
 
-  /* should maybe do something if NULL, eg generic default? */
+  for (anim = 0; anim < ANIM_COUNT; anim++) {
+    for (dir_index = 0; dir_index < num_valid_tileset_dirs; dir_index++) {
+      enum direction8 dir = valid_tileset_dirs[dir_index];
+      char buf[1024];
+      int count;
+
+      for (count = 0; count <= MAX_NUM_FRAMES; count++) {
+       struct Sprite *s;
+
+       if (count == MAX_NUM_FRAMES) {
+         freelog(LOG_ERROR, _("Only %d frames of animation are supported."),
+                 MAX_NUM_FRAMES);
+       }
+
+       my_snprintf(buf, sizeof(buf),
+                   "%s.%s.%s.%d", name, anim_types[anim],
+                   dir_get_tileset_name(dir), count);
+       s = load_sprite(buf);
+       if (!s) {
+         break;
+       }
+       sprites.units[id].anim[anim][dir].frame[count] = s;
+      }
+      sprites.units[id].anim[anim][dir].count = count;
+    }
+  }
 }
 
 /**********************************************************************
@@ -1949,6 +1996,10 @@
 {
   struct drawn_sprite *save_sprs = sprs;
   int ihp;
+  struct anim *anim = &(sprites.units[punit->type]
+                      .anim[ANIM_STAND][punit->client.facing]);
+  struct anim *fanim = &(sprites.units[punit->type]
+                        .anim[ANIM_FORTIFY][punit->client.facing]);
 
   if (is_isometric) {
     if (backdrop) {
@@ -1966,7 +2017,27 @@
     }
   }
 
-  ADD_SPRITE_FULL(unit_type(punit)->sprite);
+  if ((punit->activity == ACTIVITY_FORTIFYING
+       || punit->activity == ACTIVITY_FORTIFIED)
+      && fanim->count > 0) {
+    struct Sprite *s = fanim->frame[fanim->count - 1];
+    int w, h;
+
+    get_sprite_dimensions(s, &w, &h);
+    ADD_SPRITE(s, DRAW_NORMAL, TRUE,
+              NORMAL_TILE_WIDTH / 2 - anim_center_x,
+              NORMAL_TILE_HEIGHT / 2 - anim_center_y);
+  } else if (anim->count > 0) {
+    struct Sprite *s = anim->frame[0];
+    int w, h;
+
+    get_sprite_dimensions(s, &w, &h);
+    ADD_SPRITE(s, DRAW_NORMAL, TRUE,
+              NORMAL_TILE_WIDTH / 2 - anim_center_x,
+              NORMAL_TILE_HEIGHT / 2 - anim_center_y);
+  } else {
+    ADD_SPRITE_FULL(get_unit_sprite(punit->type));
+  }
 
   if(punit->activity!=ACTIVITY_IDLE) {
     struct Sprite *s = NULL;
@@ -2757,7 +2828,8 @@
               FALSE, 0, 0);
   }
 
-  if (punit && (draw_units || (punit == pfocus && draw_focus_unit))) {
+  if (punit && (draw_units || (punit == pfocus && draw_focus_unit))
+      && (!ptile || ptile != hidden_units_tile)) {
     bool stacked = ptile && (unit_list_size(&ptile->units) > 1);
     bool backdrop = !pcity;
 
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.90
diff -u -r1.90 tilespec.h
--- client/tilespec.h   7 Oct 2004 19:15:19 -0000       1.90
+++ client/tilespec.h   23 Oct 2004 01:59:13 -0000
@@ -20,6 +20,8 @@
 
 #include "fc_types.h"
 
+#include "map.h"
+
 #include "citydlg_common.h"    /* enum citizen_type */
 #include "colors_g.h"
 #include "options.h"
@@ -147,6 +149,10 @@
   struct Sprite *mine;
 };
 
+enum animation_type {
+  ANIM_DIE, ANIM_ATTACK, ANIM_FORTIFY, ANIM_MOVE, ANIM_STAND, ANIM_COUNT
+};
+
 struct named_sprites {
   struct Sprite
     *bulb[NUM_TILES_PROGRESS],
@@ -262,6 +268,15 @@
   } tx;                                /* terrain extra */
 
   struct terrain_drawing_data *terrain[MAX_NUM_TERRAINS];
+  struct {
+    struct Sprite *base;
+
+    struct anim {
+#define MAX_NUM_FRAMES 32
+      int count; /* Zero or more frames. */
+      struct Sprite *frame[MAX_NUM_FRAMES];
+    } anim[ANIM_COUNT][DIR8_COUNT];
+  } units[U_LAST];
 };
 
 extern struct named_sprites sprites;
@@ -269,6 +284,7 @@
 struct Sprite *get_citizen_sprite(struct citizen_type type,
                                  int citizen_index,
                                  const struct city *pcity);
+#define get_unit_sprite(type) (sprites.units[type].base)
 
 /* full pathnames: */
 extern char *main_intro_filename;
@@ -315,6 +331,9 @@
 extern bool is_isometric;
 extern int hex_width, hex_height;
 
+/* Center pixel of animation graphics: it gets placed at the tile center. */
+extern int anim_center_x, anim_center_y;
+
 /* name of font to use to draw city names on main map */
 
 extern char *city_names_font;
@@ -325,6 +344,9 @@
 
 extern int num_tiles_explode_unit;
 
+/* HACK: if this tile is non-NULL, no units will be drawn on the tile. */
+extern struct tile *hidden_units_tile;
+
 struct Sprite *load_sprite(const char *tag_name);
 void unload_sprite(const char *tag_name);
 bool sprite_exists(const char *tag_name);
Index: client/gui-gtk-2.0/graphics.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/graphics.c,v
retrieving revision 1.26
diff -u -r1.26 graphics.c
--- client/gui-gtk-2.0/graphics.c       3 Jun 2004 13:53:42 -0000       1.26
+++ client/gui-gtk-2.0/graphics.c       23 Oct 2004 01:59:13 -0000
@@ -389,7 +389,7 @@
   int width, height;
   struct unit_type *type = get_unit_type(i);
 
-  sprite_get_bounding_box(type->sprite, &x1, &y1, &x2, &y2);
+  sprite_get_bounding_box(get_unit_sprite(i), &x1, &y1, &x2, &y2);
   if (pcanvas->type == CANVAS_PIXBUF) {
     width = gdk_pixbuf_get_width(pcanvas->v.pixbuf);
     height = gdk_pixbuf_get_height(pcanvas->v.pixbuf);
@@ -410,7 +410,7 @@
   canvas_put_rectangle(pcanvas, bg_color, 0, 0, width, height);
 
   /* Finally, put a picture of the unit in the tile */
-  canvas_put_sprite(pcanvas, 0, 0, type->sprite, 
+  canvas_put_sprite(pcanvas, 0, 0, get_unit_sprite(i), 
       (x2 + x1 - width) / 2, (y1 + y2 - height) / 2, 
       UNIT_TILE_WIDTH - (x2 + x1 - width) / 2, 
       UNIT_TILE_HEIGHT - (y1 + y2 - height) / 2);
Index: client/gui-gtk-2.0/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapview.c,v
retrieving revision 1.145
diff -u -r1.145 mapview.c
--- client/gui-gtk-2.0/mapview.c        19 Oct 2004 21:17:34 -0000      1.145
+++ client/gui-gtk-2.0/mapview.c        23 Oct 2004 01:59:13 -0000
@@ -722,6 +722,17 @@
       {
        GdkPixbuf *src, *dst;
 
+       /* FIXME: is this right??? */
+       if (canvas_x < 0) {
+         offset_x -= canvas_x;
+         canvas_x = 0;
+       }
+       if (canvas_y < 0) {
+         offset_y -= canvas_y;
+         canvas_y = 0;
+       }
+
+
        src = sprite_get_pixbuf(sprite);
        dst = pcanvas->v.pixbuf;
        gdk_pixbuf_composite(src, dst, canvas_x, canvas_y,
Index: client/gui-gtk-2.0/wldlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/wldlg.c,v
retrieving revision 1.36
diff -u -r1.36 wldlg.c
--- client/gui-gtk-2.0/wldlg.c  3 Jun 2004 13:53:42 -0000       1.36
+++ client/gui-gtk-2.0/wldlg.c  23 Oct 2004 01:59:13 -0000
@@ -79,10 +79,9 @@
   max_unit_width = 0;
 
   unit_type_iterate(i) {
-    struct unit_type *type = get_unit_type(i);
     int x1, x2, y1, y2;
 
-    sprite_get_bounding_box(type->sprite, &x1, &y1, &x2, &y2);
+    sprite_get_bounding_box(get_unit_sprite(i), &x1, &y1, &x2, &y2);
     max_unit_width = MAX(max_unit_width, x2 - x1);
     max_unit_height = MAX(max_unit_height, y2 - y1);
   } unit_type_iterate_end;
Index: common/unit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v
retrieving revision 1.220
diff -u -r1.220 unit.c
--- common/unit.c       18 Oct 2004 22:40:02 -0000      1.220
+++ common/unit.c       23 Oct 2004 01:59:13 -0000
@@ -18,6 +18,8 @@
 #include <assert.h>
 
 #include "fcintl.h"
+#include "rand.h"
+
 #include "game.h"
 #include "log.h"
 #include "map.h"
@@ -1739,6 +1741,7 @@
   set_unit_activity(punit, ACTIVITY_IDLE);
   punit->occupy = 0;
   punit->client.color = DEFAULT_CITY_COLOR;
+  punit->client.facing = map.valid_dirs[myrand(map.num_valid_dirs)];
   punit->has_orders = FALSE;
 
   return punit;
Index: common/unit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v
retrieving revision 1.129
diff -u -r1.129 unit.h
--- common/unit.h       20 Oct 2004 18:20:53 -0000      1.129
+++ common/unit.h       23 Oct 2004 01:59:14 -0000
@@ -166,6 +166,10 @@
   struct {
     /* Equivalent to pcity->client.color.  Only for F_CITIES units. */
     int color;
+
+    /* The direction the unit is facing (this is a direction8 but we need
+     * some fc_types.h magic to use that here).  This is a GUI direction. */
+    int facing;
   } client;
 
   bool has_orders;
Index: common/unittype.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unittype.h,v
retrieving revision 1.31
diff -u -r1.31 unittype.h
--- common/unittype.h   3 Sep 2004 04:22:37 -0000       1.31
+++ common/unittype.h   23 Oct 2004 01:59:14 -0000
@@ -17,8 +17,6 @@
 
 #include "fc_types.h"
 
-struct Sprite;                 /* opaque; client-gui specific */
-
 typedef int Unit_Type_id;
 /*
   Above typedef replaces old "enum unit_type_id" (since no longer
@@ -182,7 +180,6 @@
   char sound_move_alt[MAX_LEN_NAME];
   char sound_fight[MAX_LEN_NAME];
   char sound_fight_alt[MAX_LEN_NAME];
-  struct Sprite *sprite;
   enum unit_move_type move_type;
   int build_cost;                      /* Use wrappers to access this. */
   int pop_cost;  /* number of workers the unit contains (e.g., settlers, 
engineers)*/
Index: data/isotrident.tilespec
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/isotrident.tilespec,v
retrieving revision 1.21
diff -u -r1.21 isotrident.tilespec
--- data/isotrident.tilespec    4 Oct 2004 19:39:18 -0000       1.21
+++ data/isotrident.tilespec    23 Oct 2004 01:59:14 -0000
@@ -31,6 +31,9 @@
 flag_offset_x = 17
 flag_offset_y = 11
 
+anim_center_x = 40
+anim_center_y = 48
+
 ; Font to use to draw city names:
 city_names_font = "9x15bold"
 
@@ -52,6 +55,7 @@
   "isotrident/tiles.spec",
   "misc/small.spec",
   "isotrident/units.spec",
+  "misc/warriors.spec",
   "misc/flags.spec",
   "misc/buildings.spec",
   "misc/space.spec",
Index: data/misc/gen.pl
===================================================================
RCS file: data/misc/gen.pl
diff -N data/misc/gen.pl
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ data/misc/gen.pl    23 Oct 2004 01:59:14 -0000
@@ -0,0 +1,50 @@
+#! /usr/bin/perl
+
+$unit = $ARGV[0];
+
+print <<EOF
+[spec]
+
+; Format and options of this spec file:
+options = "+spec3"
+
+[info]
+
+artists = "
+    (insert artists here)
+"
+
+[file]
+gfx = "misc/$unit"
+
+[grid_main]
+
+x_top_left = 0
+y_top_left = 0
+dx = 80
+dy = 80
+
+tiles = { "row", "column", "tag"
+EOF
+;
+
+# Must match the order of types in the gfx
+@types = ("die", "attack", "fortify", "move", "stand");
+
+# Must match the order of directions in the gfx
+@dirs = ("n", "ne", "e", "se", "s", "sw", "w", "nw");
+
+# Must match number of frames in the gfx
+$frames = 16;
+
+$line = 0;
+foreach $type (@types) {
+  foreach $dir (@dirs) {
+    for ($frame = 0; $frame < $frames; $frame++) {
+      print "  $line, $frame, \"u.$unit.$type.$dir.$frame\"\n";
+    }
+    $line++;
+  }
+}
+
+print "}\n";
Index: data/misc/warriors.spec
===================================================================
RCS file: data/misc/warriors.spec
diff -N data/misc/warriors.spec
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ data/misc/warriors.spec     23 Oct 2004 01:59:14 -0000
@@ -0,0 +1,663 @@
+[spec]
+
+; Format and options of this spec file:
+options = "+spec3"
+
+[info]
+
+artists = "
+    (insert artists here)
+"
+
+[file]
+gfx = "misc/warriors"
+
+[grid_main]
+
+x_top_left = 0
+y_top_left = 0
+dx = 80
+dy = 80
+
+tiles = { "row", "column", "tag"
+  0, 0, "u.warriors.die.n.0"
+  0, 1, "u.warriors.die.n.1"
+  0, 2, "u.warriors.die.n.2"
+  0, 3, "u.warriors.die.n.3"
+  0, 4, "u.warriors.die.n.4"
+  0, 5, "u.warriors.die.n.5"
+  0, 6, "u.warriors.die.n.6"
+  0, 7, "u.warriors.die.n.7"
+  0, 8, "u.warriors.die.n.8"
+  0, 9, "u.warriors.die.n.9"
+  0, 10, "u.warriors.die.n.10"
+  0, 11, "u.warriors.die.n.11"
+  0, 12, "u.warriors.die.n.12"
+  0, 13, "u.warriors.die.n.13"
+  0, 14, "u.warriors.die.n.14"
+  0, 15, "u.warriors.die.n.15"
+  1, 0, "u.warriors.die.ne.0"
+  1, 1, "u.warriors.die.ne.1"
+  1, 2, "u.warriors.die.ne.2"
+  1, 3, "u.warriors.die.ne.3"
+  1, 4, "u.warriors.die.ne.4"
+  1, 5, "u.warriors.die.ne.5"
+  1, 6, "u.warriors.die.ne.6"
+  1, 7, "u.warriors.die.ne.7"
+  1, 8, "u.warriors.die.ne.8"
+  1, 9, "u.warriors.die.ne.9"
+  1, 10, "u.warriors.die.ne.10"
+  1, 11, "u.warriors.die.ne.11"
+  1, 12, "u.warriors.die.ne.12"
+  1, 13, "u.warriors.die.ne.13"
+  1, 14, "u.warriors.die.ne.14"
+  1, 15, "u.warriors.die.ne.15"
+  2, 0, "u.warriors.die.e.0"
+  2, 1, "u.warriors.die.e.1"
+  2, 2, "u.warriors.die.e.2"
+  2, 3, "u.warriors.die.e.3"
+  2, 4, "u.warriors.die.e.4"
+  2, 5, "u.warriors.die.e.5"
+  2, 6, "u.warriors.die.e.6"
+  2, 7, "u.warriors.die.e.7"
+  2, 8, "u.warriors.die.e.8"
+  2, 9, "u.warriors.die.e.9"
+  2, 10, "u.warriors.die.e.10"
+  2, 11, "u.warriors.die.e.11"
+  2, 12, "u.warriors.die.e.12"
+  2, 13, "u.warriors.die.e.13"
+  2, 14, "u.warriors.die.e.14"
+  2, 15, "u.warriors.die.e.15"
+  3, 0, "u.warriors.die.se.0"
+  3, 1, "u.warriors.die.se.1"
+  3, 2, "u.warriors.die.se.2"
+  3, 3, "u.warriors.die.se.3"
+  3, 4, "u.warriors.die.se.4"
+  3, 5, "u.warriors.die.se.5"
+  3, 6, "u.warriors.die.se.6"
+  3, 7, "u.warriors.die.se.7"
+  3, 8, "u.warriors.die.se.8"
+  3, 9, "u.warriors.die.se.9"
+  3, 10, "u.warriors.die.se.10"
+  3, 11, "u.warriors.die.se.11"
+  3, 12, "u.warriors.die.se.12"
+  3, 13, "u.warriors.die.se.13"
+  3, 14, "u.warriors.die.se.14"
+  3, 15, "u.warriors.die.se.15"
+  4, 0, "u.warriors.die.s.0"
+  4, 1, "u.warriors.die.s.1"
+  4, 2, "u.warriors.die.s.2"
+  4, 3, "u.warriors.die.s.3"
+  4, 4, "u.warriors.die.s.4"
+  4, 5, "u.warriors.die.s.5"
+  4, 6, "u.warriors.die.s.6"
+  4, 7, "u.warriors.die.s.7"
+  4, 8, "u.warriors.die.s.8"
+  4, 9, "u.warriors.die.s.9"
+  4, 10, "u.warriors.die.s.10"
+  4, 11, "u.warriors.die.s.11"
+  4, 12, "u.warriors.die.s.12"
+  4, 13, "u.warriors.die.s.13"
+  4, 14, "u.warriors.die.s.14"
+  4, 15, "u.warriors.die.s.15"
+  5, 0, "u.warriors.die.sw.0"
+  5, 1, "u.warriors.die.sw.1"
+  5, 2, "u.warriors.die.sw.2"
+  5, 3, "u.warriors.die.sw.3"
+  5, 4, "u.warriors.die.sw.4"
+  5, 5, "u.warriors.die.sw.5"
+  5, 6, "u.warriors.die.sw.6"
+  5, 7, "u.warriors.die.sw.7"
+  5, 8, "u.warriors.die.sw.8"
+  5, 9, "u.warriors.die.sw.9"
+  5, 10, "u.warriors.die.sw.10"
+  5, 11, "u.warriors.die.sw.11"
+  5, 12, "u.warriors.die.sw.12"
+  5, 13, "u.warriors.die.sw.13"
+  5, 14, "u.warriors.die.sw.14"
+  5, 15, "u.warriors.die.sw.15"
+  6, 0, "u.warriors.die.w.0"
+  6, 1, "u.warriors.die.w.1"
+  6, 2, "u.warriors.die.w.2"
+  6, 3, "u.warriors.die.w.3"
+  6, 4, "u.warriors.die.w.4"
+  6, 5, "u.warriors.die.w.5"
+  6, 6, "u.warriors.die.w.6"
+  6, 7, "u.warriors.die.w.7"
+  6, 8, "u.warriors.die.w.8"
+  6, 9, "u.warriors.die.w.9"
+  6, 10, "u.warriors.die.w.10"
+  6, 11, "u.warriors.die.w.11"
+  6, 12, "u.warriors.die.w.12"
+  6, 13, "u.warriors.die.w.13"
+  6, 14, "u.warriors.die.w.14"
+  6, 15, "u.warriors.die.w.15"
+  7, 0, "u.warriors.die.nw.0"
+  7, 1, "u.warriors.die.nw.1"
+  7, 2, "u.warriors.die.nw.2"
+  7, 3, "u.warriors.die.nw.3"
+  7, 4, "u.warriors.die.nw.4"
+  7, 5, "u.warriors.die.nw.5"
+  7, 6, "u.warriors.die.nw.6"
+  7, 7, "u.warriors.die.nw.7"
+  7, 8, "u.warriors.die.nw.8"
+  7, 9, "u.warriors.die.nw.9"
+  7, 10, "u.warriors.die.nw.10"
+  7, 11, "u.warriors.die.nw.11"
+  7, 12, "u.warriors.die.nw.12"
+  7, 13, "u.warriors.die.nw.13"
+  7, 14, "u.warriors.die.nw.14"
+  7, 15, "u.warriors.die.nw.15"
+  8, 0, "u.warriors.attack.n.0"
+  8, 1, "u.warriors.attack.n.1"
+  8, 2, "u.warriors.attack.n.2"
+  8, 3, "u.warriors.attack.n.3"
+  8, 4, "u.warriors.attack.n.4"
+  8, 5, "u.warriors.attack.n.5"
+  8, 6, "u.warriors.attack.n.6"
+  8, 7, "u.warriors.attack.n.7"
+  8, 8, "u.warriors.attack.n.8"
+  8, 9, "u.warriors.attack.n.9"
+  8, 10, "u.warriors.attack.n.10"
+  8, 11, "u.warriors.attack.n.11"
+  8, 12, "u.warriors.attack.n.12"
+  8, 13, "u.warriors.attack.n.13"
+  8, 14, "u.warriors.attack.n.14"
+  8, 15, "u.warriors.attack.n.15"
+  9, 0, "u.warriors.attack.ne.0"
+  9, 1, "u.warriors.attack.ne.1"
+  9, 2, "u.warriors.attack.ne.2"
+  9, 3, "u.warriors.attack.ne.3"
+  9, 4, "u.warriors.attack.ne.4"
+  9, 5, "u.warriors.attack.ne.5"
+  9, 6, "u.warriors.attack.ne.6"
+  9, 7, "u.warriors.attack.ne.7"
+  9, 8, "u.warriors.attack.ne.8"
+  9, 9, "u.warriors.attack.ne.9"
+  9, 10, "u.warriors.attack.ne.10"
+  9, 11, "u.warriors.attack.ne.11"
+  9, 12, "u.warriors.attack.ne.12"
+  9, 13, "u.warriors.attack.ne.13"
+  9, 14, "u.warriors.attack.ne.14"
+  9, 15, "u.warriors.attack.ne.15"
+  10, 0, "u.warriors.attack.e.0"
+  10, 1, "u.warriors.attack.e.1"
+  10, 2, "u.warriors.attack.e.2"
+  10, 3, "u.warriors.attack.e.3"
+  10, 4, "u.warriors.attack.e.4"
+  10, 5, "u.warriors.attack.e.5"
+  10, 6, "u.warriors.attack.e.6"
+  10, 7, "u.warriors.attack.e.7"
+  10, 8, "u.warriors.attack.e.8"
+  10, 9, "u.warriors.attack.e.9"
+  10, 10, "u.warriors.attack.e.10"
+  10, 11, "u.warriors.attack.e.11"
+  10, 12, "u.warriors.attack.e.12"
+  10, 13, "u.warriors.attack.e.13"
+  10, 14, "u.warriors.attack.e.14"
+  10, 15, "u.warriors.attack.e.15"
+  11, 0, "u.warriors.attack.se.0"
+  11, 1, "u.warriors.attack.se.1"
+  11, 2, "u.warriors.attack.se.2"
+  11, 3, "u.warriors.attack.se.3"
+  11, 4, "u.warriors.attack.se.4"
+  11, 5, "u.warriors.attack.se.5"
+  11, 6, "u.warriors.attack.se.6"
+  11, 7, "u.warriors.attack.se.7"
+  11, 8, "u.warriors.attack.se.8"
+  11, 9, "u.warriors.attack.se.9"
+  11, 10, "u.warriors.attack.se.10"
+  11, 11, "u.warriors.attack.se.11"
+  11, 12, "u.warriors.attack.se.12"
+  11, 13, "u.warriors.attack.se.13"
+  11, 14, "u.warriors.attack.se.14"
+  11, 15, "u.warriors.attack.se.15"
+  12, 0, "u.warriors.attack.s.0"
+  12, 1, "u.warriors.attack.s.1"
+  12, 2, "u.warriors.attack.s.2"
+  12, 3, "u.warriors.attack.s.3"
+  12, 4, "u.warriors.attack.s.4"
+  12, 5, "u.warriors.attack.s.5"
+  12, 6, "u.warriors.attack.s.6"
+  12, 7, "u.warriors.attack.s.7"
+  12, 8, "u.warriors.attack.s.8"
+  12, 9, "u.warriors.attack.s.9"
+  12, 10, "u.warriors.attack.s.10"
+  12, 11, "u.warriors.attack.s.11"
+  12, 12, "u.warriors.attack.s.12"
+  12, 13, "u.warriors.attack.s.13"
+  12, 14, "u.warriors.attack.s.14"
+  12, 15, "u.warriors.attack.s.15"
+  13, 0, "u.warriors.attack.sw.0"
+  13, 1, "u.warriors.attack.sw.1"
+  13, 2, "u.warriors.attack.sw.2"
+  13, 3, "u.warriors.attack.sw.3"
+  13, 4, "u.warriors.attack.sw.4"
+  13, 5, "u.warriors.attack.sw.5"
+  13, 6, "u.warriors.attack.sw.6"
+  13, 7, "u.warriors.attack.sw.7"
+  13, 8, "u.warriors.attack.sw.8"
+  13, 9, "u.warriors.attack.sw.9"
+  13, 10, "u.warriors.attack.sw.10"
+  13, 11, "u.warriors.attack.sw.11"
+  13, 12, "u.warriors.attack.sw.12"
+  13, 13, "u.warriors.attack.sw.13"
+  13, 14, "u.warriors.attack.sw.14"
+  13, 15, "u.warriors.attack.sw.15"
+  14, 0, "u.warriors.attack.w.0"
+  14, 1, "u.warriors.attack.w.1"
+  14, 2, "u.warriors.attack.w.2"
+  14, 3, "u.warriors.attack.w.3"
+  14, 4, "u.warriors.attack.w.4"
+  14, 5, "u.warriors.attack.w.5"
+  14, 6, "u.warriors.attack.w.6"
+  14, 7, "u.warriors.attack.w.7"
+  14, 8, "u.warriors.attack.w.8"
+  14, 9, "u.warriors.attack.w.9"
+  14, 10, "u.warriors.attack.w.10"
+  14, 11, "u.warriors.attack.w.11"
+  14, 12, "u.warriors.attack.w.12"
+  14, 13, "u.warriors.attack.w.13"
+  14, 14, "u.warriors.attack.w.14"
+  14, 15, "u.warriors.attack.w.15"
+  15, 0, "u.warriors.attack.nw.0"
+  15, 1, "u.warriors.attack.nw.1"
+  15, 2, "u.warriors.attack.nw.2"
+  15, 3, "u.warriors.attack.nw.3"
+  15, 4, "u.warriors.attack.nw.4"
+  15, 5, "u.warriors.attack.nw.5"
+  15, 6, "u.warriors.attack.nw.6"
+  15, 7, "u.warriors.attack.nw.7"
+  15, 8, "u.warriors.attack.nw.8"
+  15, 9, "u.warriors.attack.nw.9"
+  15, 10, "u.warriors.attack.nw.10"
+  15, 11, "u.warriors.attack.nw.11"
+  15, 12, "u.warriors.attack.nw.12"
+  15, 13, "u.warriors.attack.nw.13"
+  15, 14, "u.warriors.attack.nw.14"
+  15, 15, "u.warriors.attack.nw.15"
+  16, 0, "u.warriors.fortify.n.0"
+  16, 1, "u.warriors.fortify.n.1"
+  16, 2, "u.warriors.fortify.n.2"
+  16, 3, "u.warriors.fortify.n.3"
+  16, 4, "u.warriors.fortify.n.4"
+  16, 5, "u.warriors.fortify.n.5"
+  16, 6, "u.warriors.fortify.n.6"
+  16, 7, "u.warriors.fortify.n.7"
+  16, 8, "u.warriors.fortify.n.8"
+  16, 9, "u.warriors.fortify.n.9"
+  16, 10, "u.warriors.fortify.n.10"
+  16, 11, "u.warriors.fortify.n.11"
+  16, 12, "u.warriors.fortify.n.12"
+  16, 13, "u.warriors.fortify.n.13"
+  16, 14, "u.warriors.fortify.n.14"
+  16, 15, "u.warriors.fortify.n.15"
+  17, 0, "u.warriors.fortify.ne.0"
+  17, 1, "u.warriors.fortify.ne.1"
+  17, 2, "u.warriors.fortify.ne.2"
+  17, 3, "u.warriors.fortify.ne.3"
+  17, 4, "u.warriors.fortify.ne.4"
+  17, 5, "u.warriors.fortify.ne.5"
+  17, 6, "u.warriors.fortify.ne.6"
+  17, 7, "u.warriors.fortify.ne.7"
+  17, 8, "u.warriors.fortify.ne.8"
+  17, 9, "u.warriors.fortify.ne.9"
+  17, 10, "u.warriors.fortify.ne.10"
+  17, 11, "u.warriors.fortify.ne.11"
+  17, 12, "u.warriors.fortify.ne.12"
+  17, 13, "u.warriors.fortify.ne.13"
+  17, 14, "u.warriors.fortify.ne.14"
+  17, 15, "u.warriors.fortify.ne.15"
+  18, 0, "u.warriors.fortify.e.0"
+  18, 1, "u.warriors.fortify.e.1"
+  18, 2, "u.warriors.fortify.e.2"
+  18, 3, "u.warriors.fortify.e.3"
+  18, 4, "u.warriors.fortify.e.4"
+  18, 5, "u.warriors.fortify.e.5"
+  18, 6, "u.warriors.fortify.e.6"
+  18, 7, "u.warriors.fortify.e.7"
+  18, 8, "u.warriors.fortify.e.8"
+  18, 9, "u.warriors.fortify.e.9"
+  18, 10, "u.warriors.fortify.e.10"
+  18, 11, "u.warriors.fortify.e.11"
+  18, 12, "u.warriors.fortify.e.12"
+  18, 13, "u.warriors.fortify.e.13"
+  18, 14, "u.warriors.fortify.e.14"
+  18, 15, "u.warriors.fortify.e.15"
+  19, 0, "u.warriors.fortify.se.0"
+  19, 1, "u.warriors.fortify.se.1"
+  19, 2, "u.warriors.fortify.se.2"
+  19, 3, "u.warriors.fortify.se.3"
+  19, 4, "u.warriors.fortify.se.4"
+  19, 5, "u.warriors.fortify.se.5"
+  19, 6, "u.warriors.fortify.se.6"
+  19, 7, "u.warriors.fortify.se.7"
+  19, 8, "u.warriors.fortify.se.8"
+  19, 9, "u.warriors.fortify.se.9"
+  19, 10, "u.warriors.fortify.se.10"
+  19, 11, "u.warriors.fortify.se.11"
+  19, 12, "u.warriors.fortify.se.12"
+  19, 13, "u.warriors.fortify.se.13"
+  19, 14, "u.warriors.fortify.se.14"
+  19, 15, "u.warriors.fortify.se.15"
+  20, 0, "u.warriors.fortify.s.0"
+  20, 1, "u.warriors.fortify.s.1"
+  20, 2, "u.warriors.fortify.s.2"
+  20, 3, "u.warriors.fortify.s.3"
+  20, 4, "u.warriors.fortify.s.4"
+  20, 5, "u.warriors.fortify.s.5"
+  20, 6, "u.warriors.fortify.s.6"
+  20, 7, "u.warriors.fortify.s.7"
+  20, 8, "u.warriors.fortify.s.8"
+  20, 9, "u.warriors.fortify.s.9"
+  20, 10, "u.warriors.fortify.s.10"
+  20, 11, "u.warriors.fortify.s.11"
+  20, 12, "u.warriors.fortify.s.12"
+  20, 13, "u.warriors.fortify.s.13"
+  20, 14, "u.warriors.fortify.s.14"
+  20, 15, "u.warriors.fortify.s.15"
+  21, 0, "u.warriors.fortify.sw.0"
+  21, 1, "u.warriors.fortify.sw.1"
+  21, 2, "u.warriors.fortify.sw.2"
+  21, 3, "u.warriors.fortify.sw.3"
+  21, 4, "u.warriors.fortify.sw.4"
+  21, 5, "u.warriors.fortify.sw.5"
+  21, 6, "u.warriors.fortify.sw.6"
+  21, 7, "u.warriors.fortify.sw.7"
+  21, 8, "u.warriors.fortify.sw.8"
+  21, 9, "u.warriors.fortify.sw.9"
+  21, 10, "u.warriors.fortify.sw.10"
+  21, 11, "u.warriors.fortify.sw.11"
+  21, 12, "u.warriors.fortify.sw.12"
+  21, 13, "u.warriors.fortify.sw.13"
+  21, 14, "u.warriors.fortify.sw.14"
+  21, 15, "u.warriors.fortify.sw.15"
+  22, 0, "u.warriors.fortify.w.0"
+  22, 1, "u.warriors.fortify.w.1"
+  22, 2, "u.warriors.fortify.w.2"
+  22, 3, "u.warriors.fortify.w.3"
+  22, 4, "u.warriors.fortify.w.4"
+  22, 5, "u.warriors.fortify.w.5"
+  22, 6, "u.warriors.fortify.w.6"
+  22, 7, "u.warriors.fortify.w.7"
+  22, 8, "u.warriors.fortify.w.8"
+  22, 9, "u.warriors.fortify.w.9"
+  22, 10, "u.warriors.fortify.w.10"
+  22, 11, "u.warriors.fortify.w.11"
+  22, 12, "u.warriors.fortify.w.12"
+  22, 13, "u.warriors.fortify.w.13"
+  22, 14, "u.warriors.fortify.w.14"
+  22, 15, "u.warriors.fortify.w.15"
+  23, 0, "u.warriors.fortify.nw.0"
+  23, 1, "u.warriors.fortify.nw.1"
+  23, 2, "u.warriors.fortify.nw.2"
+  23, 3, "u.warriors.fortify.nw.3"
+  23, 4, "u.warriors.fortify.nw.4"
+  23, 5, "u.warriors.fortify.nw.5"
+  23, 6, "u.warriors.fortify.nw.6"
+  23, 7, "u.warriors.fortify.nw.7"
+  23, 8, "u.warriors.fortify.nw.8"
+  23, 9, "u.warriors.fortify.nw.9"
+  23, 10, "u.warriors.fortify.nw.10"
+  23, 11, "u.warriors.fortify.nw.11"
+  23, 12, "u.warriors.fortify.nw.12"
+  23, 13, "u.warriors.fortify.nw.13"
+  23, 14, "u.warriors.fortify.nw.14"
+  23, 15, "u.warriors.fortify.nw.15"
+  24, 0, "u.warriors.move.n.0"
+  24, 1, "u.warriors.move.n.1"
+  24, 2, "u.warriors.move.n.2"
+  24, 3, "u.warriors.move.n.3"
+  24, 4, "u.warriors.move.n.4"
+  24, 5, "u.warriors.move.n.5"
+  24, 6, "u.warriors.move.n.6"
+  24, 7, "u.warriors.move.n.7"
+  24, 8, "u.warriors.move.n.8"
+  24, 9, "u.warriors.move.n.9"
+  24, 10, "u.warriors.move.n.10"
+  24, 11, "u.warriors.move.n.11"
+  24, 12, "u.warriors.move.n.12"
+  24, 13, "u.warriors.move.n.13"
+  24, 14, "u.warriors.move.n.14"
+  24, 15, "u.warriors.move.n.15"
+  25, 0, "u.warriors.move.ne.0"
+  25, 1, "u.warriors.move.ne.1"
+  25, 2, "u.warriors.move.ne.2"
+  25, 3, "u.warriors.move.ne.3"
+  25, 4, "u.warriors.move.ne.4"
+  25, 5, "u.warriors.move.ne.5"
+  25, 6, "u.warriors.move.ne.6"
+  25, 7, "u.warriors.move.ne.7"
+  25, 8, "u.warriors.move.ne.8"
+  25, 9, "u.warriors.move.ne.9"
+  25, 10, "u.warriors.move.ne.10"
+  25, 11, "u.warriors.move.ne.11"
+  25, 12, "u.warriors.move.ne.12"
+  25, 13, "u.warriors.move.ne.13"
+  25, 14, "u.warriors.move.ne.14"
+  25, 15, "u.warriors.move.ne.15"
+  26, 0, "u.warriors.move.e.0"
+  26, 1, "u.warriors.move.e.1"
+  26, 2, "u.warriors.move.e.2"
+  26, 3, "u.warriors.move.e.3"
+  26, 4, "u.warriors.move.e.4"
+  26, 5, "u.warriors.move.e.5"
+  26, 6, "u.warriors.move.e.6"
+  26, 7, "u.warriors.move.e.7"
+  26, 8, "u.warriors.move.e.8"
+  26, 9, "u.warriors.move.e.9"
+  26, 10, "u.warriors.move.e.10"
+  26, 11, "u.warriors.move.e.11"
+  26, 12, "u.warriors.move.e.12"
+  26, 13, "u.warriors.move.e.13"
+  26, 14, "u.warriors.move.e.14"
+  26, 15, "u.warriors.move.e.15"
+  27, 0, "u.warriors.move.se.0"
+  27, 1, "u.warriors.move.se.1"
+  27, 2, "u.warriors.move.se.2"
+  27, 3, "u.warriors.move.se.3"
+  27, 4, "u.warriors.move.se.4"
+  27, 5, "u.warriors.move.se.5"
+  27, 6, "u.warriors.move.se.6"
+  27, 7, "u.warriors.move.se.7"
+  27, 8, "u.warriors.move.se.8"
+  27, 9, "u.warriors.move.se.9"
+  27, 10, "u.warriors.move.se.10"
+  27, 11, "u.warriors.move.se.11"
+  27, 12, "u.warriors.move.se.12"
+  27, 13, "u.warriors.move.se.13"
+  27, 14, "u.warriors.move.se.14"
+  27, 15, "u.warriors.move.se.15"
+  28, 0, "u.warriors.move.s.0"
+  28, 1, "u.warriors.move.s.1"
+  28, 2, "u.warriors.move.s.2"
+  28, 3, "u.warriors.move.s.3"
+  28, 4, "u.warriors.move.s.4"
+  28, 5, "u.warriors.move.s.5"
+  28, 6, "u.warriors.move.s.6"
+  28, 7, "u.warriors.move.s.7"
+  28, 8, "u.warriors.move.s.8"
+  28, 9, "u.warriors.move.s.9"
+  28, 10, "u.warriors.move.s.10"
+  28, 11, "u.warriors.move.s.11"
+  28, 12, "u.warriors.move.s.12"
+  28, 13, "u.warriors.move.s.13"
+  28, 14, "u.warriors.move.s.14"
+  28, 15, "u.warriors.move.s.15"
+  29, 0, "u.warriors.move.sw.0"
+  29, 1, "u.warriors.move.sw.1"
+  29, 2, "u.warriors.move.sw.2"
+  29, 3, "u.warriors.move.sw.3"
+  29, 4, "u.warriors.move.sw.4"
+  29, 5, "u.warriors.move.sw.5"
+  29, 6, "u.warriors.move.sw.6"
+  29, 7, "u.warriors.move.sw.7"
+  29, 8, "u.warriors.move.sw.8"
+  29, 9, "u.warriors.move.sw.9"
+  29, 10, "u.warriors.move.sw.10"
+  29, 11, "u.warriors.move.sw.11"
+  29, 12, "u.warriors.move.sw.12"
+  29, 13, "u.warriors.move.sw.13"
+  29, 14, "u.warriors.move.sw.14"
+  29, 15, "u.warriors.move.sw.15"
+  30, 0, "u.warriors.move.w.0"
+  30, 1, "u.warriors.move.w.1"
+  30, 2, "u.warriors.move.w.2"
+  30, 3, "u.warriors.move.w.3"
+  30, 4, "u.warriors.move.w.4"
+  30, 5, "u.warriors.move.w.5"
+  30, 6, "u.warriors.move.w.6"
+  30, 7, "u.warriors.move.w.7"
+  30, 8, "u.warriors.move.w.8"
+  30, 9, "u.warriors.move.w.9"
+  30, 10, "u.warriors.move.w.10"
+  30, 11, "u.warriors.move.w.11"
+  30, 12, "u.warriors.move.w.12"
+  30, 13, "u.warriors.move.w.13"
+  30, 14, "u.warriors.move.w.14"
+  30, 15, "u.warriors.move.w.15"
+  31, 0, "u.warriors.move.nw.0"
+  31, 1, "u.warriors.move.nw.1"
+  31, 2, "u.warriors.move.nw.2"
+  31, 3, "u.warriors.move.nw.3"
+  31, 4, "u.warriors.move.nw.4"
+  31, 5, "u.warriors.move.nw.5"
+  31, 6, "u.warriors.move.nw.6"
+  31, 7, "u.warriors.move.nw.7"
+  31, 8, "u.warriors.move.nw.8"
+  31, 9, "u.warriors.move.nw.9"
+  31, 10, "u.warriors.move.nw.10"
+  31, 11, "u.warriors.move.nw.11"
+  31, 12, "u.warriors.move.nw.12"
+  31, 13, "u.warriors.move.nw.13"
+  31, 14, "u.warriors.move.nw.14"
+  31, 15, "u.warriors.move.nw.15"
+  32, 0, "u.warriors.stand.n.0"
+  32, 1, "u.warriors.stand.n.1"
+  32, 2, "u.warriors.stand.n.2"
+  32, 3, "u.warriors.stand.n.3"
+  32, 4, "u.warriors.stand.n.4"
+  32, 5, "u.warriors.stand.n.5"
+  32, 6, "u.warriors.stand.n.6"
+  32, 7, "u.warriors.stand.n.7"
+  32, 8, "u.warriors.stand.n.8"
+  32, 9, "u.warriors.stand.n.9"
+  32, 10, "u.warriors.stand.n.10"
+  32, 11, "u.warriors.stand.n.11"
+  32, 12, "u.warriors.stand.n.12"
+  32, 13, "u.warriors.stand.n.13"
+  32, 14, "u.warriors.stand.n.14"
+  32, 15, "u.warriors.stand.n.15"
+  33, 0, "u.warriors.stand.ne.0"
+  33, 1, "u.warriors.stand.ne.1"
+  33, 2, "u.warriors.stand.ne.2"
+  33, 3, "u.warriors.stand.ne.3"
+  33, 4, "u.warriors.stand.ne.4"
+  33, 5, "u.warriors.stand.ne.5"
+  33, 6, "u.warriors.stand.ne.6"
+  33, 7, "u.warriors.stand.ne.7"
+  33, 8, "u.warriors.stand.ne.8"
+  33, 9, "u.warriors.stand.ne.9"
+  33, 10, "u.warriors.stand.ne.10"
+  33, 11, "u.warriors.stand.ne.11"
+  33, 12, "u.warriors.stand.ne.12"
+  33, 13, "u.warriors.stand.ne.13"
+  33, 14, "u.warriors.stand.ne.14"
+  33, 15, "u.warriors.stand.ne.15"
+  34, 0, "u.warriors.stand.e.0"
+  34, 1, "u.warriors.stand.e.1"
+  34, 2, "u.warriors.stand.e.2"
+  34, 3, "u.warriors.stand.e.3"
+  34, 4, "u.warriors.stand.e.4"
+  34, 5, "u.warriors.stand.e.5"
+  34, 6, "u.warriors.stand.e.6"
+  34, 7, "u.warriors.stand.e.7"
+  34, 8, "u.warriors.stand.e.8"
+  34, 9, "u.warriors.stand.e.9"
+  34, 10, "u.warriors.stand.e.10"
+  34, 11, "u.warriors.stand.e.11"
+  34, 12, "u.warriors.stand.e.12"
+  34, 13, "u.warriors.stand.e.13"
+  34, 14, "u.warriors.stand.e.14"
+  34, 15, "u.warriors.stand.e.15"
+  35, 0, "u.warriors.stand.se.0"
+  35, 1, "u.warriors.stand.se.1"
+  35, 2, "u.warriors.stand.se.2"
+  35, 3, "u.warriors.stand.se.3"
+  35, 4, "u.warriors.stand.se.4"
+  35, 5, "u.warriors.stand.se.5"
+  35, 6, "u.warriors.stand.se.6"
+  35, 7, "u.warriors.stand.se.7"
+  35, 8, "u.warriors.stand.se.8"
+  35, 9, "u.warriors.stand.se.9"
+  35, 10, "u.warriors.stand.se.10"
+  35, 11, "u.warriors.stand.se.11"
+  35, 12, "u.warriors.stand.se.12"
+  35, 13, "u.warriors.stand.se.13"
+  35, 14, "u.warriors.stand.se.14"
+  35, 15, "u.warriors.stand.se.15"
+  36, 0, "u.warriors.stand.s.0"
+  36, 1, "u.warriors.stand.s.1"
+  36, 2, "u.warriors.stand.s.2"
+  36, 3, "u.warriors.stand.s.3"
+  36, 4, "u.warriors.stand.s.4"
+  36, 5, "u.warriors.stand.s.5"
+  36, 6, "u.warriors.stand.s.6"
+  36, 7, "u.warriors.stand.s.7"
+  36, 8, "u.warriors.stand.s.8"
+  36, 9, "u.warriors.stand.s.9"
+  36, 10, "u.warriors.stand.s.10"
+  36, 11, "u.warriors.stand.s.11"
+  36, 12, "u.warriors.stand.s.12"
+  36, 13, "u.warriors.stand.s.13"
+  36, 14, "u.warriors.stand.s.14"
+  36, 15, "u.warriors.stand.s.15"
+  37, 0, "u.warriors.stand.sw.0"
+  37, 1, "u.warriors.stand.sw.1"
+  37, 2, "u.warriors.stand.sw.2"
+  37, 3, "u.warriors.stand.sw.3"
+  37, 4, "u.warriors.stand.sw.4"
+  37, 5, "u.warriors.stand.sw.5"
+  37, 6, "u.warriors.stand.sw.6"
+  37, 7, "u.warriors.stand.sw.7"
+  37, 8, "u.warriors.stand.sw.8"
+  37, 9, "u.warriors.stand.sw.9"
+  37, 10, "u.warriors.stand.sw.10"
+  37, 11, "u.warriors.stand.sw.11"
+  37, 12, "u.warriors.stand.sw.12"
+  37, 13, "u.warriors.stand.sw.13"
+  37, 14, "u.warriors.stand.sw.14"
+  37, 15, "u.warriors.stand.sw.15"
+  38, 0, "u.warriors.stand.w.0"
+  38, 1, "u.warriors.stand.w.1"
+  38, 2, "u.warriors.stand.w.2"
+  38, 3, "u.warriors.stand.w.3"
+  38, 4, "u.warriors.stand.w.4"
+  38, 5, "u.warriors.stand.w.5"
+  38, 6, "u.warriors.stand.w.6"
+  38, 7, "u.warriors.stand.w.7"
+  38, 8, "u.warriors.stand.w.8"
+  38, 9, "u.warriors.stand.w.9"
+  38, 10, "u.warriors.stand.w.10"
+  38, 11, "u.warriors.stand.w.11"
+  38, 12, "u.warriors.stand.w.12"
+  38, 13, "u.warriors.stand.w.13"
+  38, 14, "u.warriors.stand.w.14"
+  38, 15, "u.warriors.stand.w.15"
+  39, 0, "u.warriors.stand.nw.0"
+  39, 1, "u.warriors.stand.nw.1"
+  39, 2, "u.warriors.stand.nw.2"
+  39, 3, "u.warriors.stand.nw.3"
+  39, 4, "u.warriors.stand.nw.4"
+  39, 5, "u.warriors.stand.nw.5"
+  39, 6, "u.warriors.stand.nw.6"
+  39, 7, "u.warriors.stand.nw.7"
+  39, 8, "u.warriors.stand.nw.8"
+  39, 9, "u.warriors.stand.nw.9"
+  39, 10, "u.warriors.stand.nw.10"
+  39, 11, "u.warriors.stand.nw.11"
+  39, 12, "u.warriors.stand.nw.12"
+  39, 13, "u.warriors.stand.nw.13"
+  39, 14, "u.warriors.stand.nw.14"
+  39, 15, "u.warriors.stand.nw.15"
+}

[Prev in Thread] Current Thread [Next in Thread]