Support VERSION_REVTYPE git builds on cleanup_checkout.sh
[freeciv.git] / client / tilespec.c
bloba4168b9bb2a7920c4afc2a9759e68ec090d69f59
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 /***********************************************************************
15 Functions for handling the tilespec files which describe
16 the files and contents of tilesets.
17 original author: David Pfitzner <dwp@mso.anu.edu.au>
18 ***********************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include <fc_config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h> /* exit */
26 #include <stdarg.h>
27 #include <string.h>
29 /* utility */
30 #include "astring.h"
31 #include "bitvector.h"
32 #include "capability.h"
33 #include "deprecations.h"
34 #include "fcintl.h"
35 #include "log.h"
36 #include "mem.h"
37 #include "rand.h"
38 #include "registry.h"
39 #include "shared.h"
40 #include "string_vector.h"
41 #include "support.h"
43 /* common */
44 #include "base.h"
45 #include "effects.h"
46 #include "game.h" /* game.control.styles_count */
47 #include "government.h"
48 #include "map.h"
49 #include "movement.h"
50 #include "nation.h"
51 #include "player.h"
52 #include "road.h"
53 #include "specialist.h"
54 #include "unit.h"
55 #include "unitlist.h"
57 /* client/include */
58 #include "dialogs_g.h"
59 #include "graphics_g.h"
60 #include "gui_main_g.h"
61 #include "mapview_g.h" /* for update_map_canvas_visible */
62 #include "menu_g.h"
63 #include "themes_g.h"
65 /* client */
66 #include "citydlg_common.h" /* for generate_citydlg_dimensions() */
67 #include "client_main.h"
68 #include "climap.h" /* for client_tile_get_known() */
69 #include "colors_common.h"
70 #include "control.h" /* for fill_xxx */
71 #include "editor.h"
72 #include "goto.h"
73 #include "helpdata.h"
74 #include "options.h" /* for fill_xxx */
75 #include "themes_common.h"
77 #include "tilespec.h"
79 #define TILESPEC_CAPSTR "+Freeciv-2.6-tilespec duplicates_ok"
81 * Tilespec capabilities acceptable to this program:
83 * +Freeciv-2.4-tilespec
84 * - basic format for Freeciv versions 2.4.x; required
86 * +Freeciv-tilespec-Devel-YYYY.MMM.DD
87 * - tilespec of the development version at the given data
89 * duplicates_ok
90 * - we can handle existence of duplicate tags (lattermost tag which
91 * appears is used; tilesets which have duplicates should specify
92 * "duplicates_ok")
95 #define SPEC_CAPSTR "+Freeciv-2.6-spec"
97 * Individual spec file capabilities acceptable to this program:
99 * +Freeciv-2.3-spec
100 * - basic format for Freeciv versions 2.3.x; required
103 #define TILESPEC_SUFFIX ".tilespec"
104 #define TILE_SECTION_PREFIX "tile_"
106 /* This the way directional indices are now encoded: */
107 #define MAX_INDEX_CARDINAL 64
108 #define MAX_INDEX_HALF 16
109 #define MAX_INDEX_VALID 256
111 #define NUM_TILES_HP_BAR 11
112 #define NUM_TILES_DIGITS 10
113 #define NUM_TILES_SELECT 4
114 #define MAX_NUM_UPKEEP_SPRITES 10
116 #define SPECENUM_NAME extrastyle_id
117 #define SPECENUM_VALUE0 ESTYLE_ROAD_ALL_SEPARATE
118 #define SPECENUM_VALUE0NAME "RoadAllSeparate"
119 #define SPECENUM_VALUE1 ESTYLE_ROAD_PARITY_COMBINED
120 #define SPECENUM_VALUE1NAME "RoadParityCombined"
121 #define SPECENUM_VALUE2 ESTYLE_ROAD_ALL_COMBINED
122 #define SPECENUM_VALUE2NAME "RoadAllCombined"
123 #define SPECENUM_VALUE3 ESTYLE_RIVER
124 #define SPECENUM_VALUE3NAME "River"
125 #define SPECENUM_VALUE4 ESTYLE_SINGLE1
126 #define SPECENUM_VALUE4NAME "Single1"
127 #define SPECENUM_VALUE5 ESTYLE_SINGLE2
128 #define SPECENUM_VALUE5NAME "Single2"
129 #define SPECENUM_VALUE6 ESTYLE_3LAYER
130 #define SPECENUM_VALUE6NAME "3Layer"
131 #define SPECENUM_VALUE7 ESTYLE_CARDINALS
132 #define SPECENUM_VALUE7NAME "Cardinals"
133 #define SPECENUM_COUNT ESTYLE_COUNT
134 #include "specenum_gen.h"
136 /* This could be moved to common/map.h if there's more use for it. */
137 enum direction4 {
138 DIR4_NORTH = 0, DIR4_SOUTH, DIR4_EAST, DIR4_WEST
140 static const char direction4letters[4] = "udrl";
141 /* This must correspond to enum edge_type. */
142 static const char edge_name[EDGE_COUNT][3] = {"ns", "we", "ud", "lr"};
144 static const int DIR4_TO_DIR8[4] =
145 { DIR8_NORTH, DIR8_SOUTH, DIR8_EAST, DIR8_WEST };
147 enum match_style {
148 MATCH_NONE,
149 MATCH_SAME, /* "boolean" match */
150 MATCH_PAIR,
151 MATCH_FULL
154 enum sprite_type {
155 CELL_WHOLE, /* entire tile */
156 CELL_CORNER /* corner of tile */
159 struct drawing_data {
160 bool init;
162 char *name;
164 int num_layers; /* 1 thru MAX_NUM_LAYERS. */
165 #define MAX_NUM_LAYERS 3
167 struct drawing_layer {
168 bool is_tall;
169 int offset_x, offset_y;
171 #define MAX_NUM_MATCH_WITH 8
172 enum match_style match_style;
173 int match_index[1 + MAX_NUM_MATCH_WITH];
174 int match_indices; /* 0 = no match_type, 1 = no match_with */
176 enum sprite_type sprite_type;
178 struct sprite_vector base;
179 struct sprite *match[MAX_INDEX_CARDINAL];
180 struct sprite **cells;
182 /* List of those sprites in 'cells' that are allocated by some other
183 * means than load_sprite() and thus are not freed by unload_all_sprites(). */
184 struct sprite_vector allocated;
185 } layer[MAX_NUM_LAYERS];
187 bool is_reversed;
189 int blending; /* layer, 0 = none */
190 struct sprite *blender;
191 struct sprite *blend[4]; /* indexed by a direction4 */
194 struct city_style_threshold {
195 struct sprite *sprite;
198 struct city_sprite {
199 struct {
200 int land_num_thresholds;
201 struct city_style_threshold *land_thresholds;
202 } *styles;
203 int num_styles;
206 struct river_sprites {
207 struct sprite
208 *spec[MAX_INDEX_CARDINAL],
209 *outlet[MAX_INDEX_CARDINAL];
212 struct named_sprites {
213 struct sprite
214 *indicator[INDICATOR_COUNT][NUM_TILES_PROGRESS],
215 *treaty_thumb[2], /* 0=disagree, 1=agree */
216 *arrow[ARROW_LAST], /* 0=right arrow, 1=plus, 2=minus */
218 *icon[ICON_COUNT],
220 *events[E_COUNT],
222 /* The panel sprites for showing tax % allocations. */
223 *tax_luxury, *tax_science, *tax_gold,
224 *dither_tile; /* only used for isometric view */
226 struct {
227 struct sprite
228 *tile,
229 *worked_tile,
230 *unworked_tile;
231 } mask;
233 struct sprite *tech[A_LAST];
234 struct sprite *building[B_LAST];
235 struct sprite *government[G_LAST];
237 struct {
238 struct sprite *icon[U_LAST];
239 struct sprite *facing[U_LAST][DIR8_MAGIC_MAX];
240 unsigned int default_dir_seed[U_LAST];
241 } units;
243 struct sprite *resource[MAX_NUM_RESOURCES];
245 struct sprite_vector nation_flag;
246 struct sprite_vector nation_shield;
248 struct citizen_graphic {
249 /* Each citizen type has up to MAX_NUM_CITIZEN_SPRITES different
250 * sprites, as defined by the tileset. */
251 int count;
252 struct sprite *sprite[MAX_NUM_CITIZEN_SPRITES];
253 } citizen[CITIZEN_LAST], specialist[SP_MAX];
254 struct sprite *spaceship[SPACESHIP_COUNT];
255 struct {
256 int hot_x, hot_y;
257 struct sprite *frame[NUM_CURSOR_FRAMES];
258 } cursor[CURSOR_LAST];
259 struct {
260 struct sprite_vector unit;
261 struct sprite *nuke;
262 } explode;
263 struct {
264 struct sprite
265 *hp_bar[NUM_TILES_HP_BAR],
266 *vet_lev[MAX_VET_LEVELS],
267 *select[NUM_TILES_SELECT],
268 *auto_attack,
269 *auto_settler,
270 *auto_explore,
271 *fortified,
272 *fortifying,
273 *go_to, /* goto is a C keyword :-) */
274 *irrigate,
275 *plant,
276 *pillage,
277 *sentry,
278 *stack,
279 *loaded,
280 *transform,
281 *connect,
282 *patrol,
283 *convert,
284 *battlegroup[MAX_NUM_BATTLEGROUPS],
285 *lowfuel,
286 *tired;
287 } unit;
288 struct {
289 struct sprite
290 *unhappy[MAX_NUM_UPKEEP_SPRITES],
291 *output[O_LAST][MAX_NUM_UPKEEP_SPRITES];
292 } upkeep;
293 struct {
294 struct sprite
295 *disorder,
296 *size[NUM_TILES_DIGITS],
297 *size_tens[NUM_TILES_DIGITS],
298 *size_hundreds[NUM_TILES_DIGITS],
299 *tile_foodnum[NUM_TILES_DIGITS],
300 *tile_shieldnum[NUM_TILES_DIGITS],
301 *tile_tradenum[NUM_TILES_DIGITS];
302 struct city_sprite
303 *tile,
304 *single_wall,
305 *wall[NUM_WALL_TYPES],
306 *occupied;
307 struct sprite_vector worked_tile_overlay;
308 struct sprite_vector unworked_tile_overlay;
309 } city;
310 struct citybar_sprites citybar;
311 struct editor_sprites editor;
312 struct {
313 struct {
314 struct sprite *specific;
315 struct sprite *turns[NUM_TILES_DIGITS];
316 struct sprite *turns_tens[NUM_TILES_DIGITS];
317 struct sprite *turns_hundreds[NUM_TILES_DIGITS];
318 } s[GTS_COUNT];
319 struct sprite *waypoint;
320 } path;
321 struct {
322 struct sprite *attention;
323 } user;
324 struct {
325 struct sprite
326 *fog,
327 **fullfog,
328 *darkness[MAX_INDEX_CARDINAL]; /* first unused */
329 } tx; /* terrain extra */
330 struct {
331 struct sprite
332 *activity,
333 *rmact;
334 enum extrastyle_id extrastyle;
335 union {
336 struct sprite *single;
337 struct sprite *cardinals[MAX_INDEX_CARDINAL];
338 struct {
339 struct sprite
340 *background,
341 *middleground,
342 *foreground;
343 } bmf;
344 struct {
345 struct sprite
346 /* for extrastyles ESTYLE_ROAD_ALL_SEPARATE and ESTYLE_ROAD_PARITY_COMBINED */
347 *isolated,
348 *corner[8]; /* Indexed by direction; only non-cardinal dirs used. */
349 union {
350 /* for ESTYLE_ROAD_ALL_SEPARATE */
351 struct sprite *dir[8]; /* all entries used */
352 /* ESTYLE_ROAD_PARITY_COMBINED */
353 struct {
354 struct sprite
355 *even[MAX_INDEX_HALF], /* first unused */
356 *odd[MAX_INDEX_HALF]; /* first unused */
357 } combo;
358 /* ESTYLE_ALL_SEPARATE */
359 struct sprite *total[MAX_INDEX_VALID];
360 struct river_sprites rivers;
361 } ru;
362 } road;
363 } u;
364 } extras[MAX_EXTRA_TYPES];
365 struct {
366 struct sprite
367 *main[EDGE_COUNT],
368 *city[EDGE_COUNT],
369 *worked[EDGE_COUNT],
370 *unavailable,
371 *nonnative,
372 *selected[EDGE_COUNT],
373 *coastline[EDGE_COUNT],
374 *borders[EDGE_COUNT][2];
375 } grid;
376 struct {
377 struct sprite_vector overlays;
378 } colors;
379 struct {
380 struct sprite *color; /* Generic background color */
381 struct sprite *graphic; /* Generic background graphic */
382 } background;
383 struct {
384 struct sprite *grid_borders[EDGE_COUNT][2];
385 struct sprite *color;
386 struct sprite *background;
387 } player[MAX_NUM_PLAYER_SLOTS];
389 struct drawing_data *drawing[MAX_NUM_ITEMS];
392 struct specfile {
393 struct sprite *big_sprite;
394 char *file_name;
397 #define SPECLIST_TAG specfile
398 #define SPECLIST_TYPE struct specfile
399 #include "speclist.h"
401 #define specfile_list_iterate(list, pitem) \
402 TYPED_LIST_ITERATE(struct specfile, list, pitem)
403 #define specfile_list_iterate_end LIST_ITERATE_END
406 * Information about an individual sprite. All fields except 'sprite' are
407 * filled at the time of the scan of the specfile. 'Sprite' is
408 * set/cleared on demand in load_sprite/unload_sprite.
410 struct small_sprite {
411 int ref_count;
413 /* The sprite is in this file. */
414 char *file;
416 /* Or, the sprite is in this file at the location. */
417 struct specfile *sf;
418 int x, y, width, height;
420 /* A little more (optional) data. */
421 int hot_x, hot_y;
423 struct sprite *sprite;
426 /* 'struct small_sprite_list' and related functions. */
427 #define SPECLIST_TAG small_sprite
428 #define SPECLIST_TYPE struct small_sprite
429 #include "speclist.h"
430 #define small_sprite_list_iterate(list, pitem) \
431 TYPED_LIST_ITERATE(struct small_sprite, list, pitem)
432 #define small_sprite_list_iterate_end LIST_ITERATE_END
434 /* 'struct sprite_hash' and related functions. */
435 #define SPECHASH_TAG sprite
436 #define SPECHASH_ASTR_KEY_TYPE
437 #define SPECHASH_IDATA_TYPE struct small_sprite *
438 #include "spechash.h"
439 #define sprite_hash_iterate(hash, tag_name, sprite) \
440 TYPED_HASH_ITERATE(const char *, struct small_sprite *, \
441 hash, tag_name, sprite)
442 #define sprite_hash_iterate_end HASH_ITERATE_END
444 /* 'struct drawing_hash' and related functions. */
445 static void drawing_data_destroy(struct drawing_data *draw);
447 #define SPECHASH_TAG drawing
448 #define SPECHASH_CSTR_KEY_TYPE
449 #define SPECHASH_IDATA_TYPE struct drawing_data *
450 #define SPECHASH_IDATA_FREE drawing_data_destroy
451 #include "spechash.h"
453 #define SPECHASH_TAG estyle
454 #define SPECHASH_ASTR_KEY_TYPE
455 #define SPECHASH_ENUM_DATA_TYPE extrastyle_id
456 #include "spechash.h"
458 struct tileset {
459 char name[512];
460 char given_name[MAX_LEN_NAME];
461 char version[MAX_LEN_NAME];
462 int priority;
464 char *summary;
465 char *description;
466 float scale;
468 enum ts_type type;
469 int hex_width, hex_height;
470 int ts_topo_idx;
472 int normal_tile_width, normal_tile_height;
473 int full_tile_width, full_tile_height;
474 int unit_tile_width, unit_tile_height;
475 int small_sprite_width, small_sprite_height;
477 int max_upkeep_height;
479 char *main_intro_filename;
480 char *minimap_intro_filename;
482 int city_names_font_size, city_productions_font_size;
484 enum fog_style fogstyle;
485 enum darkness_style darkness_style;
486 int darkness_layer;
488 int unit_flag_offset_x, unit_flag_offset_y;
489 int city_flag_offset_x, city_flag_offset_y;
490 int unit_offset_x, unit_offset_y;
491 int city_offset_x, city_offset_y;
493 int citybar_offset_y;
494 int tilelabel_offset_y;
495 int activity_offset_x;
496 int activity_offset_y;
497 int occupied_offset_x;
498 int occupied_offset_y;
499 int unit_upkeep_offset_y;
500 int unit_upkeep_small_offset_y;
502 #define NUM_CORNER_DIRS 4
503 #define TILES_PER_CORNER 4
504 int num_valid_tileset_dirs, num_cardinal_tileset_dirs;
505 int num_index_valid, num_index_cardinal;
506 enum direction8 valid_tileset_dirs[8], cardinal_tileset_dirs[8];
508 struct tileset_layer {
509 char **match_types;
510 size_t match_count;
511 } layers[MAX_NUM_LAYERS];
513 struct specfile_list *specfiles;
514 struct small_sprite_list *small_sprites;
516 /* This hash table maps tilespec tags to struct small_sprites. */
517 struct sprite_hash *sprite_hash;
519 /* This hash table maps terrain graphic strings to drawing data. */
520 struct drawing_hash *tile_hash;
522 struct estyle_hash *estyle_hash;
524 struct named_sprites sprites;
526 struct color_system *color_system;
528 struct extra_type_list *style_lists[ESTYLE_COUNT];
530 struct extra_type_list *flagged_bases_list;
532 int num_preferred_themes;
533 char** preferred_themes;
536 struct tileset *tileset;
538 int focus_unit_state = 0;
540 static bool tileset_update = FALSE;
543 static int fill_unit_type_sprite_array(const struct tileset *t,
544 struct drawn_sprite *sprs,
545 const struct unit_type *putype,
546 enum direction8 facing);
547 static int fill_unit_sprite_array(const struct tileset *t,
548 struct drawn_sprite *sprs,
549 const struct unit *punit,
550 bool stack, bool backdrop);
551 static bool load_river_sprites(struct tileset *t,
552 struct river_sprites *store, const char *tag_pfx);
554 static void tileset_setup_base(struct tileset *t,
555 const struct extra_type *pextra);
556 static void tileset_setup_road(struct tileset *t,
557 struct extra_type *pextra);
559 static bool is_extra_drawing_enabled(struct extra_type *pextra);
561 static int fill_basic_road_sprite_array(const struct tileset *t,
562 struct drawn_sprite *sprs,
563 const struct extra_type *pextra);
564 static int fill_basic_base_sprite_array(const struct tileset *t,
565 struct drawn_sprite *sprs,
566 const struct extra_type *pextra);
568 static void tileset_player_free(struct tileset *t, int plrid);
570 /****************************************************************************
571 Called when ever there's problem in ruleset/tileset compatibility
572 ****************************************************************************/
573 void tileset_error(enum log_level level, const char *format, ...)
575 char buf[2048];
576 va_list args;
578 va_start(args, format);
579 fc_vsnprintf(buf, sizeof(buf), format, args);
580 va_end(args);
582 log_base(level, "%s", buf);
584 if (level <= LOG_NORMAL) {
585 show_tileset_error(buf);
588 if (level == LOG_FATAL) {
589 exit(EXIT_FAILURE);
593 /****************************************************************************
594 Create a new drawing data.
595 ****************************************************************************/
596 static struct drawing_data *drawing_data_new(void)
598 struct drawing_data *draw = fc_calloc(1, sizeof(*draw));
600 draw->name = NULL;
602 return draw;
605 /****************************************************************************
606 Free a drawing data.
607 ****************************************************************************/
608 static void drawing_data_destroy(struct drawing_data *draw)
610 int i;
612 fc_assert_ret(NULL != draw);
614 if (draw->name != NULL) {
615 free(draw->name);
617 for (i = 0; i < 4; i++) {
618 if (draw->blend[i]) {
619 free_sprite(draw->blend[i]);
622 for (i = 0; i < draw->num_layers; i++) {
623 int vec_size = sprite_vector_size(&draw->layer[i].allocated);
624 int j;
626 for (j = 0; j < vec_size; j++) {
627 free_sprite(draw->layer[i].allocated.p[j]);
630 sprite_vector_free(&draw->layer[i].base);
631 sprite_vector_free(&draw->layer[i].allocated);
632 free(draw->layer[i].cells);
634 free(draw);
637 /****************************************************************************
638 Return the name of the given tileset.
639 ****************************************************************************/
640 const char *tileset_basename(const struct tileset *t)
642 return t->name;
645 /****************************************************************************
646 Return whether the current tileset is isometric.
647 ****************************************************************************/
648 bool tileset_is_isometric(const struct tileset *t)
650 return t->type == TS_ISOMETRIC;
653 /****************************************************************************
654 Return the hex_width of the current tileset. For iso-hex tilesets this
655 value will be > 0 and is_isometric will be set.
656 ****************************************************************************/
657 int tileset_hex_width(const struct tileset *t)
659 return t->hex_width;
662 /****************************************************************************
663 Return the hex_height of the current tileset. For hex tilesets this
664 value will be > 0 and is_isometric will be set.
665 ****************************************************************************/
666 int tileset_hex_height(const struct tileset *t)
668 return t->hex_height;
671 /****************************************************************************
672 Return the tile width of the current tileset. This is the tesselation
673 width of the tiled plane. This means it's the width of the bounding box
674 of the basic map tile.
676 For best results:
677 - The value should be even (or a multiple of 4 in iso-view).
678 - In iso-view, the width should be twice the height (to give a
679 perspective of 30 degrees above the horizon).
680 - In non-iso-view, width and height should be equal (overhead
681 perspective).
682 - In hex or iso-hex view, remember this is the tesselation vector.
683 hex_width and hex_height then give the size of the side of the
684 hexagon. Calculating the dimensions of a "regular" hexagon or
685 iso-hexagon may be tricky.
686 However these requirements are not absolute and callers should not
687 depend on them (although some do).
688 ****************************************************************************/
689 int tileset_tile_width(const struct tileset *t)
691 return t->normal_tile_width;
694 /****************************************************************************
695 Return the tile height of the current tileset. This is the tesselation
696 height of the tiled plane. This means it's the height of the bounding box
697 of the basic map tile.
699 See also tileset_tile_width.
700 ****************************************************************************/
701 int tileset_tile_height(const struct tileset *t)
703 return t->normal_tile_height;
706 /****************************************************************************
707 Return the full tile width of the current tileset. This is the maximum
708 width that any mapview sprite will have.
710 Note: currently this is always equal to the tile width.
711 ****************************************************************************/
712 int tileset_full_tile_width(const struct tileset *t)
714 return t->full_tile_width;
717 /****************************************************************************
718 Return the full tile height of the current tileset. This is the maximum
719 height that any mapview sprite will have. This may be greater than the
720 tile width in which case the extra area is above the "normal" tile.
722 Some callers assume the full height is 50% larger than the height in
723 iso-view, and equal in non-iso view.
724 ****************************************************************************/
725 int tileset_full_tile_height(const struct tileset *t)
727 return t->full_tile_height;
730 /****************************************************************************
731 Return the unit tile width of the current tileset.
732 ****************************************************************************/
733 int tileset_unit_width(const struct tileset *t)
735 return t->unit_tile_width;
738 /****************************************************************************
739 Return the unit tile height of the current tileset.
740 ****************************************************************************/
741 int tileset_unit_height(const struct tileset *t)
743 return t->unit_tile_height;
746 /****************************************************************************
747 Calculate the height of a unit upkeep icons.
748 ****************************************************************************/
749 static int calculate_max_upkeep_height(const struct tileset *t)
751 int i;
752 int max = 0;
754 for (i = 0; i < MAX_NUM_UPKEEP_SPRITES; i++) {
755 if (t->sprites.upkeep.unhappy[i] != NULL) {
756 int width, height;
758 /* TODO: We want only height, getting the width might waste CPU
759 * depending on gui-specific implementation. */
760 get_sprite_dimensions(t->sprites.upkeep.unhappy[i], &width, &height);
762 max = MAX(max, height);
766 output_type_iterate(o) {
767 for (i = 0; i < MAX_NUM_UPKEEP_SPRITES; i++) {
768 if (t->sprites.upkeep.output[o][i] != NULL) {
769 int width, height;
771 /* TODO: We want only height, getting the width might waste CPU
772 * depending on gui-specific implementation. */
773 get_sprite_dimensions(t->sprites.upkeep.output[o][i], &width, &height);
775 max = MAX(max, height);
778 } output_type_iterate_end;
780 return max;
783 /****************************************************************************
784 Get the height of a unit upkeep icons.
785 ****************************************************************************/
786 static int tileset_upkeep_height(const struct tileset *t)
788 /* Return cached value */
789 return t->max_upkeep_height;
792 /****************************************************************************
793 Suitable canvas height for a unit icon that includes upkeep sprites.
794 ****************************************************************************/
795 int tileset_unit_with_upkeep_height(const struct tileset *t)
797 int uk_bottom = tileset_unit_layout_offset_y(tileset) + tileset_upkeep_height(tileset);
798 int u_bottom = tileset_unit_height(tileset);
800 return MAX(uk_bottom, u_bottom);
803 /****************************************************************************
804 Suitable canvas height for a unit icon that includes upkeep sprites,
805 using small space layout.
806 ****************************************************************************/
807 int tileset_unit_with_small_upkeep_height(const struct tileset *t)
809 return tileset_unit_layout_small_offset_y(tileset) + tileset_upkeep_height(tileset);
812 /****************************************************************************
813 Offset to layout extra unit sprites, such as upkeep.
814 ****************************************************************************/
815 int tileset_unit_layout_offset_y(const struct tileset *t)
817 return t->unit_upkeep_offset_y;
820 /****************************************************************************
821 Offset to layout extra unit sprites, such as upkeep, requesting small
822 space layout.
823 ****************************************************************************/
824 int tileset_unit_layout_small_offset_y(const struct tileset *t)
826 return t->unit_upkeep_small_offset_y;
829 /****************************************************************************
830 Return the small sprite width of the current tileset. The small sprites
831 are used for various theme graphics (e.g., citymap citizens/specialists
832 as well as panel indicator icons).
833 ****************************************************************************/
834 int tileset_small_sprite_width(const struct tileset *t)
836 return t->small_sprite_width;
839 /****************************************************************************
840 Return the offset from the origin of the city tile at which to place the
841 city bar text.
842 ****************************************************************************/
843 int tileset_citybar_offset_y(const struct tileset *t)
845 return t->citybar_offset_y;
848 /****************************************************************************
849 Return the offset from the origin of the tile at which to place the
850 label text.
851 ****************************************************************************/
852 int tileset_tilelabel_offset_y(const struct tileset *t)
854 return t->tilelabel_offset_y;
857 /****************************************************************************
858 Returns tileset scale
859 ****************************************************************************/
860 float tileset_scale(const struct tileset *t)
862 return tileset->scale;
865 /****************************************************************************
866 Return the small sprite height of the current tileset. The small sprites
867 are used for various theme graphics (e.g., citymap citizens/specialists
868 as well as panel indicator icons).
869 ****************************************************************************/
870 int tileset_small_sprite_height(const struct tileset *t)
872 return t->small_sprite_height;
875 /****************************************************************************
876 Return the path within the data directories where the main intro graphics
877 file can be found. (It is left up to the GUI code to load and unload this
878 file.)
879 ****************************************************************************/
880 const char *tileset_main_intro_filename(const struct tileset *t)
882 return t->main_intro_filename;
885 /****************************************************************************
886 Return the path within the data directories where the mini intro graphics
887 file can be found. (It is left up to the GUI code to load and unload this
888 file.)
889 ****************************************************************************/
890 const char *tileset_mini_intro_filename(const struct tileset *t)
892 return t->minimap_intro_filename;
895 /****************************************************************************
896 Return the number of possible colors for city overlays.
897 ****************************************************************************/
898 int tileset_num_city_colors(const struct tileset *t)
900 return t->sprites.city.worked_tile_overlay.size;
903 /****************************************************************************
904 Return TRUE if the client will use the code to generate the fog.
905 ****************************************************************************/
906 bool tileset_use_hard_coded_fog(const struct tileset *t)
908 return FOG_AUTO == t->fogstyle;
911 /**************************************************************************
912 Initialize.
913 **************************************************************************/
914 static struct tileset *tileset_new(void)
916 struct tileset *t = fc_calloc(1, sizeof(*t));
918 t->specfiles = specfile_list_new();
919 t->small_sprites = small_sprite_list_new();
920 return t;
923 /**************************************************************************
924 Return the tileset name of the direction. This is similar to
925 dir_get_name but you shouldn't change this or all tilesets will break.
926 **************************************************************************/
927 static const char *dir_get_tileset_name(enum direction8 dir)
929 switch (dir) {
930 case DIR8_NORTH:
931 return "n";
932 case DIR8_NORTHEAST:
933 return "ne";
934 case DIR8_EAST:
935 return "e";
936 case DIR8_SOUTHEAST:
937 return "se";
938 case DIR8_SOUTH:
939 return "s";
940 case DIR8_SOUTHWEST:
941 return "sw";
942 case DIR8_WEST:
943 return "w";
944 case DIR8_NORTHWEST:
945 return "nw";
947 log_error("Wrong direction8 variant: %d.", dir);
948 return "";
951 /****************************************************************************
952 Return TRUE iff the dir is valid in this tileset.
953 ****************************************************************************/
954 static bool is_valid_tileset_dir(const struct tileset *t,
955 enum direction8 dir)
957 if (t->hex_width > 0) {
958 return dir != DIR8_NORTHEAST && dir != DIR8_SOUTHWEST;
959 } else if (t->hex_height > 0) {
960 return dir != DIR8_NORTHWEST && dir != DIR8_SOUTHEAST;
961 } else {
962 return TRUE;
966 /****************************************************************************
967 Return TRUE iff the dir is cardinal in this tileset.
969 "Cardinal", in this sense, means that a tile will share a border with
970 another tile in the direction rather than sharing just a single vertex.
971 ****************************************************************************/
972 static bool is_cardinal_tileset_dir(const struct tileset *t,
973 enum direction8 dir)
975 if (t->hex_width > 0 || t->hex_height > 0) {
976 return is_valid_tileset_dir(t, dir);
977 } else {
978 return (dir == DIR8_NORTH || dir == DIR8_EAST
979 || dir == DIR8_SOUTH || dir == DIR8_WEST);
983 /**********************************************************************
984 Convert properties of the actual topology to an index of different
985 tileset topology types.
986 ***********************************************************************/
987 static int ts_topology_index(int actual_topology)
989 int idx;
991 if ((actual_topology & TF_HEX)
992 && (actual_topology & TF_ISO)) {
993 idx = TS_TOPO_ISOHEX;
994 } else if (actual_topology & TF_ISO) {
995 idx = TS_TOPO_ISO;
996 } else if (actual_topology & TF_HEX) {
997 idx = TS_TOPO_HEX;
998 } else {
999 idx = TS_TOPO_OVERHEAD;
1002 return idx;
1005 /**********************************************************************
1006 Returns a static list of tilesets available on the system by
1007 searching all data directories for files matching TILESPEC_SUFFIX.
1008 ***********************************************************************/
1009 const struct strvec *get_tileset_list(const struct option *poption)
1011 static struct strvec *tilesets[4] = { NULL, NULL, NULL, NULL };
1012 int topo = option_get_cb_data(poption);
1013 int idx;
1015 idx = ts_topology_index(topo);
1017 fc_assert_ret_val(idx < ARRAY_SIZE(tilesets), NULL);
1019 if (tilesets[idx] == NULL) {
1020 /* Note: this means you must restart the client after installing a new
1021 tileset. */
1022 struct strvec *list = fileinfolist(get_data_dirs(), TILESPEC_SUFFIX);
1024 tilesets[idx] = strvec_new();
1025 strvec_iterate(list, file) {
1026 struct tileset *t = tileset_read_toplevel(file, FALSE, topo, 1.0f);
1028 if (t) {
1029 strvec_append(tilesets[idx], file);
1030 tileset_free(t);
1032 } strvec_iterate_end;
1033 strvec_destroy(list);
1036 return tilesets[idx];
1039 /**********************************************************************
1040 Gets full filename for tilespec file, based on input name.
1041 Returned data is allocated, and freed by user as required.
1042 Input name may be null, in which case uses default.
1043 Falls back to default if can't find specified name;
1044 dies if can't find default.
1045 ***********************************************************************/
1046 static char *tilespec_fullname(const char *tileset_name)
1048 if (tileset_name) {
1049 char fname[strlen(tileset_name) + strlen(TILESPEC_SUFFIX) + 1];
1050 const char *dname;
1052 fc_snprintf(fname, sizeof(fname),
1053 "%s%s", tileset_name, TILESPEC_SUFFIX);
1055 dname = fileinfoname(get_data_dirs(), fname);
1057 if (dname) {
1058 return fc_strdup(dname);
1062 return NULL;
1065 /**********************************************************************
1066 Checks options in filename match what we require and support.
1067 Die if not.
1068 'which' should be "tilespec" or "spec".
1069 ***********************************************************************/
1070 static bool check_tilespec_capabilities(struct section_file *file,
1071 const char *which,
1072 const char *us_capstr,
1073 const char *filename,
1074 bool verbose)
1076 enum log_level level = verbose ? LOG_ERROR : LOG_DEBUG;
1078 const char *file_capstr = secfile_lookup_str(file, "%s.options", which);
1080 if (NULL == file_capstr) {
1081 log_base(level, "\"%s\": %s file doesn't have a capability string",
1082 filename, which);
1083 return FALSE;
1085 if (!has_capabilities(us_capstr, file_capstr)) {
1086 log_base(level, "\"%s\": %s file appears incompatible:",
1087 filename, which);
1088 log_base(level, " datafile options: %s", file_capstr);
1089 log_base(level, " supported options: %s", us_capstr);
1090 return FALSE;
1092 if (!has_capabilities(file_capstr, us_capstr)) {
1093 log_base(level, "\"%s\": %s file requires option(s) "
1094 "that client doesn't support:", filename, which);
1095 log_base(level, " datafile options: %s", file_capstr);
1096 log_base(level, " supported options: %s", us_capstr);
1097 return FALSE;
1100 return TRUE;
1103 /**********************************************************************
1104 Frees the tilespec toplevel data, in preparation for re-reading it.
1106 See tilespec_read_toplevel().
1107 ***********************************************************************/
1108 static void tileset_free_toplevel(struct tileset *t)
1110 int i, j;
1112 if (t->main_intro_filename) {
1113 free(t->main_intro_filename);
1114 t->main_intro_filename = NULL;
1116 if (t->minimap_intro_filename) {
1117 free(t->minimap_intro_filename);
1118 t->minimap_intro_filename = NULL;
1121 if (t->preferred_themes) {
1122 for (i = 0; i < t->num_preferred_themes; i++) {
1123 free(t->preferred_themes[i]);
1125 free(t->preferred_themes);
1126 t->preferred_themes = NULL;
1128 t->num_preferred_themes = 0;
1130 if (t->tile_hash) {
1131 drawing_hash_destroy(t->tile_hash);
1132 t->tile_hash = NULL; /* Helpful for sanity. */
1134 if (t->estyle_hash) {
1135 estyle_hash_destroy(t->estyle_hash);
1136 t->estyle_hash = NULL;
1138 for (i = 0; i < ESTYLE_COUNT; i++) {
1139 if (t->style_lists[i] != NULL) {
1140 extra_type_list_destroy(t->style_lists[i]);
1141 t->style_lists[i] = NULL;
1145 if (t->flagged_bases_list != NULL) {
1146 extra_type_list_destroy(t->flagged_bases_list);
1147 t->flagged_bases_list = NULL;
1150 for (i = 0; i < MAX_NUM_LAYERS; i++) {
1151 struct tileset_layer *tslp = &t->layers[i];
1153 if (tslp->match_types) {
1154 for (j = 0; j < tslp->match_count; j++) {
1155 free(tslp->match_types[j]);
1157 free(tslp->match_types);
1158 tslp->match_types = NULL;
1162 if (t->color_system) {
1163 color_system_free(t->color_system);
1164 t->color_system = NULL;
1167 if (t->summary != NULL) {
1168 free(t->summary);
1169 t->summary = NULL;
1171 if (t->description != NULL) {
1172 free(t->description);
1173 t->description = NULL;
1177 /**************************************************************************
1178 Clean up.
1179 **************************************************************************/
1180 void tileset_free(struct tileset *t)
1182 int i;
1184 tileset_free_tiles(t);
1185 tileset_free_toplevel(t);
1186 for (i = 0; i < ARRAY_SIZE(t->sprites.player); i++) {
1187 tileset_player_free(t, i);
1189 specfile_list_destroy(t->specfiles);
1190 small_sprite_list_destroy(t->small_sprites);
1191 free(t);
1194 /**********************************************************************
1195 Read a new tilespec in when first starting the game.
1197 Call this function with the (guessed) name of the tileset, when
1198 starting the client.
1199 ***********************************************************************/
1200 void tilespec_try_read(const char *tileset_name, bool verbose, int topo_id,
1201 bool global_default)
1203 if (tileset_name == NULL
1204 || !(tileset = tileset_read_toplevel(tileset_name, verbose,
1205 topo_id, 1.0f))) {
1206 struct strvec *list = fileinfolist(get_data_dirs(), TILESPEC_SUFFIX);
1208 strvec_iterate(list, file) {
1209 struct tileset *t = tileset_read_toplevel(file, FALSE, topo_id, 1.0f);
1211 if (t) {
1212 if (!tileset) {
1213 tileset = t;
1214 } else if (t->priority > tileset->priority
1215 || (topo_id >= 0
1216 && tileset_topo_index(tileset) != tileset_topo_index(t))) {
1217 tileset_free(tileset);
1218 tileset = t;
1219 } else {
1220 tileset_free(t);
1223 } strvec_iterate_end;
1224 strvec_destroy(list);
1226 if (!tileset) {
1227 tileset_error(LOG_FATAL, _("No usable default tileset found, aborting!"));
1230 log_verbose("Trying tileset \"%s\".", tileset->name);
1232 option_set_default_ts(tileset);
1234 if (global_default) {
1235 sz_strlcpy(gui_options.default_tileset_name, tileset_basename(tileset));
1239 /**********************************************************************
1240 Read a new tilespec in from scratch.
1242 Unlike the initial reading code, which reads pieces one at a time,
1243 this gets rid of the old data and reads in the new all at once. If the
1244 new tileset fails to load the old tileset may be reloaded; otherwise the
1245 client will exit. If a NULL name is given the current tileset will be
1246 reread.
1248 It will also call the necessary functions to redraw the graphics.
1249 ***********************************************************************/
1250 void tilespec_reread(const char *new_tileset_name,
1251 bool game_fully_initialized, float scale)
1253 int id;
1254 struct tile *center_tile;
1255 enum client_states state = client_state();
1256 const char *name = new_tileset_name ? new_tileset_name : tileset->name;
1257 char tileset_name[strlen(name) + 1], old_name[strlen(tileset->name) + 1];
1259 /* Make local copies since these values may be freed down below */
1260 sz_strlcpy(tileset_name, name);
1261 sz_strlcpy(old_name, tileset->name);
1263 log_normal(_("Loading tileset \"%s\"."), tileset_name);
1265 /* Step 0: Record old data.
1267 * We record the current mapcanvas center, etc.
1269 center_tile = get_center_tile_mapcanvas();
1271 /* Step 1: Cleanup.
1273 * We free all old data in preparation for re-reading it.
1275 tileset_free(tileset);
1277 /* Step 2: Read.
1279 * We read in the new tileset. This should be pretty straightforward.
1281 if (!(tileset = tileset_read_toplevel(tileset_name, FALSE, -1, scale))) {
1282 if (!(tileset = tileset_read_toplevel(old_name, FALSE, -1, scale))) {
1283 /* Always fails. */
1284 fc_assert_exit_msg(NULL != tileset,
1285 "Failed to re-read the currently loaded tileset.");
1288 tileset_load_tiles(tileset);
1289 if (game_fully_initialized) {
1290 tileset_use_preferred_theme(tileset);
1293 if (game_fully_initialized) {
1294 tileset_background_init(tileset);
1295 players_iterate(pplayer) {
1296 tileset_player_init(tileset, pplayer);
1297 } players_iterate_end;
1298 boot_help_texts(); /* "About Current Tileset" */
1301 /* Step 3: Setup
1303 * This is a seriously sticky problem. On startup, we build a hash
1304 * from all the sprite data. Then, when we connect to a server, the
1305 * server sends us ruleset data a piece at a time and we use this data
1306 * to assemble the sprite structures. But if we change while connected
1307 * we have to reassemble all of these. This should just involve
1308 * calling tilespec_setup_*** on everything. But how do we tell what
1309 * "everything" is?
1311 * The below code just does things straightforwardly, by setting up
1312 * each possible sprite again. Hopefully it catches everything, and
1313 * doesn't mess up too badly if we change tilesets while not connected
1314 * to a server.
1316 if (!game.client.ruleset_ready) {
1317 /* The ruleset data is not sent until this point. */
1318 return;
1321 if (!tileset_map_topo_compatible(game.map.topology_id, tileset)) {
1322 tileset_error(LOG_NORMAL, _("Map topology and tileset incompatible."));
1325 terrain_type_iterate(pterrain) {
1326 tileset_setup_tile_type(tileset, pterrain);
1327 } terrain_type_iterate_end;
1328 resource_type_iterate(presource) {
1329 tileset_setup_resource(tileset, presource);
1330 } resource_type_iterate_end;
1331 unit_type_iterate(punittype) {
1332 tileset_setup_unit_type(tileset, punittype);
1333 } unit_type_iterate_end;
1334 governments_iterate(gov) {
1335 tileset_setup_government(tileset, gov);
1336 } governments_iterate_end;
1337 extra_type_iterate(pextra) {
1338 tileset_setup_extra(tileset, pextra);
1339 } extra_type_iterate_end;
1340 nations_iterate(pnation) {
1341 tileset_setup_nation_flag(tileset, pnation);
1342 } nations_iterate_end;
1343 improvement_iterate(pimprove) {
1344 tileset_setup_impr_type(tileset, pimprove);
1345 } improvement_iterate_end;
1346 advance_iterate(A_FIRST, padvance) {
1347 tileset_setup_tech_type(tileset, padvance);
1348 } advance_iterate_end;
1349 specialist_type_iterate(sp) {
1350 tileset_setup_specialist_type(tileset, sp);
1351 } specialist_type_iterate_end;
1353 for (id = 0; id < game.control.styles_count; id++) {
1354 tileset_setup_city_tiles(tileset, id);
1357 if (state < C_S_RUNNING) {
1358 /* Below redraws do not apply before this. */
1359 return;
1362 /* Step 4: Draw.
1364 * Do any necessary redraws.
1366 generate_citydlg_dimensions();
1367 tileset_changed();
1368 can_slide = FALSE;
1369 center_tile_mapcanvas(center_tile);
1370 /* update_map_canvas_visible forces a full redraw. Otherwise with fast
1371 * drawing we might not get one. Of course this is slower. */
1372 update_map_canvas_visible();
1373 can_slide = TRUE;
1376 /**************************************************************************
1377 This is merely a wrapper for tilespec_reread (above) for use in
1378 options.c and the client local options dialog.
1379 **************************************************************************/
1380 void tilespec_reread_callback(struct option *poption)
1382 const char *tileset_name;
1383 enum client_states state = client_state();
1385 if ((state == C_S_RUNNING || state == C_S_OVER)
1386 && option_get_cb_data(poption) != (game.map.topology_id & (TF_ISO | TF_HEX))) {
1387 /* Changed option was not for current topology */
1388 return;
1391 tileset_name = option_str_get(poption);
1393 /* As it's going to be 'current' tileset, make it global default if
1394 * options saved. */
1395 sz_strlcpy(gui_options.default_tileset_name, tileset_name);
1397 fc_assert_ret(NULL != tileset_name && tileset_name[0] != '\0');
1398 tileset_update = TRUE;
1399 tilespec_reread(tileset_name, client.conn.established, 1.0f);
1400 tileset_update = FALSE;
1401 menus_init();
1404 /**************************************************************************
1406 **************************************************************************/
1407 void tilespec_reread_frozen_refresh(const char *tname)
1409 tileset_update = TRUE;
1410 tilespec_reread(tname, TRUE, 1.0f);
1411 tileset_update = FALSE;
1412 menus_init();
1415 /**************************************************************************
1416 Loads the given graphics file (found in the data path) into a newly
1417 allocated sprite.
1418 **************************************************************************/
1419 static struct sprite *load_gfx_file(const char *gfx_filename)
1421 const char **gfx_fileexts = gfx_fileextensions(), *gfx_fileext;
1422 struct sprite *s;
1424 /* Try out all supported file extensions to find one that works. */
1425 while ((gfx_fileext = *gfx_fileexts++)) {
1426 const char *real_full_name;
1427 char full_name[strlen(gfx_filename) + strlen(".")
1428 + strlen(gfx_fileext) + 1];
1430 sprintf(full_name, "%s.%s", gfx_filename, gfx_fileext);
1431 if ((real_full_name = fileinfoname(get_data_dirs(), full_name))) {
1432 log_debug("trying to load gfx file \"%s\".", real_full_name);
1433 s = load_gfxfile(real_full_name);
1434 if (s) {
1435 return s;
1440 log_error("Could not load gfx file \"%s\".", gfx_filename);
1441 return NULL;
1444 /**************************************************************************
1445 Ensure that the big sprite of the given spec file is loaded.
1446 **************************************************************************/
1447 static void ensure_big_sprite(struct specfile *sf)
1449 struct section_file *file;
1450 const char *gfx_filename;
1452 if (sf->big_sprite) {
1453 /* Looks like it's already loaded. */
1454 return;
1457 /* Otherwise load it. The big sprite will sometimes be freed and will have
1458 * to be reloaded, but most of the time it's just loaded once, the small
1459 * sprites are extracted, and then it's freed. */
1460 if (!(file = secfile_load(sf->file_name, TRUE))) {
1461 tileset_error(LOG_FATAL, _("Could not open '%s':\n%s"), sf->file_name, secfile_error());
1464 if (!check_tilespec_capabilities(file, "spec",
1465 SPEC_CAPSTR, sf->file_name, TRUE)) {
1466 tileset_error(LOG_FATAL, _("Incompatible tileset capabilities"));
1469 gfx_filename = secfile_lookup_str(file, "file.gfx");
1471 sf->big_sprite = load_gfx_file(gfx_filename);
1473 if (!sf->big_sprite) {
1474 tileset_error(LOG_FATAL, _("Could not load gfx file for the spec file \"%s\"."),
1475 sf->file_name);
1477 secfile_destroy(file);
1480 /**************************************************************************
1481 Scan all sprites declared in the given specfile. This means that the
1482 positions of the sprites in the big_sprite are saved in the
1483 small_sprite structs.
1484 **************************************************************************/
1485 static void scan_specfile(struct tileset *t, struct specfile *sf,
1486 bool duplicates_ok)
1488 struct section_file *file;
1489 struct section_list *sections;
1490 int i;
1492 if (!(file = secfile_load(sf->file_name, TRUE))) {
1493 tileset_error(LOG_FATAL, _("Could not open '%s':\n%s"), sf->file_name, secfile_error());
1495 if (!check_tilespec_capabilities(file, "spec",
1496 SPEC_CAPSTR, sf->file_name, TRUE)) {
1497 tileset_error(LOG_FATAL, _("Specfile %s has incompatible capabilities"), sf->file_name);
1500 /* Currently unused */
1501 (void) secfile_entry_lookup(file, "info.artists");
1503 /* Not used here */
1504 (void) secfile_entry_lookup(file, "file.gfx");
1506 if ((sections = secfile_sections_by_name_prefix(file, "grid_"))) {
1507 section_list_iterate(sections, psection) {
1508 int j, k;
1509 int x_top_left, y_top_left, dx, dy;
1510 int pixel_border_x;
1511 int pixel_border_y;
1512 const char *sec_name = section_name(psection);
1514 pixel_border_x = secfile_lookup_int_default(file, 0, "%s.pixel_border",
1515 sec_name);
1516 pixel_border_y = secfile_lookup_int_default(file, pixel_border_x, "%s.pixel_border_y",
1517 sec_name);
1518 pixel_border_x = secfile_lookup_int_default(file, pixel_border_x, "%s.pixel_border_x",
1519 sec_name);
1520 if (!secfile_lookup_int(file, &x_top_left, "%s.x_top_left", sec_name)
1521 || !secfile_lookup_int(file, &y_top_left,
1522 "%s.y_top_left", sec_name)
1523 || !secfile_lookup_int(file, &dx, "%s.dx", sec_name)
1524 || !secfile_lookup_int(file, &dy, "%s.dy", sec_name)) {
1525 log_error("Grid \"%s\" invalid: %s", sec_name, secfile_error());
1526 continue;
1529 j = -1;
1530 while (NULL != secfile_entry_lookup(file, "%s.tiles%d.tag",
1531 sec_name, ++j)) {
1532 struct small_sprite *ss;
1533 int row, column;
1534 int xr, yb;
1535 const char **tags;
1536 size_t num_tags;
1537 int hot_x, hot_y;
1539 if (!secfile_lookup_int(file, &row, "%s.tiles%d.row", sec_name, j)
1540 || !secfile_lookup_int(file, &column, "%s.tiles%d.column",
1541 sec_name, j)
1542 || !(tags = secfile_lookup_str_vec(file, &num_tags,
1543 "%s.tiles%d.tag",
1544 sec_name, j))) {
1545 log_error("Small sprite \"%s.tiles%d\" invalid: %s",
1546 sec_name, j, secfile_error());
1547 continue;
1549 hot_x = secfile_lookup_int_default(file, 0, "%s.tiles%d.hot_x",
1550 sec_name, j);
1551 hot_y = secfile_lookup_int_default(file, 0, "%s.tiles%d.hot_y",
1552 sec_name, j);
1554 /* there must be at least 1 because of the while(): */
1555 fc_assert_action(num_tags > 0, continue);
1557 xr = x_top_left + (dx + pixel_border_x) * column;
1558 yb = y_top_left + (dy + pixel_border_y) * row;
1560 ss = fc_malloc(sizeof(*ss));
1561 ss->ref_count = 0;
1562 ss->file = NULL;
1563 ss->x = xr;
1564 ss->y = yb;
1565 ss->width = dx;
1566 ss->height = dy;
1567 ss->sf = sf;
1568 ss->sprite = NULL;
1569 ss->hot_x = hot_x;
1570 ss->hot_y = hot_y;
1572 small_sprite_list_prepend(t->small_sprites, ss);
1574 if (!duplicates_ok) {
1575 for (k = 0; k < num_tags; k++) {
1576 if (!sprite_hash_insert(t->sprite_hash, tags[k], ss)) {
1577 log_error("warning: already have a sprite for \"%s\".",
1578 tags[k]);
1581 } else {
1582 for (k = 0; k < num_tags; k++) {
1583 (void) sprite_hash_replace(t->sprite_hash, tags[k], ss);
1587 free(tags);
1588 tags = NULL;
1590 } section_list_iterate_end;
1591 section_list_destroy(sections);
1594 /* Load "extra" sprites. Each sprite is one file. */
1595 i = -1;
1596 while (NULL != secfile_entry_lookup(file, "extra.sprites%d.tag", ++i)) {
1597 struct small_sprite *ss;
1598 const char **tags;
1599 const char *filename;
1600 size_t num_tags, k;
1601 int hot_x, hot_y;
1603 if (!(tags = secfile_lookup_str_vec(file, &num_tags,
1604 "extra.sprites%d.tag", i))
1605 || !(filename = secfile_lookup_str(file,
1606 "extra.sprites%d.file", i))) {
1607 log_error("Extra sprite \"extra.sprites%d\" invalid: %s",
1608 i, secfile_error());
1609 continue;
1611 hot_x = secfile_lookup_int_default(file, 0, "extra.sprites%d.hot_x", i);
1612 hot_y = secfile_lookup_int_default(file, 0, "extra.sprites%d.hot_y", i);
1614 ss = fc_malloc(sizeof(*ss));
1615 ss->ref_count = 0;
1616 ss->file = fc_strdup(filename);
1617 ss->sf = NULL;
1618 ss->sprite = NULL;
1619 ss->hot_x = hot_x;
1620 ss->hot_y = hot_y;
1622 small_sprite_list_prepend(t->small_sprites, ss);
1624 if (!duplicates_ok) {
1625 for (k = 0; k < num_tags; k++) {
1626 if (!sprite_hash_insert(t->sprite_hash, tags[k], ss)) {
1627 log_error("warning: already have a sprite for \"%s\".", tags[k]);
1630 } else {
1631 for (k = 0; k < num_tags; k++) {
1632 (void) sprite_hash_replace(t->sprite_hash, tags[k], ss);
1635 free(tags);
1638 secfile_check_unused(file);
1639 secfile_destroy(file);
1642 /**********************************************************************
1643 Returns the correct name of the gfx file (with path and extension)
1644 Must be free'd when no longer used
1645 ***********************************************************************/
1646 static char *tilespec_gfx_filename(const char *gfx_filename)
1648 const char *gfx_current_fileext;
1649 const char **gfx_fileexts = gfx_fileextensions();
1651 while ((gfx_current_fileext = *gfx_fileexts++)) {
1652 const char *real_full_name;
1653 char *full_name =
1654 fc_malloc(strlen(gfx_filename) + strlen(".")
1655 + strlen(gfx_current_fileext) + 1);
1657 sprintf(full_name, "%s.%s", gfx_filename, gfx_current_fileext);
1659 real_full_name = fileinfoname(get_data_dirs(), full_name);
1660 free(full_name);
1661 if (real_full_name) {
1662 return fc_strdup(real_full_name);
1666 tileset_error(LOG_FATAL, _("Couldn't find a supported gfx file extension for \"%s\"."),
1667 gfx_filename);
1669 return NULL;
1672 /**********************************************************************
1673 Determine the sprite_type string.
1674 ***********************************************************************/
1675 static int check_sprite_type(const char *sprite_type, const char *tile_section)
1677 if (fc_strcasecmp(sprite_type, "corner") == 0) {
1678 return CELL_CORNER;
1680 if (fc_strcasecmp(sprite_type, "single") == 0) {
1681 return CELL_WHOLE;
1683 if (fc_strcasecmp(sprite_type, "whole") == 0) {
1684 return CELL_WHOLE;
1686 log_error("[%s] unknown sprite_type \"%s\".", tile_section, sprite_type);
1687 return CELL_WHOLE;
1690 /**********************************************************************
1691 Finds and reads the toplevel tilespec file based on given name.
1692 Sets global variables, including tile sizes and full names for
1693 intro files.
1694 topology_id of -1 means any topology is acceptable.
1695 ***********************************************************************/
1696 struct tileset *tileset_read_toplevel(const char *tileset_name, bool verbose,
1697 int topology_id, float scale)
1699 struct section_file *file;
1700 char *fname;
1701 const char *c;
1702 int i;
1703 size_t num_spec_files;
1704 const char **spec_filenames;
1705 size_t num_preferred_themes;
1706 struct section_list *sections = NULL;
1707 const char *file_capstr;
1708 bool duplicates_ok, is_hex;
1709 enum direction8 dir;
1710 struct tileset *t = NULL;
1711 const char *extraname;
1712 const char *tstr;
1713 int topo;
1715 fname = tilespec_fullname(tileset_name);
1716 if (!fname) {
1717 if (verbose) {
1718 log_error("Can't find tileset \"%s\".", tileset_name);
1720 return NULL;
1722 log_verbose("tilespec file is \"%s\".", fname);
1724 if (!(file = secfile_load(fname, TRUE))) {
1725 log_error("Could not open '%s':\n%s", fname, secfile_error());
1726 free(fname);
1727 return NULL;
1730 if (!check_tilespec_capabilities(file, "tilespec",
1731 TILESPEC_CAPSTR, fname, verbose)) {
1732 secfile_destroy(file);
1733 free(fname);
1734 return NULL;
1737 t = tileset_new();
1738 t->scale = scale;
1739 file_capstr = secfile_lookup_str(file, "%s.options", "tilespec");
1740 duplicates_ok = (NULL != file_capstr
1741 && has_capabilities("+duplicates_ok", file_capstr));
1743 tstr = secfile_lookup_str(file, "tilespec.name");
1744 /* Tileset name found */
1745 sz_strlcpy(t->given_name, tstr);
1746 tstr = secfile_lookup_str_default(file, "", "tilespec.version");
1747 if (tstr[0] != '\0') {
1748 /* Tileset version found */
1749 sz_strlcpy(t->version, tstr);
1750 } else {
1751 /* No version information */
1752 t->version[0] = '\0';
1755 tstr = secfile_lookup_str_default(file, "", "tilespec.summary");
1756 if (tstr[0] != '\0') {
1757 int len;
1759 /* Tileset summary found */
1760 len = strlen(tstr);
1761 t->summary = fc_malloc(len + 1);
1762 fc_strlcpy(t->summary, tstr, len + 1);
1763 } else {
1764 /* No summary */
1765 if (t->summary != NULL) {
1766 free(t->summary);
1767 t->summary = NULL;
1771 tstr = secfile_lookup_str_default(file, "", "tilespec.description");
1772 if (tstr[0] != '\0') {
1773 int len;
1775 /* Tileset description found */
1776 len = strlen(tstr);
1777 t->description = fc_malloc(len + 1);
1778 fc_strlcpy(t->description, tstr, len + 1);
1779 } else {
1780 /* No description */
1781 if (t->description != NULL) {
1782 free(t->description);
1783 t->description = NULL;
1787 sz_strlcpy(t->name, tileset_name);
1788 if (!secfile_lookup_int(file, &t->priority, "tilespec.priority")
1789 || !secfile_lookup_bool(file, &is_hex, "tilespec.is_hex")) {
1790 log_error("Tileset \"%s\" invalid: %s", t->name, secfile_error());
1791 goto ON_ERROR;
1794 tstr = secfile_lookup_str(file, "tilespec.type");
1795 if (tstr == NULL) {
1796 log_error("Tileset \"%s\": no tileset type", t->name);
1797 goto ON_ERROR;
1800 t->type = ts_type_by_name(tstr, fc_strcasecmp);
1801 if (!ts_type_is_valid(t->type)) {
1802 log_error("Tileset \"%s\": unknown tileset type \"%s\"", t->name, tstr);
1803 goto ON_ERROR;
1806 if (t->type == TS_ISOMETRIC) {
1807 topo = TF_ISO;
1808 } else {
1809 topo = 0;
1812 if (t->type == TS_ISOMETRIC) {
1813 topo = TF_ISO;
1814 } else {
1815 topo = 0;
1818 /* Read hex-tileset information. */
1819 t->hex_width = t->hex_height = 0;
1820 if (is_hex) {
1821 int hex_side;
1823 if (!secfile_lookup_int(file, &hex_side, "tilespec.hex_side")) {
1824 log_error("Tileset \"%s\" invalid: %s", t->name, secfile_error());
1825 goto ON_ERROR;
1827 hex_side = hex_side * t->scale;
1828 if (t->type == TS_ISOMETRIC) {
1829 t->hex_width = hex_side;
1830 } else {
1831 t->hex_height = hex_side;
1834 topo |= TF_HEX;
1836 /* Hex tilesets are drawn the same as isometric. */
1837 /* FIXME: There will be other legal values to be used with hex
1838 * tileset in the future, and this would just overwrite it. */
1839 t->type = TS_ISOMETRIC;
1842 if (topology_id >= 0 && topo != (topology_id & (TF_ISO | TF_HEX))) {
1843 /* Not of requested topology */
1844 goto ON_ERROR;
1847 t->ts_topo_idx = ts_topology_index(topo);
1849 if (!is_view_supported(t->type)) {
1850 log_normal(_("Client does not support %s tilesets."),
1851 _(ts_type_name(t->type)));
1852 log_normal(_("Using default tileset instead."));
1853 fc_assert(tileset_name != NULL);
1854 goto ON_ERROR;
1857 /* Create arrays of valid and cardinal tileset dirs. These depend
1858 * entirely on the tileset, not the topology. They are also in clockwise
1859 * rotational ordering. */
1860 t->num_valid_tileset_dirs = t->num_cardinal_tileset_dirs = 0;
1861 dir = DIR8_NORTH;
1862 do {
1863 if (is_valid_tileset_dir(t, dir)) {
1864 t->valid_tileset_dirs[t->num_valid_tileset_dirs] = dir;
1865 t->num_valid_tileset_dirs++;
1867 if (is_cardinal_tileset_dir(t, dir)) {
1868 t->cardinal_tileset_dirs[t->num_cardinal_tileset_dirs] = dir;
1869 t->num_cardinal_tileset_dirs++;
1872 dir = dir_cw(dir);
1873 } while (dir != DIR8_NORTH);
1874 fc_assert(t->num_valid_tileset_dirs % 2 == 0); /* Assumed elsewhere. */
1875 t->num_index_valid = 1 << t->num_valid_tileset_dirs;
1876 t->num_index_cardinal = 1 << t->num_cardinal_tileset_dirs;
1878 if (!secfile_lookup_int(file, &t->normal_tile_width,
1879 "tilespec.normal_tile_width")
1880 || !secfile_lookup_int(file, &t->normal_tile_height,
1881 "tilespec.normal_tile_height")) {
1882 log_error("Tileset \"%s\" invalid: %s", t->name, secfile_error());
1883 goto ON_ERROR;
1885 t->normal_tile_width = ceil(t->scale * t->normal_tile_width);
1886 // Adjust width to be multiple of 8
1887 if (scale != 1.0f) {
1888 i = t->normal_tile_width;
1889 while (i % 8 != 0) {
1890 i++;
1892 t->scale = (t->scale * i) / t->normal_tile_width;
1893 t->normal_tile_width = i;
1895 t->normal_tile_height = ceil(t->scale * t->normal_tile_height);
1896 if (t->type == TS_ISOMETRIC) {
1897 t->full_tile_width = t->normal_tile_width;
1898 if (tileset_hex_height(t) > 0) {
1899 t->full_tile_height = t->normal_tile_height;
1900 } else {
1901 t->full_tile_height = 3 * t->normal_tile_height / 2;
1903 } else {
1904 t->full_tile_width = t->normal_tile_width;
1905 t->full_tile_height = t->normal_tile_height;
1907 t->unit_tile_width
1908 = secfile_lookup_int_default(file, t->full_tile_width, "tilespec.unit_width");
1909 t->unit_tile_height
1910 = secfile_lookup_int_default(file, t->full_tile_height, "tilespec.unit_height");
1911 if (!secfile_lookup_int(file, &t->small_sprite_width,
1912 "tilespec.small_tile_width")
1913 || !secfile_lookup_int(file, &t->small_sprite_height,
1914 "tilespec.small_tile_height")) {
1915 log_error("Tileset \"%s\" invalid: %s", t->name, secfile_error());
1916 goto ON_ERROR;
1918 if (t->unit_tile_width != t->full_tile_width && t->scale != 1.0f) {
1919 t->unit_tile_width = ceil(t->unit_tile_width * t->scale);
1921 if (t->unit_tile_height != t->full_tile_height && t->scale != 1.0f) {
1922 t->unit_tile_height = ceil(t->unit_tile_height * t->scale);
1924 t->small_sprite_width = t->small_sprite_width * t->scale;
1925 t->small_sprite_height = t->small_sprite_height * t->scale;
1926 log_verbose("tile sizes %dx%d, %d%d unit, %d%d small",
1927 t->normal_tile_width, t->normal_tile_height,
1928 t->full_tile_width, t->full_tile_height,
1929 t->small_sprite_width, t->small_sprite_height);
1931 tstr = secfile_lookup_str(file, "tilespec.fog_style");
1932 if (tstr == NULL) {
1933 log_error("Tileset \"%s\": no fog_style", t->name);
1934 goto ON_ERROR;
1937 t->fogstyle = fog_style_by_name(tstr, fc_strcasecmp);
1938 if (!fog_style_is_valid(t->fogstyle)) {
1939 log_error("Tileset \"%s\": unknown fog_style \"%s\"", t->name, tstr);
1940 goto ON_ERROR;
1943 tstr = secfile_lookup_str(file, "tilespec.darkness_style");
1944 if (tstr == NULL) {
1945 log_error("Tileset \"%s\": no darkness_style", t->name);
1946 goto ON_ERROR;
1949 t->darkness_style = darkness_style_by_name(tstr, fc_strcasecmp);
1950 if (!darkness_style_is_valid(t->darkness_style)) {
1951 log_error("Tileset \"%s\": unknown darkness_style \"%s\"", t->name, tstr);
1952 goto ON_ERROR;
1955 if (t->darkness_style == DARKNESS_ISORECT
1956 && (t->type == TS_OVERHEAD || t->hex_width > 0 || t->hex_height > 0)) {
1957 log_error("Invalid darkness style set in tileset \"%s\".", t->name);
1958 goto ON_ERROR;
1960 t->darkness_layer = secfile_lookup_int_default(file, 0, "tilespec.darkness_layer");
1961 if (t->darkness_layer < 0 || t->darkness_layer >= TERRAIN_LAYER_COUNT) {
1962 tileset_error(LOG_ERROR, "Invalid darkness layer %d in tileset \"%s\"",
1963 t->darkness_layer, t->name);
1964 goto ON_ERROR;
1967 if (!secfile_lookup_int(file, &t->unit_flag_offset_x,
1968 "tilespec.unit_flag_offset_x")
1969 || !secfile_lookup_int(file, &t->unit_flag_offset_y,
1970 "tilespec.unit_flag_offset_y")
1971 || !secfile_lookup_int(file, &t->city_flag_offset_x,
1972 "tilespec.city_flag_offset_x")
1973 || !secfile_lookup_int(file, &t->city_flag_offset_y,
1974 "tilespec.city_flag_offset_y")
1975 || !secfile_lookup_int(file, &t->unit_offset_x,
1976 "tilespec.unit_offset_x")
1977 || !secfile_lookup_int(file, &t->unit_offset_y,
1978 "tilespec.unit_offset_y")
1979 || !secfile_lookup_int(file, &t->activity_offset_x,
1980 "tilespec.activity_offset_x")
1981 || !secfile_lookup_int(file, &t->activity_offset_y,
1982 "tilespec.activity_offset_y")
1983 || !secfile_lookup_int(file, &t->city_offset_x,
1984 "tilespec.city_offset_x")
1985 || !secfile_lookup_int(file, &t->city_offset_y,
1986 "tilespec.city_offset_y")
1987 || !secfile_lookup_int(file, &t->citybar_offset_y,
1988 "tilespec.citybar_offset_y")
1989 || !secfile_lookup_int(file, &t->tilelabel_offset_y,
1990 "tilespec.tilelabel_offset_y")
1991 || !secfile_lookup_int(file, &t->occupied_offset_x,
1992 "tilespec.occupied_offset_x")
1993 || !secfile_lookup_int(file, &t->occupied_offset_y,
1994 "tilespec.occupied_offset_y")
1995 || !secfile_lookup_int(file, &t->city_names_font_size,
1996 "tilespec.city_names_font_size")
1997 || !secfile_lookup_int(file, &t->city_productions_font_size,
1998 "tilespec.city_productions_font_size")) {
1999 log_error("Tileset \"%s\" invalid: %s", t->name, secfile_error());
2000 goto ON_ERROR;
2003 t->unit_upkeep_offset_y = secfile_lookup_int_default(file, tileset_tile_height(t),
2004 "tilespec.unit_upkeep_offset_y");
2005 t->unit_upkeep_small_offset_y = secfile_lookup_int_default(file, t->unit_upkeep_offset_y,
2006 "tilespec.unit_upkeep_small_offset_y");
2007 t->unit_flag_offset_x = t->scale * t->unit_flag_offset_x;
2008 t->unit_flag_offset_y = t->scale * t->unit_flag_offset_y;
2009 t->city_flag_offset_x = t->scale * t->city_flag_offset_x;
2010 t->city_flag_offset_y = t->scale * t->city_flag_offset_y;
2011 t->unit_offset_x = t->scale * t->unit_offset_x;
2012 t->unit_offset_y = t->scale * t->unit_offset_y;
2013 t->activity_offset_x = t->scale * t->activity_offset_x;
2014 t->activity_offset_y = t->scale * t->activity_offset_y;
2015 t->city_offset_x = t->scale * t->city_offset_x;
2016 t->city_offset_y = t->scale * t->city_offset_y;
2017 t->citybar_offset_y = t->scale * t->citybar_offset_y;
2018 t->tilelabel_offset_y = t->scale * t->tilelabel_offset_y;
2019 t->occupied_offset_x = t->scale * t->occupied_offset_x;
2020 t->occupied_offset_y = t->scale * t->occupied_offset_y;
2021 if (t->scale != 1.0f
2022 && t->unit_upkeep_offset_y != tileset_tile_height(t)) {
2023 t->unit_upkeep_offset_y = t->scale * t->unit_upkeep_offset_y;
2025 if (t->scale != 1.0f
2026 && t->unit_upkeep_small_offset_y != t->unit_upkeep_offset_y) {
2027 t->unit_upkeep_small_offset_y = t->scale * t->unit_upkeep_small_offset_y;
2029 set_city_names_font_sizes(t->city_names_font_size,
2030 t->city_productions_font_size);
2032 c = secfile_lookup_str(file, "tilespec.main_intro_file");
2033 t->main_intro_filename = tilespec_gfx_filename(c);
2034 log_debug("intro file %s", t->main_intro_filename);
2036 c = secfile_lookup_str_default(file, NULL, "tilespec.minimap_intro_file");
2037 if (c == NULL) {
2038 t->minimap_intro_filename = NULL;
2039 } else {
2040 t->minimap_intro_filename = tilespec_gfx_filename(c);
2041 log_debug("radar file %s", t->minimap_intro_filename);
2044 /* Terrain layer info. */
2045 for (i = 0; i < MAX_NUM_LAYERS; i++) {
2046 struct tileset_layer *tslp = &t->layers[i];
2047 int j, k;
2049 tslp->match_types =
2050 (char **) secfile_lookup_str_vec(file, &tslp->match_count,
2051 "layer%d.match_types", i);
2052 for (j = 0; j < tslp->match_count; j++) {
2053 tslp->match_types[j] = fc_strdup(tslp->match_types[j]);
2055 for (k = 0; k < j; k++) {
2056 if (tslp->match_types[k][0] == tslp->match_types[j][0]) {
2057 tileset_error(LOG_FATAL, _("[layer%d] match_types: \"%s\" initial "
2058 "('%c') is not unique."),
2059 i, tslp->match_types[j], tslp->match_types[j][0]);
2060 /* FIXME: Returns NULL. */
2066 /* Tile drawing info. */
2067 sections = secfile_sections_by_name_prefix(file, TILE_SECTION_PREFIX);
2068 if (NULL == sections || 0 == section_list_size(sections)) {
2069 tileset_error(LOG_ERROR, _("No [%s] sections supported by tileset \"%s\"."),
2070 TILE_SECTION_PREFIX, fname);
2071 goto ON_ERROR;
2074 fc_assert(t->tile_hash == NULL);
2075 t->tile_hash = drawing_hash_new();
2077 section_list_iterate(sections, psection) {
2078 const char *sec_name = section_name(psection);
2079 struct drawing_data *draw = drawing_data_new();
2080 const char *sprite_type;
2081 int l;
2082 const char *terrain_name;
2084 terrain_name = secfile_lookup_str(file, "%s.tag", sec_name);
2086 if (terrain_name != NULL) {
2087 draw->name = fc_strdup(terrain_name);
2088 } else {
2089 tileset_error(LOG_ERROR, _("No terrain tag given in section [%s]."), sec_name);
2090 drawing_data_destroy(draw);
2091 goto ON_ERROR;
2094 draw->blending = secfile_lookup_int_default(file, 0, "%s.blend_layer",
2095 sec_name);
2096 draw->blending = CLIP(0, draw->blending, MAX_NUM_LAYERS);
2098 draw->is_reversed = secfile_lookup_bool_default(file, FALSE,
2099 "%s.is_reversed",
2100 sec_name);
2101 draw->num_layers = secfile_lookup_int_default(file, 0, "%s.num_layers",
2102 sec_name);
2103 draw->num_layers = CLIP(1, draw->num_layers, MAX_NUM_LAYERS);
2105 for (l = 0; l < draw->num_layers; l++) {
2106 struct drawing_layer *dlp = &draw->layer[l];
2107 struct tileset_layer *tslp = &t->layers[l];
2108 const char *match_type;
2109 const char **match_with;
2110 size_t count;
2112 dlp->is_tall
2113 = secfile_lookup_bool_default(file, FALSE, "%s.layer%d_is_tall",
2114 sec_name, l);
2115 dlp->offset_x
2116 = secfile_lookup_int_default(file, 0, "%s.layer%d_offset_x",
2117 sec_name, l);
2118 dlp->offset_y
2119 = secfile_lookup_int_default(file, 0, "%s.layer%d_offset_y",
2120 sec_name, l);
2121 dlp->offset_x = ceil(t->scale * dlp->offset_x);
2122 dlp->offset_y = ceil(t->scale * dlp->offset_y);
2124 match_type = secfile_lookup_str_default(file, NULL,
2125 "%s.layer%d_match_type",
2126 sec_name, l);
2127 if (match_type) {
2128 int j;
2130 /* Determine our match_type. */
2131 for (j = 0; j < tslp->match_count; j++) {
2132 if (fc_strcasecmp(tslp->match_types[j], match_type) == 0) {
2133 break;
2136 if (j >= tslp->match_count) {
2137 log_error("[%s] invalid match_type \"%s\".", sec_name, match_type);
2138 } else {
2139 dlp->match_index[dlp->match_indices++] = j;
2143 match_with = secfile_lookup_str_vec(file, &count,
2144 "%s.layer%d_match_with",
2145 sec_name, l);
2146 if (match_with) {
2147 int j, k;
2149 if (count > MAX_NUM_MATCH_WITH) {
2150 log_error("[%s] match_with has too many types (%d, max %d)",
2151 sec_name, (int) count, MAX_NUM_MATCH_WITH);
2152 count = MAX_NUM_MATCH_WITH;
2155 if (1 < dlp->match_indices) {
2156 log_error("[%s] previous match_with ignored.", sec_name);
2157 dlp->match_indices = 1;
2158 } else if (1 > dlp->match_indices) {
2159 log_error("[%s] missing match_type, using \"%s\".",
2160 sec_name, tslp->match_types[0]);
2161 dlp->match_index[0] = 0;
2162 dlp->match_indices = 1;
2165 for (k = 0; k < count; k++) {
2166 for (j = 0; j < tslp->match_count; j++) {
2167 if (fc_strcasecmp(tslp->match_types[j], match_with[k]) == 0) {
2168 break;
2171 if (j >= tslp->match_count) {
2172 log_error("[%s] layer%d_match_with: invalid \"%s\".",
2173 sec_name, l, match_with[k]);
2174 } else if (1 < count) {
2175 int m;
2177 for (m = 0; m < dlp->match_indices; m++) {
2178 if (dlp->match_index[m] == j) {
2179 log_error("[%s] layer%d_match_with: duplicate \"%s\".",
2180 sec_name, l, match_with[k]);
2181 break;
2184 if (m >= dlp->match_indices) {
2185 dlp->match_index[dlp->match_indices++] = j;
2187 } else {
2188 dlp->match_index[dlp->match_indices++] = j;
2191 free(match_with);
2192 match_with = NULL;
2195 /* Check match_indices */
2196 switch (dlp->match_indices) {
2197 case 0:
2198 case 1:
2199 dlp->match_style = MATCH_NONE;
2200 break;
2201 case 2:
2202 if (dlp->match_index[0] == dlp->match_index[1] ) {
2203 dlp->match_style = MATCH_SAME;
2204 } else {
2205 dlp->match_style = MATCH_PAIR;
2207 break;
2208 default:
2209 dlp->match_style = MATCH_FULL;
2210 break;
2213 sprite_type
2214 = secfile_lookup_str_default(file, "whole", "%s.layer%d_sprite_type",
2215 sec_name, l);
2216 dlp->sprite_type = check_sprite_type(sprite_type, sec_name);
2218 switch (dlp->sprite_type) {
2219 case CELL_WHOLE:
2220 /* OK, no problem */
2221 break;
2222 case CELL_CORNER:
2223 if (dlp->is_tall
2224 || dlp->offset_x > 0
2225 || dlp->offset_y > 0) {
2226 log_error("[%s] layer %d: you cannot have tall terrain or\n"
2227 "a sprite offset with a cell-based drawing method.",
2228 sec_name, l);
2229 dlp->is_tall = FALSE;
2230 dlp->offset_x = dlp->offset_y = 0;
2232 break;
2236 if (!drawing_hash_insert(t->tile_hash, draw->name, draw)) {
2237 log_error("warning: multiple tile sections containing terrain tag \"%s\".",
2238 draw->name);
2239 goto ON_ERROR;
2241 } section_list_iterate_end;
2242 section_list_destroy(sections);
2243 sections = NULL;
2245 t->estyle_hash = estyle_hash_new();
2247 for (i = 0; i < ESTYLE_COUNT; i++) {
2248 t->style_lists[i] = extra_type_list_new();
2250 t->flagged_bases_list = extra_type_list_new();
2252 for (i = 0; (extraname = secfile_lookup_str_default(file, NULL,
2253 "extras.styles%d.name",
2254 i)); i++) {
2255 const char *style_name;
2256 enum extrastyle_id style;
2258 style_name = secfile_lookup_str_default(file, "Single1",
2259 "extras.styles%d.style", i);
2260 style = extrastyle_id_by_name(style_name, fc_strcasecmp);
2261 if (!extrastyle_id_is_valid(style)) {
2262 log_error("Unknown extra style \"%s\" for road \"%s\"",
2263 style_name, extraname);
2264 goto ON_ERROR;
2267 if (!estyle_hash_insert(t->estyle_hash, extraname, style)) {
2268 log_error("warning: duplicate extrastyle entry [%s].", extraname);
2269 goto ON_ERROR;
2273 spec_filenames = secfile_lookup_str_vec(file, &num_spec_files,
2274 "tilespec.files");
2275 if (NULL == spec_filenames || 0 == num_spec_files) {
2276 log_error("No tile graphics files specified in \"%s\"", fname);
2277 goto ON_ERROR;
2280 fc_assert(t->sprite_hash == NULL);
2281 t->sprite_hash = sprite_hash_new();
2282 for (i = 0; i < num_spec_files; i++) {
2283 struct specfile *sf = fc_malloc(sizeof(*sf));
2284 const char *dname;
2286 log_debug("spec file %s", spec_filenames[i]);
2288 sf->big_sprite = NULL;
2289 dname = fileinfoname(get_data_dirs(), spec_filenames[i]);
2290 if (!dname) {
2291 if (verbose) {
2292 log_error("Can't find spec file \"%s\".", spec_filenames[i]);
2294 goto ON_ERROR;
2296 sf->file_name = fc_strdup(dname);
2297 scan_specfile(t, sf, duplicates_ok);
2299 specfile_list_prepend(t->specfiles, sf);
2301 free(spec_filenames);
2303 t->color_system = color_system_read(file);
2305 /* FIXME: remove this hack. */
2306 t->preferred_themes =
2307 (char **) secfile_lookup_str_vec(file, &num_preferred_themes,
2308 "tilespec.preferred_themes");
2309 if (num_preferred_themes <= 0) {
2310 t->preferred_themes =
2311 (char **) secfile_lookup_str_vec(file, &num_preferred_themes,
2312 "tilespec.prefered_themes");
2313 if (num_preferred_themes > 0) {
2314 log_deprecation("Entry tilespec.prefered_themes in tilespec."
2315 " Use correct spelling tilespec.preferred_themes instead");
2318 t->num_preferred_themes = num_preferred_themes;
2319 for (i = 0; i < t->num_preferred_themes; i++) {
2320 t->preferred_themes[i] = fc_strdup(t->preferred_themes[i]);
2323 secfile_check_unused(file);
2324 secfile_destroy(file);
2325 log_verbose("finished reading \"%s\".", fname);
2326 free(fname);
2328 return t;
2330 ON_ERROR:
2331 secfile_destroy(file);
2332 free(fname);
2333 tileset_free(t);
2334 if (NULL != sections) {
2335 section_list_destroy(sections);
2337 return NULL;
2340 /**********************************************************************
2341 Returns a text name for the citizen, as used in the tileset.
2342 ***********************************************************************/
2343 static const char *citizen_rule_name(enum citizen_category citizen)
2345 /* These strings are used in reading the tileset. Do not
2346 * translate. */
2347 switch (citizen) {
2348 case CITIZEN_HAPPY:
2349 return "happy";
2350 case CITIZEN_CONTENT:
2351 return "content";
2352 case CITIZEN_UNHAPPY:
2353 return "unhappy";
2354 case CITIZEN_ANGRY:
2355 return "angry";
2356 default:
2357 break;
2359 log_error("Unknown citizen type: %d.", (int) citizen);
2360 return NULL;
2363 /****************************************************************************
2364 Return a directional string for the cardinal directions. Normally the
2365 binary value 1000 will be converted into "n1e0s0w0". This is in a
2366 clockwise ordering.
2367 ****************************************************************************/
2368 static const char *cardinal_index_str(const struct tileset *t, int idx)
2370 static char c[64];
2371 int i;
2373 c[0] = '\0';
2374 for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
2375 int value = (idx >> i) & 1;
2377 cat_snprintf(c, sizeof(c), "%s%d",
2378 dir_get_tileset_name(t->cardinal_tileset_dirs[i]), value);
2381 return c;
2384 /****************************************************************************
2385 Do the same thing as cardinal_str, except including all valid directions.
2386 The returned string is a pointer to static memory.
2387 ****************************************************************************/
2388 static char *valid_index_str(const struct tileset *t, int idx)
2390 static char c[64];
2391 int i;
2393 c[0] = '\0';
2394 for (i = 0; i < t->num_valid_tileset_dirs; i++) {
2395 int value = (idx >> i) & 1;
2397 cat_snprintf(c, sizeof(c), "%s%d",
2398 dir_get_tileset_name(t->valid_tileset_dirs[i]), value);
2401 return c;
2404 /**************************************************************************
2405 Loads the sprite. If the sprite is already loaded a reference
2406 counter is increased. Can return NULL if the sprite couldn't be
2407 loaded.
2408 Scale means if sprite should be scaled, smooth if scaling might use
2409 other scaling algorithm than nearest neighbor.
2410 **************************************************************************/
2411 static struct sprite *load_sprite(struct tileset *t, const char *tag_name,
2412 bool scale, bool smooth)
2414 struct small_sprite *ss;
2415 float sprite_scale = 1.0f;
2417 log_debug("load_sprite(tag='%s')", tag_name);
2418 /* Lookup information about where the sprite is found. */
2419 if (!sprite_hash_lookup(t->sprite_hash, tag_name, &ss)) {
2420 return NULL;
2423 fc_assert(ss->ref_count >= 0);
2425 if (!ss->sprite) {
2426 /* If the sprite hasn't been loaded already, then load it. */
2427 fc_assert(ss->ref_count == 0);
2428 if (ss->file) {
2429 int w, h;
2430 struct sprite *s;
2432 if (scale) {
2433 s = load_gfx_file(ss->file);
2434 get_sprite_dimensions(s, &w, &h);
2435 ss->sprite = crop_sprite(s, 0, 0, w,
2436 h, NULL, -1, -1, t->scale, smooth);
2437 free_sprite(s);
2438 } else {
2439 ss->sprite = load_gfx_file(ss->file);
2441 if (!ss->sprite) {
2442 tileset_error(LOG_FATAL, _("Couldn't load gfx file \"%s\" for sprite '%s'."),
2443 ss->file, tag_name);
2445 } else {
2446 int sf_w, sf_h;
2448 ensure_big_sprite(ss->sf);
2449 get_sprite_dimensions(ss->sf->big_sprite, &sf_w, &sf_h);
2450 if (ss->x < 0 || ss->x + ss->width > sf_w
2451 || ss->y < 0 || ss->y + ss->height > sf_h) {
2452 tileset_error(LOG_ERROR, _("Sprite '%s' in file \"%s\" isn't within the image!"),
2453 tag_name, ss->sf->file_name);
2454 return NULL;
2456 if (scale) {
2457 sprite_scale = t->scale;
2459 ss->sprite = crop_sprite(ss->sf->big_sprite, ss->x, ss->y, ss->width,
2460 ss->height, NULL, -1, -1, sprite_scale,
2461 smooth);
2465 /* Track the reference count so we know when to free the sprite. */
2466 ss->ref_count++;
2468 return ss->sprite;
2471 /**************************************************************************
2472 Create a sprite with the given color and tag.
2473 **************************************************************************/
2474 static struct sprite *create_plr_sprite(struct color *pcolor)
2476 struct sprite *sprite;
2478 fc_assert_ret_val(pcolor != NULL, NULL);
2480 sprite = create_sprite(128, 64, pcolor);
2482 return sprite;
2485 /**************************************************************************
2486 Unloads the sprite. Decrease the reference counter. If the last
2487 reference is removed the sprite is freed.
2488 **************************************************************************/
2489 static void unload_sprite(struct tileset *t, const char *tag_name)
2491 struct small_sprite *ss;
2493 sprite_hash_lookup(t->sprite_hash, tag_name, &ss);
2494 fc_assert_ret(ss);
2495 fc_assert_ret(ss->ref_count >= 1);
2496 fc_assert_ret(ss->sprite);
2498 ss->ref_count--;
2500 if (ss->ref_count == 0) {
2501 /* Nobody's using the sprite anymore, so we should free it. We know
2502 * where to find it if we need it again. */
2503 log_debug("freeing sprite '%s'.", tag_name);
2504 free_sprite(ss->sprite);
2505 ss->sprite = NULL;
2509 /**************************************************************************
2510 Return TRUE iff the specified sprite exists in the tileset (whether
2511 or not it is currently loaded).
2512 **************************************************************************/
2513 static bool sprite_exists(const struct tileset *t, const char *tag_name)
2515 /* Lookup information about where the sprite is found. */
2516 return sprite_hash_lookup(t->sprite_hash, tag_name, NULL);
2519 /* Not very safe, but convenient: */
2520 #define SET_SPRITE(field, tag) \
2521 do { \
2522 t->sprites.field = load_sprite(t, tag, TRUE, TRUE); \
2523 if (t->sprites.field == NULL) { \
2524 tileset_error(LOG_FATAL, _("Sprite for tag '%s' missing."), tag); \
2526 } while(FALSE)
2528 #define SET_SPRITE_NOTSMOOTH(field, tag) \
2529 do { \
2530 t->sprites.field = load_sprite(t, tag, TRUE, FALSE); \
2531 if (t->sprites.field == NULL) { \
2532 tileset_error(LOG_FATAL, _("Sprite for tag '%s' missing."), tag); \
2534 } while(FALSE)
2536 #define SET_SPRITE_UNSCALED(field, tag) \
2537 do { \
2538 t->sprites.field = load_sprite(t, tag, FALSE, FALSE); \
2539 if (t->sprites.field == NULL) { \
2540 tileset_error(LOG_FATAL, _("Sprite for tag '%s' missing."), tag); \
2542 } while(FALSE)
2544 /* Sets sprites.field to tag or (if tag isn't available) to alt */
2545 #define SET_SPRITE_ALT(field, tag, alt) \
2546 do { \
2547 t->sprites.field = load_sprite(t, tag, TRUE, TRUE); \
2548 if (!t->sprites.field) { \
2549 t->sprites.field = load_sprite(t, alt, TRUE, TRUE); \
2551 if (t->sprites.field == NULL) { \
2552 tileset_error(LOG_FATAL, _("Sprite for tags '%s' and alternate '%s' are " \
2553 "both missing."), tag, alt); \
2555 } while(FALSE)
2557 /* Sets sprites.field to tag, or NULL if not available */
2558 #define SET_SPRITE_OPT(field, tag) \
2559 t->sprites.field = load_sprite(t, tag, TRUE, TRUE)
2561 #define SET_SPRITE_ALT_OPT(field, tag, alt) \
2562 do { \
2563 t->sprites.field = tiles_lookup_sprite_tag_alt(t, LOG_VERBOSE, tag, alt,\
2564 "sprite", #field, TRUE); \
2565 } while (FALSE)
2567 /****************************************************************************
2568 Setup the graphics for specialist types.
2569 ****************************************************************************/
2570 void tileset_setup_specialist_type(struct tileset *t, Specialist_type_id id)
2572 /* Load the specialist sprite graphics. */
2573 char buffer[512];
2574 int j;
2575 const char *name = specialist_rule_name(specialist_by_number(id));
2576 const char *graphic_alt = specialist_by_number(id)->graphic_alt;
2578 for (j = 0; j < MAX_NUM_CITIZEN_SPRITES; j++) {
2579 /* Try rule name + index number */
2580 fc_snprintf(buffer, sizeof(buffer), "specialist.%s_%d", name, j);
2581 t->sprites.specialist[id].sprite[j] = load_sprite(t, buffer, FALSE,
2582 FALSE);
2584 /* Break if no more index specific sprites are defined */
2585 if (!t->sprites.specialist[id].sprite[j]) {
2586 break;
2590 /* Nothing? Try the alt tag */
2591 if (j == 0) {
2592 t->sprites.specialist[id].sprite[j] = load_sprite(t, graphic_alt, FALSE,
2593 FALSE);
2595 if (t->sprites.specialist[id].sprite[j]) {
2596 j = 1;
2600 t->sprites.specialist[id].count = j;
2602 /* Still nothing? Give up. */
2603 if (j == 0) {
2604 tileset_error(LOG_FATAL, _("No graphics for specialist \"%s\"."), name);
2608 /****************************************************************************
2609 Setup the graphics for (non-specialist) citizen types.
2610 ****************************************************************************/
2611 static void tileset_setup_citizen_types(struct tileset *t)
2613 int i, j;
2614 char buffer[512];
2616 /* Load the citizen sprite graphics, no specialist. */
2617 for (i = 0; i < CITIZEN_LAST; i++) {
2618 const char *name = citizen_rule_name(i);
2620 for (j = 0; j < MAX_NUM_CITIZEN_SPRITES; j++) {
2621 fc_snprintf(buffer, sizeof(buffer), "citizen.%s_%d", name, j);
2622 t->sprites.citizen[i].sprite[j] = load_sprite(t, buffer, FALSE, FALSE);
2623 if (!t->sprites.citizen[i].sprite[j]) {
2624 break;
2627 t->sprites.citizen[i].count = j;
2628 if (j == 0) {
2629 tileset_error(LOG_FATAL, _("No graphics for citizen \"%s\"."), name);
2634 /****************************************************************************
2635 Return the sprite in the city_sprite listing that corresponds to this
2636 city - based on city style and size.
2638 See also load_city_sprite, free_city_sprite.
2639 ****************************************************************************/
2640 static struct sprite *get_city_sprite(const struct city_sprite *city_sprite,
2641 const struct city *pcity)
2643 /* get style and match the best tile based on city size */
2644 int style = style_of_city(pcity);
2645 int num_thresholds;
2646 struct city_style_threshold *thresholds;
2647 int img_index;
2649 fc_assert_ret_val(style < city_sprite->num_styles, NULL);
2651 num_thresholds = city_sprite->styles[style].land_num_thresholds;
2652 thresholds = city_sprite->styles[style].land_thresholds;
2654 if (num_thresholds == 0) {
2655 return NULL;
2658 /* Get the sprite with the index defined by the effects. */
2659 img_index = pcity->client.city_image;
2660 if (img_index == -100) {
2661 /* Server doesn't know right value as this is from old savegame.
2662 * Guess here based on *client* side information as was done in
2663 * versions where information was not saved to savegame - this should
2664 * give us right answer of what city looked like by the time it was
2665 * put under FoW. */
2666 img_index = get_city_bonus(pcity, EFT_CITY_IMAGE);
2668 img_index = CLIP(0, img_index, num_thresholds - 1);
2670 return thresholds[img_index].sprite;
2673 /****************************************************************************
2674 Allocates one threshold set for city sprite
2675 ****************************************************************************/
2676 static int load_city_thresholds_sprites(struct tileset *t, const char *tag,
2677 char *graphic, char *graphic_alt,
2678 struct city_style_threshold **thresholds)
2680 char buffer[128];
2681 char *gfx_in_use = graphic;
2682 int num_thresholds = 0;
2683 struct sprite *sprite;
2684 int size;
2686 *thresholds = NULL;
2688 for (size = 0; size < MAX_CITY_SIZE; size++) {
2689 fc_snprintf(buffer, sizeof(buffer), "%s_%s_%d",
2690 gfx_in_use, tag, size);
2691 if ((sprite = load_sprite(t, buffer, TRUE, TRUE))) {
2692 num_thresholds++;
2693 *thresholds = fc_realloc(*thresholds, num_thresholds * sizeof(**thresholds));
2694 (*thresholds)[num_thresholds - 1].sprite = sprite;
2695 } else if (size == 0) {
2696 if (gfx_in_use == graphic) {
2697 /* Try again with graphic_alt. */
2698 size--;
2699 gfx_in_use = graphic_alt;
2700 } else {
2701 /* Don't load any others if the 0 element isn't there. */
2702 break;
2707 return num_thresholds;
2710 /****************************************************************************
2711 Allocates and loads a new city sprite from the given sprite tags.
2713 tag may be NULL.
2715 See also get_city_sprite, free_city_sprite.
2716 ****************************************************************************/
2717 static struct city_sprite *load_city_sprite(struct tileset *t,
2718 const char *tag)
2720 struct city_sprite *city_sprite = fc_malloc(sizeof(*city_sprite));
2721 int style;
2723 /* Store number of styles we have allocated memory for.
2724 * game.control.styles_count might change if client disconnects from
2725 * server and connects new one. */
2726 city_sprite->num_styles = game.control.styles_count;
2727 city_sprite->styles = fc_malloc(city_sprite->num_styles
2728 * sizeof(*city_sprite->styles));
2730 for (style = 0; style < city_sprite->num_styles; style++) {
2731 city_sprite->styles[style].land_num_thresholds =
2732 load_city_thresholds_sprites(t, tag, city_styles[style].graphic,
2733 city_styles[style].graphic_alt,
2734 &city_sprite->styles[style].land_thresholds);
2737 return city_sprite;
2740 /****************************************************************************
2741 Frees a city sprite.
2743 See also get_city_sprite, load_city_sprite.
2744 ****************************************************************************/
2745 static void free_city_sprite(struct city_sprite *city_sprite)
2747 int style;
2749 if (!city_sprite) {
2750 return;
2752 for (style = 0; style < city_sprite->num_styles; style++) {
2753 if (city_sprite->styles[style].land_thresholds) {
2754 free(city_sprite->styles[style].land_thresholds);
2757 free(city_sprite->styles);
2758 free(city_sprite);
2761 /**********************************************************************
2762 Initialize 'sprites' structure based on hardwired tags which
2763 freeciv always requires.
2764 ***********************************************************************/
2765 static void tileset_lookup_sprite_tags(struct tileset *t)
2767 char buffer[512], buffer2[512];
2768 const int W = t->normal_tile_width, H = t->normal_tile_height;
2769 int i, j, f;
2771 fc_assert_ret(t->sprite_hash != NULL);
2773 SET_SPRITE_UNSCALED(treaty_thumb[0], "treaty.disagree_thumb_down");
2774 SET_SPRITE_UNSCALED(treaty_thumb[1], "treaty.agree_thumb_up");
2776 for (j = 0; j < INDICATOR_COUNT; j++) {
2777 const char *names[] = {"science_bulb", "warming_sun", "cooling_flake"};
2779 for (i = 0; i < NUM_TILES_PROGRESS; i++) {
2780 fc_snprintf(buffer, sizeof(buffer), "s.%s_%d", names[j], i);
2781 SET_SPRITE_UNSCALED(indicator[j][i], buffer);
2785 SET_SPRITE(arrow[ARROW_RIGHT], "s.right_arrow");
2786 SET_SPRITE(arrow[ARROW_PLUS], "s.plus");
2787 SET_SPRITE(arrow[ARROW_MINUS], "s.minus");
2788 if (t->type == TS_ISOMETRIC) {
2789 SET_SPRITE(dither_tile, "t.dither_tile");
2792 if (tileset_is_isometric(tileset)) {
2793 SET_SPRITE_NOTSMOOTH(mask.tile, "mask.tile");
2794 } else {
2795 SET_SPRITE(mask.tile, "mask.tile");
2797 SET_SPRITE(mask.worked_tile, "mask.worked_tile");
2798 SET_SPRITE(mask.unworked_tile, "mask.unworked_tile");
2800 SET_SPRITE_UNSCALED(tax_luxury, "s.tax_luxury");
2801 SET_SPRITE_UNSCALED(tax_science, "s.tax_science");
2802 SET_SPRITE_UNSCALED(tax_gold, "s.tax_gold");
2804 tileset_setup_citizen_types(t);
2806 for (i = 0; i < SPACESHIP_COUNT; i++) {
2807 const char *names[SPACESHIP_COUNT]
2808 = {"solar_panels", "life_support", "habitation",
2809 "structural", "fuel", "propulsion", "exhaust"};
2811 fc_snprintf(buffer, sizeof(buffer), "spaceship.%s", names[i]);
2812 SET_SPRITE(spaceship[i], buffer);
2815 for (i = 0; i < CURSOR_LAST; i++) {
2816 for (f = 0; f < NUM_CURSOR_FRAMES; f++) {
2817 const char *names[CURSOR_LAST] =
2818 {"goto", "patrol", "paradrop", "nuke", "select",
2819 "invalid", "attack", "edit_paint", "edit_add", "wait"};
2820 struct small_sprite *ss;
2822 fc_assert(ARRAY_SIZE(names) == CURSOR_LAST);
2823 fc_snprintf(buffer, sizeof(buffer), "cursor.%s%d", names[i], f);
2824 SET_SPRITE(cursor[i].frame[f], buffer);
2825 if (sprite_hash_lookup(t->sprite_hash, buffer, &ss)) {
2826 t->sprites.cursor[i].hot_x = ss->hot_x;
2827 t->sprites.cursor[i].hot_y = ss->hot_y;
2832 for (i = 0; i < ICON_COUNT; i++) {
2833 const char *names[ICON_COUNT] = {"freeciv", "citydlg"};
2835 fc_snprintf(buffer, sizeof(buffer), "icon.%s", names[i]);
2836 SET_SPRITE(icon[i], buffer);
2839 for (i = 0; i < E_COUNT; i++) {
2840 const char *tag = get_event_tag(i);
2842 SET_SPRITE(events[i], tag);
2845 SET_SPRITE(explode.nuke, "explode.nuke");
2847 sprite_vector_init(&t->sprites.explode.unit);
2848 for (i = 0; ; i++) {
2849 struct sprite *sprite;
2851 fc_snprintf(buffer, sizeof(buffer), "explode.unit_%d", i);
2852 sprite = load_sprite(t, buffer, TRUE, TRUE);
2853 if (!sprite) {
2854 break;
2856 sprite_vector_append(&t->sprites.explode.unit, sprite);
2859 SET_SPRITE(unit.auto_attack, "unit.auto_attack");
2860 SET_SPRITE(unit.auto_settler, "unit.auto_settler");
2861 SET_SPRITE(unit.auto_explore, "unit.auto_explore");
2862 SET_SPRITE(unit.fortified, "unit.fortified");
2863 SET_SPRITE(unit.fortifying, "unit.fortifying");
2864 SET_SPRITE(unit.go_to, "unit.goto");
2865 SET_SPRITE(unit.irrigate, "unit.irrigate");
2866 SET_SPRITE(unit.plant, "unit.plant");
2867 SET_SPRITE(unit.pillage, "unit.pillage");
2868 SET_SPRITE(unit.sentry, "unit.sentry");
2869 SET_SPRITE(unit.convert, "unit.convert");
2870 SET_SPRITE(unit.stack, "unit.stack");
2871 SET_SPRITE(unit.loaded, "unit.loaded");
2872 SET_SPRITE(unit.transform, "unit.transform");
2873 SET_SPRITE(unit.connect, "unit.connect");
2874 SET_SPRITE(unit.patrol, "unit.patrol");
2875 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
2876 fc_snprintf(buffer, sizeof(buffer), "unit.battlegroup_%d", i);
2877 fc_snprintf(buffer2, sizeof(buffer2), "city.size_%d", i + 1);
2878 fc_assert(MAX_NUM_BATTLEGROUPS < NUM_TILES_DIGITS);
2879 SET_SPRITE_ALT(unit.battlegroup[i], buffer, buffer2);
2881 SET_SPRITE(unit.lowfuel, "unit.lowfuel");
2882 SET_SPRITE(unit.tired, "unit.tired");
2884 for(i=0; i<NUM_TILES_HP_BAR; i++) {
2885 fc_snprintf(buffer, sizeof(buffer), "unit.hp_%d", i*10);
2886 SET_SPRITE(unit.hp_bar[i], buffer);
2889 for (i = 0; i < MAX_VET_LEVELS; i++) {
2890 /* Veteran level sprites are optional. For instance "green" units
2891 * usually have no special graphic. */
2892 fc_snprintf(buffer, sizeof(buffer), "unit.vet_%d", i);
2893 t->sprites.unit.vet_lev[i] = load_sprite(t, buffer, TRUE, TRUE);
2896 t->sprites.unit.select[0] = NULL;
2897 if (sprite_exists(t, "unit.select0")) {
2898 for (i = 0; i < NUM_TILES_SELECT; i++) {
2899 fc_snprintf(buffer, sizeof(buffer), "unit.select%d", i);
2900 SET_SPRITE(unit.select[i], buffer);
2904 SET_SPRITE(citybar.shields, "citybar.shields");
2905 SET_SPRITE(citybar.food, "citybar.food");
2906 SET_SPRITE(citybar.trade, "citybar.trade");
2907 SET_SPRITE(citybar.occupied, "citybar.occupied");
2908 SET_SPRITE(citybar.background, "citybar.background");
2909 sprite_vector_init(&t->sprites.citybar.occupancy);
2910 for (i = 0; ; i++) {
2911 struct sprite *sprite;
2913 fc_snprintf(buffer, sizeof(buffer), "citybar.occupancy_%d", i);
2914 sprite = load_sprite(t, buffer, TRUE, TRUE);
2915 if (!sprite) {
2916 break;
2918 sprite_vector_append(&t->sprites.citybar.occupancy, sprite);
2920 if (t->sprites.citybar.occupancy.size < 2) {
2921 tileset_error(LOG_FATAL, _("Missing necessary citybar.occupancy_N sprites."));
2924 #define SET_EDITOR_SPRITE(x) SET_SPRITE(editor.x, "editor." #x)
2925 SET_EDITOR_SPRITE(erase);
2926 SET_EDITOR_SPRITE(brush);
2927 SET_EDITOR_SPRITE(copy);
2928 SET_EDITOR_SPRITE(paste);
2929 SET_EDITOR_SPRITE(copypaste);
2930 SET_EDITOR_SPRITE(startpos);
2931 SET_EDITOR_SPRITE(terrain);
2932 SET_EDITOR_SPRITE(terrain_resource);
2933 SET_EDITOR_SPRITE(terrain_special);
2934 SET_EDITOR_SPRITE(unit);
2935 SET_EDITOR_SPRITE(city);
2936 SET_EDITOR_SPRITE(vision);
2937 SET_EDITOR_SPRITE(territory);
2938 SET_EDITOR_SPRITE(properties);
2939 SET_EDITOR_SPRITE(road);
2940 SET_EDITOR_SPRITE(military_base);
2941 #undef SET_EDITOR_SPRITE
2943 SET_SPRITE(city.disorder, "city.disorder");
2945 /* Fallbacks for goto path turn numbers:
2946 * path.step_%d, path.exhausted_mp_%d
2947 * --> path.turns_%d
2948 * --> city.size_%d */
2949 #define SET_GOTO_TURN_SPRITE(state, state_name, factor, factor_name) \
2950 fc_snprintf(buffer, sizeof(buffer), "path." state_name "_%d" #factor, i); \
2951 SET_SPRITE_OPT(path.s[state].turns ## factor_name [i], buffer); \
2952 if (t->sprites.path.s[state].turns ## factor_name [i] == NULL) { \
2953 t->sprites.path.s[state].turns ## factor_name [i] = \
2954 t->sprites.path.s[GTS_MP_LEFT].turns ## factor_name [i]; \
2956 for(i=0; i<NUM_TILES_DIGITS; i++) {
2957 fc_snprintf(buffer, sizeof(buffer), "city.size_%d", i);
2958 SET_SPRITE(city.size[i], buffer);
2959 fc_snprintf(buffer2, sizeof(buffer2), "path.turns_%d", i);
2960 SET_SPRITE_ALT(path.s[GTS_MP_LEFT].turns[i], buffer2, buffer);
2961 SET_GOTO_TURN_SPRITE(GTS_TURN_STEP, "step",,);
2962 SET_GOTO_TURN_SPRITE(GTS_EXHAUSTED_MP, "exhausted_mp",,);
2964 fc_snprintf(buffer, sizeof(buffer), "city.size_%d0", i);
2965 SET_SPRITE(city.size_tens[i], buffer);
2966 fc_snprintf(buffer2, sizeof(buffer2), "path.turns_%d0", i);
2967 SET_SPRITE_ALT(path.s[GTS_MP_LEFT].turns_tens[i], buffer2, buffer);
2968 SET_GOTO_TURN_SPRITE(GTS_TURN_STEP, "step", 0, _tens);
2969 SET_GOTO_TURN_SPRITE(GTS_EXHAUSTED_MP, "exhausted_mp", 0, _tens);
2971 fc_snprintf(buffer, sizeof(buffer), "city.size_%d00", i);
2972 SET_SPRITE_OPT(city.size_hundreds[i], buffer);
2973 fc_snprintf(buffer2, sizeof(buffer2), "path.turns_%d00", i);
2974 SET_SPRITE_ALT_OPT(path.s[GTS_MP_LEFT].turns_hundreds[i], buffer2,
2975 buffer);
2976 SET_GOTO_TURN_SPRITE(GTS_TURN_STEP, "step", 00, _hundreds);
2977 SET_GOTO_TURN_SPRITE(GTS_EXHAUSTED_MP, "exhausted_mp", 00, _hundreds);
2979 fc_snprintf(buffer, sizeof(buffer), "city.t_food_%d", i);
2980 SET_SPRITE(city.tile_foodnum[i], buffer);
2981 fc_snprintf(buffer, sizeof(buffer), "city.t_shields_%d", i);
2982 SET_SPRITE(city.tile_shieldnum[i], buffer);
2983 fc_snprintf(buffer, sizeof(buffer), "city.t_trade_%d", i);
2984 SET_SPRITE(city.tile_tradenum[i], buffer);
2986 #undef SET_GOTO_TURN_SPRITE
2988 /* Must have at least one upkeep sprite per output type (and unhappy) */
2989 /* The rest are optional; we copy the previous sprite for unspecified ones */
2990 fc_strlcpy(buffer, "upkeep.unhappy", sizeof(buffer));
2991 SET_SPRITE(upkeep.unhappy[0], buffer);
2992 for(i=1; i<MAX_NUM_UPKEEP_SPRITES; i++) {
2993 fc_snprintf(buffer2, sizeof(buffer2), "upkeep.unhappy%d", i+1);
2994 if (sprite_exists(t, buffer2)) {
2995 SET_SPRITE(upkeep.unhappy[i], buffer2);
2996 fc_strlcpy(buffer, buffer2, sizeof(buffer));
2997 } else {
2998 SET_SPRITE(upkeep.unhappy[i], buffer);
3001 output_type_iterate(o) {
3002 fc_snprintf(buffer, sizeof(buffer),
3003 "upkeep.%s", get_output_identifier(o));
3004 SET_SPRITE_OPT(upkeep.output[o][0], buffer);
3005 for(i=1; i<MAX_NUM_UPKEEP_SPRITES; i++) {
3006 fc_snprintf(buffer2, sizeof(buffer2),
3007 "upkeep.%s%d", get_output_identifier(o), i+1);
3008 if (sprite_exists(t, buffer2)) {
3009 SET_SPRITE(upkeep.output[o][i], buffer2);
3010 fc_strlcpy(buffer, buffer2, sizeof(buffer));
3011 } else {
3012 /* Optional, as maybe the upkeep 1 sprite didn't exist either */
3013 SET_SPRITE_OPT(upkeep.output[o][i], buffer);
3016 } output_type_iterate_end;
3018 t->max_upkeep_height = calculate_max_upkeep_height(t);
3020 SET_SPRITE(user.attention, "user.attention");
3022 SET_SPRITE_OPT(path.s[GTS_MP_LEFT].specific, "path.normal");
3023 SET_SPRITE_OPT(path.s[GTS_EXHAUSTED_MP].specific, "path.exhausted_mp");
3024 SET_SPRITE_OPT(path.s[GTS_TURN_STEP].specific, "path.step");
3025 SET_SPRITE(path.waypoint, "path.waypoint");
3027 SET_SPRITE_NOTSMOOTH(tx.fog, "tx.fog");
3029 sprite_vector_init(&t->sprites.colors.overlays);
3030 for (i = 0; ; i++) {
3031 struct sprite *sprite;
3033 fc_snprintf(buffer, sizeof(buffer), "colors.overlay_%d", i);
3034 sprite = load_sprite(t, buffer, TRUE, TRUE);
3035 if (!sprite) {
3036 break;
3038 sprite_vector_append(&t->sprites.colors.overlays, sprite);
3040 if (i == 0) {
3041 tileset_error(LOG_FATAL, _("Missing overlay-color sprite colors.overlay_0."));
3044 /* Chop up and build the overlay graphics. */
3045 sprite_vector_reserve(&t->sprites.city.worked_tile_overlay,
3046 sprite_vector_size(&t->sprites.colors.overlays));
3047 sprite_vector_reserve(&t->sprites.city.unworked_tile_overlay,
3048 sprite_vector_size(&t->sprites.colors.overlays));
3049 for (i = 0; i < sprite_vector_size(&t->sprites.colors.overlays); i++) {
3050 struct sprite *color, *color_mask;
3051 struct sprite *worked, *unworked;
3053 color = *sprite_vector_get(&t->sprites.colors.overlays, i);
3054 color_mask = crop_sprite(color, 0, 0, W, H, t->sprites.mask.tile, 0, 0,
3055 1.0f, FALSE);
3056 worked = crop_sprite(color_mask, 0, 0, W, H,
3057 t->sprites.mask.worked_tile, 0, 0, 1.0f, FALSE);
3058 unworked = crop_sprite(color_mask, 0, 0, W, H,
3059 t->sprites.mask.unworked_tile, 0, 0, 1.0f, FALSE);
3060 free_sprite(color_mask);
3061 t->sprites.city.worked_tile_overlay.p[i] = worked;
3062 t->sprites.city.unworked_tile_overlay.p[i] = unworked;
3067 SET_SPRITE(grid.unavailable, "grid.unavailable");
3068 SET_SPRITE_OPT(grid.nonnative, "grid.nonnative");
3070 for (i = 0; i < EDGE_COUNT; i++) {
3071 int be;
3073 if (i == EDGE_UD && t->hex_width == 0) {
3074 continue;
3075 } else if (i == EDGE_LR && t->hex_height == 0) {
3076 continue;
3079 fc_snprintf(buffer, sizeof(buffer), "grid.main.%s", edge_name[i]);
3080 SET_SPRITE(grid.main[i], buffer);
3082 fc_snprintf(buffer, sizeof(buffer), "grid.city.%s", edge_name[i]);
3083 SET_SPRITE(grid.city[i], buffer);
3085 fc_snprintf(buffer, sizeof(buffer), "grid.worked.%s", edge_name[i]);
3086 SET_SPRITE(grid.worked[i], buffer);
3088 fc_snprintf(buffer, sizeof(buffer), "grid.selected.%s", edge_name[i]);
3089 SET_SPRITE(grid.selected[i], buffer);
3091 fc_snprintf(buffer, sizeof(buffer), "grid.coastline.%s", edge_name[i]);
3092 SET_SPRITE(grid.coastline[i], buffer);
3094 for (be = 0; be < 2; be++) {
3095 fc_snprintf(buffer, sizeof(buffer), "grid.borders.%c",
3096 edge_name[i][be]);
3097 SET_SPRITE(grid.borders[i][be], buffer);
3102 switch (t->darkness_style) {
3103 case DARKNESS_NONE:
3104 /* Nothing. */
3105 break;
3106 case DARKNESS_ISORECT:
3108 /* Isometric: take a single tx.darkness tile and split it into 4. */
3109 struct sprite *darkness = load_sprite(t, "tx.darkness", TRUE, FALSE);
3110 const int ntw = t->normal_tile_width, nth = t->normal_tile_height;
3111 int offsets[4][2] = {{ntw / 2, 0}, {0, nth / 2}, {ntw / 2, nth / 2}, {0, 0}};
3113 if (!darkness) {
3114 tileset_error(LOG_FATAL, _("Sprite tx.darkness missing."));
3116 for (i = 0; i < 4; i++) {
3117 t->sprites.tx.darkness[i] = crop_sprite(darkness, offsets[i][0],
3118 offsets[i][1], ntw / 2,
3119 nth / 2, NULL, 0, 0, 1.0f,
3120 FALSE);
3123 break;
3124 case DARKNESS_CARD_SINGLE:
3125 for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
3126 enum direction8 dir = t->cardinal_tileset_dirs[i];
3128 fc_snprintf(buffer, sizeof(buffer), "tx.darkness_%s",
3129 dir_get_tileset_name(dir));
3130 SET_SPRITE_NOTSMOOTH(tx.darkness[i], buffer);
3132 break;
3133 case DARKNESS_CARD_FULL:
3134 for(i = 1; i < t->num_index_cardinal; i++) {
3135 fc_snprintf(buffer, sizeof(buffer), "tx.darkness_%s",
3136 cardinal_index_str(t, i));
3137 SET_SPRITE_NOTSMOOTH(tx.darkness[i], buffer);
3139 break;
3140 case DARKNESS_CORNER:
3141 t->sprites.tx.fullfog = fc_realloc(t->sprites.tx.fullfog,
3142 81 * sizeof(*t->sprites.tx.fullfog));
3143 for (i = 0; i < 81; i++) {
3144 /* Unknown, fog, known. */
3145 char ids[] = {'u', 'f', 'k'};
3146 char buf[512] = "t.fog";
3147 int values[4], vi, k = i;
3149 for (vi = 0; vi < 4; vi++) {
3150 values[vi] = k % 3;
3151 k /= 3;
3153 cat_snprintf(buf, sizeof(buf), "_%c", ids[values[vi]]);
3155 fc_assert(k == 0);
3157 t->sprites.tx.fullfog[i] = load_sprite(t, buf, TRUE, FALSE);
3159 break;
3162 /* no other place to initialize these variables */
3163 sprite_vector_init(&t->sprites.nation_flag);
3164 sprite_vector_init(&t->sprites.nation_shield);
3167 /**************************************************************************
3168 Load sprites of one river type.
3169 **************************************************************************/
3170 static bool load_river_sprites(struct tileset *t,
3171 struct river_sprites *store, const char *tag_pfx)
3173 int i;
3174 char buffer[512];
3176 for (i = 0; i < t->num_index_cardinal; i++) {
3177 fc_snprintf(buffer, sizeof(buffer), "%s_s_%s",
3178 tag_pfx, cardinal_index_str(t, i));
3179 store->spec[i] = load_sprite(t, buffer, TRUE, TRUE);
3180 if (store->spec[i] == NULL) {
3181 return FALSE;
3185 for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
3186 fc_snprintf(buffer, sizeof(buffer), "%s_outlet_%s",
3187 tag_pfx, dir_get_tileset_name(t->cardinal_tileset_dirs[i]));
3188 store->outlet[i] = load_sprite(t, buffer, TRUE, TRUE);
3189 if (store->outlet[i] == NULL) {
3190 if (t->cardinal_tileset_dirs[i] == DIR8_NORTHWEST
3191 || t->cardinal_tileset_dirs[i] == DIR8_NORTHEAST
3192 || t->cardinal_tileset_dirs[i] == DIR8_SOUTHEAST
3193 || t->cardinal_tileset_dirs[i] == DIR8_SOUTHWEST) {
3194 log_debug("Missing \"%s\", support for this is deprecated.", buffer);
3195 } else {
3196 return FALSE;
3201 return TRUE;
3204 /**************************************************************************
3205 Frees any internal buffers which are created by load_sprite. Should
3206 be called after the last (for a given period of time) load_sprite
3207 call. This saves a fair amount of memory, but it will take extra time
3208 the next time we start loading sprites again.
3209 **************************************************************************/
3210 void finish_loading_sprites(struct tileset *t)
3212 specfile_list_iterate(t->specfiles, sf) {
3213 if (sf->big_sprite) {
3214 free_sprite(sf->big_sprite);
3215 sf->big_sprite = NULL;
3217 } specfile_list_iterate_end;
3220 /**********************************************************************
3221 Load the tiles; requires tilespec_read_toplevel() called previously.
3222 Leads to tile_sprites being allocated and filled with pointers
3223 to sprites. Also sets up and populates sprite_hash, and calls func
3224 to initialize 'sprites' structure.
3225 ***********************************************************************/
3226 void tileset_load_tiles(struct tileset *t)
3228 tileset_lookup_sprite_tags(t);
3229 finish_loading_sprites(t);
3232 /**********************************************************************
3233 Lookup sprite to match tag, or else to match alt if don't find,
3234 or else return NULL, and emit log message.
3235 ***********************************************************************/
3236 struct sprite *tiles_lookup_sprite_tag_alt(struct tileset *t,
3237 enum log_level level,
3238 const char *tag, const char *alt,
3239 const char *what,
3240 const char *name,
3241 bool scale)
3243 struct sprite *sp;
3245 /* (should get sprite_hash before connection) */
3246 fc_assert_ret_val_msg(NULL != t->sprite_hash, NULL,
3247 "attempt to lookup for %s \"%s\" before "
3248 "sprite_hash setup", what, name);
3250 sp = load_sprite(t, tag, scale, TRUE);
3251 if (sp) return sp;
3253 sp = load_sprite(t, alt, scale, TRUE);
3254 if (sp) {
3255 log_verbose("Using alternate graphic \"%s\" "
3256 "(instead of \"%s\") for %s \"%s\".",
3257 alt, tag, what, name);
3258 return sp;
3261 tileset_error(level, _("Don't have graphics tags \"%s\" or \"%s\" for %s \"%s\"."),
3262 tag, alt, what, name);
3264 return NULL;
3267 /**********************************************************************
3268 Helper function to load sprite for one unit orientation
3269 ***********************************************************************/
3270 static bool tileset_setup_unit_direction(struct tileset *t,
3271 int uidx,
3272 const char *base_str,
3273 enum direction8 dir,
3274 const char *dirsuffix)
3276 char buf[2048];
3278 fc_snprintf(buf, sizeof(buf), "%s_%s", base_str, dirsuffix);
3280 /* We don't use _alt graphics here, as that could lead to loading
3281 * real icon gfx, but alternative orientation gfx. Tileset author
3282 * probably meant icon gfx to be used as fallback for all orientations */
3283 t->sprites.units.facing[uidx][dir] = load_sprite(t, buf, TRUE, TRUE);
3285 if (t->sprites.units.facing[uidx][dir] != NULL) {
3286 return TRUE;
3289 return FALSE;
3292 /**********************************************************************
3293 Try to setup all unit type sprites from single tag
3294 ***********************************************************************/
3295 bool static tileset_setup_unit_type_from_tag(struct tileset *t,
3296 int uidx, const char *tag)
3298 bool facing_sprites = TRUE;
3300 t->sprites.units.icon[uidx] = load_sprite(t, tag, TRUE, TRUE);
3302 #define LOAD_FACING_SPRITE(dir, dname) \
3303 if (!tileset_setup_unit_direction(t, uidx, tag, dir, dname)) { \
3304 facing_sprites = FALSE; \
3307 LOAD_FACING_SPRITE(DIR8_NORTHWEST, "nw");
3308 LOAD_FACING_SPRITE(DIR8_NORTH, "n");
3309 LOAD_FACING_SPRITE(DIR8_NORTHEAST, "ne");
3310 LOAD_FACING_SPRITE(DIR8_WEST, "w");
3311 LOAD_FACING_SPRITE(DIR8_EAST, "e");
3312 LOAD_FACING_SPRITE(DIR8_SOUTHWEST, "sw");
3313 LOAD_FACING_SPRITE(DIR8_SOUTH, "s");
3314 LOAD_FACING_SPRITE(DIR8_SOUTHEAST, "se");
3316 if (!facing_sprites && t->sprites.units.icon[uidx] == NULL) {
3317 /* Neither icon gfx or orientation sprites */
3318 return FALSE;
3321 /* Fix a random orientation for displaying unit type in help etc.
3322 * We don't necessarily know the map topology yet, so choose a seed
3323 * that can be used to pick a valid direction later (24 is lcm(6,8)).
3324 * See get_unittype_sprite(). */
3325 t->sprites.units.default_dir_seed[uidx] = fc_rand(24);
3327 return TRUE;
3329 #undef LOAD_FACING_SPRITE
3332 /**********************************************************************
3333 Set unit_type sprite value; should only happen after
3334 tilespec_load_tiles().
3335 ***********************************************************************/
3336 void tileset_setup_unit_type(struct tileset *t, struct unit_type *ut)
3338 int uidx = utype_index(ut);
3340 if (!tileset_setup_unit_type_from_tag(t, uidx, ut->graphic_str)
3341 && !tileset_setup_unit_type_from_tag(t, uidx, ut->graphic_alt)) {
3342 tileset_error(LOG_FATAL, _("Missing %s unit sprite for tags \"%s\" and alternative \"%s\"."),
3343 utype_rule_name(ut), ut->graphic_str, ut->graphic_alt);
3347 /**********************************************************************
3348 Set improvement_type sprite value; should only happen after
3349 tilespec_load_tiles().
3350 ***********************************************************************/
3351 void tileset_setup_impr_type(struct tileset *t,
3352 struct impr_type *pimprove)
3354 t->sprites.building[improvement_index(pimprove)] =
3355 tiles_lookup_sprite_tag_alt(t, LOG_VERBOSE, pimprove->graphic_str,
3356 pimprove->graphic_alt, "improvement",
3357 improvement_rule_name(pimprove), FALSE);
3359 /* should maybe do something if NULL, eg generic default? */
3362 /**********************************************************************
3363 Set tech_type sprite value; should only happen after
3364 tilespec_load_tiles().
3365 ***********************************************************************/
3366 void tileset_setup_tech_type(struct tileset *t,
3367 struct advance *padvance)
3369 if (valid_advance(padvance)) {
3370 t->sprites.tech[advance_index(padvance)] =
3371 tiles_lookup_sprite_tag_alt(t, LOG_VERBOSE, padvance->graphic_str,
3372 padvance->graphic_alt, "technology",
3373 advance_rule_name(padvance), FALSE);
3375 /* should maybe do something if NULL, eg generic default? */
3376 } else {
3377 t->sprites.tech[advance_index(padvance)] = NULL;
3381 /****************************************************************************
3382 Set resource sprite values; should only happen after
3383 tilespec_load_tiles().
3384 ****************************************************************************/
3385 void tileset_setup_resource(struct tileset *t,
3386 const struct resource *presource)
3388 fc_assert_ret(NULL != presource);
3389 t->sprites.resource[resource_index(presource)] =
3390 tiles_lookup_sprite_tag_alt(t, LOG_VERBOSE, presource->graphic_str,
3391 presource->graphic_alt, "resource",
3392 resource_rule_name(presource), TRUE);
3395 /****************************************************************************
3396 Set extra sprite values; should only happen after
3397 tilespec_load_tiles().
3398 ****************************************************************************/
3399 void tileset_setup_extra(struct tileset *t,
3400 struct extra_type *pextra)
3402 const int id = extra_index(pextra);
3403 enum extrastyle_id extrastyle;
3405 if (!fc_strcasecmp(pextra->graphic_str, "none")) {
3406 /* Extra without graphics */
3407 t->sprites.extras[id].extrastyle = extrastyle_id_invalid();
3408 } else {
3410 if (!estyle_hash_lookup(t->estyle_hash, pextra->graphic_str,
3411 &extrastyle)
3412 && !estyle_hash_lookup(t->estyle_hash, pextra->graphic_alt,
3413 &extrastyle)) {
3414 tileset_error(LOG_FATAL, _("No extrastyle for \"%s\" or \"%s\"."),
3415 pextra->graphic_str,
3416 pextra->graphic_alt);
3419 t->sprites.extras[id].extrastyle = extrastyle;
3421 extra_type_list_append(t->style_lists[extrastyle], pextra);
3423 if (extra_has_flag(pextra, EF_SHOW_FLAG)) {
3424 extra_type_list_append(t->flagged_bases_list, pextra);
3427 switch (extrastyle) {
3428 case ESTYLE_3LAYER:
3429 tileset_setup_base(t, pextra);
3430 break;
3432 case ESTYLE_ROAD_ALL_SEPARATE:
3433 case ESTYLE_ROAD_PARITY_COMBINED:
3434 case ESTYLE_ROAD_ALL_COMBINED:
3435 case ESTYLE_RIVER:
3436 tileset_setup_road(t, pextra);
3437 break;
3439 case ESTYLE_SINGLE1:
3440 case ESTYLE_SINGLE2:
3441 SET_SPRITE_ALT(extras[id].u.single, pextra->graphic_str, pextra->graphic_alt);
3442 break;
3444 case ESTYLE_CARDINALS:
3446 int i;
3447 char buffer[512];
3449 /* We use direction-specific irrigation and farmland graphics, if they
3450 * are available. If not, we just fall back to the basic irrigation
3451 * graphics. */
3452 for (i = 0; i < t->num_index_cardinal; i++) {
3453 fc_snprintf(buffer, sizeof(buffer), "%s_%s",
3454 pextra->graphic_str, cardinal_index_str(t, i));
3455 t->sprites.extras[id].u.cardinals[i] = load_sprite(t, buffer,
3456 TRUE, TRUE);
3457 if (!t->sprites.extras[id].u.cardinals[i]) {
3458 t->sprites.extras[id].u.cardinals[i] = load_sprite(t,
3459 pextra->graphic_str, TRUE,
3460 TRUE);
3462 if (!t->sprites.extras[id].u.cardinals[i]) {
3463 fc_snprintf(buffer, sizeof(buffer), "%s_%s",
3464 pextra->graphic_alt, cardinal_index_str(t, i));
3465 t->sprites.extras[id].u.cardinals[i] = load_sprite(t, buffer,
3466 TRUE, TRUE);
3468 if (!t->sprites.extras[id].u.cardinals[i]) {
3469 t->sprites.extras[id].u.cardinals[i] = load_sprite(t,
3470 pextra->graphic_alt, TRUE,
3471 TRUE);
3473 if (!t->sprites.extras[id].u.cardinals[i]) {
3474 tileset_error(LOG_FATAL, _("Sprite for tags '%s' and alternate '%s' are "
3475 "both missing."),
3476 pextra->graphic_str, pextra->graphic_alt);
3480 break;
3481 case ESTYLE_COUNT:
3482 break;
3486 if (!fc_strcasecmp(pextra->activity_gfx, "none")) {
3487 t->sprites.extras[id].activity = NULL;
3488 } else {
3489 t->sprites.extras[id].activity = load_sprite(t, pextra->activity_gfx,
3490 TRUE, TRUE);
3491 if (t->sprites.extras[id].activity == NULL) {
3492 t->sprites.extras[id].activity = load_sprite(t, pextra->act_gfx_alt,
3493 TRUE, TRUE);
3495 if (t->sprites.extras[id].activity == NULL) {
3496 t->sprites.extras[id].activity = load_sprite(t, pextra->act_gfx_alt2,
3497 TRUE, TRUE);
3499 if (t->sprites.extras[id].activity == NULL) {
3500 tileset_error(LOG_FATAL, _("Missing %s building activity sprite for tags \"%s\" and alternatives \"%s\" and \"%s\"."),
3501 extra_rule_name(pextra), pextra->activity_gfx,
3502 pextra->act_gfx_alt, pextra->act_gfx_alt2);
3506 if (!fc_strcasecmp(pextra->rmact_gfx, "none")) {
3507 t->sprites.extras[id].rmact = NULL;
3508 } else {
3509 t->sprites.extras[id].rmact = load_sprite(t, pextra->rmact_gfx, TRUE,
3510 TRUE);
3511 if (t->sprites.extras[id].rmact == NULL) {
3512 t->sprites.extras[id].rmact = load_sprite(t, pextra->rmact_gfx_alt,
3513 TRUE, TRUE);
3514 if (t->sprites.extras[id].rmact == NULL) {
3515 tileset_error(LOG_FATAL, _("Missing %s removal activity sprite for tags \"%s\" and alternative \"%s\"."),
3516 extra_rule_name(pextra), pextra->rmact_gfx, pextra->rmact_gfx_alt);
3522 /****************************************************************************
3523 Set road sprite values; should only happen after
3524 tilespec_load_tiles().
3525 ****************************************************************************/
3526 static void tileset_setup_road(struct tileset *t,
3527 struct extra_type *pextra)
3529 char full_tag_name[MAX_LEN_NAME + strlen("_isolated")];
3530 char full_alt_name[MAX_LEN_NAME + strlen("_isolated")];
3531 const int id = extra_index(pextra);
3532 int i;
3533 enum extrastyle_id extrastyle = t->sprites.extras[id].extrastyle;
3535 /* Isolated road graphics are used by ESTYLE_ROAD_ALL_SEPARATE and
3536 ESTYLE_ROAD_PARITY_COMBINED. */
3537 if (extrastyle == ESTYLE_ROAD_ALL_SEPARATE
3538 || extrastyle == ESTYLE_ROAD_PARITY_COMBINED) {
3539 fc_snprintf(full_tag_name, sizeof(full_tag_name),
3540 "%s_isolated", pextra->graphic_str);
3541 fc_snprintf(full_alt_name, sizeof(full_alt_name),
3542 "%s_isolated", pextra->graphic_alt);
3544 SET_SPRITE_ALT(extras[id].u.road.isolated, full_tag_name, full_alt_name);
3547 if (extrastyle == ESTYLE_ROAD_ALL_SEPARATE) {
3548 /* ESTYLE_ROAD_ALL_SEPARATE has just 8 additional sprites for each road type:
3549 * one going off in each direction. */
3550 for (i = 0; i < t->num_valid_tileset_dirs; i++) {
3551 enum direction8 dir = t->valid_tileset_dirs[i];
3552 const char *dir_name = dir_get_tileset_name(dir);
3554 fc_snprintf(full_tag_name, sizeof(full_tag_name),
3555 "%s_%s", pextra->graphic_str, dir_name);
3556 fc_snprintf(full_alt_name, sizeof(full_alt_name),
3557 "%s_%s", pextra->graphic_alt, dir_name);
3559 SET_SPRITE_ALT(extras[id].u.road.ru.dir[i], full_tag_name, full_alt_name);
3561 } else if (extrastyle == ESTYLE_ROAD_PARITY_COMBINED) {
3562 int num_index = 1 << (t->num_valid_tileset_dirs / 2), j;
3564 /* ESTYLE_ROAD_PARITY_COMBINED has 32 additional sprites for each road type:
3565 * 16 each for cardinal and diagonal directions. Each set
3566 * of 16 provides a NSEW-indexed sprite to provide connectors for
3567 * all rails in the cardinal/diagonal directions. The 0 entry is
3568 * unused (the "isolated" sprite is used instead). */
3570 for (i = 1; i < num_index; i++) {
3571 char c[64] = "", d[64] = "";
3573 for (j = 0; j < t->num_valid_tileset_dirs / 2; j++) {
3574 int value = (i >> j) & 1;
3576 cat_snprintf(c, sizeof(c), "%s%d",
3577 dir_get_tileset_name(t->valid_tileset_dirs[2 * j]),
3578 value);
3579 cat_snprintf(d, sizeof(d), "%s%d",
3580 dir_get_tileset_name(t->valid_tileset_dirs[2 * j + 1]),
3581 value);
3584 fc_snprintf(full_tag_name, sizeof(full_tag_name),
3585 "%s_c_%s", pextra->graphic_str, c);
3586 fc_snprintf(full_alt_name, sizeof(full_alt_name),
3587 "%s_c_%s", pextra->graphic_alt, c);
3589 SET_SPRITE_ALT(extras[id].u.road.ru.combo.even[i], full_tag_name, full_alt_name);
3591 fc_snprintf(full_tag_name, sizeof(full_tag_name),
3592 "%s_d_%s", pextra->graphic_str, d);
3593 fc_snprintf(full_alt_name, sizeof(full_alt_name),
3594 "%s_d_%s", pextra->graphic_alt, d);
3596 SET_SPRITE_ALT(extras[id].u.road.ru.combo.odd[i], full_tag_name, full_alt_name);
3598 } else if (extrastyle == ESTYLE_ROAD_ALL_COMBINED) {
3599 /* ESTYLE_ROAD_ALL_COMBINED includes 256 sprites, one for every possibility.
3600 * Just go around clockwise, with all combinations. */
3601 for (i = 0; i < t->num_index_valid; i++) {
3602 char *idx_str = valid_index_str(t, i);
3604 fc_snprintf(full_tag_name, sizeof(full_tag_name),
3605 "%s_%s", pextra->graphic_str, idx_str);
3606 fc_snprintf(full_alt_name, sizeof(full_alt_name),
3607 "%s_%s", pextra->graphic_alt, idx_str);
3609 SET_SPRITE_ALT(extras[id].u.road.ru.total[i], full_tag_name, full_alt_name);
3611 } else if (extrastyle == ESTYLE_RIVER) {
3612 if (!load_river_sprites(t, &t->sprites.extras[id].u.road.ru.rivers,
3613 pextra->graphic_str)) {
3614 if (!load_river_sprites(t, &t->sprites.extras[id].u.road.ru.rivers,
3615 pextra->graphic_alt)) {
3616 tileset_error(LOG_FATAL, _("Cannot load river \"%s\" or \"%s\""),
3617 pextra->graphic_str, pextra->graphic_alt);
3620 } else {
3621 fc_assert(FALSE);
3624 /* Corner road graphics are used by ESTYLE_ROAD_ALL_SEPARATE and
3625 * ESTYLE_ROAD_PARITY_COMBINED. */
3626 if (extrastyle == ESTYLE_ROAD_ALL_SEPARATE
3627 || extrastyle == ESTYLE_ROAD_PARITY_COMBINED) {
3628 for (i = 0; i < t->num_valid_tileset_dirs; i++) {
3629 enum direction8 dir = t->valid_tileset_dirs[i];
3631 if (!is_cardinal_tileset_dir(t, dir)) {
3632 const char *dtn = dir_get_tileset_name(dir);
3634 fc_snprintf(full_tag_name, sizeof(full_tag_name),
3635 "%s_c_%s", pextra->graphic_str, dtn);
3636 fc_snprintf(full_alt_name, sizeof(full_alt_name),
3637 "%s_c_%s", pextra->graphic_alt, dtn);
3639 SET_SPRITE_ALT_OPT(extras[id].u.road.corner[dir], full_tag_name, full_alt_name);
3645 /****************************************************************************
3646 Set base sprite values; should only happen after
3647 tilespec_load_tiles().
3648 ****************************************************************************/
3649 static void tileset_setup_base(struct tileset *t,
3650 const struct extra_type *pextra)
3652 char full_tag_name[MAX_LEN_NAME + strlen("_fg")];
3653 const int id = extra_index(pextra);
3655 fc_assert_ret(id >= 0 && id < extra_count());
3657 sz_strlcpy(full_tag_name, pextra->graphic_str);
3658 strcat(full_tag_name, "_bg");
3659 t->sprites.extras[id].u.bmf.background = load_sprite(t, full_tag_name,
3660 TRUE, TRUE);
3662 sz_strlcpy(full_tag_name, pextra->graphic_str);
3663 strcat(full_tag_name, "_mg");
3664 t->sprites.extras[id].u.bmf.middleground = load_sprite(t, full_tag_name,
3665 TRUE, TRUE);
3667 sz_strlcpy(full_tag_name, pextra->graphic_str);
3668 strcat(full_tag_name, "_fg");
3669 t->sprites.extras[id].u.bmf.foreground = load_sprite(t, full_tag_name,
3670 TRUE, TRUE);
3672 if (t->sprites.extras[id].u.bmf.background == NULL
3673 && t->sprites.extras[id].u.bmf.middleground == NULL
3674 && t->sprites.extras[id].u.bmf.foreground == NULL) {
3675 /* No primary graphics at all. Try alternative */
3676 log_verbose("Using alternate graphic \"%s\" "
3677 "(instead of \"%s\") for extra \"%s\".",
3678 pextra->graphic_alt, pextra->graphic_str,
3679 extra_rule_name(pextra));
3681 sz_strlcpy(full_tag_name, pextra->graphic_alt);
3682 strcat(full_tag_name, "_bg");
3683 t->sprites.extras[id].u.bmf.background = load_sprite(t, full_tag_name,
3684 TRUE, TRUE);
3686 sz_strlcpy(full_tag_name, pextra->graphic_alt);
3687 strcat(full_tag_name, "_mg");
3688 t->sprites.extras[id].u.bmf.middleground = load_sprite(t, full_tag_name,
3689 TRUE, TRUE);
3691 sz_strlcpy(full_tag_name, pextra->graphic_alt);
3692 strcat(full_tag_name, "_fg");
3693 t->sprites.extras[id].u.bmf.foreground = load_sprite(t, full_tag_name,
3694 TRUE, TRUE);
3696 if (t->sprites.extras[id].u.bmf.background == NULL
3697 && t->sprites.extras[id].u.bmf.middleground == NULL
3698 && t->sprites.extras[id].u.bmf.foreground == NULL) {
3699 /* Cannot find alternative graphics either */
3700 tileset_error(LOG_FATAL, _("No graphics for extra \"%s\" at all!"),
3701 extra_rule_name(pextra));
3706 /**********************************************************************
3707 Set tile_type sprite values; should only happen after
3708 tilespec_load_tiles().
3709 ***********************************************************************/
3710 void tileset_setup_tile_type(struct tileset *t,
3711 const struct terrain *pterrain)
3713 struct drawing_data *draw;
3714 struct sprite *sprite;
3715 char buffer[MAX_LEN_NAME + 20];
3716 int i, l;
3718 if (0 == strlen(terrain_rule_name(pterrain))) {
3719 return;
3722 if (!drawing_hash_lookup(t->tile_hash, pterrain->graphic_str, &draw)
3723 && !drawing_hash_lookup(t->tile_hash, pterrain->graphic_alt, &draw)) {
3724 tileset_error(LOG_FATAL, _("Terrain \"%s\": no graphic tile \"%s\" or \"%s\"."),
3725 terrain_rule_name(pterrain), pterrain->graphic_str,
3726 pterrain->graphic_alt);
3729 if (draw->init) {
3730 t->sprites.drawing[terrain_index(pterrain)] = draw;
3731 return;
3734 /* Set up each layer of the drawing. */
3735 for (l = 0; l < draw->num_layers; l++) {
3736 struct drawing_layer *dlp = &draw->layer[l];
3737 struct tileset_layer *tslp = &t->layers[l];
3738 sprite_vector_init(&dlp->base);
3739 sprite_vector_init(&dlp->allocated);
3741 switch (dlp->sprite_type) {
3742 case CELL_WHOLE:
3743 switch (dlp->match_style) {
3744 case MATCH_NONE:
3745 /* Load whole sprites for this tile. */
3746 for (i = 0; ; i++) {
3747 fc_snprintf(buffer, sizeof(buffer), "t.l%d.%s%d",
3748 l, draw->name, i + 1);
3749 sprite = load_sprite(t, buffer, TRUE, FALSE);
3750 if (!sprite) {
3751 break;
3753 sprite_vector_reserve(&dlp->base, i + 1);
3754 dlp->base.p[i] = sprite;
3756 /* check for base sprite, allowing missing sprites above base */
3757 if (0 == i && 0 == l) {
3758 /* TRANS: 'base' means 'base of terrain gfx', not 'military base' */
3759 tileset_error(LOG_FATAL, _("Missing base sprite for tag \"%s\"."), buffer);
3761 break;
3762 case MATCH_SAME:
3763 /* Load 16 cardinally-matched sprites. */
3764 for (i = 0; i < t->num_index_cardinal; i++) {
3765 fc_snprintf(buffer, sizeof(buffer), "t.l%d.%s_%s",
3766 l, draw->name, cardinal_index_str(t, i));
3767 dlp->match[i] =
3768 tiles_lookup_sprite_tag_alt(t, LOG_FATAL, buffer, "",
3769 "matched terrain",
3770 terrain_rule_name(pterrain), TRUE);
3772 break;
3773 case MATCH_PAIR:
3774 case MATCH_FULL:
3775 fc_assert(FALSE); /* not yet defined */
3776 break;
3778 break;
3779 case CELL_CORNER:
3781 const int count = dlp->match_indices;
3782 int number = NUM_CORNER_DIRS;
3784 switch (dlp->match_style) {
3785 case MATCH_NONE:
3786 /* do nothing */
3787 break;
3788 case MATCH_PAIR:
3789 case MATCH_SAME:
3790 /* N directions (NSEW) * 3 dimensions of matching */
3791 fc_assert(count == 2);
3792 number = NUM_CORNER_DIRS * 2 * 2 * 2;
3793 break;
3794 case MATCH_FULL:
3795 default:
3796 /* N directions (NSEW) * 3 dimensions of matching */
3797 /* could use exp() or expi() here? */
3798 number = NUM_CORNER_DIRS * count * count * count;
3799 break;
3802 dlp->cells
3803 = fc_calloc(number, sizeof(*dlp->cells));
3805 for (i = 0; i < number; i++) {
3806 enum direction4 dir = i % NUM_CORNER_DIRS;
3807 int value = i / NUM_CORNER_DIRS;
3809 switch (dlp->match_style) {
3810 case MATCH_NONE:
3811 fc_snprintf(buffer, sizeof(buffer), "t.l%d.%s_cell_%c",
3812 l, draw->name, direction4letters[dir]);
3813 dlp->cells[i] =
3814 tiles_lookup_sprite_tag_alt(t, LOG_FATAL, buffer, "",
3815 "cell terrain",
3816 terrain_rule_name(pterrain), TRUE);
3817 break;
3818 case MATCH_SAME:
3819 fc_snprintf(buffer, sizeof(buffer), "t.l%d.%s_cell_%c%d%d%d",
3820 l, draw->name, direction4letters[dir],
3821 (value) & 1, (value >> 1) & 1, (value >> 2) & 1);
3822 dlp->cells[i] =
3823 tiles_lookup_sprite_tag_alt(t, LOG_FATAL, buffer, "",
3824 "same cell terrain",
3825 terrain_rule_name(pterrain), TRUE);
3826 break;
3827 case MATCH_PAIR:
3828 fc_snprintf(buffer, sizeof(buffer), "t.l%d.%s_cell_%c_%c_%c_%c",
3829 l, draw->name, direction4letters[dir],
3830 tslp->match_types[dlp->match_index[(value) & 1]][0],
3831 tslp->match_types[dlp->match_index[(value >> 1) & 1]][0],
3832 tslp->match_types[dlp->match_index[(value >> 2) & 1]][0]);
3833 dlp->cells[i] =
3834 tiles_lookup_sprite_tag_alt(t, LOG_FATAL, buffer, "",
3835 "cell pair terrain",
3836 terrain_rule_name(pterrain), TRUE);
3837 break;
3838 case MATCH_FULL:
3840 int this = dlp->match_index[0];
3841 int n, s, e, w;
3842 int v1, v2, v3;
3844 v1 = dlp->match_index[value % count];
3845 value /= count;
3846 v2 = dlp->match_index[value % count];
3847 value /= count;
3848 v3 = dlp->match_index[value % count];
3850 fc_assert(v1 < count && v2 < count && v3 < count);
3852 /* Assume merged cells. This should be a separate option. */
3853 switch (dir) {
3854 case DIR4_NORTH:
3855 s = this;
3856 w = v1;
3857 n = v2;
3858 e = v3;
3859 break;
3860 case DIR4_EAST:
3861 w = this;
3862 n = v1;
3863 e = v2;
3864 s = v3;
3865 break;
3866 case DIR4_SOUTH:
3867 n = this;
3868 e = v1;
3869 s = v2;
3870 w = v3;
3871 break;
3872 case DIR4_WEST:
3873 default: /* avoid warnings */
3874 e = this;
3875 s = v1;
3876 w = v2;
3877 n = v3;
3878 break;
3881 /* Use first character of match_types,
3882 * already checked for uniqueness. */
3883 fc_snprintf(buffer, sizeof(buffer),
3884 "t.l%d.cellgroup_%c_%c_%c_%c", l,
3885 tslp->match_types[n][0], tslp->match_types[e][0],
3886 tslp->match_types[s][0], tslp->match_types[w][0]);
3887 sprite = load_sprite(t, buffer, TRUE, FALSE);
3889 if (sprite) {
3890 /* Crop the sprite to separate this cell. */
3891 int vec_size = sprite_vector_size(&dlp->allocated);
3893 const int W = t->normal_tile_width;
3894 const int H = t->normal_tile_height;
3895 int x[4] = {W / 4, W / 4, 0, W / 2};
3896 int y[4] = {H / 2, 0, H / 4, H / 4};
3897 int xo[4] = {0, 0, -W / 2, W / 2};
3898 int yo[4] = {H / 2, -H / 2, 0, 0};
3900 sprite = crop_sprite(sprite, x[dir], y[dir], W / 2, H / 2,
3901 t->sprites.mask.tile, xo[dir], yo[dir], 1.0f,
3902 FALSE);
3903 /* We allocated new sprite with crop_sprite. Store its
3904 * address so we can free it. */
3905 sprite_vector_reserve(&dlp->allocated, vec_size + 1);
3906 dlp->allocated.p[vec_size] = sprite;
3907 } else {
3908 log_error("Terrain graphics sprite for tag \"%s\" missing.", buffer);
3911 dlp->cells[i] = sprite;
3913 break;
3917 break;
3921 /* try an optional special name */
3922 fc_snprintf(buffer, sizeof(buffer), "t.blend.%s", draw->name);
3923 draw->blender =
3924 tiles_lookup_sprite_tag_alt(t, LOG_VERBOSE, buffer, "",
3925 "blend terrain",
3926 terrain_rule_name(pterrain), TRUE);
3928 if (draw->blending > 0) {
3929 const int bl = draw->blending - 1;
3931 if (NULL == draw->blender) {
3932 int li = 0;
3934 /* try an already loaded base */
3935 while (NULL == draw->blender
3936 && li < draw->blending
3937 && 0 < draw->layer[li].base.size) {
3938 draw->blender = draw->layer[li++].base.p[0];
3942 if (NULL == draw->blender) {
3943 /* try an unloaded base name */
3944 fc_snprintf(buffer, sizeof(buffer), "t.l%d.%s1", bl, draw->name);
3945 draw->blender =
3946 tiles_lookup_sprite_tag_alt(t, LOG_FATAL, buffer, "",
3947 "base (blend) terrain",
3948 terrain_rule_name(pterrain), TRUE);
3952 if (NULL != draw->blender) {
3953 /* Set up blending sprites. This only works in iso-view! */
3954 const int W = t->normal_tile_width;
3955 const int H = t->normal_tile_height;
3956 const int offsets[4][2] = {
3957 {W / 2, 0}, {0, H / 2}, {W / 2, H / 2}, {0, 0}
3959 enum direction4 dir = 0;
3961 for (; dir < 4; dir++) {
3962 draw->blend[dir] = crop_sprite(draw->blender, offsets[dir][0],
3963 offsets[dir][1], W / 2, H / 2,
3964 t->sprites.dither_tile, 0, 0, 1.0f,
3965 FALSE);
3969 draw->init = TRUE;
3970 t->sprites.drawing[terrain_index(pterrain)] = draw;
3973 /**********************************************************************
3974 Set government sprite value; should only happen after
3975 tilespec_load_tiles().
3976 ***********************************************************************/
3977 void tileset_setup_government(struct tileset *t,
3978 struct government *gov)
3980 t->sprites.government[government_index(gov)] =
3981 tiles_lookup_sprite_tag_alt(t, LOG_FATAL, gov->graphic_str,
3982 gov->graphic_alt, "government",
3983 government_rule_name(gov), FALSE);
3985 /* should probably do something if NULL, eg generic default? */
3988 /**********************************************************************
3989 Set nation flag sprite value; should only happen after
3990 tilespec_load_tiles().
3991 ***********************************************************************/
3992 void tileset_setup_nation_flag(struct tileset *t,
3993 struct nation_type *nation)
3995 char *tags[] = {nation->flag_graphic_str,
3996 nation->flag_graphic_alt,
3997 "unknown", NULL};
3998 int i;
3999 struct sprite *flag = NULL, *shield = NULL;
4000 char buf[1024];
4002 for (i = 0; tags[i] && !flag; i++) {
4003 fc_snprintf(buf, sizeof(buf), "f.%s", tags[i]);
4004 flag = load_sprite(t, buf, TRUE, TRUE);
4006 for (i = 0; tags[i] && !shield; i++) {
4007 fc_snprintf(buf, sizeof(buf), "f.shield.%s", tags[i]);
4008 shield = load_sprite(t, buf, TRUE, TRUE);
4010 if (!flag || !shield) {
4011 /* Should never get here because of the f.unknown fallback. */
4012 tileset_error(LOG_FATAL, _("Nation %s: no national flag."), nation_rule_name(nation));
4015 sprite_vector_reserve(&t->sprites.nation_flag, nation_count());
4016 t->sprites.nation_flag.p[nation_index(nation)] = flag;
4018 sprite_vector_reserve(&t->sprites.nation_shield, nation_count());
4019 t->sprites.nation_shield.p[nation_index(nation)] = shield;
4022 /**********************************************************************
4023 Return the flag graphic to be used by the city.
4024 ***********************************************************************/
4025 struct sprite *get_city_flag_sprite(const struct tileset *t,
4026 const struct city *pcity)
4028 return get_nation_flag_sprite(t, nation_of_city(pcity));
4031 /**********************************************************************
4032 Return a sprite for the national flag for this unit.
4033 ***********************************************************************/
4034 static struct sprite *get_unit_nation_flag_sprite(const struct tileset *t,
4035 const struct unit *punit)
4037 struct nation_type *pnation = nation_of_unit(punit);
4039 if (gui_options.draw_unit_shields) {
4040 return t->sprites.nation_shield.p[nation_index(pnation)];
4041 } else {
4042 return t->sprites.nation_flag.p[nation_index(pnation)];
4046 #define FULL_TILE_X_OFFSET ((t->normal_tile_width - t->full_tile_width) / 2)
4047 #define FULL_TILE_Y_OFFSET (t->normal_tile_height - t->full_tile_height)
4049 #define ADD_SPRITE(s, draw_fog, x_offset, y_offset) \
4050 (fc_assert(s != NULL), \
4051 sprs->sprite = s, \
4052 sprs->foggable = (draw_fog && t->fogstyle == FOG_AUTO), \
4053 sprs->offset_x = x_offset, \
4054 sprs->offset_y = y_offset, \
4055 sprs++)
4056 #define ADD_SPRITE_SIMPLE(s) ADD_SPRITE(s, TRUE, 0, 0)
4057 #define ADD_SPRITE_FULL(s) \
4058 ADD_SPRITE(s, TRUE, FULL_TILE_X_OFFSET, FULL_TILE_Y_OFFSET)
4060 /**************************************************************************
4061 Assemble some data that is used in building the tile sprite arrays.
4062 (map_x, map_y) : the (normalized) map position
4063 The values we fill in:
4064 tterrain_near : terrain types of all adjacent terrain
4065 tspecial_near : specials of all adjacent terrain
4066 **************************************************************************/
4067 static void build_tile_data(const struct tile *ptile,
4068 struct terrain *pterrain,
4069 struct terrain **tterrain_near,
4070 bv_extras *textras_near)
4072 enum direction8 dir;
4074 /* Loop over all adjacent tiles. We should have an iterator for this. */
4075 for (dir = 0; dir < 8; dir++) {
4076 struct tile *tile1 = mapstep(ptile, dir);
4078 if (tile1 && client_tile_get_known(tile1) != TILE_UNKNOWN) {
4079 struct terrain *terrain1 = tile_terrain(tile1);
4081 if (NULL != terrain1) {
4082 tterrain_near[dir] = terrain1;
4083 textras_near[dir] = *tile_extras(tile1);
4084 continue;
4086 log_error("build_tile_data() tile (%d,%d) has no terrain!",
4087 TILE_XY(tile1));
4089 /* At the edges of the (known) map, pretend the same terrain continued
4090 * past the edge of the map. */
4091 tterrain_near[dir] = pterrain;
4092 BV_CLR_ALL(textras_near[dir]);
4096 /**********************************************************************
4097 Fill in the sprite array for the unit type.
4098 ***********************************************************************/
4099 static int fill_unit_type_sprite_array(const struct tileset *t,
4100 struct drawn_sprite *sprs,
4101 const struct unit_type *putype,
4102 enum direction8 facing)
4104 struct drawn_sprite *save_sprs = sprs;
4105 struct sprite *uspr = get_unittype_sprite(t, putype, facing, FALSE);
4107 ADD_SPRITE(uspr, TRUE,
4108 FULL_TILE_X_OFFSET + t->unit_offset_x,
4109 FULL_TILE_Y_OFFSET + t->unit_offset_y);
4111 return sprs - save_sprs;
4114 /**********************************************************************
4115 Fill in the sprite array for the unit.
4116 ***********************************************************************/
4117 static int fill_unit_sprite_array(const struct tileset *t,
4118 struct drawn_sprite *sprs,
4119 const struct unit *punit,
4120 bool stack, bool backdrop)
4122 struct drawn_sprite *save_sprs = sprs;
4123 int ihp;
4124 struct unit_type *ptype = unit_type_get(punit);
4126 if (backdrop) {
4127 if (!gui_options.solid_color_behind_units) {
4128 ADD_SPRITE(get_unit_nation_flag_sprite(t, punit), TRUE,
4129 FULL_TILE_X_OFFSET + t->unit_flag_offset_x,
4130 FULL_TILE_Y_OFFSET + t->unit_flag_offset_y);
4131 } else {
4132 /* Taken care of in the LAYER_BACKGROUND. */
4136 /* Add the sprite for the unit type. */
4137 sprs += fill_unit_type_sprite_array(t, sprs, ptype,
4138 punit->facing);
4140 if (t->sprites.unit.loaded && unit_transported(punit)) {
4141 ADD_SPRITE_FULL(t->sprites.unit.loaded);
4144 if (punit->activity != ACTIVITY_IDLE) {
4145 struct sprite *s = NULL;
4147 switch (punit->activity) {
4148 case ACTIVITY_MINE:
4149 if (punit->activity_target == NULL) {
4150 s = t->sprites.unit.plant;
4151 } else {
4152 s = t->sprites.extras[extra_index(punit->activity_target)].activity;
4154 break;
4155 case ACTIVITY_IRRIGATE:
4156 if (punit->activity_target == NULL) {
4157 s = t->sprites.unit.irrigate;
4158 } else {
4159 s = t->sprites.extras[extra_index(punit->activity_target)].activity;
4161 break;
4162 case ACTIVITY_POLLUTION:
4163 case ACTIVITY_FALLOUT:
4164 s = t->sprites.extras[extra_index(punit->activity_target)].rmact;
4165 break;
4166 case ACTIVITY_PILLAGE:
4167 s = t->sprites.unit.pillage;
4168 break;
4169 case ACTIVITY_EXPLORE:
4170 s = t->sprites.unit.auto_explore;
4171 break;
4172 case ACTIVITY_FORTIFIED:
4173 s = t->sprites.unit.fortified;
4174 break;
4175 case ACTIVITY_FORTIFYING:
4176 s = t->sprites.unit.fortifying;
4177 break;
4178 case ACTIVITY_SENTRY:
4179 s = t->sprites.unit.sentry;
4180 break;
4181 case ACTIVITY_GOTO:
4182 s = t->sprites.unit.go_to;
4183 break;
4184 case ACTIVITY_TRANSFORM:
4185 s = t->sprites.unit.transform;
4186 break;
4187 case ACTIVITY_BASE:
4188 case ACTIVITY_GEN_ROAD:
4189 s = t->sprites.extras[extra_index(punit->activity_target)].activity;
4190 break;
4191 case ACTIVITY_CONVERT:
4192 s = t->sprites.unit.convert;
4193 break;
4194 default:
4195 break;
4198 if (s != NULL) {
4199 ADD_SPRITE(s, TRUE, FULL_TILE_X_OFFSET + t->activity_offset_x,
4200 FULL_TILE_Y_OFFSET + t->activity_offset_y);
4204 if (punit->ai_controlled && punit->activity != ACTIVITY_EXPLORE) {
4205 if (is_military_unit(punit)) {
4206 ADD_SPRITE_FULL(t->sprites.unit.auto_attack);
4207 } else {
4208 ADD_SPRITE_FULL(t->sprites.unit.auto_settler);
4212 if (unit_has_orders(punit)) {
4213 if (punit->orders.repeat) {
4214 ADD_SPRITE_FULL(t->sprites.unit.patrol);
4215 } else if (punit->activity != ACTIVITY_IDLE) {
4216 ADD_SPRITE_SIMPLE(t->sprites.unit.connect);
4217 } else {
4218 ADD_SPRITE(t->sprites.unit.go_to, TRUE, FULL_TILE_X_OFFSET + t->activity_offset_x,
4219 FULL_TILE_Y_OFFSET + t->activity_offset_y);
4223 if (punit->battlegroup != BATTLEGROUP_NONE) {
4224 ADD_SPRITE_FULL(t->sprites.unit.battlegroup[punit->battlegroup]);
4227 if (t->sprites.unit.lowfuel
4228 && utype_fuel(ptype)
4229 && punit->fuel == 1
4230 && punit->moves_left <= 2 * SINGLE_MOVE) {
4231 /* Show a low-fuel graphic if the plane has 2 or fewer moves left. */
4232 ADD_SPRITE_FULL(t->sprites.unit.lowfuel);
4234 if (t->sprites.unit.tired
4235 && punit->moves_left < SINGLE_MOVE
4236 && ptype->move_rate > 0) {
4237 /* Show a "tired" graphic if the unit has fewer than one move
4238 * remaining, except for units for which it's full movement. */
4239 ADD_SPRITE_FULL(t->sprites.unit.tired);
4242 if (stack || punit->client.occupied) {
4243 ADD_SPRITE_FULL(t->sprites.unit.stack);
4246 if (t->sprites.unit.vet_lev[punit->veteran]) {
4247 ADD_SPRITE_FULL(t->sprites.unit.vet_lev[punit->veteran]);
4250 ihp = ((NUM_TILES_HP_BAR-1)*punit->hp) / ptype->hp;
4251 ihp = CLIP(0, ihp, NUM_TILES_HP_BAR-1);
4252 ADD_SPRITE_FULL(t->sprites.unit.hp_bar[ihp]);
4254 return sprs - save_sprs;
4257 /**************************************************************************
4258 Add any corner road sprites to the sprite array.
4259 **************************************************************************/
4260 static int fill_road_corner_sprites(const struct tileset *t,
4261 const struct extra_type *pextra,
4262 struct drawn_sprite *sprs,
4263 bool road, bool *road_near,
4264 bool hider, bool *hider_near)
4266 struct drawn_sprite *saved_sprs = sprs;
4267 int i;
4268 int extra_idx = extra_index(pextra);
4270 if (is_cardinal_only_road(pextra)) {
4271 return 0;
4274 /* Roads going diagonally adjacent to this tile need to be
4275 * partly drawn on this tile. */
4277 /* Draw the corner sprite if:
4278 * - There is a diagonal road (not rail!) between two adjacent tiles.
4279 * - There is no diagonal road (not rail!) that intersects this road.
4280 * The logic is simple: roads are drawn underneath railrods, but are
4281 * not always covered by them (even in the corners!). But if a railroad
4282 * connects two tiles, only the railroad (no road) is drawn between
4283 * those tiles.
4285 for (i = 0; i < t->num_valid_tileset_dirs; i++) {
4286 enum direction8 dir = t->valid_tileset_dirs[i];
4288 if (!is_cardinal_tileset_dir(t, dir)) {
4289 /* Draw corner sprites for this non-cardinal direction. */
4290 int cw = (i + 1) % t->num_valid_tileset_dirs;
4291 int ccw
4292 = (i + t->num_valid_tileset_dirs - 1) % t->num_valid_tileset_dirs;
4293 enum direction8 cwdir = t->valid_tileset_dirs[cw];
4294 enum direction8 ccwdir = t->valid_tileset_dirs[ccw];
4296 if (t->sprites.extras[extra_idx].u.road.corner[dir]
4297 && (road_near[cwdir] && road_near[ccwdir]
4298 && !(hider_near[cwdir] && hider_near[ccwdir]))
4299 && !(road && road_near[dir] && !(hider && hider_near[dir]))) {
4300 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_idx].u.road.corner[dir]);
4305 return sprs - saved_sprs;
4308 /**************************************************************************
4309 Fill all road and rail sprites into the sprite array.
4310 **************************************************************************/
4311 static int fill_road_sprite_array(const struct tileset *t,
4312 const struct extra_type *pextra,
4313 struct drawn_sprite *sprs,
4314 bv_extras textras,
4315 bv_extras *textras_near,
4316 struct terrain *tterrain_near[8],
4317 const struct city *pcity)
4319 struct drawn_sprite *saved_sprs = sprs;
4320 bool road, road_near[8], hider, hider_near[8];
4321 bool land_near[8], hland_near[8];
4322 bool draw_road[8], draw_single_road;
4323 enum direction8 dir;
4324 int extra_idx = -1;
4325 bool cl = FALSE;
4326 enum extrastyle_id extrastyle;
4327 const struct road_type *proad = extra_road_get(pextra);
4329 extra_idx = extra_index(pextra);
4331 extrastyle = t->sprites.extras[extra_idx].extrastyle;
4333 if (extra_has_flag(pextra, EF_CONNECT_LAND)) {
4334 cl = TRUE;
4335 } else {
4336 int i;
4338 for (i = 0; i < 8; i++) {
4339 land_near[i] = FALSE;
4343 /* Fill some data arrays. rail_near and road_near store whether road/rail
4344 * is present in the given direction. draw_rail and draw_road store
4345 * whether road/rail is to be drawn in that direction. draw_single_road
4346 * and draw_single_rail store whether we need an isolated road/rail to be
4347 * drawn. */
4348 road = BV_ISSET(textras, extra_idx);
4350 hider = FALSE;
4351 extra_type_list_iterate(pextra->hiders, phider) {
4352 if (BV_ISSET(textras, extra_index(phider))) {
4353 hider = TRUE;
4354 break;
4356 } extra_type_list_iterate_end;
4358 if (road && (!pcity || !gui_options.draw_cities) && !hider) {
4359 draw_single_road = TRUE;
4360 } else {
4361 draw_single_road = FALSE;
4364 for (dir = 0; dir < 8; dir++) {
4365 bool roads_exist;
4367 /* Check if there is adjacent road/rail. */
4368 if (!is_cardinal_only_road(pextra)
4369 || is_cardinal_tileset_dir(t, dir)) {
4370 road_near[dir] = FALSE;
4371 extra_type_list_iterate(proad->integrators, iextra) {
4372 if (BV_ISSET(textras_near[dir], extra_index(iextra))) {
4373 road_near[dir] = TRUE;
4374 break;
4376 } extra_type_list_iterate_end;
4377 if (cl) {
4378 land_near[dir] = (tterrain_near[dir] != T_UNKNOWN
4379 && terrain_type_terrain_class(tterrain_near[dir]) != TC_OCEAN);
4381 } else {
4382 road_near[dir] = FALSE;
4383 land_near[dir] = FALSE;
4386 /* Draw rail/road if there is a connection from this tile to the
4387 * adjacent tile. But don't draw road if there is also a rail
4388 * connection. */
4389 roads_exist = road && (road_near[dir] || land_near[dir]);
4390 draw_road[dir] = roads_exist;
4391 hider_near[dir] = FALSE;
4392 hland_near[dir] = tterrain_near[dir] != T_UNKNOWN
4393 && terrain_type_terrain_class(tterrain_near[dir]) != TC_OCEAN;
4394 extra_type_list_iterate(pextra->hiders, phider) {
4395 bool hider_dir = FALSE;
4396 bool land_dir = FALSE;
4398 if (!is_cardinal_only_road(phider)
4399 || is_cardinal_tileset_dir(t, dir)) {
4400 if (BV_ISSET(textras_near[dir], extra_index(phider))) {
4401 hider_near[dir] = TRUE;
4402 hider_dir = TRUE;
4404 if (hland_near[dir]
4405 && is_extra_caused_by(phider, EC_ROAD)
4406 && extra_has_flag(phider, EF_CONNECT_LAND)) {
4407 land_dir = TRUE;
4409 if (hider_dir || land_dir) {
4410 if (BV_ISSET(textras, extra_index(phider))) {
4411 draw_road[dir] = FALSE;
4415 } extra_type_list_iterate_end;
4417 /* Don't draw an isolated road/rail if there's any connection.
4418 * draw_single_road would be true in the first place only if start tile has road,
4419 * so it will have road connection with any adjacent road tile. We check from real
4420 * existence of road (road_near[dir]) and not from whether road gets drawn (draw_road[dir])
4421 * as latter can be FALSE when road is simply hidden by another one, and we don't want to
4422 * draw single road in that case either. */
4423 if (draw_single_road && road_near[dir]) {
4424 draw_single_road = FALSE;
4428 /* Draw road corners */
4429 sprs
4430 += fill_road_corner_sprites(t, pextra, sprs, road, road_near, hider, hider_near);
4432 if (extrastyle == ESTYLE_ROAD_ALL_SEPARATE) {
4433 /* With ESTYLE_ROAD_ALL_SEPARATE, we simply draw one road for every connection.
4434 * This means we only need a few sprites, but a lot of drawing is
4435 * necessary and it generally doesn't look very good. */
4436 int i;
4438 /* First draw roads under rails. */
4439 if (road) {
4440 for (i = 0; i < t->num_valid_tileset_dirs; i++) {
4441 if (draw_road[t->valid_tileset_dirs[i]]) {
4442 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_idx].u.road.ru.dir[i]);
4446 } else if (extrastyle == ESTYLE_ROAD_PARITY_COMBINED) {
4447 /* With ESTYLE_ROAD_PARITY_COMBINED, we draw one sprite for cardinal
4448 * road connections, one sprite for diagonal road connections.
4449 * This means we need about 4x more sprites than in style 0, but up to
4450 * 4x less drawing is needed. The drawing quality may also be
4451 * improved. */
4453 /* First draw roads under rails. */
4454 if (road) {
4455 int road_even_tileno = 0, road_odd_tileno = 0, i;
4457 for (i = 0; i < t->num_valid_tileset_dirs / 2; i++) {
4458 enum direction8 even = t->valid_tileset_dirs[2 * i];
4459 enum direction8 odd = t->valid_tileset_dirs[2 * i + 1];
4461 if (draw_road[even]) {
4462 road_even_tileno |= 1 << i;
4464 if (draw_road[odd]) {
4465 road_odd_tileno |= 1 << i;
4469 /* Draw the cardinal/even roads first. */
4470 if (road_even_tileno != 0) {
4471 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_idx].u.road.ru.combo.even[road_even_tileno]);
4473 if (road_odd_tileno != 0) {
4474 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_idx].u.road.ru.combo.odd[road_odd_tileno]);
4477 } else if (extrastyle == ESTYLE_ROAD_ALL_COMBINED) {
4478 /* RSTYLE_ALL_COMBINED is a very simple method that lets us simply retrieve
4479 * entire finished tiles, with a bitwise index of the presence of
4480 * roads in each direction. */
4482 /* Draw roads first */
4483 if (road) {
4484 int road_tileno = 0, i;
4486 for (i = 0; i < t->num_valid_tileset_dirs; i++) {
4487 enum direction8 vdir = t->valid_tileset_dirs[i];
4489 if (draw_road[vdir]) {
4490 road_tileno |= 1 << i;
4494 if (road_tileno != 0 || draw_single_road) {
4495 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_idx].u.road.ru.total[road_tileno]);
4498 } else {
4499 fc_assert(FALSE);
4502 /* Draw isolated rail/road separately (ESTYLE_ROAD_ALL_SEPARATE and
4503 ESTYLE_ROAD_PARITY_COMBINED only). */
4504 if (extrastyle == ESTYLE_ROAD_ALL_SEPARATE
4505 || extrastyle == ESTYLE_ROAD_PARITY_COMBINED) {
4506 if (draw_single_road) {
4507 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_idx].u.road.isolated);
4511 return sprs - saved_sprs;
4514 /**************************************************************************
4515 Return the index of the sprite to be used for irrigation or farmland in
4516 this tile.
4518 We assume that the current tile has farmland or irrigation. We then
4519 choose a sprite (index) based upon which cardinally adjacent tiles have
4520 either farmland or irrigation (the two are considered interchangable for
4521 this).
4522 **************************************************************************/
4523 static int get_irrigation_index(const struct tileset *t,
4524 struct extra_type *pextra,
4525 bv_extras *textras_near)
4527 int tileno = 0, i;
4529 for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
4530 enum direction8 dir = t->cardinal_tileset_dirs[i];
4532 if (BV_ISSET(textras_near[dir], extra_index(pextra))) {
4533 tileno |= 1 << i;
4537 return tileno;
4540 /**************************************************************************
4541 Fill in the farmland/irrigation sprite for the tile.
4542 **************************************************************************/
4543 static int fill_irrigation_sprite_array(const struct tileset *t,
4544 struct drawn_sprite *sprs,
4545 bv_extras textras,
4546 bv_extras *textras_near,
4547 const struct city *pcity)
4549 struct drawn_sprite *saved_sprs = sprs;
4551 /* We don't draw the irrigation if there's a city (it just gets overdrawn
4552 * anyway, and ends up looking bad). */
4553 if (!(pcity && gui_options.draw_cities)) {
4554 extra_type_list_iterate(t->style_lists[ESTYLE_CARDINALS], pextra) {
4555 if (is_extra_drawing_enabled(pextra)) {
4556 int eidx = extra_index(pextra);
4558 if (BV_ISSET(textras, eidx)) {
4559 bool hidden = FALSE;
4561 extra_type_list_iterate(pextra->hiders, phider) {
4562 if (BV_ISSET(textras, extra_index(phider))) {
4563 hidden = TRUE;
4564 break;
4566 } extra_type_list_iterate_end;
4568 if (!hidden) {
4569 int idx = get_irrigation_index(t, pextra, textras_near);
4571 ADD_SPRITE_SIMPLE(t->sprites.extras[eidx].u.cardinals[idx]);
4575 } extra_type_list_iterate_end;
4578 return sprs - saved_sprs;
4581 /**************************************************************************
4582 Fill in the city overlays for the tile. This includes the citymap
4583 overlays on the mapview as well as the tile output sprites.
4584 **************************************************************************/
4585 static int fill_city_overlays_sprite_array(const struct tileset *t,
4586 struct drawn_sprite *sprs,
4587 const struct tile *ptile,
4588 const struct city *citymode)
4590 const struct city *pcity;
4591 const struct city *pwork;
4592 struct unit *psettler;
4593 struct drawn_sprite *saved_sprs = sprs;
4594 int city_x, city_y;
4595 const int NUM_CITY_COLORS = t->sprites.city.worked_tile_overlay.size;
4597 if (NULL == ptile || TILE_UNKNOWN == client_tile_get_known(ptile)) {
4598 return 0;
4600 pwork = tile_worked(ptile);
4602 if (citymode) {
4603 pcity = citymode;
4604 } else {
4605 pcity = find_city_or_settler_near_tile(ptile, &psettler);
4608 /* Below code does not work if pcity is invisible.
4609 * Make sure it is not. */
4610 fc_assert_ret_val(pcity == NULL || pcity->tile != NULL, 0);
4611 if (pcity && !pcity->tile) {
4612 pcity = NULL;
4615 if (pcity && city_base_to_city_map(&city_x, &city_y, pcity, ptile)) {
4616 /* FIXME: check elsewhere for valid tile (instead of above) */
4618 if (!citymode && pcity->client.colored) {
4619 /* Add citymap overlay for a city. */
4620 int idx = pcity->client.color_index % NUM_CITY_COLORS;
4622 if (NULL != pwork && pwork == pcity) {
4623 ADD_SPRITE_SIMPLE(t->sprites.city.worked_tile_overlay.p[idx]);
4624 } else if (city_can_work_tile(pcity, ptile)) {
4625 ADD_SPRITE_SIMPLE(t->sprites.city.unworked_tile_overlay.p[idx]);
4627 } else if (NULL != pwork && pwork == pcity
4628 && (citymode || gui_options.draw_city_output)) {
4629 /* Add on the tile output sprites. */
4630 int food = city_tile_output_now(pcity, ptile, O_FOOD);
4631 int shields = city_tile_output_now(pcity, ptile, O_SHIELD);
4632 int trade = city_tile_output_now(pcity, ptile, O_TRADE);
4633 const int ox = t->type == TS_ISOMETRIC ? t->normal_tile_width / 3 : 0;
4634 const int oy = t->type == TS_ISOMETRIC ? -t->normal_tile_height / 3 : 0;
4636 food = CLIP(0, food, NUM_TILES_DIGITS - 1);
4637 shields = CLIP(0, shields, NUM_TILES_DIGITS - 1);
4638 trade = CLIP(0, trade, NUM_TILES_DIGITS - 1);
4640 ADD_SPRITE(t->sprites.city.tile_foodnum[food], TRUE, ox, oy);
4641 ADD_SPRITE(t->sprites.city.tile_shieldnum[shields], TRUE, ox, oy);
4642 ADD_SPRITE(t->sprites.city.tile_tradenum[trade], TRUE, ox, oy);
4644 } else if (psettler && psettler->client.colored) {
4645 /* Add citymap overlay for a unit. */
4646 int idx = psettler->client.color_index % NUM_CITY_COLORS;
4648 ADD_SPRITE_SIMPLE(t->sprites.city.unworked_tile_overlay.p[idx]);
4651 return sprs - saved_sprs;
4654 /****************************************************************************
4655 Helper function for fill_terrain_sprite_layer.
4656 Fill in the sprite array for blended terrain.
4657 ****************************************************************************/
4658 static int fill_terrain_sprite_blending(const struct tileset *t,
4659 struct drawn_sprite *sprs,
4660 const struct tile *ptile,
4661 const struct terrain *pterrain,
4662 struct terrain **tterrain_near)
4664 struct drawn_sprite *saved_sprs = sprs;
4665 const int W = t->normal_tile_width, H = t->normal_tile_height;
4666 const int offsets[4][2] = {
4667 {W/2, 0}, {0, H / 2}, {W / 2, H / 2}, {0, 0}
4669 enum direction4 dir = 0;
4672 * We want to mark unknown tiles so that an unreal tile will be
4673 * given the same marking as our current tile - that way we won't
4674 * get the "unknown" dither along the edge of the map.
4676 for (; dir < 4; dir++) {
4677 struct tile *tile1 = mapstep(ptile, DIR4_TO_DIR8[dir]);
4678 struct terrain *other;
4680 if (!tile1
4681 || client_tile_get_known(tile1) == TILE_UNKNOWN
4682 || pterrain == (other = tterrain_near[DIR4_TO_DIR8[dir]])
4683 || (0 == t->sprites.drawing[terrain_index(other)]->blending
4684 && NULL == t->sprites.drawing[terrain_index(other)]->blender)) {
4685 continue;
4688 ADD_SPRITE(t->sprites.drawing[terrain_index(other)]->blend[dir], TRUE,
4689 offsets[dir][0], offsets[dir][1]);
4692 return sprs - saved_sprs;
4695 /****************************************************************************
4696 Add sprites for fog (and some forms of darkness).
4697 ****************************************************************************/
4698 static int fill_fog_sprite_array(const struct tileset *t,
4699 struct drawn_sprite *sprs,
4700 const struct tile *ptile,
4701 const struct tile_edge *pedge,
4702 const struct tile_corner *pcorner)
4704 struct drawn_sprite *saved_sprs = sprs;
4706 if (t->fogstyle == FOG_SPRITE && gui_options.draw_fog_of_war
4707 && NULL != ptile
4708 && TILE_KNOWN_UNSEEN == client_tile_get_known(ptile)) {
4709 /* With FOG_AUTO, fog is done this way. */
4710 ADD_SPRITE_SIMPLE(t->sprites.tx.fog);
4713 if (t->darkness_style == DARKNESS_CORNER && pcorner
4714 && gui_options.draw_fog_of_war) {
4715 int i, tileno = 0;
4717 for (i = 3; i >= 0; i--) {
4718 const int unknown = 0, fogged = 1, known = 2;
4719 int value = -1;
4721 if (!pcorner->tile[i]) {
4722 value = fogged;
4723 } else {
4724 switch (client_tile_get_known(pcorner->tile[i])) {
4725 case TILE_KNOWN_SEEN:
4726 value = known;
4727 break;
4728 case TILE_KNOWN_UNSEEN:
4729 value = fogged;
4730 break;
4731 case TILE_UNKNOWN:
4732 value = unknown;
4733 break;
4736 fc_assert(value >= 0 && value < 3);
4738 tileno = tileno * 3 + value;
4741 if (t->sprites.tx.fullfog[tileno]) {
4742 ADD_SPRITE_SIMPLE(t->sprites.tx.fullfog[tileno]);
4746 return sprs - saved_sprs;
4749 /****************************************************************************
4750 Helper function for fill_terrain_sprite_layer.
4751 ****************************************************************************/
4752 static int fill_terrain_sprite_array(struct tileset *t,
4753 struct drawn_sprite *sprs,
4754 int l, /* layer_num */
4755 const struct tile *ptile,
4756 const struct terrain *pterrain,
4757 struct terrain **tterrain_near,
4758 struct drawing_data *draw)
4760 struct drawn_sprite *saved_sprs = sprs;
4761 struct drawing_layer *dlp = &draw->layer[l];
4762 int this = dlp->match_index[0];
4763 int that = dlp->match_index[1];
4764 int ox = dlp->offset_x;
4765 int oy = dlp->offset_y;
4766 int i;
4768 #define MATCH(dir) \
4769 (t->sprites.drawing[terrain_index(tterrain_near[(dir)])]->num_layers > l \
4770 ? t->sprites.drawing[terrain_index(tterrain_near[(dir)])]->layer[l].match_index[0] \
4771 : -1)
4773 switch (dlp->sprite_type) {
4774 case CELL_WHOLE:
4776 switch (dlp->match_style) {
4777 case MATCH_NONE:
4779 int count = sprite_vector_size(&dlp->base);
4781 if (count > 0) {
4782 /* Pseudo-random reproducable algorithm to pick a sprite. Use modulo
4783 * to limit the number to a handleable size [0..32000). */
4784 count = fc_randomly(tile_index(ptile) % 32000, count);
4786 if (dlp->is_tall) {
4787 ox += FULL_TILE_X_OFFSET;
4788 oy += FULL_TILE_Y_OFFSET;
4790 ADD_SPRITE(dlp->base.p[count], TRUE, ox, oy);
4792 break;
4794 case MATCH_SAME:
4796 int tileno = 0;
4798 for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
4799 enum direction8 dir = t->cardinal_tileset_dirs[i];
4801 if (MATCH(dir) == this) {
4802 tileno |= 1 << i;
4806 if (dlp->is_tall) {
4807 ox += FULL_TILE_X_OFFSET;
4808 oy += FULL_TILE_Y_OFFSET;
4810 ADD_SPRITE(dlp->match[tileno], TRUE, ox, oy);
4811 break;
4813 case MATCH_PAIR:
4814 case MATCH_FULL:
4815 fc_assert(FALSE); /* not yet defined */
4816 break;
4818 break;
4820 case CELL_CORNER:
4822 /* Divide the tile up into four rectangular cells. Each of these
4823 * cells covers one corner, and each is adjacent to 3 different
4824 * tiles. For each cell we pick a sprite based upon the adjacent
4825 * terrains at each of those tiles. Thus, we have 8 different sprites
4826 * for each of the 4 cells (32 sprites total).
4828 * These arrays correspond to the direction4 ordering. */
4829 const int W = t->normal_tile_width;
4830 const int H = t->normal_tile_height;
4831 const int iso_offsets[4][2] = {
4832 {W / 4, 0}, {W / 4, H / 2}, {W / 2, H / 4}, {0, H / 4}
4834 const int noniso_offsets[4][2] = {
4835 {0, 0}, {W / 2, H / 2}, {W / 2, 0}, {0, H / 2}
4838 /* put corner cells */
4839 for (i = 0; i < NUM_CORNER_DIRS; i++) {
4840 const int count = dlp->match_indices;
4841 int array_index = 0;
4842 enum direction8 dir = dir_ccw(DIR4_TO_DIR8[i]);
4843 int x = (t->type == TS_ISOMETRIC ? iso_offsets[i][0] : noniso_offsets[i][0]);
4844 int y = (t->type == TS_ISOMETRIC ? iso_offsets[i][1] : noniso_offsets[i][1]);
4845 int m[3] = {MATCH(dir_ccw(dir)), MATCH(dir), MATCH(dir_cw(dir))};
4846 struct sprite *s;
4848 /* synthesize 4 dimensional array? */
4849 switch (dlp->match_style) {
4850 case MATCH_NONE:
4851 /* We have no need for matching, just plug the piece in place. */
4852 break;
4853 case MATCH_SAME:
4854 array_index = array_index * 2 + (m[2] != this);
4855 array_index = array_index * 2 + (m[1] != this);
4856 array_index = array_index * 2 + (m[0] != this);
4857 break;
4858 case MATCH_PAIR:
4859 array_index = array_index * 2 + (m[2] == that);
4860 array_index = array_index * 2 + (m[1] == that);
4861 array_index = array_index * 2 + (m[0] == that);
4862 break;
4863 case MATCH_FULL:
4864 default:
4866 int n[3];
4867 int j = 0;
4868 for (; j < 3; j++) {
4869 int k = 0;
4870 for (; k < count; k++) {
4871 n[j] = k; /* default to last entry */
4872 if (m[j] == dlp->match_index[k])
4874 break;
4878 array_index = array_index * count + n[2];
4879 array_index = array_index * count + n[1];
4880 array_index = array_index * count + n[0];
4882 break;
4884 array_index = array_index * NUM_CORNER_DIRS + i;
4886 s = dlp->cells[array_index];
4887 if (s) {
4888 ADD_SPRITE(s, TRUE, x, y);
4891 break;
4894 #undef MATCH
4896 return sprs - saved_sprs;
4899 /****************************************************************************
4900 Helper function for fill_terrain_sprite_layer.
4901 Fill in the sprite array of darkness.
4902 ****************************************************************************/
4903 static int fill_terrain_sprite_darkness(struct tileset *t,
4904 struct drawn_sprite *sprs,
4905 const struct tile *ptile,
4906 struct terrain **tterrain_near)
4908 struct drawn_sprite *saved_sprs = sprs;
4909 int i, tileno;
4910 struct tile *adjc_tile;
4912 #define UNKNOWN(dir) \
4913 ((adjc_tile = mapstep(ptile, (dir))) \
4914 && client_tile_get_known(adjc_tile) == TILE_UNKNOWN)
4916 switch (t->darkness_style) {
4917 case DARKNESS_NONE:
4918 break;
4919 case DARKNESS_ISORECT:
4920 for (i = 0; i < 4; i++) {
4921 const int W = t->normal_tile_width, H = t->normal_tile_height;
4922 int offsets[4][2] = {{W / 2, 0}, {0, H / 2}, {W / 2, H / 2}, {0, 0}};
4924 if (UNKNOWN(DIR4_TO_DIR8[i])) {
4925 ADD_SPRITE(t->sprites.tx.darkness[i], TRUE,
4926 offsets[i][0], offsets[i][1]);
4929 break;
4930 case DARKNESS_CARD_SINGLE:
4931 for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
4932 if (UNKNOWN(t->cardinal_tileset_dirs[i])) {
4933 ADD_SPRITE_SIMPLE(t->sprites.tx.darkness[i]);
4936 break;
4937 case DARKNESS_CARD_FULL:
4938 /* We're looking to find the INDEX_NSEW for the directions that
4939 * are unknown. We want to mark unknown tiles so that an unreal
4940 * tile will be given the same marking as our current tile - that
4941 * way we won't get the "unknown" dither along the edge of the
4942 * map. */
4943 tileno = 0;
4944 for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
4945 if (UNKNOWN(t->cardinal_tileset_dirs[i])) {
4946 tileno |= 1 << i;
4950 if (tileno != 0) {
4951 ADD_SPRITE_SIMPLE(t->sprites.tx.darkness[tileno]);
4953 break;
4954 case DARKNESS_CORNER:
4955 /* Handled separately. */
4956 break;
4958 #undef UNKNOWN
4960 return sprs - saved_sprs;
4963 /****************************************************************************
4964 Add sprites for the base tile to the sprite list. This doesn't
4965 include specials or rivers.
4966 ****************************************************************************/
4967 static int fill_terrain_sprite_layer(struct tileset *t,
4968 struct drawn_sprite *sprs,
4969 int layer_num,
4970 const struct tile *ptile,
4971 const struct terrain *pterrain,
4972 struct terrain **tterrain_near)
4974 struct sprite *sprite;
4975 struct drawn_sprite *saved_sprs = sprs;
4976 struct drawing_data *draw = t->sprites.drawing[terrain_index(pterrain)];
4977 const int l = (draw->is_reversed
4978 ? (draw->num_layers - layer_num - 1) : layer_num);
4980 fc_assert(layer_num < TERRAIN_LAYER_COUNT);
4982 /* Skip the normal drawing process. */
4983 /* FIXME: this should avoid calling load_sprite since it's slow and
4984 * increases the refcount without limit. */
4985 if (ptile->spec_sprite && (sprite = load_sprite(t, ptile->spec_sprite,
4986 TRUE, FALSE))) {
4987 if (l == 0) {
4988 ADD_SPRITE_SIMPLE(sprite);
4989 return 1;
4990 } else {
4991 return 0;
4995 if (l < draw->num_layers) {
4996 sprs += fill_terrain_sprite_array(t, sprs, l, ptile, pterrain, tterrain_near, draw);
4998 if ((l + 1) == draw->blending) {
4999 sprs += fill_terrain_sprite_blending(t, sprs, ptile, pterrain, tterrain_near);
5003 /* Add darkness on top of the designed terrain layer. Note that darkness is always
5004 * drawn, even in citymode, etc. */
5005 if (layer_num == t->darkness_layer) {
5006 sprs += fill_terrain_sprite_darkness(t, sprs, ptile, tterrain_near);
5009 return sprs - saved_sprs;
5012 /****************************************************************************
5013 Indicate whether a unit is to be drawn with a surrounding city outline
5014 under current conditions.
5015 (This includes being in focus, but if the caller has already checked that,
5016 they can bypass this slightly expensive check with check_focus == FALSE.)
5017 ****************************************************************************/
5018 bool unit_drawn_with_city_outline(const struct unit *punit, bool check_focus)
5020 /* Display an outline for city-builder type units if they are selected,
5021 * and on a tile where a city can be built.
5022 * But suppress the outline if the unit has orders (likely it is in
5023 * transit to somewhere else and this will just slow down redraws). */
5024 return gui_options.draw_city_outlines
5025 && unit_is_cityfounder(punit)
5026 && !unit_has_orders(punit)
5027 && (client_tile_get_known(unit_tile(punit)) != TILE_UNKNOWN
5028 && city_can_be_built_here(unit_tile(punit), punit))
5029 && (!check_focus || unit_is_in_focus(punit));
5032 /****************************************************************************
5033 Fill in the grid sprites for the given tile, city, and unit.
5034 ****************************************************************************/
5035 static int fill_grid_sprite_array(const struct tileset *t,
5036 struct drawn_sprite *sprs,
5037 const struct tile *ptile,
5038 const struct tile_edge *pedge,
5039 const struct tile_corner *pcorner,
5040 const struct unit *punit,
5041 const struct city *pcity,
5042 const struct city *citymode)
5044 struct drawn_sprite *saved_sprs = sprs;
5046 if (pedge) {
5047 bool known[NUM_EDGE_TILES], city[NUM_EDGE_TILES];
5048 bool unit[NUM_EDGE_TILES], worked[NUM_EDGE_TILES];
5049 int i;
5050 struct unit_list *pfocus_units = get_units_in_focus();
5052 for (i = 0; i < NUM_EDGE_TILES; i++) {
5053 int dummy_x, dummy_y;
5054 const struct tile *tile = pedge->tile[i];
5055 struct player *powner = tile ? tile_owner(tile) : NULL;
5057 known[i] = tile && client_tile_get_known(tile) != TILE_UNKNOWN;
5058 unit[i] = FALSE;
5059 if (tile && !citymode) {
5060 unit_list_iterate(pfocus_units, pfocus_unit) {
5061 if (unit_drawn_with_city_outline(pfocus_unit, FALSE)
5062 && city_tile_to_city_map(&dummy_x, &dummy_y,
5063 game.info.init_city_radius_sq,
5064 unit_tile(pfocus_unit), tile)) {
5065 unit[i] = TRUE;
5066 break;
5068 } unit_list_iterate_end;
5070 worked[i] = FALSE;
5072 city[i] = (tile
5073 && (NULL == powner || NULL == client.conn.playing
5074 || powner == client.conn.playing)
5075 && player_in_city_map(client.conn.playing, tile));
5076 if (city[i]) {
5077 if (citymode) {
5078 /* In citymode, we only draw worked tiles for this city - other
5079 * tiles may be marked as unavailable. */
5080 worked[i] = (tile_worked(tile) == citymode);
5081 } else {
5082 worked[i] = (NULL != tile_worked(tile));
5087 if (mapdeco_is_highlight_set(pedge->tile[0])
5088 || mapdeco_is_highlight_set(pedge->tile[1])) {
5089 ADD_SPRITE_SIMPLE(t->sprites.grid.selected[pedge->type]);
5090 } else if (!gui_options.draw_terrain && gui_options.draw_coastline
5091 && pedge->tile[0] && pedge->tile[1]
5092 && known[0] && known[1]
5093 && (is_ocean_tile(pedge->tile[0])
5094 ^ is_ocean_tile(pedge->tile[1]))) {
5095 ADD_SPRITE_SIMPLE(t->sprites.grid.coastline[pedge->type]);
5096 } else {
5097 if (gui_options.draw_map_grid) {
5098 if (worked[0] || worked[1]) {
5099 ADD_SPRITE_SIMPLE(t->sprites.grid.worked[pedge->type]);
5100 } else if (city[0] || city[1]) {
5101 ADD_SPRITE_SIMPLE(t->sprites.grid.city[pedge->type]);
5102 } else if (known[0] || known[1]) {
5103 ADD_SPRITE_SIMPLE(t->sprites.grid.main[pedge->type]);
5106 if (gui_options.draw_city_outlines) {
5107 if (XOR(city[0], city[1])) {
5108 ADD_SPRITE_SIMPLE(t->sprites.grid.city[pedge->type]);
5110 if (XOR(unit[0], unit[1])) {
5111 ADD_SPRITE_SIMPLE(t->sprites.grid.worked[pedge->type]);
5116 if (gui_options.draw_borders
5117 && BORDERS_DISABLED != game.info.borders
5118 && known[0]
5119 && known[1]) {
5120 struct player *owner0 = tile_owner(pedge->tile[0]);
5121 struct player *owner1 = tile_owner(pedge->tile[1]);
5123 if (owner0 != owner1) {
5124 if (owner0) {
5125 int plrid = player_index(owner0);
5126 ADD_SPRITE_SIMPLE(t->sprites.player[plrid].grid_borders
5127 [pedge->type][0]);
5129 if (owner1) {
5130 int plrid = player_index(owner1);
5131 ADD_SPRITE_SIMPLE(t->sprites.player[plrid].grid_borders
5132 [pedge->type][1]);
5136 } else if (NULL != ptile && TILE_UNKNOWN != client_tile_get_known(ptile)) {
5137 int cx, cy;
5139 if (citymode
5140 /* test to ensure valid coordinates? */
5141 && city_base_to_city_map(&cx, &cy, citymode, ptile)
5142 && !client_city_can_work_tile(citymode, ptile)) {
5143 ADD_SPRITE_SIMPLE(t->sprites.grid.unavailable);
5146 if (gui_options.draw_native && citymode == NULL) {
5147 bool native = TRUE;
5148 struct unit_list *pfocus_units = get_units_in_focus();
5150 unit_list_iterate(pfocus_units, pfocus) {
5151 if (!is_native_tile(unit_type_get(pfocus), ptile)) {
5152 native = FALSE;
5153 break;
5155 } unit_list_iterate_end;
5157 if (!native) {
5158 if (t->sprites.grid.nonnative != NULL) {
5159 ADD_SPRITE_SIMPLE(t->sprites.grid.nonnative);
5160 } else {
5161 ADD_SPRITE_SIMPLE(t->sprites.grid.unavailable);
5167 return sprs - saved_sprs;
5170 /****************************************************************************
5171 Fill in the given sprite array with any needed goto sprites.
5172 ****************************************************************************/
5173 static int fill_goto_sprite_array(const struct tileset *t,
5174 struct drawn_sprite *sprs,
5175 const struct tile *ptile,
5176 const struct tile_edge *pedge,
5177 const struct tile_corner *pcorner)
5179 struct drawn_sprite *saved_sprs = sprs;
5180 struct sprite *sprite;
5181 bool warn = FALSE;
5182 enum goto_tile_state state;
5183 int length;
5184 bool waypoint;
5186 if (goto_tile_state(ptile, &state, &length, &waypoint)) {
5187 if (length >= 0) {
5188 fc_assert(state >= 0);
5189 fc_assert(state < ARRAY_SIZE(t->sprites.path.s));
5191 sprite = t->sprites.path.s[state].specific;
5192 if (sprite != NULL) {
5193 ADD_SPRITE(sprite, FALSE, 0, 0);
5196 sprite = t->sprites.path.s[state].turns[length % 10];
5197 ADD_SPRITE_SIMPLE(sprite);
5198 if (length >= 10) {
5199 sprite = t->sprites.path.s[state].turns_tens[(length / 10) % 10];
5200 ADD_SPRITE_SIMPLE(sprite);
5201 if (length >= 100) {
5202 sprite = t->sprites.path.s[state].turns_hundreds[(length / 100)
5203 % 10];
5205 if (sprite != NULL) {
5206 ADD_SPRITE_SIMPLE(sprite);
5207 if (length >= 1000) {
5208 warn = TRUE;
5210 } else {
5211 warn = TRUE;
5217 if (waypoint) {
5218 ADD_SPRITE(t->sprites.path.waypoint, FALSE, 0, 0);
5221 if (warn) {
5222 /* Warn only once by tileset. */
5223 static char last_reported[256] = "";
5225 if (0 != strcmp(last_reported, t->name)) {
5226 log_normal(_("Tileset \"%s\" doesn't support long goto paths, "
5227 "such as %d. Path not displayed as expected."),
5228 t->name, length);
5229 sz_strlcpy(last_reported, t->name);
5234 return sprs - saved_sprs;
5237 /****************************************************************************
5238 Should the given extra be drawn
5239 ****************************************************************************/
5240 static bool is_extra_drawing_enabled(struct extra_type *pextra)
5242 bool no_disable = TRUE; /* Draw if matches no cause */
5244 if (is_extra_caused_by(pextra, EC_IRRIGATION)) {
5245 if (gui_options.draw_irrigation) {
5246 return TRUE;
5248 no_disable = FALSE;
5250 if (is_extra_caused_by(pextra, EC_POLLUTION)
5251 || is_extra_caused_by(pextra, EC_FALLOUT)) {
5252 if (gui_options.draw_pollution) {
5253 return TRUE;
5255 no_disable = FALSE;
5257 if (is_extra_caused_by(pextra, EC_MINE)) {
5258 if (gui_options.draw_mines) {
5259 return TRUE;
5261 no_disable = FALSE;
5263 if (is_extra_caused_by(pextra, EC_HUT)) {
5264 if (gui_options.draw_huts) {
5265 return TRUE;
5267 no_disable = FALSE;
5269 if (is_extra_caused_by(pextra, EC_BASE)) {
5270 if (gui_options.draw_fortress_airbase) {
5271 return TRUE;
5273 no_disable = FALSE;
5275 if (is_extra_caused_by(pextra, EC_ROAD)) {
5276 if (gui_options.draw_roads_rails) {
5277 return TRUE;
5279 no_disable = FALSE;
5282 return no_disable;
5285 /****************************************************************************
5286 Fill in the sprite array for the given tile, city, and unit.
5288 ptile, if specified, gives the tile. If specified the terrain and specials
5289 will be drawn for this tile. In this case (map_x,map_y) should give the
5290 location of the tile.
5292 punit, if specified, gives the unit. For tile drawing this should
5293 generally be get_drawable_unit(); otherwise it can be any unit.
5295 pcity, if specified, gives the city. For tile drawing this should
5296 generally be tile_city(ptile); otherwise it can be any city.
5298 citymode specifies whether this is part of a citydlg. If so some drawing
5299 is done differently.
5300 ****************************************************************************/
5301 int fill_sprite_array(struct tileset *t,
5302 struct drawn_sprite *sprs, enum mapview_layer layer,
5303 const struct tile *ptile,
5304 const struct tile_edge *pedge,
5305 const struct tile_corner *pcorner,
5306 const struct unit *punit, const struct city *pcity,
5307 const struct city *citymode,
5308 const struct unit_type *putype)
5310 int tileno, dir;
5311 bv_extras textras_near[8];
5312 bv_extras textras;
5313 struct terrain *tterrain_near[8];
5314 struct terrain *pterrain = NULL;
5315 struct drawn_sprite *save_sprs = sprs;
5316 struct player *owner = NULL;
5317 /* Unit drawing is disabled when the view options are turned off,
5318 * but only where we're drawing on the mapview. */
5319 bool do_draw_unit = (punit && (gui_options.draw_units || !ptile
5320 || (gui_options.draw_focus_unit
5321 && unit_is_in_focus(punit))));
5322 bool solid_bg = (gui_options.solid_color_behind_units
5323 && (do_draw_unit
5324 || (pcity && gui_options.draw_cities)
5325 || (ptile && !gui_options.draw_terrain)));
5327 if (citymode) {
5328 int count = 0, i, cx, cy;
5329 const struct tile *const *tiles = NULL;
5330 bool valid = FALSE;
5332 if (ptile) {
5333 tiles = &ptile;
5334 count = 1;
5335 } else if (pcorner) {
5336 tiles = pcorner->tile;
5337 count = NUM_CORNER_TILES;
5338 } else if (pedge) {
5339 tiles = pedge->tile;
5340 count = NUM_EDGE_TILES;
5343 for (i = 0; i < count; i++) {
5344 if (tiles[i] && city_base_to_city_map(&cx, &cy, citymode, tiles[i])) {
5345 valid = TRUE;
5346 break;
5349 if (!valid) {
5350 return 0;
5354 if (ptile && client_tile_get_known(ptile) != TILE_UNKNOWN) {
5355 textras = *tile_extras(ptile);
5356 pterrain = tile_terrain(ptile);
5358 if (NULL != pterrain) {
5359 if (layer == LAYER_TERRAIN1
5360 || layer == LAYER_TERRAIN2
5361 || layer == LAYER_TERRAIN3
5362 || layer == LAYER_WATER
5363 || layer == LAYER_ROADS) {
5364 build_tile_data(ptile, pterrain, tterrain_near, textras_near);
5366 } else {
5367 log_error("fill_sprite_array() tile (%d,%d) has no terrain!",
5368 TILE_XY(ptile));
5370 } else {
5371 BV_CLR_ALL(textras);
5374 switch (layer) {
5375 case LAYER_BACKGROUND:
5376 /* Set up background color. */
5377 if (gui_options.solid_color_behind_units) {
5378 if (do_draw_unit) {
5379 owner = unit_owner(punit);
5380 } else if (pcity && gui_options.draw_cities) {
5381 owner = city_owner(pcity);
5384 if (owner) {
5385 ADD_SPRITE_SIMPLE(t->sprites.player[player_index(owner)].background);
5386 } else if (ptile && !gui_options.draw_terrain) {
5387 ADD_SPRITE_SIMPLE(t->sprites.background.graphic);
5389 break;
5391 case LAYER_TERRAIN1:
5392 if (NULL != pterrain && gui_options.draw_terrain && !solid_bg) {
5393 sprs += fill_terrain_sprite_layer(t, sprs, 0, ptile, pterrain, tterrain_near);
5395 break;
5397 case LAYER_TERRAIN2:
5398 if (NULL != pterrain && gui_options.draw_terrain && !solid_bg) {
5399 sprs += fill_terrain_sprite_layer(t, sprs, 1, ptile, pterrain, tterrain_near);
5401 break;
5403 case LAYER_TERRAIN3:
5404 if (NULL != pterrain && gui_options.draw_terrain && !solid_bg) {
5405 fc_assert(MAX_NUM_LAYERS == 3);
5406 sprs += fill_terrain_sprite_layer(t, sprs, 2, ptile, pterrain, tterrain_near);
5408 break;
5410 case LAYER_WATER:
5411 if (NULL != pterrain) {
5412 if (gui_options.draw_terrain && !solid_bg
5413 && terrain_type_terrain_class(pterrain) == TC_OCEAN) {
5414 for (dir = 0; dir < t->num_cardinal_tileset_dirs; dir++) {
5415 int didx = t->cardinal_tileset_dirs[dir];
5417 extra_type_list_iterate(t->style_lists[ESTYLE_RIVER], priver) {
5418 int idx = extra_index(priver);
5420 if (BV_ISSET(textras_near[didx], idx)) {
5421 if (t->sprites.extras[idx].u.road.ru.rivers.outlet[dir] != NULL) {
5422 ADD_SPRITE_SIMPLE(t->sprites.extras[idx].u.road.ru.rivers.outlet[dir]);
5424 break;
5426 } extra_type_list_iterate_end;
5430 sprs += fill_irrigation_sprite_array(t, sprs, textras, textras_near,
5431 pcity);
5433 if (gui_options.draw_terrain && !solid_bg) {
5434 extra_type_list_iterate(t->style_lists[ESTYLE_RIVER], priver) {
5435 int idx = extra_index(priver);
5437 if (BV_ISSET(textras, idx)) {
5438 int i;
5440 /* Draw rivers on top of irrigation. */
5441 tileno = 0;
5442 for (i = 0; i < t->num_cardinal_tileset_dirs; i++) {
5443 enum direction8 cdir = t->cardinal_tileset_dirs[i];
5445 if (terrain_type_terrain_class(tterrain_near[cdir]) == TC_OCEAN
5446 || BV_ISSET(textras_near[cdir], idx)) {
5447 tileno |= 1 << i;
5451 ADD_SPRITE_SIMPLE(t->sprites.extras[idx].u.road.ru.rivers.spec[tileno]);
5453 } extra_type_list_iterate_end;
5456 break;
5458 case LAYER_ROADS:
5459 if (NULL != pterrain) {
5460 extra_type_list_iterate(t->style_lists[ESTYLE_ROAD_ALL_SEPARATE], pextra) {
5461 if (is_extra_drawing_enabled(pextra)) {
5462 sprs += fill_road_sprite_array(t, pextra, sprs,
5463 textras, textras_near,
5464 tterrain_near, pcity);
5466 } extra_type_list_iterate_end;
5467 extra_type_list_iterate(t->style_lists[ESTYLE_ROAD_PARITY_COMBINED], pextra) {
5468 if (is_extra_drawing_enabled(pextra)) {
5469 sprs += fill_road_sprite_array(t, pextra, sprs,
5470 textras, textras_near,
5471 tterrain_near, pcity);
5473 } extra_type_list_iterate_end;
5474 extra_type_list_iterate(t->style_lists[ESTYLE_ROAD_ALL_COMBINED], pextra) {
5475 if (is_extra_drawing_enabled(pextra)) {
5476 sprs += fill_road_sprite_array(t, pextra, sprs,
5477 textras, textras_near,
5478 tterrain_near, pcity);
5480 } extra_type_list_iterate_end;
5482 break;
5484 case LAYER_SPECIAL1:
5485 if (NULL != pterrain) {
5486 if (gui_options.draw_specials) {
5487 if (tile_resource_is_valid(ptile)) {
5488 ADD_SPRITE_SIMPLE(t->sprites.resource[resource_index(tile_resource(ptile))]);
5492 if (ptile) {
5493 extra_type_list_iterate(t->style_lists[ESTYLE_3LAYER], pextra) {
5494 if (tile_has_extra(ptile, pextra)
5495 && is_extra_drawing_enabled(pextra)
5496 && t->sprites.extras[extra_index(pextra)].u.bmf.background) {
5497 bool hidden = FALSE;
5499 extra_type_list_iterate(pextra->hiders, phider) {
5500 if (BV_ISSET(textras, extra_index(phider))) {
5501 hidden = TRUE;
5502 break;
5504 } extra_type_list_iterate_end;
5506 if (!hidden) {
5507 ADD_SPRITE_FULL(t->sprites.extras[extra_index(pextra)].u.bmf.background);
5510 } extra_type_list_iterate_end;
5513 extra_type_list_iterate(t->style_lists[ESTYLE_SINGLE1], pextra) {
5514 if (BV_ISSET(textras, extra_index(pextra))
5515 && is_extra_drawing_enabled(pextra)) {
5516 bool hidden = FALSE;
5518 extra_type_list_iterate(pextra->hiders, phider) {
5519 if (BV_ISSET(textras, extra_index(phider))) {
5520 hidden = TRUE;
5521 break;
5523 } extra_type_list_iterate_end;
5525 if (!hidden) {
5526 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_index(pextra)].u.single);
5529 } extra_type_list_iterate_end;
5531 break;
5533 case LAYER_GRID1:
5534 if (t->type == TS_ISOMETRIC) {
5535 sprs += fill_grid_sprite_array(t, sprs, ptile, pedge, pcorner,
5536 punit, pcity, citymode);
5538 break;
5540 case LAYER_CITY1:
5541 /* City. Some city sprites are drawn later. */
5542 if (pcity && gui_options.draw_cities) {
5543 if (!gui_options.draw_full_citybar && !gui_options.solid_color_behind_units) {
5544 ADD_SPRITE(get_city_flag_sprite(t, pcity), TRUE,
5545 FULL_TILE_X_OFFSET + t->city_flag_offset_x,
5546 FULL_TILE_Y_OFFSET + t->city_flag_offset_y);
5548 /* For iso-view the city.wall graphics include the full city, whereas
5549 * for non-iso view they are an overlay on top of the base city
5550 * graphic. */
5551 if (t->type == TS_OVERHEAD || pcity->client.walls <= 0) {
5552 ADD_SPRITE(get_city_sprite(t->sprites.city.tile, pcity), TRUE,
5553 FULL_TILE_X_OFFSET + t->city_offset_x,
5554 FULL_TILE_Y_OFFSET + t->city_offset_y);
5556 if (t->type == TS_ISOMETRIC && pcity->client.walls > 0) {
5557 struct city_sprite *cspr = t->sprites.city.wall[pcity->client.walls - 1];
5558 struct sprite *spr = NULL;
5560 if (cspr != NULL) {
5561 spr = get_city_sprite(cspr, pcity);
5563 if (spr == NULL) {
5564 cspr = t->sprites.city.single_wall;
5565 if (cspr != NULL) {
5566 spr = get_city_sprite(cspr, pcity);
5570 if (spr != NULL) {
5571 ADD_SPRITE(spr, TRUE,
5572 FULL_TILE_X_OFFSET + t->city_offset_x,
5573 FULL_TILE_Y_OFFSET + t->city_offset_y);
5576 if (!gui_options.draw_full_citybar && pcity->client.occupied) {
5577 ADD_SPRITE(get_city_sprite(t->sprites.city.occupied, pcity), TRUE,
5578 FULL_TILE_X_OFFSET + t->occupied_offset_x,
5579 FULL_TILE_Y_OFFSET + t->occupied_offset_y);
5581 if (t->type == TS_OVERHEAD && pcity->client.walls > 0) {
5582 struct city_sprite *cspr = t->sprites.city.wall[pcity->client.walls - 1];
5583 struct sprite *spr = NULL;
5585 if (cspr != NULL) {
5586 spr = get_city_sprite(cspr, pcity);
5588 if (spr == NULL) {
5589 cspr = t->sprites.city.single_wall;
5590 if (cspr != NULL) {
5591 spr = get_city_sprite(cspr, pcity);
5595 if (spr != NULL) {
5596 ADD_SPRITE_FULL(spr);
5599 if (pcity->client.unhappy) {
5600 ADD_SPRITE_FULL(t->sprites.city.disorder);
5603 break;
5605 case LAYER_SPECIAL2:
5606 if (NULL != pterrain) {
5607 if (ptile) {
5608 extra_type_list_iterate(t->style_lists[ESTYLE_3LAYER], pextra) {
5609 if (tile_has_extra(ptile, pextra)
5610 && is_extra_drawing_enabled(pextra)
5611 && t->sprites.extras[extra_index(pextra)].u.bmf.middleground) {
5612 bool hidden = FALSE;
5614 extra_type_list_iterate(pextra->hiders, phider) {
5615 if (BV_ISSET(textras, extra_index(phider))) {
5616 hidden = TRUE;
5617 break;
5619 } extra_type_list_iterate_end;
5621 if (!hidden) {
5622 ADD_SPRITE_FULL(t->sprites.extras[extra_index(pextra)].u.bmf.middleground);
5625 } extra_type_list_iterate_end;
5628 extra_type_list_iterate(t->style_lists[ESTYLE_SINGLE2], pextra) {
5629 if (BV_ISSET(textras, extra_index(pextra))
5630 && is_extra_drawing_enabled(pextra)) {
5631 bool hidden = FALSE;
5633 extra_type_list_iterate(pextra->hiders, phider) {
5634 if (BV_ISSET(textras, extra_index(phider))) {
5635 hidden = TRUE;
5636 break;
5638 } extra_type_list_iterate_end;
5640 if (!hidden) {
5641 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_index(pextra)].u.single);
5644 } extra_type_list_iterate_end;
5646 break;
5648 case LAYER_UNIT:
5649 case LAYER_FOCUS_UNIT:
5650 if (do_draw_unit && XOR(layer == LAYER_UNIT, unit_is_in_focus(punit))) {
5651 bool stacked = ptile && (unit_list_size(ptile->units) > 1);
5652 bool backdrop = !pcity;
5654 if (ptile && unit_is_in_focus(punit)
5655 && t->sprites.unit.select[0]) {
5656 /* Special case for drawing the selection rectangle. The blinking
5657 * unit is handled separately, inside get_drawable_unit(). */
5658 ADD_SPRITE_SIMPLE(t->sprites.unit.select[focus_unit_state]);
5661 sprs += fill_unit_sprite_array(t, sprs, punit, stacked, backdrop);
5662 } else if (putype != NULL && layer == LAYER_UNIT) {
5663 /* Only the sprite for the unit type. */
5664 sprs += fill_unit_type_sprite_array(t, sprs, putype,
5665 direction8_invalid());
5667 break;
5669 case LAYER_SPECIAL3:
5670 if (NULL != pterrain) {
5671 if (ptile) {
5672 bool show_flag = FALSE;
5673 struct player *eowner = extra_owner(ptile);
5675 extra_type_list_iterate(t->style_lists[ESTYLE_3LAYER], pextra) {
5676 if (is_extra_drawing_enabled(pextra)
5677 && tile_has_extra(ptile, pextra)
5678 && t->sprites.extras[extra_index(pextra)].u.bmf.foreground) {
5679 bool hidden = FALSE;
5681 extra_type_list_iterate(pextra->hiders, phider) {
5682 if (BV_ISSET(textras, extra_index(phider))) {
5683 hidden = TRUE;
5684 break;
5686 } extra_type_list_iterate_end;
5688 if (!hidden) {
5689 if (t->sprites.extras[extra_index(pextra)].u.bmf.foreground) {
5690 ADD_SPRITE_FULL(t->sprites.extras[extra_index(pextra)].u.bmf.foreground);
5694 } extra_type_list_iterate_end;
5696 /* Show base flag. Not part of previous iteration as
5697 * "extras of ESTYLE_3_LAYER" != "bases" */
5698 if (eowner != NULL) {
5699 extra_type_list_iterate(t->flagged_bases_list, pextra) {
5700 if (tile_has_extra(ptile, pextra)) {
5701 bool hidden = FALSE;
5703 extra_type_list_iterate(pextra->hiders, phider) {
5704 if (BV_ISSET(textras, extra_index(phider))) {
5705 hidden = TRUE;
5706 break;
5708 } extra_type_list_iterate_end;
5710 if (!hidden) {
5711 show_flag = TRUE;
5714 } extra_type_list_iterate_end;
5716 if (show_flag) {
5717 ADD_SPRITE(get_nation_flag_sprite(t, nation_of_player(eowner)), TRUE,
5718 FULL_TILE_X_OFFSET + t->city_flag_offset_x,
5719 FULL_TILE_Y_OFFSET + t->city_flag_offset_y);
5724 break;
5726 case LAYER_FOG:
5727 sprs += fill_fog_sprite_array(t, sprs, ptile, pedge, pcorner);
5728 break;
5730 case LAYER_CITY2:
5731 /* City size. Drawing this under fog makes it hard to read. */
5732 if (pcity && gui_options.draw_cities && !gui_options.draw_full_citybar) {
5733 bool warn = FALSE;
5735 ADD_SPRITE(t->sprites.city.size[city_size_get(pcity) % 10],
5736 FALSE, FULL_TILE_X_OFFSET, FULL_TILE_Y_OFFSET);
5737 if (10 <= city_size_get(pcity)) {
5738 ADD_SPRITE(t->sprites.city.size_tens[(city_size_get(pcity) / 10)
5739 % 10], FALSE, FULL_TILE_X_OFFSET, FULL_TILE_Y_OFFSET);
5740 if (100 <= city_size_get(pcity)) {
5741 struct sprite *sprite =
5742 t->sprites.city.size_hundreds[(city_size_get(pcity) / 100) % 10];
5744 if (NULL != sprite) {
5745 ADD_SPRITE(sprite, FALSE,
5746 FULL_TILE_X_OFFSET, FULL_TILE_Y_OFFSET);
5747 } else {
5748 warn = TRUE;
5750 if (1000 <= city_size_get(pcity)) {
5751 warn = TRUE;
5756 if (warn) {
5757 /* Warn only once by tileset. */
5758 static char last_reported[256] = "";
5760 if (0 != strcmp(last_reported, t->name)) {
5761 log_normal(_("Tileset \"%s\" doesn't support big cities size, "
5762 "such as %d. Size not displayed as expected."),
5763 t->name, city_size_get(pcity));
5764 sz_strlcpy(last_reported, t->name);
5768 break;
5770 case LAYER_GRID2:
5771 if (t->type == TS_OVERHEAD) {
5772 sprs += fill_grid_sprite_array(t, sprs, ptile, pedge, pcorner,
5773 punit, pcity, citymode);
5775 break;
5777 case LAYER_OVERLAYS:
5778 sprs += fill_city_overlays_sprite_array(t, sprs, ptile, citymode);
5779 if (mapdeco_is_crosshair_set(ptile)) {
5780 ADD_SPRITE_SIMPLE(t->sprites.user.attention);
5782 break;
5784 case LAYER_CITYBAR:
5785 case LAYER_TILELABEL:
5786 /* Nothing. This is just a placeholder. */
5787 break;
5789 case LAYER_GOTO:
5790 if (ptile && goto_is_active()) {
5791 sprs += fill_goto_sprite_array(t, sprs, ptile, pedge, pcorner);
5793 break;
5795 case LAYER_WORKERTASK:
5796 if (citymode != NULL && ptile != NULL) {
5797 worker_task_list_iterate(citymode->task_reqs, ptask) {
5798 if (ptask->ptile == ptile) {
5799 switch (ptask->act) {
5800 case ACTIVITY_MINE:
5801 if (ptask->tgt == NULL) {
5802 ADD_SPRITE_SIMPLE(t->sprites.unit.plant);
5803 } else {
5804 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_index(ptask->tgt)].activity);
5806 break;
5807 case ACTIVITY_IRRIGATE:
5808 if (ptask->tgt == NULL) {
5809 ADD_SPRITE_SIMPLE(t->sprites.unit.irrigate);
5810 } else {
5811 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_index(ptask->tgt)].activity);
5813 break;
5814 case ACTIVITY_GEN_ROAD:
5815 ADD_SPRITE_SIMPLE(t->sprites.extras[extra_index(ptask->tgt)].activity);
5816 break;
5817 case ACTIVITY_TRANSFORM:
5818 ADD_SPRITE_SIMPLE(t->sprites.unit.transform);
5819 break;
5820 default:
5821 break;
5824 } worker_task_list_iterate_end;
5826 break;
5828 case LAYER_EDITOR:
5829 if (ptile && editor_is_active()) {
5830 if (editor_tile_is_selected(ptile)) {
5831 int color = 2 % tileset_num_city_colors(tileset);
5832 ADD_SPRITE_SIMPLE(t->sprites.city.unworked_tile_overlay.p[color]);
5835 if (NULL != map_startpos_get(ptile)) {
5836 /* FIXME: Use a more representative sprite. */
5837 ADD_SPRITE_SIMPLE(t->sprites.user.attention);
5840 break;
5842 case LAYER_COUNT:
5843 fc_assert(FALSE);
5844 break;
5847 return sprs - save_sprs;
5850 /**********************************************************************
5851 Set city tiles sprite values; should only happen after
5852 tilespec_load_tiles().
5853 ***********************************************************************/
5854 void tileset_setup_city_tiles(struct tileset *t, int style)
5856 if (style == game.control.styles_count - 1) {
5857 int i;
5859 /* Free old sprites */
5860 free_city_sprite(t->sprites.city.tile);
5862 for (i = 0; i < NUM_WALL_TYPES; i++) {
5863 free_city_sprite(t->sprites.city.wall[i]);
5864 t->sprites.city.wall[i] = NULL;
5866 free_city_sprite(t->sprites.city.single_wall);
5867 t->sprites.city.single_wall = NULL;
5869 free_city_sprite(t->sprites.city.occupied);
5871 t->sprites.city.tile = load_city_sprite(t, "city");
5873 for (i = 0; i < NUM_WALL_TYPES; i++) {
5874 char buffer[256];
5876 fc_snprintf(buffer, sizeof(buffer), "bldg_%d", i);
5877 t->sprites.city.wall[i] = load_city_sprite(t, buffer);
5879 t->sprites.city.single_wall = load_city_sprite(t, "wall");
5881 t->sprites.city.occupied = load_city_sprite(t, "occupied");
5883 for (style = 0; style < game.control.styles_count; style++) {
5884 if (t->sprites.city.tile->styles[style].land_num_thresholds == 0) {
5885 tileset_error(LOG_FATAL, _("City style \"%s\": no city graphics."),
5886 city_style_rule_name(style));
5888 if (t->sprites.city.occupied->styles[style].land_num_thresholds == 0) {
5889 tileset_error(LOG_FATAL, _("City style \"%s\": no occupied graphics."),
5890 city_style_rule_name(style));
5896 /****************************************************************************
5897 Return the amount of time between calls to toggle_focus_unit_state.
5898 The main loop needs to call toggle_focus_unit_state about this often
5899 to do the active-unit animation.
5900 ****************************************************************************/
5901 double get_focus_unit_toggle_timeout(const struct tileset *t)
5903 if (t->sprites.unit.select[0]) {
5904 return 0.1;
5905 } else {
5906 return 0.5;
5910 /****************************************************************************
5911 Reset the focus unit state. This should be called when changing
5912 focus units.
5913 ****************************************************************************/
5914 void reset_focus_unit_state(struct tileset *t)
5916 focus_unit_state = 0;
5919 /****************************************************************************
5920 Setup tileset for showing combat where focus unit participates.
5921 ****************************************************************************/
5922 void focus_unit_in_combat(struct tileset *t)
5924 if (!t->sprites.unit.select[0]) {
5925 reset_focus_unit_state(t);
5929 /****************************************************************************
5930 Toggle/increment the focus unit state. This should be called once
5931 every get_focus_unit_toggle_timeout() seconds.
5932 ****************************************************************************/
5933 void toggle_focus_unit_state(struct tileset *t)
5935 focus_unit_state++;
5936 if (t->sprites.unit.select[0]) {
5937 focus_unit_state %= NUM_TILES_SELECT;
5938 } else {
5939 focus_unit_state %= 2;
5943 /**********************************************************************
5944 Find unit that we can display from given tile.
5945 ***********************************************************************/
5946 struct unit *get_drawable_unit(const struct tileset *t,
5947 struct tile *ptile,
5948 const struct city *citymode)
5950 struct unit *punit = find_visible_unit(ptile);
5952 if (punit == NULL) {
5953 return NULL;
5956 if (citymode && unit_owner(punit) == city_owner(citymode)) {
5957 return NULL;
5960 if (!unit_is_in_focus(punit)
5961 || t->sprites.unit.select[0] || focus_unit_state == 0) {
5962 return punit;
5963 } else {
5964 return NULL;
5968 /****************************************************************************
5969 This patch unloads all sprites from the sprite hash (the hash itself
5970 is left intact).
5971 ****************************************************************************/
5972 static void unload_all_sprites(struct tileset *t)
5974 if (t->sprite_hash) {
5975 sprite_hash_iterate(t->sprite_hash, tag_name, ss) {
5976 while (ss->ref_count > 0) {
5977 unload_sprite(t, tag_name);
5979 } sprite_hash_iterate_end;
5983 /**********************************************************************
5984 Free all sprites from tileset.
5985 ***********************************************************************/
5986 void tileset_free_tiles(struct tileset *t)
5988 int i;
5990 log_debug("tileset_free_tiles()");
5992 unload_all_sprites(t);
5994 free_city_sprite(t->sprites.city.tile);
5995 t->sprites.city.tile = NULL;
5997 for (i = 0; i < NUM_WALL_TYPES; i++) {
5998 free_city_sprite(t->sprites.city.wall[i]);
5999 t->sprites.city.wall[i] = NULL;
6001 free_city_sprite(t->sprites.city.single_wall);
6002 t->sprites.city.single_wall = NULL;
6004 free_city_sprite(t->sprites.city.occupied);
6005 t->sprites.city.occupied = NULL;
6007 if (t->sprite_hash) {
6008 sprite_hash_destroy(t->sprite_hash);
6009 t->sprite_hash = NULL;
6012 small_sprite_list_iterate(t->small_sprites, ss) {
6013 small_sprite_list_remove(t->small_sprites, ss);
6014 if (ss->file) {
6015 free(ss->file);
6017 fc_assert(ss->sprite == NULL);
6018 free(ss);
6019 } small_sprite_list_iterate_end;
6021 specfile_list_iterate(t->specfiles, sf) {
6022 specfile_list_remove(t->specfiles, sf);
6023 free(sf->file_name);
6024 if (sf->big_sprite) {
6025 free_sprite(sf->big_sprite);
6026 sf->big_sprite = NULL;
6028 free(sf);
6029 } specfile_list_iterate_end;
6031 sprite_vector_iterate(&t->sprites.city.worked_tile_overlay, psprite) {
6032 free_sprite(*psprite);
6033 } sprite_vector_iterate_end;
6034 sprite_vector_free(&t->sprites.city.worked_tile_overlay);
6036 sprite_vector_iterate(&t->sprites.city.unworked_tile_overlay, psprite) {
6037 free_sprite(*psprite);
6038 } sprite_vector_iterate_end;
6039 sprite_vector_free(&t->sprites.city.unworked_tile_overlay);
6041 if (t->sprites.tx.fullfog) {
6042 free(t->sprites.tx.fullfog);
6043 t->sprites.tx.fullfog = NULL;
6046 sprite_vector_free(&t->sprites.colors.overlays);
6047 sprite_vector_free(&t->sprites.explode.unit);
6048 sprite_vector_free(&t->sprites.nation_flag);
6049 sprite_vector_free(&t->sprites.nation_shield);
6050 sprite_vector_free(&t->sprites.citybar.occupancy);
6052 tileset_background_free(t);
6055 /**************************************************************************
6056 Return the sprite for drawing the given spaceship part.
6057 **************************************************************************/
6058 struct sprite *get_spaceship_sprite(const struct tileset *t,
6059 enum spaceship_part part)
6061 return t->sprites.spaceship[part];
6064 /**************************************************************************
6065 Return a sprite for the given citizen. The citizen's type is given,
6066 as well as their index (in the range [0..city_size_get(pcity))). The
6067 citizen's city can be used to determine which sprite to use (a NULL
6068 value indicates there is no city; i.e., the sprite is just being
6069 used as a picture).
6070 **************************************************************************/
6071 struct sprite *get_citizen_sprite(const struct tileset *t,
6072 enum citizen_category type,
6073 int citizen_index,
6074 const struct city *pcity)
6076 const struct citizen_graphic *graphic;
6077 int gfx_index = citizen_index;
6079 if (pcity != NULL) {
6080 gfx_index += pcity->client.first_citizen_index;
6083 if (type < CITIZEN_SPECIALIST) {
6084 fc_assert(type >= 0);
6085 graphic = &t->sprites.citizen[type];
6086 } else {
6087 fc_assert(type < (CITIZEN_SPECIALIST + SP_MAX));
6088 graphic = &t->sprites.specialist[type - CITIZEN_SPECIALIST];
6091 if (graphic->count == 0) {
6092 return NULL;
6095 return graphic->sprite[gfx_index % graphic->count];
6098 /**************************************************************************
6099 Return the sprite for the nation.
6100 **************************************************************************/
6101 struct sprite *get_nation_flag_sprite(const struct tileset *t,
6102 const struct nation_type *pnation)
6104 return t->sprites.nation_flag.p[nation_index(pnation)];
6107 /**************************************************************************
6108 Return the shield sprite for the nation.
6109 **************************************************************************/
6110 struct sprite *get_nation_shield_sprite(const struct tileset *t,
6111 const struct nation_type *pnation)
6113 return t->sprites.nation_shield.p[nation_index(pnation)];
6116 /**************************************************************************
6117 Return the sprite for the technology/advance.
6118 **************************************************************************/
6119 struct sprite *get_tech_sprite(const struct tileset *t, Tech_type_id tech)
6121 fc_assert_ret_val(0 <= tech && tech < advance_count(), NULL);
6122 return t->sprites.tech[tech];
6125 /**************************************************************************
6126 Return the sprite for the building/improvement.
6127 **************************************************************************/
6128 struct sprite *get_building_sprite(const struct tileset *t,
6129 struct impr_type *pimprove)
6131 fc_assert_ret_val(NULL != pimprove, NULL);
6132 return t->sprites.building[improvement_index(pimprove)];
6135 /****************************************************************************
6136 Return the sprite for the government.
6137 ****************************************************************************/
6138 struct sprite *get_government_sprite(const struct tileset *t,
6139 const struct government *gov)
6141 fc_assert_ret_val(NULL != gov, NULL);
6142 return t->sprites.government[government_index(gov)];
6145 /****************************************************************************
6146 Return the sprite for the unit type (the base "unit" sprite).
6147 ****************************************************************************/
6148 struct sprite *get_unittype_sprite(const struct tileset *t,
6149 const struct unit_type *punittype,
6150 enum direction8 facing,
6151 bool icon)
6153 int uidx = utype_index(punittype);
6155 fc_assert_ret_val(NULL != punittype, NULL);
6157 if (!direction8_is_valid(facing) || !is_valid_dir(facing)) {
6158 /* Fallback to random orientation sprite.
6159 * The randomness was fixed at tileset load time for stability
6160 * (in tileset_setup_unit_type_from_tag()); here we need to adapt
6161 * that to the map topology (which is now known).
6162 * default_dir_seed was set to give uniform distribution for either
6163 * 6 or 8 valid directions.
6164 * Thus this direction is stable for a given unit type unless the
6165 * map topology changes. */
6166 unsigned int dir_index;
6168 fc_assert_ret_val(game.map.num_valid_dirs > 0, NULL);
6169 dir_index
6170 = t->sprites.units.default_dir_seed[uidx] % game.map.num_valid_dirs;
6171 facing = game.map.valid_dirs[dir_index];
6172 fc_assert_ret_val(is_valid_dir(facing), NULL);
6175 if (t->sprites.units.icon[uidx]
6176 && (icon || t->sprites.units.facing[uidx][facing] == NULL)) {
6177 /* Has icon sprite */
6178 return t->sprites.units.icon[uidx];
6179 } else {
6180 return t->sprites.units.facing[uidx][facing];
6184 /**************************************************************************
6185 Return a "sample" sprite for this city style.
6186 **************************************************************************/
6187 struct sprite *get_sample_city_sprite(const struct tileset *t,
6188 int style_idx)
6190 int num_thresholds =
6191 t->sprites.city.tile->styles[style_idx].land_num_thresholds;
6193 if (num_thresholds == 0) {
6194 return NULL;
6195 } else {
6196 return (t->sprites.city.tile->styles[style_idx]
6197 .land_thresholds[num_thresholds - 1].sprite);
6201 /**************************************************************************
6202 Return a sprite with an "arrow" theme graphic.
6203 **************************************************************************/
6204 struct sprite *get_arrow_sprite(const struct tileset *t,
6205 enum arrow_type arrow)
6207 fc_assert_ret_val(arrow >= 0 && arrow < ARROW_LAST, NULL);
6209 return t->sprites.arrow[arrow];
6212 /**************************************************************************
6213 Return a tax sprite for the given output type (usually gold/lux/sci).
6214 **************************************************************************/
6215 struct sprite *get_tax_sprite(const struct tileset *t, Output_type_id otype)
6217 switch (otype) {
6218 case O_SCIENCE:
6219 return t->sprites.tax_science;
6220 case O_GOLD:
6221 return t->sprites.tax_gold;
6222 case O_LUXURY:
6223 return t->sprites.tax_luxury;
6224 case O_TRADE:
6225 case O_FOOD:
6226 case O_SHIELD:
6227 case O_LAST:
6228 break;
6230 return NULL;
6233 /**************************************************************************
6234 Return event icon sprite
6235 **************************************************************************/
6236 struct sprite *get_event_sprite(const struct tileset *t, enum event_type event)
6238 return t->sprites.events[event];
6241 /**************************************************************************
6242 Return a thumbs-up/thumbs-down sprite to show treaty approval or
6243 disapproval.
6244 **************************************************************************/
6245 struct sprite *get_treaty_thumb_sprite(const struct tileset *t, bool on_off)
6247 return t->sprites.treaty_thumb[on_off ? 1 : 0];
6250 /**************************************************************************
6251 Return a sprite_vector containing the animation sprites for a unit
6252 explosion.
6253 **************************************************************************/
6254 const struct sprite_vector *get_unit_explode_animation(const struct
6255 tileset *t)
6257 return &t->sprites.explode.unit;
6260 /****************************************************************************
6261 Return a sprite contining the single nuke graphic.
6263 TODO: This should be an animation like the unit explode animation.
6264 ****************************************************************************/
6265 struct sprite *get_nuke_explode_sprite(const struct tileset *t)
6267 return t->sprites.explode.nuke;
6270 /**************************************************************************
6271 Return all the sprites used for city bar drawing.
6272 **************************************************************************/
6273 const struct citybar_sprites *get_citybar_sprites(const struct tileset *t)
6275 if (gui_options.draw_full_citybar) {
6276 return &t->sprites.citybar;
6277 } else {
6278 return NULL;
6282 /**************************************************************************
6283 Return all the sprites used for editor icons, images, etc.
6284 **************************************************************************/
6285 const struct editor_sprites *get_editor_sprites(const struct tileset *t)
6287 return &t->sprites.editor;
6290 /**************************************************************************
6291 Returns a sprite for the given cursor. The "hot" coordinates (the
6292 active coordinates of the mouse relative to the sprite) are placed int
6293 (*hot_x, *hot_y).
6294 A cursor can consist of several frames to be used for animation.
6295 **************************************************************************/
6296 struct sprite *get_cursor_sprite(const struct tileset *t,
6297 enum cursor_type cursor,
6298 int *hot_x, int *hot_y, int frame)
6300 *hot_x = t->sprites.cursor[cursor].hot_x;
6301 *hot_y = t->sprites.cursor[cursor].hot_y;
6302 return t->sprites.cursor[cursor].frame[frame];
6305 /****************************************************************************
6306 Return a sprite for the given icon. Icons are used by the operating
6307 system/window manager. Usually freeciv has to tell the OS what icon to
6308 use.
6310 Note that this function will return NULL before the sprites are loaded.
6311 The GUI code must be sure to call tileset_load_tiles before setting the
6312 top-level icon.
6313 ****************************************************************************/
6314 struct sprite *get_icon_sprite(const struct tileset *t, enum icon_type icon)
6316 return t->sprites.icon[icon];
6319 /****************************************************************************
6320 Returns a sprite with the "user-attention" crosshair graphic.
6322 FIXME: This function shouldn't be needed if the attention graphics are
6323 drawn natively by the tileset code.
6324 ****************************************************************************/
6325 struct sprite *get_attention_crosshair_sprite(const struct tileset *t)
6327 return t->sprites.user.attention;
6330 /****************************************************************************
6331 Returns a sprite for the given indicator with the given index. The
6332 index should be in [0, NUM_TILES_PROGRESS).
6333 ****************************************************************************/
6334 struct sprite *get_indicator_sprite(const struct tileset *t,
6335 enum indicator_type indicator,
6336 int idx)
6338 idx = CLIP(0, idx, NUM_TILES_PROGRESS - 1);
6340 fc_assert_ret_val(indicator >= 0 && indicator < INDICATOR_COUNT, NULL);
6342 return t->sprites.indicator[indicator][idx];
6345 /****************************************************************************
6346 Return a sprite for the unhappiness of the unit - to be shown as an
6347 overlay on the unit in the city support dialog, for instance.
6349 May return NULL if there's no unhappiness.
6350 ****************************************************************************/
6351 struct sprite *get_unit_unhappy_sprite(const struct tileset *t,
6352 const struct unit *punit,
6353 int happy_cost)
6355 const int unhappy = CLIP(0, happy_cost, MAX_NUM_UPKEEP_SPRITES+1);
6357 if (unhappy > 0) {
6358 return t->sprites.upkeep.unhappy[unhappy - 1];
6359 } else {
6360 return NULL;
6364 /****************************************************************************
6365 Return a sprite for the upkeep of the unit - to be shown as an overlay
6366 on the unit in the city support dialog, for instance.
6368 May return NULL if there's no upkeep of the kind.
6369 ****************************************************************************/
6370 struct sprite *get_unit_upkeep_sprite(const struct tileset *t,
6371 Output_type_id otype,
6372 const struct unit *punit,
6373 const int *upkeep_cost)
6375 const int upkeep = CLIP(0, upkeep_cost[otype], MAX_NUM_UPKEEP_SPRITES + 1);
6377 if (upkeep > 0) {
6378 return t->sprites.upkeep.output[otype][upkeep - 1];
6379 } else {
6380 return NULL;
6384 /****************************************************************************
6385 Return a rectangular sprite containing a fog "color". This can be used
6386 for drawing fog onto arbitrary areas (like the overview).
6387 ****************************************************************************/
6388 struct sprite *get_basic_fog_sprite(const struct tileset *t)
6390 return t->sprites.tx.fog;
6393 /****************************************************************************
6394 Return the tileset's color system.
6395 ****************************************************************************/
6396 struct color_system *get_color_system(const struct tileset *t)
6398 return t->color_system;
6401 /****************************************************************************
6402 Loads preferred theme if there's any.
6403 ****************************************************************************/
6404 void tileset_use_preferred_theme(const struct tileset *t)
6406 char *default_theme_name = NULL;
6407 size_t default_theme_name_sz = 0;
6408 int i;
6410 switch (get_gui_type()) {
6411 case GUI_GTK2:
6412 default_theme_name = gui_options.gui_gtk2_default_theme_name;
6413 default_theme_name_sz = sizeof(gui_options.gui_gtk2_default_theme_name);
6414 break;
6415 case GUI_GTK3:
6416 default_theme_name = gui_options.gui_gtk3_default_theme_name;
6417 default_theme_name_sz = sizeof(gui_options.gui_gtk3_default_theme_name);
6418 break;
6419 case GUI_GTK3_22:
6420 default_theme_name = gui_options.gui_gtk3_22_default_theme_name;
6421 default_theme_name_sz = sizeof(gui_options.gui_gtk3_22_default_theme_name);
6422 break;
6423 case GUI_SDL:
6424 default_theme_name = gui_options.gui_sdl_default_theme_name;
6425 default_theme_name_sz = sizeof(gui_options.gui_sdl_default_theme_name);
6426 break;
6427 case GUI_SDL2:
6428 default_theme_name = gui_options.gui_sdl2_default_theme_name;
6429 default_theme_name_sz = sizeof(gui_options.gui_sdl2_default_theme_name);
6430 break;
6431 case GUI_STUB:
6432 case GUI_XAW:
6433 case GUI_QT:
6434 case GUI_WEB:
6435 break;
6438 if (NULL == default_theme_name || 0 == default_theme_name_sz) {
6439 /* Theme is not supported by this client. */
6440 return;
6443 for (i = 0; i < t->num_preferred_themes; i++) {
6444 if (strcmp(t->preferred_themes[i], default_theme_name)) {
6445 if (popup_theme_suggestion_dialog(t->preferred_themes[i])) {
6446 log_debug("trying theme \"%s\".", t->preferred_themes[i]);
6447 if (load_theme(t->preferred_themes[i])) {
6448 (void) fc_strlcpy(default_theme_name, t->preferred_themes[i],
6449 default_theme_name_sz);
6450 return;
6455 log_verbose("The tileset doesn't specify preferred themes or none of its "
6456 "preferred themes can be used. Using system default.");
6457 gui_clear_theme();
6460 /****************************************************************************
6461 Initialize tileset structure
6462 ****************************************************************************/
6463 void tileset_init(struct tileset *t)
6465 int wi;
6467 /* We currently have no city sprites loaded. */
6468 t->sprites.city.tile = NULL;
6470 for (wi = 0; wi < NUM_WALL_TYPES; wi++) {
6471 t->sprites.city.wall[wi] = NULL;
6473 t->sprites.city.single_wall = NULL;
6475 t->sprites.city.occupied = NULL;
6477 t->sprites.background.color = NULL;
6478 t->sprites.background.graphic = NULL;
6480 player_slots_iterate(pslot) {
6481 int edge, j, id = player_slot_index(pslot);
6483 for (edge = 0; edge < EDGE_COUNT; edge++) {
6484 for (j = 0; j < 2; j++) {
6485 t->sprites.player[id].grid_borders[edge][j] = NULL;
6489 t->sprites.player[id].color = NULL;
6490 t->sprites.player[id].background = NULL;
6491 } player_slots_iterate_end;
6493 t->max_upkeep_height = 0;
6496 /****************************************************************************
6497 Fill the sprite array with sprites that together make a representative
6498 image of the given terrain type. Suitable for use as an icon and in list
6499 views.
6501 NB: The 'layer' argument is NOT a LAYER_* value, but rather one of 0, 1, 2.
6502 Using other values for 'layer' here will result in undefined behaviour. ;)
6503 ****************************************************************************/
6504 int fill_basic_terrain_layer_sprite_array(struct tileset *t,
6505 struct drawn_sprite *sprs,
6506 int layer,
6507 struct terrain *pterrain)
6509 struct drawn_sprite *save_sprs = sprs;
6510 struct drawing_data *draw = t->sprites.drawing[terrain_index(pterrain)];
6512 struct terrain *tterrain_near[8];
6513 bv_special tspecial_near[8];
6515 struct tile dummy_tile; /* :( */
6517 int i;
6520 memset(&dummy_tile, 0, sizeof(struct tile));
6522 for (i = 0; i < 8; i++) {
6523 tterrain_near[i] = pterrain;
6524 BV_CLR_ALL(tspecial_near[i]);
6527 i = draw->is_reversed ? draw->num_layers - layer - 1 : layer;
6528 sprs += fill_terrain_sprite_array(t, sprs, i, &dummy_tile,
6529 pterrain, tterrain_near, draw);
6531 return sprs - save_sprs;
6534 /****************************************************************************
6535 Return the sprite for the given resource type.
6536 ****************************************************************************/
6537 struct sprite *get_resource_sprite(const struct tileset *t,
6538 const struct resource *presource)
6540 if (presource == NULL) {
6541 return NULL;
6544 return t->sprites.resource[resource_index(presource)];
6547 /****************************************************************************
6548 Return a representative sprite for the given extra type.
6549 ****************************************************************************/
6550 int fill_basic_extra_sprite_array(const struct tileset *t,
6551 struct drawn_sprite *sprs,
6552 const struct extra_type *pextra)
6554 int idx = extra_index(pextra);
6555 struct drawn_sprite *saved_sprs = sprs;
6557 switch (t->sprites.extras[idx].extrastyle) {
6558 case ESTYLE_SINGLE1:
6559 case ESTYLE_SINGLE2:
6560 ADD_SPRITE_SIMPLE(t->sprites.extras[idx].u.single);
6561 break;
6562 case ESTYLE_CARDINALS:
6563 ADD_SPRITE_SIMPLE(t->sprites.extras[idx].u.cardinals[0]);
6564 break;
6565 case ESTYLE_ROAD_ALL_SEPARATE:
6566 case ESTYLE_ROAD_PARITY_COMBINED:
6567 case ESTYLE_ROAD_ALL_COMBINED:
6568 case ESTYLE_RIVER:
6569 return fill_basic_road_sprite_array(t, sprs, pextra);
6570 case ESTYLE_3LAYER:
6571 return fill_basic_base_sprite_array(t, sprs, pextra);
6572 case ESTYLE_COUNT:
6573 fc_assert(t->sprites.extras[idx].extrastyle != ESTYLE_COUNT);
6574 break;
6577 return sprs - saved_sprs;
6580 /****************************************************************************
6581 Fills the sprite array with sprites that together make a representative
6582 image of the given road type. The image is suitable for use as an icon
6583 for the road type, for example.
6584 ****************************************************************************/
6585 int fill_basic_road_sprite_array(const struct tileset *t,
6586 struct drawn_sprite *sprs,
6587 const struct extra_type *pextra)
6589 struct drawn_sprite *saved_sprs = sprs;
6590 int idx;
6591 int i;
6592 enum extrastyle_id extrastyle;
6594 if (!t || !sprs || !pextra) {
6595 return 0;
6598 idx = extra_index(pextra);
6600 if (!(0 <= idx && idx < game.control.num_extra_types)) {
6601 return 0;
6604 extrastyle = t->sprites.extras[idx].extrastyle;
6606 if (extrastyle == ESTYLE_RIVER) {
6607 ADD_SPRITE_SIMPLE(t->sprites.extras[idx].u.road.ru.rivers.spec[0]);
6608 } else {
6609 for (i = 0; i < t->num_valid_tileset_dirs; i++) {
6610 if (!t->valid_tileset_dirs[i]) {
6611 continue;
6613 if (extrastyle == ESTYLE_ROAD_ALL_SEPARATE) {
6614 ADD_SPRITE_SIMPLE(t->sprites.extras[idx].u.road.ru.dir[i]);
6615 } else if (extrastyle == ESTYLE_ROAD_PARITY_COMBINED) {
6616 if ((i % 2) == 0) {
6617 ADD_SPRITE_SIMPLE(t->sprites.extras[idx].u.road.ru.combo.even[1 << (i / 2)]);
6619 } else if (extrastyle == ESTYLE_ROAD_ALL_COMBINED) {
6620 ADD_SPRITE_SIMPLE(t->sprites.extras[idx].u.road.ru.total[1 << i]);
6625 return sprs - saved_sprs;
6628 /****************************************************************************
6629 Fills the sprite array with sprites that together make a representative
6630 image of the given base type. The image is suitable for use as an icon
6631 for the base type, for example.
6632 ****************************************************************************/
6633 int fill_basic_base_sprite_array(const struct tileset *t,
6634 struct drawn_sprite *sprs,
6635 const struct extra_type *pextra)
6637 struct drawn_sprite *saved_sprs = sprs;
6638 int idx;
6640 if (!t || !sprs || !pextra) {
6641 return 0;
6644 idx = extra_index(pextra);
6646 if (!(0 <= idx && idx < game.control.num_extra_types)) {
6647 return 0;
6650 #define ADD_SPRITE_IF_NOT_NULL(x) do {\
6651 if ((x) != NULL) {\
6652 ADD_SPRITE_FULL(x);\
6654 } while (0)
6656 /* Corresponds to LAYER_SPECIAL{1,2,3} order. */
6657 ADD_SPRITE_IF_NOT_NULL(t->sprites.extras[idx].u.bmf.background);
6658 ADD_SPRITE_IF_NOT_NULL(t->sprites.extras[idx].u.bmf.middleground);
6659 ADD_SPRITE_IF_NOT_NULL(t->sprites.extras[idx].u.bmf.foreground);
6661 #undef ADD_SPRITE_IF_NOT_NULL
6663 return sprs - saved_sprs;
6666 /****************************************************************************
6667 Setup tiles for one player using the player color.
6668 ****************************************************************************/
6669 void tileset_player_init(struct tileset *t, struct player *pplayer)
6671 int plrid, i, j;
6672 struct sprite *color;
6674 fc_assert_ret(pplayer != NULL);
6676 plrid = player_index(pplayer);
6677 fc_assert_ret(plrid >= 0);
6678 fc_assert_ret(plrid < ARRAY_SIZE(t->sprites.player));
6680 /* Free all data before recreating it. */
6681 tileset_player_free(t, plrid);
6683 if (player_has_color(t, pplayer)) {
6684 t->sprites.player[plrid].color = color
6685 = create_plr_sprite(get_player_color(t, pplayer));
6686 } else {
6687 /* XXX: if player hasn't been assigned a color, perhaps there's no
6688 * point proceeding with an arbitrary color; this should only happen
6689 * in pregame. Probably blank sprites would be better. */
6691 fc_assert_ret(t->sprites.background.color != NULL);
6693 color = t->sprites.background.color;
6696 t->sprites.player[plrid].background
6697 = crop_sprite(color, 0, 0,
6698 t->normal_tile_width, t->normal_tile_height,
6699 t->sprites.mask.tile, 0, 0, t->scale, FALSE);
6701 for (i = 0; i < EDGE_COUNT; i++) {
6702 for (j = 0; j < 2; j++) {
6703 struct sprite *s;
6705 if (color && t->sprites.grid.borders[i][j]) {
6706 s = crop_sprite(color, 0, 0,
6707 t->normal_tile_width, t->normal_tile_height,
6708 t->sprites.grid.borders[i][j], 0, 0, 1.0f, FALSE);
6709 } else {
6710 s = t->sprites.grid.borders[i][j];
6712 t->sprites.player[plrid].grid_borders[i][j] = s;
6717 /****************************************************************************
6718 Free tiles for one player using the player color.
6719 ****************************************************************************/
6720 static void tileset_player_free(struct tileset *t, int plrid)
6722 int i, j;
6724 fc_assert_ret(plrid >= 0);
6725 fc_assert_ret(plrid < ARRAY_SIZE(t->sprites.player));
6727 if (t->sprites.player[plrid].color) {
6728 free_sprite(t->sprites.player[plrid].color);
6729 t->sprites.player[plrid].color = NULL;
6731 if (t->sprites.player[plrid].background) {
6732 free_sprite(t->sprites.player[plrid].background);
6733 t->sprites.player[plrid].background = NULL;
6736 for (i = 0; i < EDGE_COUNT; i++) {
6737 for (j = 0; j < 2; j++) {
6738 if (t->sprites.player[plrid].grid_borders[i][j]) {
6739 free_sprite(t->sprites.player[plrid].grid_borders[i][j]);
6740 t->sprites.player[plrid].grid_borders[i][j] = NULL;
6746 /****************************************************************************
6747 Setup tiles for the background.
6748 ****************************************************************************/
6749 void tileset_background_init(struct tileset *t)
6751 /* Free all data before recreating it. */
6752 tileset_background_free(t);
6754 /* generate background color */
6755 t->sprites.background.color
6756 = create_plr_sprite(ensure_color(game.plr_bg_color));
6758 /* Chop up and build the background graphics. */
6759 t->sprites.background.graphic
6760 = crop_sprite(t->sprites.background.color, 0, 0,
6761 t->normal_tile_width, t->normal_tile_height,
6762 t->sprites.mask.tile, 0, 0, t->scale, FALSE);
6765 /****************************************************************************
6766 Free tiles for the background.
6767 ****************************************************************************/
6768 void tileset_background_free(struct tileset *t)
6770 if (t->sprites.background.color) {
6771 free_sprite(t->sprites.background.color);
6772 t->sprites.background.color = NULL;
6775 if (t->sprites.background.graphic) {
6776 free_sprite(t->sprites.background.graphic);
6777 t->sprites.background.graphic = NULL;
6781 /****************************************************************************
6782 Reset tileset data specific to ruleset.
6783 ****************************************************************************/
6784 void tileset_ruleset_reset(struct tileset *t)
6786 int i;
6788 for (i = 0; i < ESTYLE_COUNT; i++) {
6789 if (t->style_lists[i] != NULL) {
6790 extra_type_list_destroy(t->style_lists[i]);
6791 t->style_lists[i] = extra_type_list_new();
6795 if (t->flagged_bases_list != NULL) {
6796 extra_type_list_destroy(t->flagged_bases_list);
6797 t->flagged_bases_list = extra_type_list_new();
6801 /****************************************************************************
6802 Is tileset in sane state?
6803 ****************************************************************************/
6804 bool tileset_is_fully_loaded(void)
6806 return !tileset_update;
6809 /****************************************************************************
6810 Return tileset name
6811 ****************************************************************************/
6812 const char *tileset_name_get(struct tileset *t)
6814 return t->given_name;
6817 /****************************************************************************
6818 Return tileset version
6819 ****************************************************************************/
6820 const char *tileset_version(struct tileset *t)
6822 return t->version;
6825 /****************************************************************************
6826 Return tileset description summary
6827 ****************************************************************************/
6828 const char *tileset_summary(struct tileset *t)
6830 return t->summary;
6833 /****************************************************************************
6834 Return tileset description body
6835 ****************************************************************************/
6836 const char *tileset_description(struct tileset *t)
6838 return t->description;
6841 /****************************************************************************
6842 Return tileset topology index
6843 ****************************************************************************/
6844 int tileset_topo_index(struct tileset *t)
6846 return t->ts_topo_idx;