Complete.Org: Mailing Lists: Archives: freeciv-dev: March 2005:
[Freeciv-Dev] (PR#12425) objectify the tileset data
Home

[Freeciv-Dev] (PR#12425) objectify the tileset data

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#12425) objectify the tileset data
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 3 Mar 2005 11:36:30 -0800
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=12425 >

This patch takes the tileset data (currently a bunch of static variables 
in tilespec.c) and turns it into a structure (aka object).

There is a single global "tileset" variable.  Some places still use this 
global value (leading to hacks in a few places) but the majority pass 
around a tileset structure and access it directly.  The named_sprite 
structure is still in tilespec.h and accessed separately.

This is a fairly mammoth patch.  Almost every function in tilespec.c is 
touched.  The changes to the interface are fairly modest so outside of 
tilespec.c the changes are mostly search-and-replace.

This is a big step toward making tileset loading code more modular and 
robust.

-jason

Index: client/civclient.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v
retrieving revision 1.216
diff -u -r1.216 civclient.c
--- client/civclient.c  23 Feb 2005 03:34:05 -0000      1.216
+++ client/civclient.c  3 Mar 2005 19:27:25 -0000
@@ -339,10 +339,9 @@
   mysrand(time(NULL));
   control_init();
   helpdata_init();
-  tilespec_init();
   boot_help_texts();
 
-  if (!tilespec_read_toplevel(tileset_name)) {
+  if (!(tileset = tileset_read_toplevel(tileset_name))) {
     /* get tile sizes etc */
     exit(EXIT_FAILURE);
   }
@@ -372,7 +371,7 @@
   if (save_options_on_exit) {
     save_options();
   }
-  tilespec_done();
+  tileset_free(tileset);
   control_done();
   chatline_common_done();
   client_game_free();
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.203
diff -u -r1.203 mapview_common.c
--- client/mapview_common.c     2 Mar 2005 19:00:33 -0000       1.203
+++ client/mapview_common.c     3 Mar 2005 19:27:26 -0000
@@ -981,7 +981,8 @@
                     const struct city *citymode)
 {
   struct drawn_sprite tile_sprs[80];
-  int count = fill_sprite_array(tile_sprs, layer, ptile, pedge, pcorner,
+  int count = fill_sprite_array(tileset, tile_sprs, layer,
+                               ptile, pedge, pcorner,
                                punit, pcity, citymode);
   bool fog = (ptile && draw_fog_of_war
              && tile_get_known(ptile) == TILE_KNOWN_FOGGED);
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.473
diff -u -r1.473 packhand.c
--- client/packhand.c   23 Feb 2005 03:34:05 -0000      1.473
+++ client/packhand.c   3 Mar 2005 19:27:26 -0000
@@ -2058,7 +2058,7 @@
 {
   int i;
 
-  tilespec_free_city_tiles(game.styles_count);
+  tileset_free_city_tiles(tileset, game.styles_count);
   ruleset_data_free();
 
   ruleset_cache_init();
@@ -2090,7 +2090,7 @@
   game.playable_nation_count = packet->playable_nation_count;
 
   city_styles_alloc(packet->style_count);
-  tilespec_alloc_city_tiles(game.styles_count);
+  tileset_alloc_city_tiles(tileset, game.styles_count);
 
   game.terrain_count = packet->terrain_count;
 
@@ -2160,7 +2160,7 @@
 
   u->helptext = mystrdup(p->helptext);
 
-  tilespec_setup_unit_type(p->id);
+  tileset_setup_unit_type(tileset, p->id);
 }
 
 /**************************************************************************
@@ -2189,7 +2189,7 @@
   a->num_reqs = p->num_reqs;
   a->helptext = mystrdup(p->helptext);
   
-  tilespec_setup_tech_type(p->id);
+  tileset_setup_tech_type(tileset, p->id);
 }
 
 /**************************************************************************
@@ -2275,7 +2275,7 @@
   }
 #endif
   
-  tilespec_setup_impr_type(p->id);
+  tileset_setup_impr_type(tileset, p->id);
 }
 
 /**************************************************************************
@@ -2336,7 +2336,7 @@
 
   gov->helptext = mystrdup(p->helptext);
   
-  tilespec_setup_government(p->id);
+  tileset_setup_government(tileset, p->id);
 }
 
 void handle_ruleset_government_ruler_title
@@ -2423,7 +2423,7 @@
 
   t->helptext = mystrdup(p->helptext);
   
-  tilespec_setup_tile_type(p->id);
+  tileset_setup_tile_type(tileset, p->id);
 }
 
 /**************************************************************************
@@ -2477,7 +2477,7 @@
     pl->legend = mystrdup("");
   }
 
-  tilespec_setup_nation_flag(p->id);
+  tileset_setup_nation_flag(tileset, p->id);
 }
 
 /**************************************************************************
@@ -2506,7 +2506,7 @@
   sz_strlcpy(cs->citizens_graphic, packet->citizens_graphic);
   sz_strlcpy(cs->citizens_graphic_alt, packet->citizens_graphic_alt);
 
-  tilespec_setup_city_tiles(id);
+  tileset_setup_city_tiles(tileset, id);
 }
 
 /**************************************************************************
@@ -2541,7 +2541,7 @@
                          packet->specialist_req_value[index]);
     }
   } specialist_type_iterate_end;
-  tilespec_setup_specialist_types();
+  tileset_setup_specialist_types(tileset);
 
   game.rgame.changable_tax = packet->changable_tax;
   game.rgame.forced_science = packet->forced_science;
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.255
diff -u -r1.255 tilespec.c
--- client/tilespec.c   3 Mar 2005 17:18:28 -0000       1.255
+++ client/tilespec.c   3 Mar 2005 19:27:27 -0000
@@ -56,9 +56,6 @@
 
 #define TILESPEC_SUFFIX ".tilespec"
 
-static char *main_intro_filename;
-static char *minimap_intro_filename;
-
 struct named_sprites sprites;
 
 /* Stores the currently loaded tileset.  This differs from the value in
@@ -70,43 +67,15 @@
 
 int OVERVIEW_TILE_SIZE = 2;
 
-static bool is_isometric;
-static int hex_width, hex_height;
-
-static int normal_tile_width, normal_tile_height;
-static int full_tile_width, full_tile_height;
-static int small_sprite_width, small_sprite_height;
-
-static int city_names_font_size, city_productions_font_size;
-
-static int roadstyle;
-
 /* Don't reorder this enum since tilesets depend on it. */
 enum fog_style {
   FOG_AUTO, /* Fog is automatically appended by the code. */
   FOG_SPRITE, /* A single fog sprite is provided by the tileset (tx.fog). */
   FOG_NONE /* No fog. */
 };
-static enum fog_style fogstyle;
-
-static int flag_offset_x, flag_offset_y;
-static int unit_offset_x, unit_offset_y;
-
-#define NUM_CORNER_DIRS 4
-#define TILES_PER_CORNER 4
-
-static int num_valid_tileset_dirs, num_cardinal_tileset_dirs;
-static int num_index_valid, num_index_cardinal;
-static enum direction8 valid_tileset_dirs[8], cardinal_tileset_dirs[8];
-
-static struct {
-  enum match_style match_style;
-  int count;
-  char **match_types;
-} layers[MAX_NUM_LAYERS];
 
 /* Darkness style.  Don't reorder this enum since tilesets depend on it. */
-static enum {
+enum darkness_style {
   /* No darkness sprites are drawn. */
   DARKNESS_NONE = 0,
 
@@ -124,9 +93,12 @@
 
   /* Corner darkness & fog.  3^4 = 81 sprites. */
   DARKNESS_CORNER = 4
-} darkness_style;
+};
 
-struct specfile;
+struct specfile {
+  struct Sprite *big_sprite;
+  char *file_name;
+};
 
 #define SPECLIST_TAG specfile
 #define SPECLIST_TYPE struct specfile
@@ -136,23 +108,6 @@
     TYPED_LIST_ITERATE(struct specfile, list, pitem)
 #define specfile_list_iterate_end  LIST_ITERATE_END
 
-struct small_sprite;
-#define SPECLIST_TAG small_sprite
-#define SPECLIST_TYPE struct small_sprite
-#include "speclist.h"
-
-#define small_sprite_list_iterate(list, pitem) \
-    TYPED_LIST_ITERATE(struct small_sprite, list, pitem)
-#define small_sprite_list_iterate_end  LIST_ITERATE_END
-
-static struct specfile_list *specfiles;
-static struct small_sprite_list *small_sprites;
-
-struct specfile {
-  struct Sprite *big_sprite;
-  char *file_name;
-};
-
 /* 
  * Information about an individual sprite. All fields except 'sprite' are
  * filled at the time of the scan of the specfile. 'Sprite' is
@@ -174,13 +129,59 @@
   struct Sprite *sprite;
 };
 
-/*
- * This hash table maps tilespec tags to struct small_sprites.
- */
-static struct hash_table *sprite_hash = NULL;
+#define SPECLIST_TAG small_sprite
+#define SPECLIST_TYPE struct small_sprite
+#include "speclist.h"
+
+#define small_sprite_list_iterate(list, pitem) \
+    TYPED_LIST_ITERATE(struct small_sprite, list, pitem)
+#define small_sprite_list_iterate_end  LIST_ITERATE_END
+
+struct tileset {
+  bool is_isometric;
+  int hex_width, hex_height;
+
+  int normal_tile_width, normal_tile_height;
+  int full_tile_width, full_tile_height;
+  int small_sprite_width, small_sprite_height;
 
-/* This hash table maps terrain graphic strings to drawing data. */
-static struct hash_table *terrain_hash;
+  char *main_intro_filename;
+  char *minimap_intro_filename;
+
+  int city_names_font_size, city_productions_font_size;
+
+  int roadstyle;
+  enum fog_style fogstyle;
+  enum darkness_style darkness_style;
+
+  int flag_offset_x, flag_offset_y;
+  int unit_offset_x, unit_offset_y;
+
+#define NUM_CORNER_DIRS 4
+#define TILES_PER_CORNER 4
+  int num_valid_tileset_dirs, num_cardinal_tileset_dirs;
+  int num_index_valid, num_index_cardinal;
+  enum direction8 valid_tileset_dirs[8], cardinal_tileset_dirs[8];
+
+  struct {
+    enum match_style match_style;
+    int count;
+    char **match_types;
+  } layers[MAX_NUM_LAYERS];
+
+  struct specfile_list *specfiles;
+  struct small_sprite_list *small_sprites;
+
+  /*
+   * This hash table maps tilespec tags to struct small_sprites.
+   */
+  struct hash_table *sprite_hash;
+
+  /* This hash table maps terrain graphic strings to drawing data. */
+  struct hash_table *terrain_hash;
+};
+
+struct tileset *tileset;
 
 #define TILESPEC_CAPSTR "+tilespec3 duplicates_ok"
 /*
@@ -202,7 +203,8 @@
 
 int focus_unit_state = 0;
 
-static struct Sprite* lookup_sprite_tag_alt(const char *tag, const char *alt,
+static struct Sprite* lookup_sprite_tag_alt(struct tileset *t,
+                                           const char *tag, const char *alt,
                                            bool required, const char *what,
                                            const char *name);
 
@@ -212,7 +214,7 @@
 ****************************************************************************/
 bool tileset_is_isometric(void)
 {
-  return is_isometric;
+  return tileset->is_isometric;
 }
 
 /****************************************************************************
@@ -221,15 +223,25 @@
 ****************************************************************************/
 int tileset_hex_width(void)
 {
-  return hex_width;
+  return tileset->hex_width;
+}
+
+/****************************************************************************
+  Return the hex_height of the current tileset.  For iso-hex tilesets this
+  value will be > 0 and is_isometric will be set.
+****************************************************************************/
+int tileset_hex_height(void)
+{
+  return tileset->hex_height;
 }
+
 /****************************************************************************
   Return the tile width of the current tileset.  This is the tesselation
   width of the tiled plane.
 ****************************************************************************/
 int tileset_tile_width(void)
 {
-  return normal_tile_width;
+  return tileset->normal_tile_width;
 }
 
 /****************************************************************************
@@ -238,7 +250,7 @@
 ****************************************************************************/
 int tileset_tile_height(void)
 {
-  return normal_tile_height;
+  return tileset->normal_tile_height;
 }
 
 /****************************************************************************
@@ -249,7 +261,7 @@
 ****************************************************************************/
 int tileset_full_tile_width(void)
 {
-  return full_tile_width;
+  return tileset->full_tile_width;
 }
 
 /****************************************************************************
@@ -259,7 +271,7 @@
 ****************************************************************************/
 int tileset_full_tile_height(void)
 {
-  return full_tile_height;
+  return tileset->full_tile_height;
 }
 
 /****************************************************************************
@@ -269,7 +281,7 @@
 ****************************************************************************/
 int tileset_small_sprite_width(void)
 {
-  return small_sprite_width;
+  return tileset->small_sprite_width;
 }
 
 /****************************************************************************
@@ -279,16 +291,7 @@
 ****************************************************************************/
 int tileset_small_sprite_height(void)
 {
-  return small_sprite_height;
-}
-
-/****************************************************************************
-  Return the hex_height of the current tileset.  For isohex tilesets this
-  value will be > 0 and is_isometric will be set.
-****************************************************************************/
-int tileset_hex_height(void)
-{
-  return hex_height;
+  return tileset->small_sprite_height;
 }
 
 /****************************************************************************
@@ -298,7 +301,7 @@
 ****************************************************************************/
 const char *tileset_main_intro_filename(void)
 {
-  return main_intro_filename;
+  return tileset->main_intro_filename;
 }
 
 /****************************************************************************
@@ -308,25 +311,29 @@
 ****************************************************************************/
 const char *tileset_mini_intro_filename(void)
 {
-  return minimap_intro_filename;
+  return tileset->minimap_intro_filename;
 }
 
 /**************************************************************************
   Initialize.
 **************************************************************************/
-void tilespec_init(void)
+static struct tileset *tileset_new(void)
 {
-  specfiles = specfile_list_new();
-  small_sprites = small_sprite_list_new();
+  struct tileset *t = fc_calloc(1, sizeof(*t));
+
+  t->specfiles = specfile_list_new();
+  t->small_sprites = small_sprite_list_new();
+  return t;
 }
 
 /**************************************************************************
   Clean up.
 **************************************************************************/
-void tilespec_done(void)
+void tileset_free(struct tileset *t)
 {
-  specfile_list_free(specfiles);
-  small_sprite_list_free(small_sprites);
+  specfile_list_free(t->specfiles);
+  small_sprite_list_free(t->small_sprites);
+  free(t);
 }
 
 /**************************************************************************
@@ -360,11 +367,11 @@
 /****************************************************************************
   Return TRUE iff the dir is valid in this tileset.
 ****************************************************************************/
-static bool is_valid_tileset_dir(enum direction8 dir)
+static bool is_valid_tileset_dir(struct tileset *t, enum direction8 dir)
 {
-  if (hex_width > 0) {
+  if (t->hex_width > 0) {
     return dir != DIR8_NORTHEAST && dir != DIR8_SOUTHWEST;
-  } else if (hex_height > 0) {
+  } else if (t->hex_height > 0) {
     return dir != DIR8_NORTHWEST && dir != DIR8_SOUTHEAST;
   } else {
     return TRUE;
@@ -377,10 +384,10 @@
   "Cardinal", in this sense, means that a tile will share a border with
   another tile in the direction rather than sharing just a single vertex.
 ****************************************************************************/
-static bool is_cardinal_tileset_dir(enum direction8 dir)
+static bool is_cardinal_tileset_dir(struct tileset *t, enum direction8 dir)
 {
-  if (hex_width > 0 || hex_height > 0) {
-    return is_valid_tileset_dir(dir);
+  if (t->hex_width > 0 || t->hex_height > 0) {
+    return is_valid_tileset_dir(t, dir);
   } else {
     return (dir == DIR8_NORTH || dir == DIR8_EAST
            || dir == DIR8_SOUTH || dir == DIR8_WEST);
@@ -489,30 +496,30 @@
 
   See tilespec_read_toplevel().
 ***********************************************************************/
-static void tilespec_free_toplevel(void)
+static void tileset_free_toplevel(struct tileset *t)
 {
-  if (main_intro_filename) {
-    free(main_intro_filename);
-    main_intro_filename = NULL;
+  if (t->main_intro_filename) {
+    free(t->main_intro_filename);
+    t->main_intro_filename = NULL;
   }
-  if (minimap_intro_filename) {
-    free(minimap_intro_filename);
-    minimap_intro_filename = NULL;
+  if (t->minimap_intro_filename) {
+    free(t->minimap_intro_filename);
+    t->minimap_intro_filename = NULL;
   }
 
-  while (hash_num_entries(terrain_hash) > 0) {
+  while (hash_num_entries(t->terrain_hash) > 0) {
     const struct terrain_drawing_data *draw;
 
-    draw = hash_value_by_number(terrain_hash, 0);
-    hash_delete_entry(terrain_hash, draw->name);
+    draw = hash_value_by_number(t->terrain_hash, 0);
+    hash_delete_entry(t->terrain_hash, draw->name);
     free(draw->name);
     if (draw->mine_tag) {
       free(draw->mine_tag);
     }
     free((void *) draw);
   }
-  hash_free(terrain_hash);
-  terrain_hash = NULL; /* Helpful for sanity. */
+  hash_free(t->terrain_hash);
+  t->terrain_hash = NULL; /* Helpful for sanity. */
 }
 
 /**********************************************************************
@@ -548,20 +555,20 @@
    *
    * We free all old data in preparation for re-reading it.
    */
-  tilespec_free_tiles();
-  tilespec_free_city_tiles(game.styles_count);
-  tilespec_free_toplevel();
+  tileset_free_tiles(tileset);
+  tileset_free_city_tiles(tileset, game.styles_count);
+  tileset_free_toplevel(tileset);
 
   /* Step 2:  Read.
    *
    * We read in the new tileset.  This should be pretty straightforward.
    */
-  if (!tilespec_read_toplevel(tileset_name)) {
-    if (!tilespec_read_toplevel(current_tileset)) {
+  if (!(tileset = tileset_read_toplevel(tileset_name))) {
+    if (!(tileset = tileset_read_toplevel(current_tileset))) {
       die("Failed to re-read the currently loaded tileset.");
     }
   }
-  tilespec_load_tiles();
+  tileset_load_tiles(tileset);
 
   /* Step 3: Setup
    *
@@ -583,32 +590,32 @@
     return;
   }
   for (id = T_FIRST; id < T_COUNT; id++) {
-    tilespec_setup_tile_type(id);
+    tileset_setup_tile_type(tileset, id);
   }
   unit_type_iterate(id) {
-    tilespec_setup_unit_type(id);
+    tileset_setup_unit_type(tileset, id);
   } unit_type_iterate_end;
   government_iterate(gov) {
-    tilespec_setup_government(gov->index);
+    tileset_setup_government(tileset, gov->index);
   } government_iterate_end;
   for (id = 0; id < game.nation_count; id++) {
-    tilespec_setup_nation_flag(id);
+    tileset_setup_nation_flag(tileset, id);
   }
   impr_type_iterate(imp_id) {
-    tilespec_setup_impr_type(imp_id);
+    tileset_setup_impr_type(tileset, imp_id);
   } impr_type_iterate_end;
   tech_type_iterate(tech_id) {
     if (tech_id != A_NONE && tech_exists(tech_id)) {
-      tilespec_setup_tech_type(tech_id);
+      tileset_setup_tech_type(tileset, tech_id);
     }
   } tech_type_iterate_end;
-  tilespec_setup_specialist_types();
+  tileset_setup_specialist_types(tileset);
 
   /* tilespec_load_tiles reverts the city tile pointers to 0.  This
      is a workaround. */
-  tilespec_alloc_city_tiles(game.styles_count);
+  tileset_alloc_city_tiles(tileset, game.styles_count);
   for (id = 0; id < game.styles_count; id++) {
-    tilespec_setup_city_tiles(id);
+    tileset_setup_city_tiles(tileset, id);
   }
 
   /* Step 4:  Draw.
@@ -712,7 +719,8 @@
   positions of the sprites in the big_sprite are saved in the
   small_sprite structs.
 **************************************************************************/
-static void scan_specfile(struct specfile *sf, bool duplicates_ok)
+static void scan_specfile(struct tileset *t, struct specfile *sf,
+                         bool duplicates_ok)
 {
   struct section_file the_file, *file = &the_file;
   char **gridnames;
@@ -787,17 +795,17 @@
       ss->hot_x = hot_x;
       ss->hot_y = hot_y;
 
-      small_sprite_list_prepend(small_sprites, ss);
+      small_sprite_list_prepend(t->small_sprites, ss);
 
       if (!duplicates_ok) {
         for (k = 0; k < num_tags; k++) {
-          if (!hash_insert(sprite_hash, mystrdup(tags[k]), ss)) {
+          if (!hash_insert(t->sprite_hash, mystrdup(tags[k]), ss)) {
            freelog(LOG_ERROR, "warning: already have a sprite for %s", 
tags[k]);
           }
         }
       } else {
         for (k = 0; k < num_tags; k++) {
-      (void) hash_replace(sprite_hash, mystrdup(tags[k]), ss);
+         (void) hash_replace(t->sprite_hash, mystrdup(tags[k]), ss);
         }
       }
 
@@ -831,17 +839,17 @@
     ss->hot_x = hot_x;
     ss->hot_y = hot_y;
 
-    small_sprite_list_prepend(small_sprites, ss);
+    small_sprite_list_prepend(t->small_sprites, ss);
 
     if (!duplicates_ok) {
       for (k = 0; k < num_tags; k++) {
-       if (!hash_insert(sprite_hash, mystrdup(tags[k]), ss)) {
+       if (!hash_insert(t->sprite_hash, mystrdup(tags[k]), ss)) {
          freelog(LOG_ERROR, "warning: already have a sprite for %s", tags[k]);
        }
       }
     } else {
       for (k = 0; k < num_tags; k++) {
-       (void) hash_replace(sprite_hash, mystrdup(tags[k]), ss);
+       (void) hash_replace(t->sprite_hash, mystrdup(tags[k]), ss);
       }
     }
     free(tags);
@@ -886,7 +894,7 @@
   Sets global variables, including tile sizes and full names for
   intro files.
 ***********************************************************************/
-bool tilespec_read_toplevel(const char *tileset_name)
+struct tileset *tileset_read_toplevel(const char *tileset_name)
 {
   struct section_file the_file, *file = &the_file;
   char *fname, *c;
@@ -896,18 +904,20 @@
   char *file_capstr;
   bool duplicates_ok, is_hex;
   enum direction8 dir;
+  struct tileset *t = tileset_new();
 
+  tileset = t; /* HACK: because some functions still use the global value. */
   fname = tilespec_fullname(tileset_name);
   freelog(LOG_VERBOSE, "tilespec file is %s", fname);
 
   if (!section_file_load(file, fname)) {
     freelog(LOG_ERROR, _("Could not open \"%s\"."), fname);
-    return FALSE;
+    return NULL;
   }
 
   if (!check_tilespec_capabilities(file, "tilespec",
                                   TILESPEC_CAPSTR, fname)) {
-    return FALSE;
+    return NULL;
   }
 
   file_capstr = secfile_lookup_str(file, "%s.options", "tilespec");
@@ -915,115 +925,120 @@
 
   (void) section_file_lookup(file, "tilespec.name"); /* currently unused */
 
-  is_isometric = secfile_lookup_bool_default(file, FALSE, 
"tilespec.is_isometric");
+  t->is_isometric = secfile_lookup_bool_default(file, FALSE,
+                                               "tilespec.is_isometric");
 
   /* Read hex-tileset information. */
   is_hex = secfile_lookup_bool_default(file, FALSE, "tilespec.is_hex");
   hex_side = secfile_lookup_int_default(file, 0, "tilespec.hex_side");
-  hex_width = hex_height = 0;
+  t->hex_width = t->hex_height = 0;
   if (is_hex) {
-    if (is_isometric) {
-      hex_height = hex_side;
+    if (t->is_isometric) {
+      t->hex_height = hex_side;
     } else {
-      hex_width = hex_side;
+      t->hex_width = hex_side;
     }
-    is_isometric = TRUE; /* Hex tilesets are drawn the same as isometric. */
+    /* Hex tilesets are drawn the same as isometric. */
+    t->is_isometric = TRUE;
   }
 
-  if (is_isometric && !isometric_view_supported()) {
+  if (t->is_isometric && !isometric_view_supported()) {
     freelog(LOG_ERROR, _("Client does not support isometric tilesets."
            " Using default tileset instead."));
     assert(tileset_name != NULL);
     section_file_free(file);
     free(fname);
-    return tilespec_read_toplevel(NULL);
+    return tileset_read_toplevel(NULL);
   }
-  if (!is_isometric && !overhead_view_supported()) {
+  if (!t->is_isometric && !overhead_view_supported()) {
     freelog(LOG_ERROR, _("Client does not support overhead view tilesets."
            " Using default tileset instead."));
     assert(tileset_name != NULL);
     section_file_free(file);
     free(fname);
-    return tilespec_read_toplevel(NULL);
+    return tileset_read_toplevel(NULL);
   }
 
   /* Create arrays of valid and cardinal tileset dirs.  These depend
    * entirely on the tileset, not the topology.  They are also in clockwise
    * rotational ordering. */
-  num_valid_tileset_dirs = num_cardinal_tileset_dirs = 0;
+  t->num_valid_tileset_dirs = t->num_cardinal_tileset_dirs = 0;
   dir = DIR8_NORTH;
   do {
-    if (is_valid_tileset_dir(dir)) {
-      valid_tileset_dirs[num_valid_tileset_dirs] = dir;
-      num_valid_tileset_dirs++;
-    }
-    if (is_cardinal_tileset_dir(dir)) {
-      cardinal_tileset_dirs[num_cardinal_tileset_dirs] = dir;
-      num_cardinal_tileset_dirs++;
+    if (is_valid_tileset_dir(t, dir)) {
+      t->valid_tileset_dirs[t->num_valid_tileset_dirs] = dir;
+      t->num_valid_tileset_dirs++;
+    }
+    if (is_cardinal_tileset_dir(t, dir)) {
+      t->cardinal_tileset_dirs[t->num_cardinal_tileset_dirs] = dir;
+      t->num_cardinal_tileset_dirs++;
     }
 
     dir = dir_cw(dir);
   } while (dir != DIR8_NORTH);
-  assert(num_valid_tileset_dirs % 2 == 0); /* Assumed elsewhere. */
-  num_index_valid = 1 << num_valid_tileset_dirs;
-  num_index_cardinal = 1 << num_cardinal_tileset_dirs;
-
-  normal_tile_width = secfile_lookup_int(file, "tilespec.normal_tile_width");
-  normal_tile_height = secfile_lookup_int(file, "tilespec.normal_tile_height");
-  if (is_isometric) {
-    full_tile_width = NORMAL_TILE_WIDTH;
-    full_tile_height = 3 * NORMAL_TILE_HEIGHT / 2;
+  assert(t->num_valid_tileset_dirs % 2 == 0); /* Assumed elsewhere. */
+  t->num_index_valid = 1 << t->num_valid_tileset_dirs;
+  t->num_index_cardinal = 1 << t->num_cardinal_tileset_dirs;
+
+  t->normal_tile_width
+    = secfile_lookup_int(file, "tilespec.normal_tile_width");
+  t->normal_tile_height
+    = secfile_lookup_int(file, "tilespec.normal_tile_height");
+  if (t->is_isometric) {
+    t->full_tile_width = NORMAL_TILE_WIDTH;
+    t->full_tile_height = 3 * NORMAL_TILE_HEIGHT / 2;
   } else {
-    full_tile_width = NORMAL_TILE_WIDTH;
-    full_tile_height = NORMAL_TILE_HEIGHT;
+    t->full_tile_width = NORMAL_TILE_WIDTH;
+    t->full_tile_height = NORMAL_TILE_HEIGHT;
   }
-  small_sprite_width
+  t->small_sprite_width
     = secfile_lookup_int(file, "tilespec.small_tile_width");
-  small_sprite_height
+  t->small_sprite_height
     = secfile_lookup_int(file, "tilespec.small_tile_height");
   freelog(LOG_VERBOSE, "tile sizes %dx%d, %d%d unit, %d%d small",
          NORMAL_TILE_WIDTH, NORMAL_TILE_HEIGHT,
          UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT,
          SMALL_TILE_WIDTH, SMALL_TILE_HEIGHT);
 
-  roadstyle = secfile_lookup_int_default(file, is_isometric ? 0 : 1,
-                                        "tilespec.roadstyle");
-  fogstyle
-    = secfile_lookup_int_default(file, is_isometric ? FOG_AUTO : FOG_SPRITE,
+  t->roadstyle = secfile_lookup_int_default(file, t->is_isometric ? 0 : 1,
+                                           "tilespec.roadstyle");
+  t->fogstyle
+    = secfile_lookup_int_default(file,
+                                t->is_isometric ? FOG_AUTO : FOG_SPRITE,
                                 "tilespec.fogstyle");
-  darkness_style = secfile_lookup_int(file, "tilespec.darkness_style");
-  if (darkness_style < DARKNESS_NONE
-      || darkness_style > DARKNESS_CORNER
-      || (darkness_style == DARKNESS_ISORECT
-         && (!is_isometric || hex_width > 0 || hex_height > 0))) {
+  t->darkness_style = secfile_lookup_int(file, "tilespec.darkness_style");
+  if (t->darkness_style < DARKNESS_NONE
+      || t->darkness_style > DARKNESS_CORNER
+      || (t->darkness_style == DARKNESS_ISORECT
+         && (!t->is_isometric || t->hex_width > 0 || t->hex_height > 0))) {
     freelog(LOG_FATAL, _("Invalid darkness style set in tileset."));
     exit(EXIT_FAILURE);
   }
-  flag_offset_x = secfile_lookup_int_default(file, 0,
-                                            "tilespec.flag_offset_x");
-  flag_offset_y = secfile_lookup_int_default(file, 0,
-                                            "tilespec.flag_offset_y");
-  unit_offset_x = secfile_lookup_int_default(file, 0,
-                                            "tilespec.unit_offset_x");
-  unit_offset_y = secfile_lookup_int_default(file, 0,
-                                            "tilespec.unit_offset_y");
+  t->flag_offset_x = secfile_lookup_int_default(file, 0,
+                                               "tilespec.flag_offset_x");
+  t->flag_offset_y = secfile_lookup_int_default(file, 0,
+                                               "tilespec.flag_offset_y");
+  t->unit_offset_x = secfile_lookup_int_default(file, 0,
+                                               "tilespec.unit_offset_x");
+  t->unit_offset_y = secfile_lookup_int_default(file, 0,
+                                               "tilespec.unit_offset_y");
 
-  city_names_font_size
+  t->city_names_font_size
     = secfile_lookup_int_default(file, 10, "tilespec.city_names_font_size");
 
-  city_productions_font_size
+  t->city_productions_font_size
     = secfile_lookup_int_default(file, 10,
                                 "tilespec.city_productions_font_size");
-  set_city_names_font_sizes(city_names_font_size,
-                           city_productions_font_size);
+  set_city_names_font_sizes(t->city_names_font_size,
+                           t->city_productions_font_size);
 
   c = secfile_lookup_str(file, "tilespec.main_intro_file");
-  main_intro_filename = tilespec_gfx_filename(c);
-  freelog(LOG_DEBUG, "intro file %s", main_intro_filename);
+  t->main_intro_filename = tilespec_gfx_filename(c);
+  freelog(LOG_DEBUG, "intro file %s", t->main_intro_filename);
   
   c = secfile_lookup_str(file, "tilespec.minimap_intro_file");
-  minimap_intro_filename = tilespec_gfx_filename(c);
-  freelog(LOG_DEBUG, "radar file %s", minimap_intro_filename);
+  t->minimap_intro_filename = tilespec_gfx_filename(c);
+  freelog(LOG_DEBUG, "radar file %s", t->minimap_intro_filename);
 
   /* Terrain layer info. */
   for (i = 0; i < MAX_NUM_LAYERS; i++) {
@@ -1032,17 +1047,18 @@
     int j;
 
     if (mystrcasecmp(style, "full") == 0) {
-      layers[i].match_style = MATCH_FULL;
+      t->layers[i].match_style = MATCH_FULL;
     } else if (mystrcasecmp(style, "bool") == 0) {
-      layers[i].match_style = MATCH_BOOLEAN;
+      t->layers[i].match_style = MATCH_BOOLEAN;
     } else {
-      layers[i].match_style = MATCH_NONE;
+      t->layers[i].match_style = MATCH_NONE;
     }
 
-    layers[i].match_types = secfile_lookup_str_vec(file, &layers[i].count,
-                                                  "layer%d.match_types", i);
-    for (j = 0; j < layers[i].count; j++) {
-      layers[i].match_types[j] = mystrdup(layers[i].match_types[j]);
+    t->layers[i].match_types
+      = secfile_lookup_str_vec(file, &t->layers[i].count,
+                              "layer%d.match_types", i);
+    for (j = 0; j < t->layers[i].count; j++) {
+      t->layers[i].match_types[j] = mystrdup(t->layers[i].match_types[j]);
     }
   }
 
@@ -1050,11 +1066,11 @@
   terrains = secfile_get_secnames_prefix(file, "terrain_", &num_terrains);
   if (num_terrains == 0) {
     freelog(LOG_ERROR, "No terrain types supported by tileset.");
-    return FALSE;
+    return NULL;
   }
 
-  assert(terrain_hash == NULL);
-  terrain_hash = hash_new(hash_fval_string, hash_fcmp_string);
+  assert(t->terrain_hash == NULL);
+  t->terrain_hash = hash_new(hash_fval_string, hash_fcmp_string);
 
   for (i = 0; i < num_terrains; i++) {
     struct terrain_drawing_data *terr = fc_malloc(sizeof(*terr));
@@ -1102,7 +1118,7 @@
          terr->layer[l].match_count = 0;
          break;
        case MATCH_FULL:
-         terr->layer[l].match_count = layers[l].count;
+         terr->layer[l].match_count = t->layers[l].count;
          break;
        case MATCH_BOOLEAN:
          terr->layer[l].match_count = 2;
@@ -1110,27 +1126,27 @@
        }
 
        /* Determine our match_type. */
-       for (j = 0; j < layers[l].count; j++) {
-         if (mystrcasecmp(layers[l].match_types[j], match_type) == 0) {
+       for (j = 0; j < t->layers[l].count; j++) {
+         if (mystrcasecmp(t->layers[l].match_types[j], match_type) == 0) {
            break;
          }
        }
        terr->layer[l].match_type = j;
-       if (j >= layers[l].count) {
+       if (j >= t->layers[l].count) {
          freelog(LOG_ERROR, "Invalid match type given for %s.", terrains[i]);
          terr->layer[l].match_type = 0;
          terr->layer[l].match_style = MATCH_NONE;
        }
       } else {
        terr->layer[l].match_style = MATCH_NONE;
-       if (layers[l].match_style != MATCH_NONE) {
+       if (t->layers[l].match_style != MATCH_NONE) {
          freelog(LOG_ERROR, "Layer %d has a match_style set; all terrains"
                  " must have a match_type.  %s doesn't.", l, terrains[i]);
        }
       }
 
       if (terr->layer[l].match_style == MATCH_NONE
-         && layers[l].match_style == MATCH_FULL) {
+         && t->layers[l].match_style == MATCH_FULL) {
        freelog(LOG_ERROR, "Layer %d has match_type full set; all terrains"
                " must match this.  %s doesn't.", l, terrains[i]);
       }
@@ -1165,10 +1181,10 @@
       terr->mine_tag = mystrdup(terr->mine_tag);
     }
 
-    if (!hash_insert(terrain_hash, terr->name, terr)) {
+    if (!hash_insert(t->terrain_hash, terr->name, terr)) {
       freelog(LOG_NORMAL, "warning: duplicate terrain entry %s.",
              terrains[i]);
-      return FALSE;
+      return NULL;
     }
   }
   free(terrains);
@@ -1178,10 +1194,11 @@
                                          "tilespec.files");
   if (num_spec_files == 0) {
     freelog(LOG_ERROR, "No tile files specified in \"%s\"", fname);
-    return FALSE;
+    return NULL;
   }
 
-  sprite_hash = hash_new(hash_fval_string, hash_fcmp_string);
+  assert(t->sprite_hash == NULL);
+  t->sprite_hash = hash_new(hash_fval_string, hash_fcmp_string);
   for (i = 0; i < num_spec_files; i++) {
     struct specfile *sf = fc_malloc(sizeof(*sf));
 
@@ -1189,9 +1206,9 @@
     
     sf->big_sprite = NULL;
     sf->file_name = mystrdup(datafilename_required(spec_filenames[i]));
-    scan_specfile(sf, duplicates_ok);
+    scan_specfile(t, sf, duplicates_ok);
 
-    specfile_list_prepend(specfiles, sf);
+    specfile_list_prepend(t->specfiles, sf);
   }
   free(spec_filenames);
 
@@ -1203,7 +1220,7 @@
 
   sz_strlcpy(current_tileset, tileset_name);
 
-  return TRUE;
+  return t;
 }
 
 /**********************************************************************
@@ -1236,17 +1253,17 @@
   binary value 1000 will be converted into "n1e0s0w0".  This is in a
   clockwise ordering.
 ****************************************************************************/
-static const char *cardinal_index_str(int idx)
+static const char *cardinal_index_str(struct tileset *t, int idx)
 {
   static char c[64];
   int i;
 
   c[0] = '\0';
-  for (i = 0; i < num_cardinal_tileset_dirs; i++) {
+  for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
     int value = (idx >> i) & 1;
 
     snprintf(c + strlen(c), sizeof(c) - strlen(c), "%s%d",
-            dir_get_tileset_name(cardinal_tileset_dirs[i]), value);
+            dir_get_tileset_name(t->cardinal_tileset_dirs[i]), value);
   }
 
   return c;
@@ -1256,54 +1273,57 @@
   Do the same thing as cardinal_str, except including all valid directions.
   The returned string is a pointer to static memory.
 ****************************************************************************/
-static char *valid_index_str(int index)
+static char *valid_index_str(struct tileset *t, int index)
 {
   static char c[64];
   int i;
 
   c[0] = '\0';
-  for (i = 0; i < num_valid_tileset_dirs; i++) {
+  for (i = 0; i < t->num_valid_tileset_dirs; i++) {
     int value = (index >> i) & 1;
 
     snprintf(c + strlen(c), sizeof(c) - strlen(c), "%s%d",
-            dir_get_tileset_name(valid_tileset_dirs[i]), value);
+            dir_get_tileset_name(t->valid_tileset_dirs[i]), value);
   }
 
   return c;
 }
      
 /* Not very safe, but convenient: */
-#define SET_SPRITE(field, tag) do {                       \
-       sprites.field = load_sprite(tag);                  \
-       if (!sprites.field) {                              \
-         die("Sprite tag %s missing.", tag);              \
-       }                                                  \
-    } while(FALSE)
+#define SET_SPRITE(field, tag)                                   \
+  do {                                                           \
+    sprites.field = load_sprite(t, tag);                         \
+    if (!sprites.field) {                                        \
+      die("Sprite tag %s missing.", tag);                        \
+    }                                                            \
+  } while(FALSE)
 
 /* Sets sprites.field to tag or (if tag isn't available) to alt */
-#define SET_SPRITE_ALT(field, tag, alt) do {                   \
-       sprites.field = load_sprite(tag);                       \
-       if (!sprites.field) {                                   \
-           sprites.field = load_sprite(alt);                   \
-       }                                                       \
-       if (!sprites.field) {                                   \
-         die("Sprite tag %s and alternate %s are both missing.", tag, alt); \
-       }                                                       \
-    } while(FALSE)
+#define SET_SPRITE_ALT(field, tag, alt)                                        
    \
+  do {                                                                     \
+    sprites.field = load_sprite(t, tag);                                   \
+    if (!sprites.field) {                                                  \
+      sprites.field = load_sprite(t, alt);                                 \
+    }                                                                      \
+    if (!sprites.field) {                                                  \
+      die("Sprite tag %s and alternate %s are both missing.", tag, alt);    \
+    }                                                                      \
+  } while(FALSE)
 
 /* Sets sprites.field to tag, or NULL if not available */
 #define SET_SPRITE_OPT(field, tag) \
-  sprites.field = load_sprite(tag)
+  sprites.field = load_sprite(t, tag)
 
-#define SET_SPRITE_ALT_OPT(field, tag, alt) do {               \
-      sprites.field = lookup_sprite_tag_alt(tag, alt, FALSE,   \
-                                           "sprite", #field); \
-    } while (FALSE)
+#define SET_SPRITE_ALT_OPT(field, tag, alt)                    \
+  do {                                                         \
+    sprites.field = lookup_sprite_tag_alt(t, tag, alt, FALSE,   \
+                                         "sprite", #field);    \
+  } while (FALSE)
 
 /****************************************************************************
   Setup the graphics for specialist types.
 ****************************************************************************/
-void tilespec_setup_specialist_types(void)
+void tileset_setup_specialist_types(struct tileset *t)
 {
   /* Load the specialist sprite graphics. */
   specialist_type_iterate(i) {
@@ -1314,7 +1334,7 @@
 
     for (j = 0; j < NUM_TILES_CITIZEN; j++) {
       my_snprintf(buffer, sizeof(buffer), "specialist.%s_%d", name, j);
-      sprites.specialist[i].sprite[j] = load_sprite(buffer);
+      sprites.specialist[i].sprite[j] = load_sprite(t, buffer);
       if (!sprites.specialist[i].sprite[j]) {
        break;
       }
@@ -1330,7 +1350,7 @@
 /****************************************************************************
   Setup the graphics for (non-specialist) citizen types.
 ****************************************************************************/
-static void tilespec_setup_citizen_types(void)
+static void tileset_setup_citizen_types(struct tileset *t)
 {
   int i, j;
   char buffer[512];
@@ -1346,7 +1366,7 @@
 
     for (j = 0; j < NUM_TILES_CITIZEN; j++) {
       my_snprintf(buffer, sizeof(buffer), "citizen.%s_%d", name, j);
-      sprites.citizen[i].sprite[j] = load_sprite(buffer);
+      sprites.citizen[i].sprite[j] = load_sprite(t, buffer);
       if (!sprites.citizen[i].sprite[j]) {
        break;
       }
@@ -1363,14 +1383,14 @@
   Initialize 'sprites' structure based on hardwired tags which
   freeciv always requires. 
 ***********************************************************************/
-static void tilespec_lookup_sprite_tags(void)
+static void tileset_lookup_sprite_tags(struct tileset *t)
 {
   char buffer[512];
   const char dir_char[] = "nsew";
   const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
   int i;
   
-  assert(sprite_hash != NULL);
+  assert(t->sprite_hash != NULL);
 
   SET_SPRITE(treaty_thumb[0], "treaty.disagree_thumb_down");
   SET_SPRITE(treaty_thumb[1], "treaty.agree_thumb_up");
@@ -1385,7 +1405,7 @@
   }
 
   SET_SPRITE(right_arrow, "s.right_arrow");
-  if (is_isometric) {
+  if (t->is_isometric) {
     SET_SPRITE(dither_tile, "t.dither_tile");
   }
 
@@ -1397,7 +1417,7 @@
   SET_SPRITE(tax_science, "s.tax_science");
   SET_SPRITE(tax_gold, "s.tax_gold");
 
-  tilespec_setup_citizen_types();
+  tileset_setup_citizen_types(t);
 
   SET_SPRITE(spaceship.solar_panels, "spaceship.solar_panels");
   SET_SPRITE(spaceship.life_support, "spaceship.life_support");
@@ -1412,22 +1432,22 @@
 
     my_snprintf(buffer, sizeof(buffer), "cursor.%s", names[i]);
     SET_SPRITE(cursor[i].icon, buffer);
-    ss = hash_lookup_data(sprite_hash, buffer);
+    ss = hash_lookup_data(t->sprite_hash, buffer);
     sprites.cursor[i].hot_x = ss->hot_x;
     sprites.cursor[i].hot_y = ss->hot_y;
   }
 
   /* Isolated road graphics are used by roadstyle 0 and 1*/
-  if (roadstyle == 0 || roadstyle == 1) {
+  if (t->roadstyle == 0 || t->roadstyle == 1) {
     SET_SPRITE(road.isolated, "r.road_isolated");
     SET_SPRITE(rail.isolated, "r.rail_isolated");
   }
   
-  if (roadstyle == 0) {
+  if (t->roadstyle == 0) {
     /* Roadstyle 0 has just 8 additional sprites for both road and rail:
      * one for the road/rail going off in each direction. */
-    for (i = 0; i < num_valid_tileset_dirs; i++) {
-      enum direction8 dir = valid_tileset_dirs[i];
+    for (i = 0; i < t->num_valid_tileset_dirs; i++) {
+      enum direction8 dir = t->valid_tileset_dirs[i];
       const char *dir_name = dir_get_tileset_name(dir);
 
       my_snprintf(buffer, sizeof(buffer), "r.road_%s", dir_name);
@@ -1435,8 +1455,8 @@
       my_snprintf(buffer, sizeof(buffer), "r.rail_%s", dir_name);
       SET_SPRITE(rail.dir[i], buffer);
     }
-  } else if (roadstyle == 1) {
-    int num_index = 1 << (num_valid_tileset_dirs / 2), j;
+  } else if (t->roadstyle == 1) {
+    int num_index = 1 << (t->num_valid_tileset_dirs / 2), j;
 
     /* Roadstyle 1 has 32 additional sprites for both road and rail:
      * 16 each for cardinal and diagonal directions.  Each set
@@ -1447,13 +1467,13 @@
     for (i = 1; i < num_index; i++) {
       char c[64] = "", d[64] = "";
 
-      for (j = 0; j < num_valid_tileset_dirs / 2; j++) {
+      for (j = 0; j < t->num_valid_tileset_dirs / 2; j++) {
        int value = (i >> j) & 1;
 
        snprintf(c + strlen(c), sizeof(c) - strlen(c), "%s%d",
-                dir_get_tileset_name(valid_tileset_dirs[2 * j]), value);
+                dir_get_tileset_name(t->valid_tileset_dirs[2 * j]), value);
        snprintf(d + strlen(d), sizeof(d) - strlen(d), "%s%d",
-                dir_get_tileset_name(valid_tileset_dirs[2 * j + 1]), value);
+                dir_get_tileset_name(t->valid_tileset_dirs[2 * j + 1]), value);
       }
 
       my_snprintf(buffer, sizeof(buffer), "r.c_road_%s", c);
@@ -1471,21 +1491,23 @@
   } else {
     /* Roadstyle 2 includes 256 sprites, one for every possibility.
      * Just go around clockwise, with all combinations. */
-    for (i = 0; i < num_index_valid; i++) {
-      my_snprintf(buffer, sizeof(buffer), "r.road_%s", valid_index_str(i));
+    for (i = 0; i < t->num_index_valid; i++) {
+      my_snprintf(buffer, sizeof(buffer),
+                 "r.road_%s", valid_index_str(t, i));
       SET_SPRITE(road.total[i], buffer);
 
-      my_snprintf(buffer, sizeof(buffer), "r.rail_%s", valid_index_str(i));
+      my_snprintf(buffer, sizeof(buffer),
+                 "r.rail_%s", valid_index_str(t, i));
       SET_SPRITE(rail.total[i], buffer);
     }
   }
 
   /* Corner road/rail graphics are used by roadstyle 0 and 1. */
-  if (roadstyle == 0 || roadstyle == 1) {
-    for (i = 0; i < num_valid_tileset_dirs; i++) {
-      enum direction8 dir = valid_tileset_dirs[i];
+  if (t->roadstyle == 0 || t->roadstyle == 1) {
+    for (i = 0; i < t->num_valid_tileset_dirs; i++) {
+      enum direction8 dir = t->valid_tileset_dirs[i];
 
-      if (!is_cardinal_tileset_dir(dir)) {
+      if (!is_cardinal_tileset_dir(t, dir)) {
        my_snprintf(buffer, sizeof(buffer), "r.c_road_%s",
                    dir_get_tileset_name(dir));
        SET_SPRITE_OPT(road.corner[dir], buffer);
@@ -1504,7 +1526,7 @@
     struct Sprite *sprite;
 
     my_snprintf(buffer, sizeof(buffer), "explode.unit_%d", i);
-    sprite = load_sprite(buffer);
+    sprite = load_sprite(t, buffer);
     if (!sprite) {
       break;
     }
@@ -1543,11 +1565,11 @@
     /* Veteran level sprites are optional.  For instance "green" units
      * usually have no special graphic. */
     my_snprintf(buffer, sizeof(buffer), "unit.vet_%d", i);
-    sprites.unit.vet_lev[i] = load_sprite(buffer);
+    sprites.unit.vet_lev[i] = load_sprite(t, buffer);
   }
 
   sprites.unit.select[0] = NULL;
-  if (load_sprite("unit.select0")) {
+  if (load_sprite(t, "unit.select0")) {
     for (i = 0; i < NUM_TILES_SELECT; i++) {
       my_snprintf(buffer, sizeof(buffer), "unit.select%d", i);
       SET_SPRITE(unit.select[i], buffer);
@@ -1583,10 +1605,10 @@
   output_type_iterate(o) {
     my_snprintf(buffer, sizeof(buffer),
                "upkeep.%s", get_output_identifier(o));
-    sprites.upkeep.output[o][0] = load_sprite(buffer);
+    sprites.upkeep.output[o][0] = load_sprite(t, buffer);
     my_snprintf(buffer, sizeof(buffer),
                "upkeep.%s2", get_output_identifier(o));
-    sprites.upkeep.output[o][1] = load_sprite(buffer);
+    sprites.upkeep.output[o][1] = load_sprite(t, buffer);
   } output_type_iterate_end;
   
   SET_SPRITE(user.attention, "user.attention");
@@ -1609,7 +1631,7 @@
     struct Sprite *sprite;
 
     my_snprintf(buffer, sizeof(buffer), "colors.overlay_%d", i);
-    sprite = load_sprite(buffer);
+    sprite = load_sprite(t, buffer);
     if (!sprite) {
       break;
     }
@@ -1640,16 +1662,16 @@
     sprites.city.unworked_tile_overlay.p[i] = unworked;
   }
 
-  if (load_sprite("grid.main.ns")) {
+  if (load_sprite(t, "grid.main.ns")) {
     SET_SPRITE(grid.unavailable, "grid.unavailable");
 
     for (i = 0; i < EDGE_COUNT; i++) {
       char *name[EDGE_COUNT] = {"ns", "we", "ud", "lr"};
       int j, p;
 
-      if (i == EDGE_UD && hex_width == 0) {
+      if (i == EDGE_UD && t->hex_width == 0) {
        continue;
-      } else if (i == EDGE_LR && hex_height == 0) {
+      } else if (i == EDGE_LR && t->hex_height == 0) {
        continue;
       }
 
@@ -1688,34 +1710,34 @@
     }
   }
 
-  for (i = 0; i < num_index_cardinal; i++) {
+  for (i = 0; i < t->num_index_cardinal; i++) {
     my_snprintf(buffer, sizeof(buffer), "tx.s_river_%s",
-               cardinal_index_str(i));
+               cardinal_index_str(t, i));
     SET_SPRITE(tx.spec_river[i], buffer);
   }
 
   /* We use direction-specific irrigation and farmland graphics, if they
    * are available.  If not, we just fall back to the basic irrigation
    * graphics. */
-  for (i = 0; i < num_index_cardinal; i++) {
+  for (i = 0; i < t->num_index_cardinal; i++) {
     my_snprintf(buffer, sizeof(buffer), "tx.s_irrigation_%s",
-               cardinal_index_str(i));
+               cardinal_index_str(t, i));
     SET_SPRITE_ALT(tx.irrigation[i], buffer, "tx.irrigation");
   }
-  for (i = 0; i < num_index_cardinal; i++) {
+  for (i = 0; i < t->num_index_cardinal; i++) {
     my_snprintf(buffer, sizeof(buffer), "tx.s_farmland_%s",
-               cardinal_index_str(i));
+               cardinal_index_str(t, i));
     SET_SPRITE_ALT(tx.farmland[i], buffer, "tx.farmland");
   }
 
-  switch (darkness_style) {
+  switch (t->darkness_style) {
   case DARKNESS_NONE:
     /* Nothing. */
     break;
   case DARKNESS_ISORECT:
     {
       /* Isometric: take a single tx.darkness tile and split it into 4. */
-      struct Sprite *darkness = load_sprite("tx.darkness");
+      struct Sprite *darkness = load_sprite(t, "tx.darkness");
       const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
       int offsets[4][2] = {{W / 2, 0}, {0, H / 2}, {W / 2, H / 2}, {0, 0}};
 
@@ -1731,8 +1753,8 @@
     }
     break;
   case DARKNESS_CARD_SINGLE:
-    for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-      enum direction8 dir = cardinal_tileset_dirs[i];
+    for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
+      enum direction8 dir = t->cardinal_tileset_dirs[i];
 
       my_snprintf(buffer, sizeof(buffer), "tx.darkness_%s",
                  dir_get_tileset_name(dir));
@@ -1740,9 +1762,9 @@
     }
     break;
   case DARKNESS_CARD_FULL:
-    for(i = 1; i < num_index_cardinal; i++) {
+    for(i = 1; i < t->num_index_cardinal; i++) {
       my_snprintf(buffer, sizeof(buffer), "tx.darkness_%s",
-                 cardinal_index_str(i));
+                 cardinal_index_str(t, i));
       SET_SPRITE(tx.darkness[i], buffer);
     }
     break;
@@ -1763,7 +1785,7 @@
       }
       assert(k == 0);
 
-      sprites.tx.fullfog[i] = load_sprite(buf);
+      sprites.tx.fullfog[i] = load_sprite(t, buf);
     }
     break;
   }
@@ -1777,37 +1799,53 @@
   sprites.city.tile = NULL;         /* no place to initialize this variable */
 }
 
+/**************************************************************************
+  Frees any internal buffers which are created by load_sprite. Should
+  be called after the last (for a given period of time) load_sprite
+  call.  This saves a fair amount of memory, but it will take extra time
+  the next time we start loading sprites again.
+**************************************************************************/
+static void finish_loading_sprites(struct tileset *t)
+{
+  specfile_list_iterate(t->specfiles, sf) {
+    if (sf->big_sprite) {
+      free_sprite(sf->big_sprite);
+      sf->big_sprite = NULL;
+    }
+  } specfile_list_iterate_end;
+}
 /**********************************************************************
   Load the tiles; requires tilespec_read_toplevel() called previously.
   Leads to tile_sprites being allocated and filled with pointers
   to sprites.   Also sets up and populates sprite_hash, and calls func
   to initialize 'sprites' structure.
 ***********************************************************************/
-void tilespec_load_tiles(void)
+void tileset_load_tiles(struct tileset *t)
 {
-  tilespec_lookup_sprite_tags();
-  finish_loading_sprites();
+  tileset_lookup_sprite_tags(t);
+  finish_loading_sprites(t);
 }
 
 /**********************************************************************
   Lookup sprite to match tag, or else to match alt if don't find,
   or else return NULL, and emit log message.
 ***********************************************************************/
-static struct Sprite* lookup_sprite_tag_alt(const char *tag, const char *alt,
+static struct Sprite* lookup_sprite_tag_alt(struct tileset *t,
+                                           const char *tag, const char *alt,
                                            bool required, const char *what,
                                            const char *name)
 {
   struct Sprite *sp;
   
   /* (should get sprite_hash before connection) */
-  if (!sprite_hash) {
+  if (!t->sprite_hash) {
     die("attempt to lookup for %s %s before sprite_hash setup", what, name);
   }
 
-  sp = load_sprite(tag);
+  sp = load_sprite(t, tag);
   if (sp) return sp;
 
-  sp = load_sprite(alt);
+  sp = load_sprite(t, alt);
   if (sp) {
     freelog(LOG_VERBOSE,
            "Using alternate graphic %s (instead of %s) for %s %s",
@@ -1828,11 +1866,11 @@
   Set unit_type sprite value; should only happen after
   tilespec_load_tiles().
 ***********************************************************************/
-void tilespec_setup_unit_type(int id)
+void tileset_setup_unit_type(struct tileset *t, int id)
 {
   struct unit_type *ut = get_unit_type(id);
   
-  ut->sprite = lookup_sprite_tag_alt(ut->graphic_str, ut->graphic_alt,
+  ut->sprite = lookup_sprite_tag_alt(t, ut->graphic_str, ut->graphic_alt,
                                     TRUE, "unit_type", ut->name);
 
   /* should maybe do something if NULL, eg generic default? */
@@ -1842,11 +1880,11 @@
   Set improvement_type sprite value; should only happen after
   tilespec_load_tiles().
 ***********************************************************************/
-void tilespec_setup_impr_type(int id)
+void tileset_setup_impr_type(struct tileset *t, int id)
 {
   struct impr_type *pimpr = get_improvement_type(id);
 
-  pimpr->sprite = lookup_sprite_tag_alt(pimpr->graphic_str,
+  pimpr->sprite = lookup_sprite_tag_alt(t, pimpr->graphic_str,
                                        pimpr->graphic_alt,
                                        FALSE, "impr_type",
                                        pimpr->name);
@@ -1858,11 +1896,11 @@
   Set tech_type sprite value; should only happen after
   tilespec_load_tiles().
 ***********************************************************************/
-void tilespec_setup_tech_type(int id)
+void tileset_setup_tech_type(struct tileset *t, int id)
 {
   if (tech_exists(id)) {
     advances[id].sprite
-      = lookup_sprite_tag_alt(advances[id].graphic_str,
+      = lookup_sprite_tag_alt(t, advances[id].graphic_str,
                              advances[id].graphic_alt,
                              FALSE, "tech_type",
                              get_tech_name(game.player_ptr, id));
@@ -1877,7 +1915,7 @@
   Set tile_type sprite values; should only happen after
   tilespec_load_tiles().
 ***********************************************************************/
-void tilespec_setup_tile_type(Terrain_type_id terrain)
+void tileset_setup_tile_type(struct tileset *t, Terrain_type_id terrain)
 {
   struct tile_type *tt = get_tile_type(terrain);
   struct terrain_drawing_data *draw;
@@ -1888,9 +1926,9 @@
     return;
   }
 
-  draw = hash_lookup_data(terrain_hash, tt->graphic_str);
+  draw = hash_lookup_data(t->terrain_hash, tt->graphic_str);
   if (!draw) {
-    draw = hash_lookup_data(terrain_hash, tt->graphic_alt);
+    draw = hash_lookup_data(t->terrain_hash, tt->graphic_alt);
     if (!draw) {
       freelog(LOG_FATAL, "No graphics %s or %s for %s terrain.",
              tt->graphic_str, tt->graphic_alt, tt->terrain_name);
@@ -1908,7 +1946,7 @@
        struct Sprite *sprite;
 
        my_snprintf(buffer1, sizeof(buffer1), "t.%s%d", draw->name, i + 1);
-       sprite = load_sprite(buffer1);
+       sprite = load_sprite(t, buffer1);
        if (!sprite) {
          break;
        }
@@ -1925,10 +1963,10 @@
       switch (draw->layer[l].cell_type) {
       case CELL_SINGLE:
        /* Load 16 cardinally-matched sprites. */
-       for (i = 0; i < num_index_cardinal; i++) {
+       for (i = 0; i < t->num_index_cardinal; i++) {
          my_snprintf(buffer1, sizeof(buffer1),
-                     "t.%s_%s", draw->name, cardinal_index_str(i));
-         draw->layer[l].match[i] = lookup_sprite_tag_alt(buffer1, "", TRUE,
+                     "t.%s_%s", draw->name, cardinal_index_str(t, i));
+         draw->layer[l].match[i] = lookup_sprite_tag_alt(t, buffer1, "", TRUE,
                                                          "tile_type",
                                                          tt->terrain_name);
        }
@@ -1960,7 +1998,7 @@
                          (value >> 1) & 1,
                          (value >> 2) & 1);
              draw->layer[l].cells[i]
-               = lookup_sprite_tag_alt(buffer1, "", TRUE, "tile_type",
+               = lookup_sprite_tag_alt(t, buffer1, "", TRUE, "tile_type",
                                        tt->terrain_name);
              break;
            case MATCH_FULL:
@@ -2007,11 +2045,11 @@
                }
                my_snprintf(buffer1, sizeof(buffer1),
                            "t.cellgroup_%s_%s_%s_%s",
-                           layers[l].match_types[n],
-                           layers[l].match_types[e],
-                           layers[l].match_types[s],
-                           layers[l].match_types[w]);
-               sprite = load_sprite(buffer1);
+                           t->layers[l].match_types[n],
+                           t->layers[l].match_types[e],
+                           t->layers[l].match_types[s],
+                           t->layers[l].match_types[w]);
+               sprite = load_sprite(t, buffer1);
 
                if (sprite) {
                  /* Crop the sprite to separate this cell. */
@@ -2034,14 +2072,14 @@
        }
        my_snprintf(buffer1, sizeof(buffer1), "t.%s1", draw->name);
        draw->layer[l].base.p[0]
-         = lookup_sprite_tag_alt(buffer1, "", FALSE, "tile_type",
+         = lookup_sprite_tag_alt(t, buffer1, "", FALSE, "tile_type",
                                  tt->terrain_name);
        break;
       }
     }
   }
 
-  if (draw->is_blended && is_isometric) {
+  if (draw->is_blended && t->is_isometric) {
     /* Set up blending sprites. This only works in iso-view! */
     const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
     const int offsets[4][2] = {
@@ -2063,7 +2101,7 @@
 
     if (name[0] != '\0') {
       draw->special[i]
-       = lookup_sprite_tag_alt(tt->special[i].graphic_str,
+       = lookup_sprite_tag_alt(t, tt->special[i].graphic_str,
                                tt->special[i].graphic_alt,
                                TRUE, "tile_type special", name);
       assert(draw->special[i] != NULL);
@@ -2074,7 +2112,7 @@
   }
 
   if (draw->mine_tag) {
-    draw->mine = load_sprite(draw->mine_tag);
+    draw->mine = load_sprite(t, draw->mine_tag);
   } else {
     draw->mine = NULL;
   }
@@ -2086,11 +2124,11 @@
   Set government sprite value; should only happen after
   tilespec_load_tiles().
 ***********************************************************************/
-void tilespec_setup_government(int id)
+void tileset_setup_government(struct tileset *t, int id)
 {
   struct government *gov = get_government(id);
   
-  gov->sprite = lookup_sprite_tag_alt(gov->graphic_str, gov->graphic_alt,
+  gov->sprite = lookup_sprite_tag_alt(t, gov->graphic_str, gov->graphic_alt,
                                      TRUE, "government", gov->name);
   
   /* should probably do something if NULL, eg generic default? */
@@ -2100,7 +2138,7 @@
   Set nation flag sprite value; should only happen after
   tilespec_load_tiles().
 ***********************************************************************/
-void tilespec_setup_nation_flag(int id)
+void tileset_setup_nation_flag(struct tileset *t, int id)
 {
   struct nation_type *nation = get_nation_by_idx(id);
   char *tags[] = {nation->flag_graphic_str,
@@ -2110,7 +2148,7 @@
 
   nation->flag_sprite = NULL;
   for (i = 0; tags[i] && !nation->flag_sprite; i++) {
-    nation->flag_sprite = load_sprite(tags[i]);
+    nation->flag_sprite = load_sprite(t, tags[i]);
   }
   if (!nation->flag_sprite) {
     /* Should never get here because of the f.unknown fallback. */
@@ -2138,7 +2176,8 @@
 /**************************************************************************
 Return the sprite needed to draw the city
 **************************************************************************/
-static struct Sprite *get_city_sprite(const struct city *pcity)
+static struct Sprite *get_city_sprite(struct tileset *t,
+                                     const struct city *pcity)
 {
   int size, style;
 
@@ -2148,7 +2187,7 @@
     if( pcity->size < city_styles[style].tresh[size]) 
       break;
 
-  if (is_isometric) {
+  if (t->is_isometric) {
     if (city_got_citywalls(pcity))
       return sprites.city.tile_wall[style][size-1];
     else
@@ -2179,14 +2218,14 @@
   return sprites.city.tile[style][city_styles[style].tiles_num+1];
 }
 
-#define ADD_SPRITE(s, draw_style, draw_fog, x_offset, y_offset)        \
-  (assert(s != NULL),                                          \
-   sprs->type = DRAWN_SPRITE,                                  \
-   sprs->data.sprite.style = draw_style,                       \
-   sprs->data.sprite.sprite = s,                               \
-   sprs->data.sprite.foggable = (draw_fog && fogstyle == FOG_AUTO),    \
-   sprs->data.sprite.offset_x = x_offset,                      \
-   sprs->data.sprite.offset_y = y_offset,                      \
+#define ADD_SPRITE(s, draw_style, draw_fog, x_offset, y_offset)                
    \
+  (assert(s != NULL),                                                      \
+   sprs->type = DRAWN_SPRITE,                                              \
+   sprs->data.sprite.style = draw_style,                                   \
+   sprs->data.sprite.sprite = s,                                           \
+   sprs->data.sprite.foggable = (draw_fog && t->fogstyle == FOG_AUTO),     \
+   sprs->data.sprite.offset_x = x_offset,                                  \
+   sprs->data.sprite.offset_y = y_offset,                                  \
    sprs++)
 #define ADD_SPRITE_SIMPLE(s) ADD_SPRITE(s, DRAW_NORMAL, TRUE, 0, 0)
 #define ADD_SPRITE_FULL(s) ADD_SPRITE(s, DRAW_FULL, TRUE, 0, 0)
@@ -2241,7 +2280,8 @@
 /**********************************************************************
   Fill in the sprite array for the unit
 ***********************************************************************/
-static int fill_unit_sprite_array(struct drawn_sprite *sprs,
+static int fill_unit_sprite_array(struct tileset *t,
+                                 struct drawn_sprite *sprs,
                                  const struct unit *punit,
                                  bool stack, bool backdrop)
 {
@@ -2251,14 +2291,14 @@
   if (backdrop) {
     if (!solid_color_behind_units) {
       ADD_SPRITE(get_unit_nation_flag_sprite(punit),
-                DRAW_FULL, TRUE, flag_offset_x, flag_offset_y);
+                DRAW_FULL, TRUE, t->flag_offset_x, t->flag_offset_y);
     } else {
       /* Taken care of in the LAYER_BACKGROUND. */
     }
   }
 
   ADD_SPRITE(unit_type(punit)->sprite, DRAW_FULL, TRUE,
-            unit_offset_x, unit_offset_y);
+            t->unit_offset_x, t->unit_offset_y);
 
   if (sprites.unit.loaded && punit->transported_by != -1) {
     ADD_SPRITE_FULL(sprites.unit.loaded);
@@ -2367,7 +2407,8 @@
 /**************************************************************************
   Add any corner road sprites to the sprite array.
 **************************************************************************/
-static int fill_road_corner_sprites(struct drawn_sprite *sprs,
+static int fill_road_corner_sprites(struct tileset *t,
+                                   struct drawn_sprite *sprs,
                                    bool road, bool *road_near,
                                    bool rail, bool *rail_near)
 {
@@ -2387,15 +2428,16 @@
    * connects two tiles, only the railroad (no road) is drawn between
    * those tiles.
    */
-  for (i = 0; i < num_valid_tileset_dirs; i++) {
-    enum direction8 dir = valid_tileset_dirs[i];
+  for (i = 0; i < t->num_valid_tileset_dirs; i++) {
+    enum direction8 dir = t->valid_tileset_dirs[i];
 
-    if (!is_cardinal_tileset_dir(dir)) {
+    if (!is_cardinal_tileset_dir(t, dir)) {
       /* Draw corner sprites for this non-cardinal direction. */
-      int cw = (i + 1) % num_valid_tileset_dirs;
-      int ccw = (i + num_valid_tileset_dirs - 1) % num_valid_tileset_dirs;
-      enum direction8 dir_cw = valid_tileset_dirs[cw];
-      enum direction8 dir_ccw = valid_tileset_dirs[ccw];
+      int cw = (i + 1) % t->num_valid_tileset_dirs;
+      int ccw
+       = (i + t->num_valid_tileset_dirs - 1) % t->num_valid_tileset_dirs;
+      enum direction8 dir_cw = t->valid_tileset_dirs[cw];
+      enum direction8 dir_ccw = t->valid_tileset_dirs[ccw];
 
       if (sprites.road.corner[dir]
          && (road_near[dir_cw] && road_near[dir_ccw]
@@ -2412,7 +2454,8 @@
 /**************************************************************************
   Add any corner rail sprites to the sprite array.
 **************************************************************************/
-static int fill_rail_corner_sprites(struct drawn_sprite *sprs,
+static int fill_rail_corner_sprites(struct tileset *t,
+                                   struct drawn_sprite *sprs,
                                    bool rail, bool *rail_near)
 {
   struct drawn_sprite *saved_sprs = sprs;
@@ -2423,15 +2466,16 @@
   /* Rails going diagonally adjacent to this tile need to be
    * partly drawn on this tile. */
 
-  for (i = 0; i < num_valid_tileset_dirs; i++) {
-    enum direction8 dir = valid_tileset_dirs[i];
+  for (i = 0; i < t->num_valid_tileset_dirs; i++) {
+    enum direction8 dir = t->valid_tileset_dirs[i];
 
-    if (!is_cardinal_tileset_dir(dir)) {
+    if (!is_cardinal_tileset_dir(t, dir)) {
       /* Draw corner sprites for this non-cardinal direction. */
-      int cw = (i + 1) % num_valid_tileset_dirs;
-      int ccw = (i + num_valid_tileset_dirs - 1) % num_valid_tileset_dirs;
-      enum direction8 dir_cw = valid_tileset_dirs[cw];
-      enum direction8 dir_ccw = valid_tileset_dirs[ccw];
+      int cw = (i + 1) % t->num_valid_tileset_dirs;
+      int ccw
+       = (i + t->num_valid_tileset_dirs - 1) % t->num_valid_tileset_dirs;
+      enum direction8 dir_cw = t->valid_tileset_dirs[cw];
+      enum direction8 dir_ccw = t->valid_tileset_dirs[ccw];
 
       if (sprites.rail.corner[dir]
          && rail_near[dir_cw] && rail_near[dir_ccw]
@@ -2447,7 +2491,8 @@
 /**************************************************************************
   Fill all road and rail sprites into the sprite array.
 **************************************************************************/
-static int fill_road_rail_sprite_array(struct drawn_sprite *sprs,
+static int fill_road_rail_sprite_array(struct tileset *t,
+                                      struct drawn_sprite *sprs,
                                       enum tile_special_type tspecial,
                                       enum tile_special_type *tspecial_near,
                                       const struct city *pcity)
@@ -2488,9 +2533,10 @@
   }
 
   /* Draw road corners underneath rails (styles 0 and 1). */
-  sprs += fill_road_corner_sprites(sprs, road, road_near, rail, rail_near);
+  sprs
+    += fill_road_corner_sprites(t, sprs, road, road_near, rail, rail_near);
 
-  if (roadstyle == 0) {
+  if (t->roadstyle == 0) {
     /* With roadstyle 0, we simply draw one road/rail for every connection.
      * This means we only need a few sprites, but a lot of drawing is
      * necessary and it generally doesn't look very good. */
@@ -2498,8 +2544,8 @@
 
     /* First raw roads under rails. */
     if (road) {
-      for (i = 0; i < num_valid_tileset_dirs; i++) {
-       if (draw_road[valid_tileset_dirs[i]]) {
+      for (i = 0; i < t->num_valid_tileset_dirs; i++) {
+       if (draw_road[t->valid_tileset_dirs[i]]) {
          ADD_SPRITE_SIMPLE(sprites.road.dir[i]);
        }
       }
@@ -2507,13 +2553,13 @@
 
     /* Then draw rails over roads. */
     if (rail) {
-      for (i = 0; i < num_valid_tileset_dirs; i++) {
-       if (draw_rail[valid_tileset_dirs[i]]) {
+      for (i = 0; i < t->num_valid_tileset_dirs; i++) {
+       if (draw_rail[t->valid_tileset_dirs[i]]) {
          ADD_SPRITE_SIMPLE(sprites.rail.dir[i]);
        }
       }
     }
-  } else if (roadstyle == 1) {
+  } else if (t->roadstyle == 1) {
     /* With roadstyle 1, we draw one sprite for cardinal road connections,
      * one sprite for diagonal road connections, and the same for rail.
      * This means we need about 4x more sprites than in style 0, but up to
@@ -2524,9 +2570,9 @@
     if (road) {
       int road_even_tileno = 0, road_odd_tileno = 0, i;
 
-      for (i = 0; i < num_valid_tileset_dirs / 2; i++) {
-       enum direction8 even = valid_tileset_dirs[2 * i];
-       enum direction8 odd = valid_tileset_dirs[2 * i + 1];
+      for (i = 0; i < t->num_valid_tileset_dirs / 2; i++) {
+       enum direction8 even = t->valid_tileset_dirs[2 * i];
+       enum direction8 odd = t->valid_tileset_dirs[2 * i + 1];
 
        if (draw_road[even]) {
          road_even_tileno |= 1 << i;
@@ -2549,9 +2595,9 @@
     if (rail) {
       int rail_even_tileno = 0, rail_odd_tileno = 0, i;
 
-      for (i = 0; i < num_valid_tileset_dirs / 2; i++) {
-       enum direction8 even = valid_tileset_dirs[2 * i];
-       enum direction8 odd = valid_tileset_dirs[2 * i + 1];
+      for (i = 0; i < t->num_valid_tileset_dirs / 2; i++) {
+       enum direction8 even = t->valid_tileset_dirs[2 * i];
+       enum direction8 odd = t->valid_tileset_dirs[2 * i + 1];
 
        if (draw_rail[even]) {
          rail_even_tileno |= 1 << i;
@@ -2578,8 +2624,8 @@
     if (road) {
       int road_tileno = 0, i;
 
-      for (i = 0; i < num_valid_tileset_dirs; i++) {
-       enum direction8 dir = valid_tileset_dirs[i];
+      for (i = 0; i < t->num_valid_tileset_dirs; i++) {
+       enum direction8 dir = t->valid_tileset_dirs[i];
 
        if (draw_road[dir]) {
          road_tileno |= 1 << i;
@@ -2595,8 +2641,8 @@
     if (rail) {
       int rail_tileno = 0, i;
 
-      for (i = 0; i < num_valid_tileset_dirs; i++) {
-       enum direction8 dir = valid_tileset_dirs[i];
+      for (i = 0; i < t->num_valid_tileset_dirs; i++) {
+       enum direction8 dir = t->valid_tileset_dirs[i];
 
        if (draw_rail[dir]) {
          rail_tileno |= 1 << i;
@@ -2610,7 +2656,7 @@
   }
 
   /* Draw isolated rail/road separately (styles 0 and 1 only). */
-  if (roadstyle == 0 || roadstyle == 1) { 
+  if (t->roadstyle == 0 || t->roadstyle == 1) { 
     if (draw_single_rail) {
       ADD_SPRITE_SIMPLE(sprites.rail.isolated);
     } else if (draw_single_road) {
@@ -2619,7 +2665,7 @@
   }
 
   /* Draw rail corners over roads (styles 0 and 1). */
-  sprs += fill_rail_corner_sprites(sprs, rail, rail_near);
+  sprs += fill_rail_corner_sprites(t, sprs, rail, rail_near);
 
   return sprs - saved_sprs;
 }
@@ -2633,12 +2679,13 @@
   either farmland or irrigation (the two are considered interchangable for
   this).
 **************************************************************************/
-static int get_irrigation_index(enum tile_special_type *tspecial_near)
+static int get_irrigation_index(struct tileset *t,
+                               enum tile_special_type *tspecial_near)
 {
   int tileno = 0, i;
 
-  for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-    enum direction8 dir = cardinal_tileset_dirs[i];
+  for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
+    enum direction8 dir = t->cardinal_tileset_dirs[i];
 
     /* A tile with S_FARMLAND will also have S_IRRIGATION set. */
     if (contains_special(tspecial_near[dir], S_IRRIGATION)) {
@@ -2652,7 +2699,8 @@
 /**************************************************************************
   Fill in the farmland/irrigation sprite for the tile.
 **************************************************************************/
-static int fill_irrigation_sprite_array(struct drawn_sprite *sprs,
+static int fill_irrigation_sprite_array(struct tileset *t,
+                                       struct drawn_sprite *sprs,
                                        enum tile_special_type tspecial,
                                        enum tile_special_type *tspecial_near,
                                        const struct city *pcity)
@@ -2668,7 +2716,7 @@
   if (draw_irrigation
       && contains_special(tspecial, S_IRRIGATION)
       && !(pcity && draw_cities)) {
-    int index = get_irrigation_index(tspecial_near);
+    int index = get_irrigation_index(t, tspecial_near);
 
     if (contains_special(tspecial, S_FARMLAND)) {
       ADD_SPRITE_SIMPLE(sprites.tx.farmland[index]);
@@ -2683,14 +2731,15 @@
 /****************************************************************************
   Fill in the sprite array for blended terrain.
 ****************************************************************************/
-static int fill_blending_sprite_array(struct drawn_sprite *sprs,
+static int fill_blending_sprite_array(struct tileset *t,
+                                     struct drawn_sprite *sprs,
                                      const struct tile *ptile,
                                      Terrain_type_id *ttype_near)
 {
   struct drawn_sprite *saved_sprs = sprs;
   Terrain_type_id ttype = map_get_terrain(ptile);
 
-  if (is_isometric && sprites.terrain[ttype]->is_blended) {
+  if (t->is_isometric && sprites.terrain[ttype]->is_blended) {
     enum direction4 dir;
     const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
     const int offsets[4][2] = {
@@ -2724,20 +2773,21 @@
 /****************************************************************************
   Add sprites for fog (and some forms of darkness).
 ****************************************************************************/
-static int fill_fog_sprite_array(struct drawn_sprite *sprs,
+static int fill_fog_sprite_array(struct tileset *t,
+                                struct drawn_sprite *sprs,
                                 const struct tile *ptile,
                                 const struct tile_edge *pedge,
                                 const struct tile_corner *pcorner)
 {
   struct drawn_sprite *saved_sprs = sprs;
 
-  if (fogstyle == FOG_SPRITE && draw_fog_of_war
+  if (t->fogstyle == FOG_SPRITE && draw_fog_of_war
       && ptile && tile_get_known(ptile) == TILE_KNOWN_FOGGED) {
     /* With FOG_AUTO, fog is done this way. */
     ADD_SPRITE_SIMPLE(sprites.tx.fog);
   }
 
-  if (darkness_style == DARKNESS_CORNER && pcorner && draw_fog_of_war) {
+  if (t->darkness_style == DARKNESS_CORNER && pcorner && draw_fog_of_war) {
     int i, tileno = 0;
 
     for (i = 3; i >= 0; i--) {
@@ -2776,7 +2826,8 @@
   Add sprites for the base terrain to the sprite list.  This doesn't
   include specials or rivers.
 ****************************************************************************/
-static int fill_terrain_sprite_array(struct drawn_sprite *sprs,
+static int fill_terrain_sprite_array(struct tileset *t,
+                                    struct drawn_sprite *sprs,
                                     int layer,
                                     const struct tile *ptile,
                                     Terrain_type_id *ttype_near)
@@ -2794,7 +2845,7 @@
   }
 
   /* Skip the normal drawing process. */
-  if (ptile->spec_sprite && (sprite = load_sprite(ptile->spec_sprite))) {
+  if (ptile->spec_sprite && (sprite = load_sprite(t, ptile->spec_sprite))) {
     if (layer == 0) {
       ADD_SPRITE_SIMPLE(sprite);
       return 1;
@@ -2830,8 +2881,8 @@
     if (draw->layer[l].cell_type == CELL_SINGLE) {
       tileno = 0;
       assert(draw->layer[l].match_style == MATCH_BOOLEAN);
-      for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-       enum direction8 dir = cardinal_tileset_dirs[i];
+      for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
+       enum direction8 dir = t->cardinal_tileset_dirs[i];
 
        if (MATCH(dir) == match_type) {
          tileno |= 1 << i;
@@ -2863,8 +2914,8 @@
        const int count = draw->layer[l].match_count;
        int array_index = 0;
        enum direction8 dir = dir_ccw(DIR4_TO_DIR8[i]);
-       int x = (is_isometric ? iso_offsets[i][0] : noniso_offsets[i][0]);
-       int y = (is_isometric ? iso_offsets[i][1] : noniso_offsets[i][1]);
+       int x = (t->is_isometric ? iso_offsets[i][0] : noniso_offsets[i][0]);
+       int y = (t->is_isometric ? iso_offsets[i][1] : noniso_offsets[i][1]);
        int m[3] = {MATCH(dir_ccw(dir)), MATCH(dir), MATCH(dir_cw(dir))};
        struct Sprite *s;
 
@@ -2901,7 +2952,7 @@
 
   /* Add blending on top of the first layer. */
   if (l == 0 && draw->is_blended) {
-    sprs += fill_blending_sprite_array(sprs, ptile, ttype_near);
+    sprs += fill_blending_sprite_array(t, sprs, ptile, ttype_near);
   }
 
   /* Add darkness on top of the first layer.  Note that darkness is always
@@ -2911,7 +2962,7 @@
     ((adjc_tile = mapstep(ptile, (dir)))                   \
      && tile_get_known(adjc_tile) == TILE_UNKNOWN)
 
-    switch (darkness_style) {
+    switch (t->darkness_style) {
     case DARKNESS_NONE:
       break;
     case DARKNESS_ISORECT:
@@ -2926,8 +2977,8 @@
       }
       break;
     case DARKNESS_CARD_SINGLE:
-      for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-       if (UNKNOWN(cardinal_tileset_dirs[i])) {
+      for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
+       if (UNKNOWN(t->cardinal_tileset_dirs[i])) {
          ADD_SPRITE_SIMPLE(sprites.tx.darkness[i]);
        }
       }
@@ -2939,8 +2990,8 @@
        * way we won't get the "unknown" dither along the edge of the
        * map. */
       tileno = 0;
-      for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-       if (UNKNOWN(cardinal_tileset_dirs[i])) {
+      for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
+       if (UNKNOWN(t->cardinal_tileset_dirs[i])) {
          tileno |= 1 << i;
        }
       }
@@ -2963,7 +3014,8 @@
 /****************************************************************************
   Fill in the grid sprites for the given tile, city, and unit.
 ****************************************************************************/
-static int fill_grid_sprite_array(struct drawn_sprite *sprs,
+static int fill_grid_sprite_array(struct tileset *t,
+                                 struct drawn_sprite *sprs,
                                  const struct tile *ptile,
                                  const struct tile_edge *pedge,
                                  const struct tile_corner *pcorner,
@@ -3099,7 +3151,8 @@
   citymode specifies whether this is part of a citydlg.  If so some drawing
   is done differently.
 ****************************************************************************/
-int fill_sprite_array(struct drawn_sprite *sprs, enum mapview_layer layer,
+int fill_sprite_array(struct tileset *t,
+                     struct drawn_sprite *sprs, enum mapview_layer layer,
                      const struct tile *ptile,
                      const struct tile_edge *pedge,
                      const struct tile_corner *pcorner,
@@ -3178,7 +3231,7 @@
      * upper layers will cover layers underneath. */
     if (ptile && !solid_bg && tile_get_known(ptile) != TILE_UNKNOWN) {
       assert(MAX_NUM_LAYERS == 2);
-      sprs += fill_terrain_sprite_array(sprs,
+      sprs += fill_terrain_sprite_array(t, sprs,
                                        (layer == LAYER_TERRAIN1) ? 0 : 1,
                                        ptile, ttype_near);
     }
@@ -3194,7 +3247,7 @@
        }
       }
 
-      sprs += fill_irrigation_sprite_array(sprs, tspecial, tspecial_near,
+      sprs += fill_irrigation_sprite_array(t, sprs, tspecial, tspecial_near,
                                           pcity);
 
       if (draw_terrain && !solid_bg && contains_special(tspecial, S_RIVER)) {
@@ -3202,8 +3255,8 @@
 
        /* Draw rivers on top of irrigation. */
        tileno = 0;
-       for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-         enum direction8 dir = cardinal_tileset_dirs[i];
+       for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
+         enum direction8 dir = t->cardinal_tileset_dirs[i];
 
          if (contains_special(tspecial_near[dir], S_RIVER)
              || is_ocean(ttype_near[dir])) {
@@ -3217,7 +3270,7 @@
 
   case LAYER_ROADS:
     if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
-      sprs += fill_road_rail_sprite_array(sprs,
+      sprs += fill_road_rail_sprite_array(t, sprs,
                                          tspecial, tspecial_near, pcity);
     }
     break;
@@ -3249,8 +3302,8 @@
     break;
 
   case LAYER_GRID1:
-    if (is_isometric) {
-      sprs += fill_grid_sprite_array(sprs, ptile, pedge, pcorner,
+    if (t->is_isometric) {
+      sprs += fill_grid_sprite_array(t, sprs, ptile, pedge, pcorner,
                                     punit, pcity, citymode);
     }
     break;
@@ -3260,13 +3313,13 @@
     if (pcity && draw_cities) {
       if (!solid_color_behind_units) {
        ADD_SPRITE(get_city_nation_flag_sprite(pcity),
-                  DRAW_FULL, TRUE, flag_offset_x, flag_offset_y);
+                  DRAW_FULL, TRUE, t->flag_offset_x, t->flag_offset_y);
       }
-      ADD_SPRITE_FULL(get_city_sprite(pcity));
+      ADD_SPRITE_FULL(get_city_sprite(t, pcity));
       if (pcity->client.occupied) {
        ADD_SPRITE_FULL(get_city_occupied_sprite(pcity));
       }
-      if (!is_isometric && city_got_citywalls(pcity)) {
+      if (!t->is_isometric && city_got_citywalls(pcity)) {
        /* In iso-view the city wall is a part of the city sprite. */
        ADD_SPRITE_SIMPLE(get_city_wall_sprite(pcity));
       }
@@ -3292,7 +3345,7 @@
     break;
 
   case LAYER_FOG:
-    sprs += fill_fog_sprite_array(sprs, ptile, pedge, pcorner);
+    sprs += fill_fog_sprite_array(t, sprs, ptile, pedge, pcorner);
     break;
 
   case LAYER_CITY2:
@@ -3318,13 +3371,13 @@
        ADD_SPRITE_SIMPLE(sprites.unit.select[focus_unit_state]);
       }
 
-      sprs += fill_unit_sprite_array(sprs, punit, stacked, backdrop);
+      sprs += fill_unit_sprite_array(t, sprs, punit, stacked, backdrop);
     }
     break;
 
   case LAYER_SPECIAL3:
     if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
-      if (is_isometric && draw_fortress_airbase
+      if (t->is_isometric && draw_fortress_airbase
          && contains_special(tspecial, S_FORTRESS)) {
        /* Draw fortress front in iso-view (non-iso view only has a fortress
         * back). */
@@ -3334,8 +3387,8 @@
     break;
 
   case LAYER_GRID2:
-    if (!is_isometric) {
-      sprs += fill_grid_sprite_array(sprs, ptile, pedge, pcorner,
+    if (!t->is_isometric) {
+      sprs += fill_grid_sprite_array(t, sprs, ptile, pedge, pcorner,
                                     punit, pcity, citymode);
     }
     break;
@@ -3358,7 +3411,8 @@
   Set city tiles sprite values; should only happen after
   tilespec_load_tiles().
 ***********************************************************************/
-static void tilespec_setup_style_tile(int style, char *graphics)
+static void tileset_setup_style_tile(struct tileset *t,
+                                    int style, char *graphics)
 {
   struct Sprite *sp;
   char buffer[128];
@@ -3370,14 +3424,14 @@
 
   for(j=0; j<32 && city_styles[style].tiles_num < MAX_CITY_TILES; j++) {
     my_snprintf(buffer, sizeof(buffer), "%s_%d", graphics, j);
-    sp = load_sprite(buffer);
-    if (is_isometric) {
+    sp = load_sprite(t, buffer);
+    if (t->is_isometric) {
       my_snprintf(buffer, sizeof(buffer_wall), "%s_%d_wall", graphics, j);
-      sp_wall = load_sprite(buffer);
+      sp_wall = load_sprite(t, buffer);
     }
     if (sp) {
       sprites.city.tile[style][city_styles[style].tiles_num] = sp;
-      if (is_isometric) {
+      if (t->is_isometric) {
        assert(sp_wall != NULL);
        sprites.city.tile_wall[style][city_styles[style].tiles_num] = sp_wall;
       }
@@ -3390,10 +3444,10 @@
   if(city_styles[style].tiles_num == 0)      /* don't waste more time */
     return;
 
-  if (!is_isometric) {
+  if (!t->is_isometric) {
     /* the wall tile */
     my_snprintf(buffer, sizeof(buffer), "%s_wall", graphics);
-    sp = load_sprite(buffer);
+    sp = load_sprite(t, buffer);
     if (sp) {
       sprites.city.tile[style][city_styles[style].tiles_num] = sp;
     } else {
@@ -3403,7 +3457,7 @@
 
   /* occupied tile */
   my_snprintf(buffer, sizeof(buffer), "%s_occupied", graphics);
-  sp = load_sprite(buffer);
+  sp = load_sprite(t, buffer);
   if (sp) {
     sprites.city.tile[style][city_styles[style].tiles_num+1] = sp;
   } else {
@@ -3415,16 +3469,16 @@
   Set city tiles sprite values; should only happen after
   tilespec_load_tiles().
 ***********************************************************************/
-void tilespec_setup_city_tiles(int style)
+void tileset_setup_city_tiles(struct tileset *t, int style)
 {
-  tilespec_setup_style_tile(style, city_styles[style].graphic);
+  tileset_setup_style_tile(t, style, city_styles[style].graphic);
 
   if (city_styles[style].tiles_num == 0) {
     /* no tiles found, try alternate */
     freelog(LOG_NORMAL, "No tiles for %s style, trying alternate %s style",
             city_styles[style].graphic, city_styles[style].graphic_alt);
 
-    tilespec_setup_style_tile(style, city_styles[style].graphic_alt);
+    tileset_setup_style_tile(t, style, city_styles[style].graphic_alt);
   }
 
   if (city_styles[style].tiles_num == 0) {
@@ -3434,9 +3488,9 @@
            "No tiles for alternate %s style, using default tiles",
             city_styles[style].graphic_alt);
 
-    sprites.city.tile[style][0] = load_sprite("cd.city");
-    sprites.city.tile[style][1] = load_sprite("cd.city_wall");
-    sprites.city.tile[style][2] = load_sprite("cd.occupied");
+    sprites.city.tile[style][0] = load_sprite(t, "cd.city");
+    sprites.city.tile[style][1] = load_sprite(t, "cd.city_wall");
+    sprites.city.tile[style][2] = load_sprite(t, "cd.occupied");
     city_styles[style].tiles_num = 1;
     city_styles[style].tresh[0] = 0;
   }
@@ -3445,16 +3499,16 @@
 /**********************************************************************
   alloc memory for city tiles sprites
 ***********************************************************************/
-void tilespec_alloc_city_tiles(int count)
+void tileset_alloc_city_tiles(struct tileset *t, int count)
 {
   int i;
 
-  if (is_isometric)
+  if (t->is_isometric)
     sprites.city.tile_wall = fc_calloc( count, sizeof(struct Sprite**) );
   sprites.city.tile = fc_calloc( count, sizeof(struct Sprite**) );
 
   for (i=0; i<count; i++) {
-    if (is_isometric)
+    if (t->is_isometric)
       sprites.city.tile_wall[i] = fc_calloc(MAX_CITY_TILES+2, sizeof(struct 
Sprite*));
     sprites.city.tile[i] = fc_calloc(MAX_CITY_TILES+2, sizeof(struct Sprite*));
   }
@@ -3463,12 +3517,12 @@
 /**********************************************************************
   alloc memory for city tiles sprites
 ***********************************************************************/
-void tilespec_free_city_tiles(int count)
+void tileset_free_city_tiles(struct tileset *t, int count)
 {
   int i;
 
   for (i=0; i<count; i++) {
-    if (is_isometric) {
+    if (t->is_isometric) {
       free(sprites.city.tile_wall[i]);
       sprites.city.tile_wall[i] = NULL;
     }
@@ -3476,7 +3530,7 @@
     sprites.city.tile[i] = NULL;
   }
 
-  if (is_isometric) {
+  if (t->is_isometric) {
     free(sprites.city.tile_wall);
     sprites.city.tile_wall = NULL;
   }
@@ -3598,16 +3652,20 @@
     return NULL;
 }
 
-static void unload_all_sprites(void )
+/****************************************************************************
+  This patch unloads all sprites from the sprite hash (the hash itself
+  is left intact).
+****************************************************************************/
+static void unload_all_sprites(struct tileset *t)
 {
-  int i, entries = hash_num_entries(sprite_hash);
+  int i, entries = hash_num_entries(t->sprite_hash);
 
   for (i = 0; i < entries; i++) {
-    const char *tag_name = hash_key_by_number(sprite_hash, i);
-    struct small_sprite *ss = hash_lookup_data(sprite_hash, tag_name);
+    const char *tag_name = hash_key_by_number(t->sprite_hash, i);
+    struct small_sprite *ss = hash_lookup_data(t->sprite_hash, tag_name);
 
     while (ss->ref_count > 0) {
-      unload_sprite(tag_name);
+      unload_sprite(t, tag_name);
     }
   }
 }
@@ -3615,26 +3673,26 @@
 /**********************************************************************
 ...
 ***********************************************************************/
-void tilespec_free_tiles(void)
+void tileset_free_tiles(struct tileset *t)
 {
-  int i, entries = hash_num_entries(sprite_hash);
+  int i, entries = hash_num_entries(t->sprite_hash);
 
   freelog(LOG_DEBUG, "tilespec_free_tiles");
 
-  unload_all_sprites();
+  unload_all_sprites(t);
 
   for (i = 0; i < entries; i++) {
-    const char *key = hash_key_by_number(sprite_hash, 0);
+    const char *key = hash_key_by_number(t->sprite_hash, 0);
 
-    hash_delete_entry(sprite_hash, key);
+    hash_delete_entry(t->sprite_hash, key);
     free((void *) key);
   }
 
-  hash_free(sprite_hash);
-  sprite_hash = NULL;
+  hash_free(t->sprite_hash);
+  t->sprite_hash = NULL;
 
-  small_sprite_list_iterate(small_sprites, ss) {
-    small_sprite_list_unlink(small_sprites, ss);
+  small_sprite_list_iterate(t->small_sprites, ss) {
+    small_sprite_list_unlink(t->small_sprites, ss);
     if (ss->file) {
       free(ss->file);
     }
@@ -3642,8 +3700,8 @@
     free(ss);
   } small_sprite_list_iterate_end;
 
-  specfile_list_iterate(specfiles, sf) {
-    specfile_list_unlink(specfiles, sf);
+  specfile_list_iterate(t->specfiles, sf) {
+    specfile_list_unlink(t->specfiles, sf);
     free(sf->file_name);
     if (sf->big_sprite) {
       free_sprite(sf->big_sprite);
@@ -3752,10 +3810,10 @@
   counter is increased. Can return NULL if the sprite couldn't be
   loaded.
 **************************************************************************/
-struct Sprite *load_sprite(const char *tag_name)
+struct Sprite *load_sprite(struct tileset *t, const char *tag_name)
 {
   /* Lookup information about where the sprite is found. */
-  struct small_sprite *ss = hash_lookup_data(sprite_hash, tag_name);
+  struct small_sprite *ss = hash_lookup_data(t->sprite_hash, tag_name);
 
   freelog(LOG_DEBUG, "load_sprite(tag='%s')", tag_name);
   if (!ss) {
@@ -3802,9 +3860,9 @@
   Unloads the sprite. Decrease the reference counter. If the last
   reference is removed the sprite is freed.
 **************************************************************************/
-void unload_sprite(const char *tag_name)
+void unload_sprite(struct tileset *t, const char *tag_name)
 {
-  struct small_sprite *ss = hash_lookup_data(sprite_hash, tag_name);
+  struct small_sprite *ss = hash_lookup_data(t->sprite_hash, tag_name);
 
   assert(ss);
   assert(ss->ref_count >= 1);
@@ -3825,26 +3883,10 @@
   Return TRUE iff the specified sprite exists in the tileset (whether
   or not it is currently loaded).
 **************************************************************************/
-bool sprite_exists(const char *tag_name)
+bool sprite_exists(struct tileset *t, const char *tag_name)
 {
   /* Lookup information about where the sprite is found. */
-  struct small_sprite *ss = hash_lookup_data(sprite_hash, tag_name);
+  struct small_sprite *ss = hash_lookup_data(t->sprite_hash, tag_name);
 
   return (ss != NULL);
 }
-
-/**************************************************************************
-  Frees any internal buffers which are created by load_sprite. Should
-  be called after the last (for a given period of time) load_sprite
-  call.  This saves a fair amount of memory, but it will take extra time
-  the next time we start loading sprites again.
-**************************************************************************/
-void finish_loading_sprites(void)
-{
-  specfile_list_iterate(specfiles, sf) {
-    if (sf->big_sprite) {
-      free_sprite(sf->big_sprite);
-      sf->big_sprite = NULL;
-    }
-  } specfile_list_iterate_end;
-}
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.118
diff -u -r1.118 tilespec.h
--- client/tilespec.h   3 Mar 2005 17:18:29 -0000       1.118
+++ client/tilespec.h   3 Mar 2005 19:27:27 -0000
@@ -111,31 +111,35 @@
   }                                                                        \
 }
 
+struct tileset;
+
+extern struct tileset *tileset;
+
 const char **get_tileset_list(void);
 
-void tilespec_init(void);
-void tilespec_done(void);
-bool tilespec_read_toplevel(const char *tileset_name);
-void tilespec_load_tiles(void);
-void tilespec_free_tiles(void);
+struct tileset *tileset_read_toplevel(const char *tileset_name);
+void tileset_free(struct tileset *tileset);
+void tileset_load_tiles(struct tileset *t);
+void tileset_free_tiles(struct tileset *t);
 
 void tilespec_reread(const char *tileset_name);
 void tilespec_reread_callback(struct client_option *option);
 
-void tilespec_setup_specialist_types(void);
-void tilespec_setup_unit_type(int id);
-void tilespec_setup_impr_type(int id);
-void tilespec_setup_tech_type(int id);
-void tilespec_setup_tile_type(Terrain_type_id terrain);
-void tilespec_setup_government(int id);
-void tilespec_setup_nation_flag(int id);
-void tilespec_setup_city_tiles(int style);
-void tilespec_alloc_city_tiles(int count);
-void tilespec_free_city_tiles(int count);
+void tileset_setup_specialist_types(struct tileset *t);
+void tileset_setup_unit_type(struct tileset *t, int id);
+void tileset_setup_impr_type(struct tileset *t, int id);
+void tileset_setup_tech_type(struct tileset *t, int id);
+void tileset_setup_tile_type(struct tileset *t, Terrain_type_id terrain);
+void tileset_setup_government(struct tileset *t, int id);
+void tileset_setup_nation_flag(struct tileset *t, int id);
+void tileset_setup_city_tiles(struct tileset *t, int style);
+void tileset_alloc_city_tiles(struct tileset *t, int count);
+void tileset_free_city_tiles(struct tileset *t, int count);
 
 /* Gfx support */
 
-int fill_sprite_array(struct drawn_sprite *sprs, enum mapview_layer layer,
+int fill_sprite_array(struct tileset *t,
+                     struct drawn_sprite *sprs, enum mapview_layer layer,
                      const struct tile *ptile,
                      const struct tile_edge *pedge,
                      const struct tile_corner *pcorner,
@@ -427,9 +431,8 @@
 const char *tileset_main_intro_filename(void);
 const char *tileset_mini_intro_filename(void);
 
-struct Sprite *load_sprite(const char *tag_name);
-void unload_sprite(const char *tag_name);
-bool sprite_exists(const char *tag_name);
-void finish_loading_sprites(void);
+struct Sprite *load_sprite(struct tileset *t, const char *tag_name);
+void unload_sprite(struct tileset *t, const char *tag_name);
+bool sprite_exists(struct tileset *t, const char *tag_name);
 
 #endif  /* FC__TILESPEC_H */
Index: client/gui-ftwl/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-ftwl/gui_main.c,v
retrieving revision 1.10
diff -u -r1.10 gui_main.c
--- client/gui-ftwl/gui_main.c  12 Feb 2005 18:47:18 -0000      1.10
+++ client/gui-ftwl/gui_main.c  3 Mar 2005 19:27:27 -0000
@@ -246,7 +246,7 @@
 
   chat_create(); 
   chatline_create();
-  tilespec_load_tiles();
+  tileset_load_tiles(tileset);
   timer_callback(NULL);
   sw_window_set_key_notify(root_window, my_key_handler, NULL);
 
Index: client/gui-gtk/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/gui_main.c,v
retrieving revision 1.163
diff -u -r1.163 gui_main.c
--- client/gui-gtk/gui_main.c   28 Feb 2005 04:16:45 -0000      1.163
+++ client/gui-gtk/gui_main.c   3 Mar 2005 19:27:28 -0000
@@ -967,7 +967,7 @@
     gdk_gc_set_foreground(mask_bg_gc, &pixel);
   }
 
-  tilespec_load_tiles();
+  tileset_load_tiles(tileset);
 
   setup_widgets();
   load_intro_gfx();
@@ -988,7 +988,7 @@
   gtk_main();
 
   free_color_system();
-  tilespec_free_tiles();
+  tileset_free_tiles(tileset);
 }
 
 /**************************************************************************
Index: client/gui-gtk-2.0/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gui_main.c,v
retrieving revision 1.111
diff -u -r1.111 gui_main.c
--- client/gui-gtk-2.0/gui_main.c       28 Feb 2005 04:16:45 -0000      1.111
+++ client/gui-gtk-2.0/gui_main.c       3 Mar 2005 19:27:28 -0000
@@ -1188,7 +1188,7 @@
     gdk_gc_set_foreground(mask_bg_gc, &pixel);
   }
 
-  tilespec_load_tiles();
+  tileset_load_tiles(tileset);
 
   setup_widgets();
   load_cursors();
@@ -1217,7 +1217,7 @@
   diplomacy_dialog_done();
   cma_fe_done();
   free_color_system();
-  tilespec_free_tiles();
+  tileset_free_tiles(tileset);
 }
 
 /**************************************************************************
Index: client/gui-gtk-2.0/pages.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/pages.c,v
retrieving revision 1.18
diff -u -r1.18 pages.c
--- client/gui-gtk-2.0/pages.c  3 Mar 2005 17:18:29 -0000       1.18
+++ client/gui-gtk-2.0/pages.c  3 Mar 2005 19:27:28 -0000
@@ -1437,7 +1437,7 @@
   GdkPixbuf *im, *im2;
   SPRITE *flag;
 
-  flag = load_sprite(flag_str);
+  flag = load_sprite(tileset, flag_str);
 
   if (!flag) {
     return NULL;
@@ -1461,7 +1461,7 @@
   im = gdk_pixbuf_new_subpixbuf(sprite_get_pixbuf(flag), x0, y0, w, h);
   im2 = gdk_pixbuf_copy(im);
   g_object_unref(im);
-  unload_sprite(flag_str);
+  unload_sprite(tileset, flag_str);
 
   /* and finaly store the scaled flag pixbuf in the static flags array */
   return im2;
Index: client/gui-mui/graphics.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/graphics.c,v
retrieving revision 1.35
diff -u -r1.35 graphics.c
--- client/gui-mui/graphics.c   28 Feb 2005 04:01:53 -0000      1.35
+++ client/gui-mui/graphics.c   3 Mar 2005 19:27:29 -0000
@@ -119,7 +119,7 @@
   struct SpriteNode *node = (struct SpriteNode *) AllocVec(sizeof(*node), 
0x10000);
   if (node)
   {
-    struct Sprite *sprite = load_sprite(filename, TRUE);
+    struct Sprite *sprite = load_sprite(tileset, filename, TRUE);
     if (sprite)
     {
       if (!sprite_initialized)
@@ -158,7 +158,7 @@
 /****************************************************************
  Allocate and load a sprite
 *****************************************************************/
-struct Sprite *load_sprite(const char *filename, ULONG usemask)
+struct Sprite *load_sprite(tileset, const char *filename, ULONG usemask)
 {
   struct Sprite *sprite = (struct Sprite *) malloc(sizeof(struct Sprite));
 
@@ -281,7 +281,7 @@
 
     cleanup_sprite(sprite);
 
-    if ((ns = load_sprite(node->filename, sprite->hasmask)))
+    if ((ns = load_sprite(tileset, node->filename, sprite->hasmask)))
     {
       sprite->picture = ns->picture;
       sprite->hasmask = ns->hasmask;
@@ -406,7 +406,7 @@
 {
   if ((pen_shared_map = CreatePenShareMapA(NULL)))
   {
-    tilespec_load_tiles();
+    tileset_load_tiles(tileset);
     return TRUE;
   }
   return FALSE;
Index: client/gui-mui/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/gui_main.c,v
retrieving revision 1.91
diff -u -r1.91 gui_main.c
--- client/gui-mui/gui_main.c   12 Feb 2005 18:47:19 -0000      1.91
+++ client/gui-mui/gui_main.c   3 Mar 2005 19:27:29 -0000
@@ -1364,7 +1364,7 @@
 
   atexit(ui_exit);
 
-  if (init_timer() && load_all_sprites())      /* includes tilespec_load_tiles 
*/
+  if (init_timer() && load_all_sprites())      /* includes tileset_load_tiles 
*/
   {
     if (init_gui())
     {
Index: client/gui-mui/mapclass.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/mapclass.c,v
retrieving revision 1.103
diff -u -r1.103 mapclass.c
--- client/gui-mui/mapclass.c   3 Mar 2005 17:18:29 -0000       1.103
+++ client/gui-mui/mapclass.c   3 Mar 2005 19:27:29 -0000
@@ -811,8 +811,8 @@
     colors_pen[i] = ObtainBestPenA(cm, r, g, b, 0); /* global in colors.c */
   }
 
-  data->intro_gfx_sprite = load_sprite(tileset_main_intro_filename(), FALSE);
-  data->radar_gfx_sprite = load_sprite(tileset_mini_intro_filename(), FALSE);
+  data->intro_gfx_sprite = load_sprite(tileset, tileset_main_intro_filename(), 
FALSE);
+  data->radar_gfx_sprite = load_sprite(tileset, tileset_mini_intro_filename(), 
FALSE);
 
   if ((dh = data->drawhandle = ObtainDrawHandle(pen_shared_map, 
&_screen(o)->RastPort, _screen(o)->ViewPort.ColorMap,
                                           GGFX_DitherMode, DITHERMODE_NONE,
Index: client/gui-sdl/graphics.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/graphics.c,v
retrieving revision 1.34
diff -u -r1.34 graphics.c
--- client/gui-sdl/graphics.c   3 Mar 2005 17:18:29 -0000       1.34
+++ client/gui-sdl/graphics.c   3 Mar 2005 19:27:30 -0000
@@ -3477,13 +3477,13 @@
 SDL_Surface * get_city_gfx(void)
 {
   SDL_Surface *pCity_Surf;
-  struct Sprite *pSpr = load_sprite("theme.city");
+  struct Sprite *pSpr = load_sprite(tileset, "theme.city");
   
   pCity_Surf = (pSpr ? GET_SURF(pSpr) : NULL);
   assert(pCity_Surf != NULL);
   
   pSpr->psurface = NULL;
-  unload_sprite("theme.city");
+  unload_sprite(tileset, "theme.city");
   
   return pCity_Surf;
 }
Index: client/gui-sdl/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/gui_main.c,v
retrieving revision 1.52
diff -u -r1.52 gui_main.c
--- client/gui-sdl/gui_main.c   28 Feb 2005 04:01:54 -0000      1.52
+++ client/gui-sdl/gui_main.c   3 Mar 2005 19:27:30 -0000
@@ -853,7 +853,7 @@
                       CF_CIV3_CITY_TEXT_STYLE|
                       CF_DRAW_MAP_DITHER);
                       
-  tilespec_load_tiles();
+  tileset_load_tiles(tileset);
   
   load_cursors();
   tilespec_setup_theme();
Index: client/gui-sdl/gui_tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/gui_tilespec.c,v
retrieving revision 1.21
diff -u -r1.21 gui_tilespec.c
--- client/gui-sdl/gui_tilespec.c       28 Feb 2005 04:01:54 -0000      1.21
+++ client/gui-sdl/gui_tilespec.c       3 Mar 2005 19:27:30 -0000
@@ -54,11 +54,11 @@
 
 #define load_GUI_surface(pSpr, pStruct, pSurf, tag)            \
 do {                                                           \
-  pSpr = load_sprite(tag);                                     \
+  pSpr = load_sprite(tileset, tag);                                    \
   pStruct->pSurf = (pSpr ? GET_SURF(pSpr) : NULL);             \
   assert(pStruct->pSurf != NULL);                              \
   pSpr->psurface = NULL;                                       \
-  unload_sprite(tag);                                          \
+  unload_sprite(tileset, tag);                                         \
 } while(0)
 
 
@@ -128,12 +128,12 @@
          city_styles[style].citizens_graphic , get_citizen_name(i));  
     
     
-    pSpr = load_sprite(tag);
+    pSpr = load_sprite(tileset, tag);
     if(!pSpr) {
       freelog(LOG_DEBUG,"Can't find %s", tag);
       my_snprintf(tag, sizeof(tag), "citizen%s%s", alt_buf 
,get_citizen_name(i));  
       freelog(LOG_DEBUG,"Trying load alternative %s", tag);
-      pSpr = load_sprite(tag);
+      pSpr = load_sprite(tileset, tag);
     }
     
     FREESURFACE(citizen[i].surface[0]);
@@ -145,20 +145,20 @@
        * citizen.entertainer. */
       citizen[i].count = 1;
       pSpr->psurface = NULL;
-      unload_sprite(tag);
+      unload_sprite(tileset, tag);
       continue;
     }
     for (j = 0; j < MAX_NUM_CITIZEN_SPRITES; j++) {
       my_snprintf(tag, sizeof(tag), "citizen.%s_%s_%d",
          city_styles[style].citizens_graphic ,get_citizen_name(i) , j );
       
-      pSpr = load_sprite(tag);
+      pSpr = load_sprite(tileset, tag);
       if(!pSpr) {
         freelog(LOG_DEBUG,"Can't find %s", tag);
         my_snprintf(tag, sizeof(tag), "citizen%s%s_%d", alt_buf,
                                        get_citizen_name(i), j);
         freelog(LOG_DEBUG,"Trying load alternative %s", tag);
-        pSpr = load_sprite(tag);
+        pSpr = load_sprite(tileset, tag);
       }
       
       FREESURFACE(citizen[i].surface[j]);
@@ -167,7 +167,7 @@
        break;
       }
       pSpr->psurface = NULL;
-      unload_sprite(tag);
+      unload_sprite(tileset, tag);
     }
     citizen[i].count = j;
     assert(j > 0);
@@ -271,7 +271,7 @@
 
 /**********************************************************************
   Set city icons sprite value; should only happen after
-  tilespec_load_tiles().
+  tileset_load_tiles(tileset).
 ***********************************************************************/
 void tilespec_setup_city_icons(void)
 {
@@ -507,7 +507,7 @@
       pBuf = sprites.dither_tile;
       pDitherMask = GET_SURF(pBuf);
       pBuf->psurface = NULL;
-      unload_sprite("t.dither_tile");
+      unload_sprite(tileset, "t.dither_tile");
       assert(pDitherMask != NULL);       
   /* ------------------------------ */
   /* Map Borders */
@@ -569,7 +569,7 @@
     pAnim->Cursors.Type = CALLOC(num + 1, sizeof(SDL_Cursor *));       \
     for( iter=0; iter<num; iter++) {   \
       my_snprintf(cBuf,sizeof(cBuf), "%s_%d", Tag, iter);      \
-      pSpr = load_sprite(cBuf);        \
+      pSpr = load_sprite(tileset, cBuf);       \
       image = (pSpr ? GET_SURF(pSpr) : NULL);  \
       assert(image != NULL);   \
       if (center) {    \
@@ -577,7 +577,7 @@
       } else { \
        pAnim->Cursors.Type[iter] = SurfaceToCursor(image, x, y);       \
       }        \
-      unload_sprite(cBuf);     \
+      unload_sprite(tileset, cBuf);    \
     }  \
   }    \
 } while(0)
@@ -788,39 +788,39 @@
 
 void unload_unused_graphics(void)
 {
-  unload_sprite("treaty.disagree_thumb_down");
-  unload_sprite("treaty.agree_thumb_up");
-  unload_sprite("spaceship.solar_panels");
-  unload_sprite("spaceship.life_support");
-  unload_sprite("spaceship.habitation");
-  unload_sprite("spaceship.structural");
-  unload_sprite("spaceship.fuel");
-  unload_sprite("spaceship.propulsion");
-  unload_sprite("citizen.entertainer");
-  unload_sprite("citizen.scientist");
-  unload_sprite("citizen.tax_collector");
-  unload_sprite("citizen.content_0");
-  unload_sprite("citizen.content_1");
-  unload_sprite("citizen.happy_0");
-  unload_sprite("citizen.happy_1");
-  unload_sprite("citizen.unhappy_0");
-  unload_sprite("citizen.unhappy_1");
-  unload_sprite("citizen.angry_0");
-  unload_sprite("citizen.angry_1");
-  unload_sprite("s.right_arrow");
+  unload_sprite(tileset, "treaty.disagree_thumb_down");
+  unload_sprite(tileset, "treaty.agree_thumb_up");
+  unload_sprite(tileset, "spaceship.solar_panels");
+  unload_sprite(tileset, "spaceship.life_support");
+  unload_sprite(tileset, "spaceship.habitation");
+  unload_sprite(tileset, "spaceship.structural");
+  unload_sprite(tileset, "spaceship.fuel");
+  unload_sprite(tileset, "spaceship.propulsion");
+  unload_sprite(tileset, "citizen.entertainer");
+  unload_sprite(tileset, "citizen.scientist");
+  unload_sprite(tileset, "citizen.tax_collector");
+  unload_sprite(tileset, "citizen.content_0");
+  unload_sprite(tileset, "citizen.content_1");
+  unload_sprite(tileset, "citizen.happy_0");
+  unload_sprite(tileset, "citizen.happy_1");
+  unload_sprite(tileset, "citizen.unhappy_0");
+  unload_sprite(tileset, "citizen.unhappy_1");
+  unload_sprite(tileset, "citizen.angry_0");
+  unload_sprite(tileset, "citizen.angry_1");
+  unload_sprite(tileset, "s.right_arrow");
   if (sprite_exists("t.coast_color"))
   {
-    unload_sprite("t.coast_color");
+    unload_sprite(tileset, "t.coast_color");
   }
-  unload_sprite("upkeep.gold");
-  unload_sprite("upkeep.gold2");
-  unload_sprite("upkeep.food");
-  unload_sprite("upkeep.food2");
-  unload_sprite("upkeep.unhappy");
-  unload_sprite("upkeep.unhappy2");
-  unload_sprite("upkeep.shield");
+  unload_sprite(tileset, "upkeep.gold");
+  unload_sprite(tileset, "upkeep.gold2");
+  unload_sprite(tileset, "upkeep.food");
+  unload_sprite(tileset, "upkeep.food2");
+  unload_sprite(tileset, "upkeep.unhappy");
+  unload_sprite(tileset, "upkeep.unhappy2");
+  unload_sprite(tileset, "upkeep.shield");
   if (tileset_is_isometric() && sprite_exists("explode.iso_nuke"))
   {
-    unload_sprite("explode.iso_nuke");
+    unload_sprite(tileset, "explode.iso_nuke");
   }
 }
Index: client/gui-win32/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/gui_main.c,v
retrieving revision 1.43
diff -u -r1.43 gui_main.c
--- client/gui-win32/gui_main.c 14 Feb 2005 02:47:42 -0000      1.43
+++ client/gui-win32/gui_main.c 3 Mar 2005 19:27:30 -0000
@@ -609,7 +609,7 @@
   SetMenu(root_window,create_mainmenu());
   ShowWindow(root_window,SW_SHOWNORMAL);
   UpdateWindow(root_window);
-  tilespec_load_tiles();
+  tileset_load_tiles(tileset);
   init_fog_bmp();
   load_cursors();
 
Index: client/gui-xaw/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/gui_main.c,v
retrieving revision 1.105
diff -u -r1.105 gui_main.c
--- client/gui-xaw/gui_main.c   28 Feb 2005 04:16:46 -0000      1.105
+++ client/gui-xaw/gui_main.c   3 Mar 2005 19:27:33 -0000
@@ -442,7 +442,7 @@
      setup_widgets() has enough colors available:  (on 256-colour systems)
   */
   setup_widgets();
-  tilespec_load_tiles();
+  tileset_load_tiles(tileset);
   load_intro_gfx();
   load_cursors();
 
@@ -711,7 +711,7 @@
 **************************************************************************/
 void xaw_ui_exit(void)
 {
-  tilespec_free_tiles();
+  tileset_free_tiles(tileset);
   ui_exit();
 }
 

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#12425) objectify the tileset data, Jason Short <=