1 #include "AppHdr.h"
2 
3 #include "tilepick.h"
4 
5 #include "artefact.h"
6 #include "art-enum.h"
7 #include "cloud.h"
8 #include "colour.h"
9 #include "coord.h"
10 #include "coordit.h"
11 #include "describe.h"
12 #include "debug.h"
13 #include "env.h"
14 #include "tile-env.h"
15 #include "files.h"
16 #include "item-name.h"
17 #include "item-prop.h"
18 #include "item-status-flag-type.h"
19 #include "level-state-type.h"
20 #include "libutil.h"
21 #include "mon-death.h"
22 #include "mon-tentacle.h"
23 #include "mon-util.h"
24 #include "options.h"
25 #include "player.h"
26 #include "shopping.h"
27 #include "state.h"
28 #include "stringutil.h"
29 #include "terrain.h"
30 #include "rltiles/tiledef-dngn.h"
31 #include "tile-flags.h"
32 #include "rltiles/tiledef-gui.h"
33 #include "rltiles/tiledef-icons.h"
34 #include "rltiles/tiledef-main.h"
35 #include "rltiles/tiledef-player.h"
36 #include "rltiles/tiledef-unrand.h"
37 #include "tag-version.h"
38 #include "tilemcache.h"
39 #include "tileview.h"
40 #include "transform.h"
41 #include "traps.h"
42 #include "viewgeom.h"
43 
44 // This should not be changed.
45 COMPILE_CHECK(TILE_DNGN_UNSEEN == 0);
46 
47 // NOTE: If one of the following asserts fail, it's because the corresponding
48 // enum in item-prop-enum.h was modified, but rltiles/dc-item.txt was not
49 // modified in parallel.
50 
51 // These brands start with "normal" which there's no tile for, so subtract 1.
52 COMPILE_CHECK(NUM_REAL_SPECIAL_WEAPONS - 1
53               == TILE_BRAND_WEP_LAST - TILE_BRAND_WEP_FIRST + 1);
54 COMPILE_CHECK(NUM_REAL_SPECIAL_ARMOURS - 1
55               == TILE_BRAND_ARM_LAST - TILE_BRAND_ARM_FIRST + 1);
56 
57 COMPILE_CHECK(NUM_RINGS == TILE_RING_ID_LAST - TILE_RING_ID_FIRST + 1);
58 COMPILE_CHECK(NUM_JEWELLERY - AMU_FIRST_AMULET
59               == TILE_AMU_ID_LAST - TILE_AMU_ID_FIRST + 1);
60 COMPILE_CHECK(NUM_SCROLLS == TILE_SCR_ID_LAST - TILE_SCR_ID_FIRST + 1);
61 COMPILE_CHECK(NUM_STAVES == TILE_STAFF_ID_LAST - TILE_STAFF_ID_FIRST + 1);
62 #if TAG_MAJOR_VERSION == 34
63 COMPILE_CHECK(NUM_RODS == TILE_ROD_ID_LAST - TILE_ROD_ID_FIRST + 1);
64 #endif
65 COMPILE_CHECK(NUM_WANDS == TILE_WAND_ID_LAST - TILE_WAND_ID_FIRST + 1);
66 COMPILE_CHECK(NUM_POTIONS == TILE_POT_ID_LAST - TILE_POT_ID_FIRST + 1);
67 
get_tile_texture(tileidx_t idx)68 TextureID get_tile_texture(tileidx_t idx)
69 {
70     if (idx < TILE_FLOOR_MAX)
71         return TEX_FLOOR;
72     else if (idx < TILE_WALL_MAX)
73         return TEX_WALL;
74     else if (idx < TILE_FEAT_MAX)
75         return TEX_FEAT;
76     else if (idx < TILE_MAIN_MAX)
77         return TEX_DEFAULT;
78     else if (idx < TILEP_PLAYER_MAX)
79         return TEX_PLAYER;
80     else if (idx < TILEG_GUI_MAX)
81         return TEX_GUI;
82     else if (idx < TILEI_ICONS_MAX)
83         return TEX_ICONS;
84     else
85         die("Cannot get texture for bad tileidx %" PRIu64, idx);
86 }
87 
tileidx_trap(trap_type type)88 tileidx_t tileidx_trap(trap_type type)
89 {
90     switch (type)
91     {
92     case TRAP_ARROW:
93         return TILE_DNGN_TRAP_ARROW;
94     case TRAP_SPEAR:
95         return TILE_DNGN_TRAP_SPEAR;
96     case TRAP_DISPERSAL:
97         return TILE_DNGN_TRAP_DISPERSAL;
98     case TRAP_TELEPORT:
99         return TILE_DNGN_TRAP_TELEPORT;
100     case TRAP_TELEPORT_PERMANENT:
101         return TILE_DNGN_TRAP_TELEPORT_PERMANENT;
102     case TRAP_ALARM:
103         return TILE_DNGN_TRAP_ALARM;
104     case TRAP_BLADE:
105         return TILE_DNGN_TRAP_BLADE;
106     case TRAP_BOLT:
107         return TILE_DNGN_TRAP_BOLT;
108     case TRAP_NET:
109         return TILE_DNGN_TRAP_NET;
110     case TRAP_ZOT:
111         return TILE_DNGN_TRAP_ZOT;
112     case TRAP_DART:
113         return TILE_DNGN_TRAP_DART;
114     case TRAP_SHAFT:
115         return TILE_DNGN_TRAP_SHAFT;
116     case TRAP_GOLUBRIA:
117         return TILE_DNGN_TRAP_GOLUBRIA;
118     case TRAP_PLATE:
119         return TILE_DNGN_TRAP_PLATE;
120     case TRAP_WEB:
121         return TILE_DNGN_TRAP_WEB;
122     default:
123         return TILE_DNGN_ERROR;
124     }
125 }
126 
tileidx_shop(const shop_struct * shop)127 tileidx_t tileidx_shop(const shop_struct *shop)
128 {
129     if (!shop)
130         return TILE_DNGN_ERROR;
131 
132     switch (shop->type)
133     {
134         case SHOP_WEAPON:
135         case SHOP_WEAPON_ANTIQUE:
136             return TILE_SHOP_WEAPONS;
137         case SHOP_ARMOUR:
138         case SHOP_ARMOUR_ANTIQUE:
139             return TILE_SHOP_ARMOUR;
140         case SHOP_JEWELLERY:
141             return TILE_SHOP_JEWELLERY;
142 #if TAG_MAJOR_VERSION == 34
143         case SHOP_EVOKABLES:
144             return TILE_SHOP_GADGETS;
145         case SHOP_FOOD:
146             return TILE_SHOP_FOOD;
147 #endif
148         case SHOP_BOOK:
149             return TILE_SHOP_BOOKS;
150         case SHOP_SCROLL:
151             return TILE_SHOP_SCROLLS;
152         case SHOP_DISTILLERY:
153             return TILE_SHOP_POTIONS;
154         case SHOP_GENERAL:
155         case SHOP_GENERAL_ANTIQUE:
156             return TILE_SHOP_GENERAL;
157         default:
158             return TILE_DNGN_ERROR;
159     }
160 }
161 
tileidx_feature_base(dungeon_feature_type feat)162 tileidx_t tileidx_feature_base(dungeon_feature_type feat)
163 {
164     switch (feat)
165     {
166     case DNGN_UNSEEN:
167         return TILE_DNGN_UNSEEN;
168     case DNGN_ROCK_WALL:
169         return TILE_WALL_NORMAL;
170     case DNGN_PERMAROCK_WALL:
171         return TILE_WALL_PERMAROCK;
172     case DNGN_SLIMY_WALL:
173         return TILE_WALL_SLIME;
174     case DNGN_RUNED_DOOR:
175         return TILE_DNGN_RUNED_DOOR;
176     case DNGN_RUNED_CLEAR_DOOR:
177         return TILE_DNGN_RUNED_CLEAR_DOOR;
178     case DNGN_SEALED_DOOR:
179         return TILE_DNGN_SEALED_DOOR;
180     case DNGN_SEALED_CLEAR_DOOR:
181         return TILE_DNGN_SEALED_CLEAR_DOOR;
182     case DNGN_GRATE:
183         return TILE_DNGN_GRATE;
184     case DNGN_CLEAR_ROCK_WALL:
185         return TILE_DNGN_TRANSPARENT_WALL;
186     case DNGN_CLEAR_STONE_WALL:
187         return TILE_DNGN_TRANSPARENT_STONE;
188     case DNGN_CLEAR_PERMAROCK_WALL:
189         return TILE_WALL_PERMAROCK_CLEAR;
190     case DNGN_STONE_WALL:
191         return TILE_DNGN_STONE_WALL;
192     case DNGN_CLOSED_DOOR:
193         return TILE_DNGN_CLOSED_DOOR;
194     case DNGN_CLOSED_CLEAR_DOOR:
195         return TILE_DNGN_CLOSED_CLEAR_DOOR;
196     case DNGN_METAL_WALL:
197         return TILE_DNGN_METAL_WALL;
198     case DNGN_CRYSTAL_WALL:
199         return TILE_DNGN_CRYSTAL_WALL;
200     case DNGN_ORCISH_IDOL:
201         return TILE_DNGN_ORCISH_IDOL;
202     case DNGN_TREE:
203         return TILE_DNGN_TREE;
204     case DNGN_MANGROVE:
205         return TILE_DNGN_MANGROVE;
206     case DNGN_PETRIFIED_TREE:
207         return TILE_DNGN_PETRIFIED_TREE;
208     case DNGN_DEMONIC_TREE:
209         return TILE_DNGN_DEMONIC_TREE;
210     case DNGN_GRANITE_STATUE:
211         return TILE_DNGN_GRANITE_STATUE;
212     case DNGN_LAVA:
213         return TILE_DNGN_LAVA;
214     case DNGN_LAVA_SEA:
215         return TILE_DNGN_LAVA_SEA;
216     case DNGN_DEEP_WATER:
217         return TILE_DNGN_DEEP_WATER;
218     case DNGN_SHALLOW_WATER:
219         return TILE_DNGN_SHALLOW_WATER;
220     case DNGN_OPEN_SEA:
221         return TILE_DNGN_OPEN_SEA;
222     case DNGN_TOXIC_BOG:
223         return TILE_DNGN_TOXIC_BOG;
224     case DNGN_FLOOR:
225         return TILE_FLOOR_NORMAL;
226     case DNGN_ENDLESS_SALT:
227         return TILE_DNGN_ENDLESS_SALT;
228     case DNGN_ENTER_HELL:
229         if (player_in_hell())
230             return TILE_DNGN_RETURN_VESTIBULE;
231         return TILE_DNGN_ENTER_HELL;
232     case DNGN_OPEN_DOOR:
233         return TILE_DNGN_OPEN_DOOR;
234     case DNGN_OPEN_CLEAR_DOOR:
235         return TILE_DNGN_OPEN_CLEAR_DOOR;
236 #if TAG_MAJOR_VERSION == 34
237     case DNGN_TRAP_MECHANICAL:
238         return TILE_DNGN_TRAP_ARROW;
239 #endif
240     case DNGN_TRAP_ARROW:
241         return TILE_DNGN_TRAP_ARROW;
242     case DNGN_TRAP_SPEAR:
243         return TILE_DNGN_TRAP_SPEAR;
244     case DNGN_TRAP_BLADE:
245         return TILE_DNGN_TRAP_BLADE;
246     case DNGN_TRAP_DART:
247         return TILE_DNGN_TRAP_DART;
248     case DNGN_TRAP_BOLT:
249         return TILE_DNGN_TRAP_BOLT;
250     case DNGN_TRAP_NET:
251         return TILE_DNGN_TRAP_NET;
252     case DNGN_TRAP_PLATE:
253         return TILE_DNGN_TRAP_PLATE;
254     case DNGN_TRAP_DISPERSAL:
255         return TILE_DNGN_TRAP_DISPERSAL;
256     case DNGN_TRAP_TELEPORT:
257         return TILE_DNGN_TRAP_TELEPORT;
258     case DNGN_TRAP_TELEPORT_PERMANENT:
259         return TILE_DNGN_TRAP_TELEPORT_PERMANENT;
260     case DNGN_TRAP_ALARM:
261         return TILE_DNGN_TRAP_ALARM;
262     case DNGN_TRAP_ZOT:
263         return TILE_DNGN_TRAP_ZOT;
264     case DNGN_TRAP_SHAFT:
265         return TILE_DNGN_TRAP_SHAFT;
266     case DNGN_TRAP_WEB:
267         return TILE_DNGN_TRAP_WEB;
268 #if TAG_MAJOR_VERSION == 34
269     case DNGN_TELEPORTER:
270         return TILE_DNGN_TRAP_GOLUBRIA;
271 #endif
272     case DNGN_TRANSPORTER:
273         return TILE_DNGN_TRANSPORTER;
274     case DNGN_TRANSPORTER_LANDING:
275         return TILE_DNGN_TRANSPORTER_LANDING;
276     case DNGN_ENTER_SHOP:
277         return TILE_SHOP_GENERAL;
278     case DNGN_ABANDONED_SHOP:
279         return TILE_DNGN_ABANDONED_SHOP;
280     case DNGN_ENTER_GAUNTLET:
281         return TILE_DNGN_PORTAL_GAUNTLET;
282     case DNGN_STONE_STAIRS_DOWN_I:
283     case DNGN_STONE_STAIRS_DOWN_II:
284     case DNGN_STONE_STAIRS_DOWN_III:
285         return TILE_DNGN_STONE_STAIRS_DOWN;
286     case DNGN_ESCAPE_HATCH_DOWN:
287         return TILE_DNGN_ESCAPE_HATCH_DOWN;
288     case DNGN_SEALED_STAIRS_DOWN:
289         return TILE_DNGN_SEALED_STAIRS_DOWN;
290     case DNGN_STONE_STAIRS_UP_I:
291     case DNGN_STONE_STAIRS_UP_II:
292     case DNGN_STONE_STAIRS_UP_III:
293         return TILE_DNGN_STONE_STAIRS_UP;
294     case DNGN_EXIT_GAUNTLET:
295     case DNGN_ESCAPE_HATCH_UP:
296         return TILE_DNGN_ESCAPE_HATCH_UP;
297     case DNGN_SEALED_STAIRS_UP:
298         return TILE_DNGN_SEALED_STAIRS_UP;
299     case DNGN_EXIT_DUNGEON:
300         return TILE_DNGN_EXIT_DUNGEON;
301     case DNGN_ENTER_DIS:
302         return TILE_DNGN_ENTER_DIS;
303     case DNGN_ENTER_GEHENNA:
304         return TILE_DNGN_ENTER_GEHENNA;
305     case DNGN_ENTER_COCYTUS:
306         return TILE_DNGN_ENTER_COCYTUS;
307     case DNGN_ENTER_TARTARUS:
308         return TILE_DNGN_ENTER_TARTARUS;
309     case DNGN_ENTER_ABYSS:
310     case DNGN_EXIT_THROUGH_ABYSS:
311         return TILE_DNGN_ENTER_ABYSS;
312     case DNGN_ABYSSAL_STAIR:
313         return TILE_DNGN_ABYSSAL_STAIR;
314     case DNGN_EXIT_HELL:
315         return TILE_DNGN_RETURN_HELL;
316     case DNGN_EXIT_ABYSS:
317         return TILE_DNGN_EXIT_ABYSS;
318     case DNGN_STONE_ARCH:
319         if (player_in_branch(BRANCH_VESTIBULE))
320             return TILE_DNGN_STONE_ARCH_HELL;
321         return TILE_DNGN_STONE_ARCH;
322     case DNGN_ENTER_PANDEMONIUM:
323         return TILE_DNGN_ENTER_PANDEMONIUM;
324     case DNGN_TRANSIT_PANDEMONIUM:
325         return TILE_DNGN_TRANSIT_PANDEMONIUM;
326     case DNGN_EXIT_PANDEMONIUM:
327         return TILE_DNGN_EXIT_PANDEMONIUM;
328 
329     // branch entry stairs
330 #if TAG_MAJOR_VERSION == 34
331     case DNGN_ENTER_DWARF:
332     case DNGN_ENTER_FOREST:
333     case DNGN_ENTER_BLADE:
334         return TILE_DNGN_ENTER;
335 #endif
336     case DNGN_ENTER_TEMPLE:
337         return TILE_DNGN_ENTER_TEMPLE;
338     case DNGN_ENTER_ORC:
339         return TILE_DNGN_ENTER_ORC;
340     case DNGN_ENTER_ELF:
341         return TILE_DNGN_ENTER_ELF;
342     case DNGN_ENTER_LAIR:
343         return TILE_DNGN_ENTER_LAIR;
344     case DNGN_ENTER_SNAKE:
345         return TILE_DNGN_ENTER_SNAKE;
346     case DNGN_ENTER_SWAMP:
347         return TILE_DNGN_ENTER_SWAMP;
348     case DNGN_ENTER_SPIDER:
349         return TILE_DNGN_ENTER_SPIDER;
350     case DNGN_ENTER_SHOALS:
351         return TILE_DNGN_ENTER_SHOALS;
352     case DNGN_ENTER_SLIME:
353         return TILE_DNGN_ENTER_SLIME;
354     case DNGN_ENTER_DEPTHS:
355         return TILE_DNGN_ENTER_DEPTHS;
356     case DNGN_ENTER_VAULTS:
357         return you.level_visited(level_id(BRANCH_VAULTS, 1)) ? TILE_DNGN_ENTER_VAULTS_OPEN
358                               : TILE_DNGN_ENTER_VAULTS_CLOSED;
359     case DNGN_ENTER_CRYPT:
360         return TILE_DNGN_ENTER_CRYPT;
361     case DNGN_ENTER_TOMB:
362         return TILE_DNGN_ENTER_TOMB;
363     case DNGN_ENTER_ZOT:
364         return you.level_visited(level_id(BRANCH_ZOT, 1)) ? TILE_DNGN_ENTER_ZOT_OPEN
365                               : TILE_DNGN_ENTER_ZOT_CLOSED;
366     case DNGN_ENTER_ZIGGURAT:
367         return TILE_DNGN_PORTAL_ZIGGURAT;
368     case DNGN_ENTER_BAZAAR:
369         return TILE_DNGN_PORTAL_BAZAAR;
370     case DNGN_ENTER_TROVE:
371         return TILE_DNGN_PORTAL_TROVE;
372     case DNGN_ENTER_SEWER:
373         return TILE_DNGN_PORTAL_SEWER;
374     case DNGN_ENTER_OSSUARY:
375         return TILE_DNGN_PORTAL_OSSUARY;
376     case DNGN_ENTER_BAILEY:
377         return TILE_DNGN_PORTAL_BAILEY;
378     case DNGN_ENTER_ICE_CAVE:
379         return TILE_DNGN_PORTAL_ICE_CAVE;
380     case DNGN_ENTER_VOLCANO:
381         return TILE_DNGN_PORTAL_VOLCANO;
382     case DNGN_ENTER_WIZLAB:
383         return TILE_DNGN_PORTAL_WIZARD_LAB;
384     case DNGN_ENTER_DESOLATION:
385         return TILE_DNGN_PORTAL_DESOLATION;
386 
387     // branch exit stairs
388 #if TAG_MAJOR_VERSION == 34
389     case DNGN_EXIT_DWARF:
390     case DNGN_EXIT_FOREST:
391     case DNGN_EXIT_BLADE:
392         return TILE_DNGN_RETURN;
393 #endif
394     case DNGN_EXIT_TEMPLE:
395         return TILE_DNGN_EXIT_TEMPLE;
396     case DNGN_EXIT_ORC:
397         return TILE_DNGN_EXIT_ORC;
398     case DNGN_EXIT_ELF:
399         return TILE_DNGN_EXIT_ELF;
400     case DNGN_EXIT_LAIR:
401         return TILE_DNGN_EXIT_LAIR;
402     case DNGN_EXIT_SNAKE:
403         return TILE_DNGN_EXIT_SNAKE;
404     case DNGN_EXIT_SWAMP:
405         return TILE_DNGN_EXIT_SWAMP;
406     case DNGN_EXIT_SPIDER:
407         return TILE_DNGN_EXIT_SPIDER;
408     case DNGN_EXIT_SHOALS:
409         return TILE_DNGN_EXIT_SHOALS;
410     case DNGN_EXIT_SLIME:
411         return TILE_DNGN_EXIT_SLIME;
412     case DNGN_EXIT_DEPTHS:
413         return TILE_DNGN_RETURN_DEPTHS;
414     case DNGN_EXIT_VAULTS:
415         return TILE_DNGN_EXIT_VAULTS;
416     case DNGN_EXIT_CRYPT:
417         return TILE_DNGN_EXIT_CRYPT;
418     case DNGN_EXIT_TOMB:
419         return TILE_DNGN_EXIT_TOMB;
420     case DNGN_EXIT_ZOT:
421         return TILE_DNGN_RETURN_ZOT;
422 
423     case DNGN_EXIT_ZIGGURAT:
424     case DNGN_EXIT_BAZAAR:
425     case DNGN_EXIT_TROVE:
426     case DNGN_EXIT_SEWER:
427     case DNGN_EXIT_OSSUARY:
428     case DNGN_EXIT_BAILEY:
429     case DNGN_EXIT_DESOLATION:
430         return TILE_DNGN_PORTAL;
431     case DNGN_EXIT_ICE_CAVE:
432         return TILE_DNGN_PORTAL_ICE_CAVE;
433     case DNGN_EXIT_VOLCANO:
434         return TILE_DNGN_EXIT_VOLCANO;
435     case DNGN_EXIT_WIZLAB:
436         return TILE_DNGN_PORTAL_WIZARD_LAB;
437 
438 #if TAG_MAJOR_VERSION == 34
439     case DNGN_ENTER_PORTAL_VAULT:
440     case DNGN_EXIT_PORTAL_VAULT:
441         return TILE_DNGN_PORTAL;
442 #endif
443     case DNGN_EXPIRED_PORTAL:
444         return TILE_DNGN_PORTAL_EXPIRED;
445     case DNGN_MALIGN_GATEWAY:
446         return TILE_DNGN_STARRY_PORTAL;
447 
448     // altars
449     case DNGN_ALTAR_ZIN:
450         return TILE_DNGN_ALTAR_ZIN;
451     case DNGN_ALTAR_SHINING_ONE:
452         return TILE_DNGN_ALTAR_SHINING_ONE;
453     case DNGN_ALTAR_KIKUBAAQUDGHA:
454         return TILE_DNGN_ALTAR_KIKUBAAQUDGHA;
455     case DNGN_ALTAR_YREDELEMNUL:
456         return TILE_DNGN_ALTAR_YREDELEMNUL;
457     case DNGN_ALTAR_XOM:
458         return TILE_DNGN_ALTAR_XOM;
459     case DNGN_ALTAR_VEHUMET:
460         return TILE_DNGN_ALTAR_VEHUMET;
461     case DNGN_ALTAR_OKAWARU:
462         return TILE_DNGN_ALTAR_OKAWARU;
463     case DNGN_ALTAR_MAKHLEB:
464         return TILE_DNGN_ALTAR_MAKHLEB;
465     case DNGN_ALTAR_SIF_MUNA:
466         return TILE_DNGN_ALTAR_SIF_MUNA;
467     case DNGN_ALTAR_TROG:
468         return TILE_DNGN_ALTAR_TROG;
469     case DNGN_ALTAR_NEMELEX_XOBEH:
470         return TILE_DNGN_ALTAR_NEMELEX_XOBEH;
471     case DNGN_ALTAR_ELYVILON:
472         return TILE_DNGN_ALTAR_ELYVILON;
473     case DNGN_ALTAR_LUGONU:
474         return TILE_DNGN_ALTAR_LUGONU;
475     case DNGN_ALTAR_BEOGH:
476         return TILE_DNGN_ALTAR_BEOGH;
477     case DNGN_ALTAR_JIYVA:
478         return TILE_DNGN_ALTAR_JIYVA;
479     case DNGN_ALTAR_FEDHAS:
480         return TILE_DNGN_ALTAR_FEDHAS;
481     case DNGN_ALTAR_CHEIBRIADOS:
482         return TILE_DNGN_ALTAR_CHEIBRIADOS;
483     case DNGN_ALTAR_ASHENZARI:
484         return TILE_DNGN_ALTAR_ASHENZARI;
485     case DNGN_ALTAR_DITHMENOS:
486         return TILE_DNGN_ALTAR_DITHMENOS;
487     case DNGN_ALTAR_GOZAG:
488         return TILE_DNGN_ALTAR_GOZAG;
489     case DNGN_ALTAR_QAZLAL:
490         return TILE_DNGN_ALTAR_QAZLAL;
491     case DNGN_ALTAR_RU:
492         return TILE_DNGN_ALTAR_RU;
493 #if TAG_MAJOR_VERSION == 34
494     case DNGN_ALTAR_PAKELLAS:
495         return TILE_DNGN_ALTAR_PAKELLAS;
496 #endif
497     case DNGN_ALTAR_USKAYAW:
498         return TILE_DNGN_ALTAR_USKAYAW;
499     case DNGN_ALTAR_HEPLIAKLQANA:
500         return TILE_DNGN_ALTAR_HEPLIAKLQANA;
501     case DNGN_ALTAR_WU_JIAN:
502         return TILE_DNGN_ALTAR_WU_JIAN;
503     case DNGN_ALTAR_ECUMENICAL:
504         return TILE_DNGN_ALTAR_ECUMENICAL;
505     case DNGN_FOUNTAIN_BLUE:
506         return TILE_DNGN_BLUE_FOUNTAIN;
507     case DNGN_FOUNTAIN_SPARKLING:
508         return TILE_DNGN_SPARKLING_FOUNTAIN;
509     case DNGN_FOUNTAIN_BLOOD:
510         return TILE_DNGN_BLOOD_FOUNTAIN;
511     case DNGN_DRY_FOUNTAIN:
512         return TILE_DNGN_DRY_FOUNTAIN;
513     case DNGN_PASSAGE_OF_GOLUBRIA:
514         return TILE_DNGN_TRAP_GOLUBRIA;
515     case DNGN_UNKNOWN_ALTAR:
516         return TILE_DNGN_UNKNOWN_ALTAR;
517     case DNGN_UNKNOWN_PORTAL:
518         return TILE_DNGN_UNKNOWN_PORTAL;
519     default:
520         return TILE_DNGN_ERROR;
521     }
522 }
523 
is_door_tile(tileidx_t tile)524 bool is_door_tile(tileidx_t tile)
525 {
526     return tile >= TILE_DNGN_CLOSED_DOOR &&
527         tile < TILE_DNGN_STONE_ARCH;
528 }
529 
tileidx_feature(const coord_def & gc)530 tileidx_t tileidx_feature(const coord_def &gc)
531 {
532     dungeon_feature_type feat = env.map_knowledge(gc).feat();
533 
534     tileidx_t override = tile_env.flv(gc).feat;
535     bool can_override = !feat_is_door(feat)
536                         && feat != DNGN_FLOOR
537                         && feat != DNGN_UNSEEN
538                         && feat != DNGN_PASSAGE_OF_GOLUBRIA
539                         && feat != DNGN_MALIGN_GATEWAY;
540     if (override && can_override)
541         return override;
542 
543     // Any grid-specific tiles.
544     switch (feat)
545     {
546     case DNGN_FLOOR:
547         if (env.level_state & LSTATE_SLIMY_WALL)
548             for (adjacent_iterator ai(gc); ai; ++ai)
549                 if (env.map_knowledge(*ai).feat() == DNGN_SLIMY_WALL)
550                     return TILE_FLOOR_SLIME_ACIDIC;
551 
552         if (env.level_state & LSTATE_ICY_WALL)
553         {
554             for (adjacent_iterator ai(gc); ai; ++ai)
555             {
556                 if (feat_is_wall(env.map_knowledge(*ai).feat())
557                     && env.map_knowledge(*ai).flags & MAP_ICY)
558                 {
559                     return TILE_FLOOR_ICY;
560                 }
561             }
562         }
563         // deliberate fall-through
564     case DNGN_ROCK_WALL:
565     case DNGN_STONE_WALL:
566     case DNGN_CRYSTAL_WALL:
567     case DNGN_PERMAROCK_WALL:
568     case DNGN_CLEAR_PERMAROCK_WALL:
569     {
570         unsigned colour = env.map_knowledge(gc).feat_colour();
571         if (colour == 0)
572         {
573             colour = feat == DNGN_FLOOR     ? env.floor_colour :
574                      feat == DNGN_ROCK_WALL ? env.rock_colour
575                                             : 0; // meh
576         }
577         if (colour >= ETC_FIRST)
578         {
579             tileidx_t idx = (feat == DNGN_FLOOR) ? tile_env.flv(gc).floor :
580                 (feat == DNGN_ROCK_WALL) ? tile_env.flv(gc).wall
581                 : tileidx_feature_base(feat);
582 
583 #ifdef USE_TILE
584             if (feat == DNGN_STONE_WALL)
585                 apply_variations(tile_env.flv(gc), &idx, gc);
586 #endif
587 
588             tileidx_t base = tile_dngn_basetile(idx);
589             tileidx_t spec = idx - base;
590             unsigned rc = real_colour(colour, gc);
591             return tile_dngn_coloured(base, rc) + spec; // XXX
592         }
593         return tileidx_feature_base(feat);
594     }
595 
596 #if TAG_MAJOR_VERSION == 34
597     // New trap-type-specific features are handled in default case.
598     case DNGN_TRAP_MECHANICAL:
599     case DNGN_TRAP_TELEPORT:
600         return tileidx_trap(env.map_knowledge(gc).trap());
601 #endif
602 
603     case DNGN_TRAP_WEB:
604     {
605         /*
606         trap_type this_trap_type = get_trap_type(gc);
607         // There's room here to have different types of webs (acid? fire? ice? different strengths?)
608         if (this_trap_type==TRAP_WEB) {*/
609 
610         // Determine web connectivity on all sides
611         const coord_def neigh[4] =
612         {
613             coord_def(gc.x, gc.y - 1),
614             coord_def(gc.x + 1, gc.y),
615             coord_def(gc.x, gc.y + 1),
616             coord_def(gc.x - 1, gc.y),
617         };
618         int solid = 0;
619         for (int i = 0; i < 4; i++)
620             if (feat_is_solid(env.map_knowledge(neigh[i]).feat())
621                 || env.map_knowledge(neigh[i]).trap() == TRAP_WEB)
622             {
623                 solid |= 1 << i;
624             }
625         if (solid)
626             return TILE_DNGN_TRAP_WEB_N - 1 + solid;
627         return TILE_DNGN_TRAP_WEB;
628     }
629     case DNGN_ENTER_SHOP:
630         return tileidx_shop(shop_at(gc));
631 
632     case DNGN_DEEP_WATER:
633         if (env.map_knowledge(gc).feat_colour() == GREEN
634             || env.map_knowledge(gc).feat_colour() == LIGHTGREEN)
635         {
636             return TILE_DNGN_DEEP_WATER_MURKY;
637         }
638         else if (player_in_branch(BRANCH_SHOALS))
639             return TILE_SHOALS_DEEP_WATER;
640 
641         return TILE_DNGN_DEEP_WATER;
642     case DNGN_SHALLOW_WATER:
643         {
644             tileidx_t t = TILE_DNGN_SHALLOW_WATER;
645             if (env.map_knowledge(gc).feat_colour() == GREEN
646                 || env.map_knowledge(gc).feat_colour() == LIGHTGREEN)
647             {
648                 t = TILE_DNGN_SHALLOW_WATER_MURKY;
649             }
650             else if (player_in_branch(BRANCH_SHOALS))
651                 t = TILE_SHOALS_SHALLOW_WATER;
652 
653             if (env.map_knowledge(gc).invisible_monster())
654             {
655                 // Add disturbance to tile.
656                 t += tile_dngn_count(t);
657             }
658 
659             return t;
660         }
661     default:
662         return tileidx_feature_base(feat);
663     }
664 }
665 
_mon_random(tileidx_t tile,int mon_id)666 static tileidx_t _mon_random(tileidx_t tile, int mon_id)
667 {
668     int count = tile_player_count(tile);
669     return tile + hash_with_seed(count, mon_id, you.frame_no);
670 }
671 
672 #ifdef USE_TILE
_mons_is_kraken_tentacle(const int mtype)673 static bool _mons_is_kraken_tentacle(const int mtype)
674 {
675     return mtype == MONS_KRAKEN_TENTACLE
676            || mtype == MONS_KRAKEN_TENTACLE_SEGMENT;
677 }
678 #endif
679 
tileidx_tentacle(const monster_info & mon)680 tileidx_t tileidx_tentacle(const monster_info& mon)
681 {
682     ASSERT(mons_is_tentacle_or_tentacle_segment(mon.type));
683 
684     // If the tentacle is submerged, we shouldn't even get here.
685     ASSERT(!mon.is(MB_SUBMERGED));
686 
687     // Get tentacle position.
688     const coord_def t_pos = mon.pos;
689     // No parent tentacle, or the connection to the head is unknown.
690     bool no_head_connect  = !mon.props.exists("inwards");
691     coord_def h_pos       = coord_def(); // head position
692     if (!no_head_connect)
693     {
694         // Get the parent tentacle's location.
695         h_pos = t_pos + mon.props["inwards"].get_coord();
696     }
697     if (no_head_connect && (mon.type == MONS_SNAPLASHER_VINE
698                             || mon.type == MONS_SNAPLASHER_VINE_SEGMENT))
699     {
700         // Find an adjacent tree to pretend we're connected to.
701         for (adjacent_iterator ai(t_pos); ai; ++ai)
702         {
703             if (feat_is_tree(env.grid(*ai)))
704             {
705                 h_pos = *ai;
706                 no_head_connect = false;
707                 break;
708             }
709         }
710     }
711 
712     // Is there a connection to the given direction?
713     // (either through head or next)
714     bool north = false, east = false,
715         south = false, west = false,
716         north_east = false, south_east = false,
717         south_west = false, north_west = false;
718 
719     if (!no_head_connect)
720     {
721         if (h_pos.x == t_pos.x)
722         {
723             if (h_pos.y < t_pos.y)
724                 north = true;
725             else
726                 south = true;
727         }
728         else if (h_pos.y == t_pos.y)
729         {
730             if (h_pos.x < t_pos.x)
731                 west = true;
732             else
733                 east = true;
734         }
735         else if (h_pos.x < t_pos.x)
736         {
737             if (h_pos.y < t_pos.y)
738                 north_west = true;
739             else
740                 south_west = true;
741         }
742         else if (h_pos.x > t_pos.x)
743         {
744             if (h_pos.y < t_pos.y)
745                 north_east = true;
746             else
747                 south_east = true;
748         }
749     }
750 
751     // Tentacle only requires checking of head position.
752     if (mons_is_tentacle(mon.type))
753     {
754         if (no_head_connect)
755         {
756             tileidx_t tile;
757             switch (mon.type)
758             {
759                 case MONS_KRAKEN_TENTACLE: tile = TILEP_MONS_KRAKEN_TENTACLE_WATER; break;
760                 case MONS_STARSPAWN_TENTACLE: tile = TILEP_MONS_STARSPAWN_TENTACLE_S; break;
761                 case MONS_ELDRITCH_TENTACLE: tile = TILEP_MONS_ELDRITCH_TENTACLE_PORTAL; break;
762                 case MONS_SNAPLASHER_VINE: tile = TILEP_MONS_VINE_S; break;
763                 default: die("bad tentacle type");
764             }
765 
766             bool vary = !(mon.props.exists("fake") && mon.props["fake"].get_bool());
767             return vary ? _mon_random(tile, t_pos.y*GXM + t_pos.x) : tile;
768         }
769 
770         // Different handling according to relative positions.
771         if (north)
772             return TILEP_MONS_KRAKEN_TENTACLE_N;
773         if (south)
774             return TILEP_MONS_KRAKEN_TENTACLE_S;
775         if (west)
776             return TILEP_MONS_KRAKEN_TENTACLE_W;
777         if (east)
778             return TILEP_MONS_KRAKEN_TENTACLE_E;
779         if (north_west)
780             return TILEP_MONS_KRAKEN_TENTACLE_NW;
781         if (south_west)
782             return TILEP_MONS_KRAKEN_TENTACLE_SW;
783         if (north_east)
784             return TILEP_MONS_KRAKEN_TENTACLE_NE;
785         if (south_east)
786             return TILEP_MONS_KRAKEN_TENTACLE_SE;
787         die("impossible kraken direction");
788     }
789     // Only tentacle segments from now on.
790     ASSERT(mons_is_tentacle_segment(mon.type));
791 
792     // For segments, we also need the next segment (or end piece).
793     coord_def n_pos;
794     bool no_next_connect = !mon.props.exists("outwards");
795     if (!no_next_connect)
796         n_pos = t_pos + mon.props["outwards"].get_coord();
797 
798     if (no_head_connect && no_next_connect)
799     {
800         // Both head and next are submerged.
801         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_WATER;
802     }
803 
804     if (!no_next_connect)
805     {
806         if (n_pos.x == t_pos.x)
807         {
808             if (n_pos.y < t_pos.y)
809                 north = true;
810             else
811                 south = true;
812         }
813         else if (n_pos.y == t_pos.y)
814         {
815             if (n_pos.x < t_pos.x)
816                 west = true;
817             else
818                 east = true;
819         }
820         else if (n_pos.x < t_pos.x)
821         {
822             if (n_pos.y < t_pos.y)
823                 north_west = true;
824             else
825                 south_west = true;
826         }
827         else if (n_pos.x > t_pos.x)
828         {
829             if (n_pos.y < t_pos.y)
830                 north_east = true;
831             else
832                 south_east = true;
833         }
834     }
835 
836     if (no_head_connect || no_next_connect)
837     {
838         // One segment end goes into water, the other
839         // into the direction of head or next.
840 
841         if (north)
842             return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N;
843         if (south)
844             return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_S;
845         if (west)
846             return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W;
847         if (east)
848             return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E;
849         if (north_west)
850             return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NW;
851         if (south_west)
852             return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_SW;
853         if (north_east)
854             return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NE;
855         if (south_east)
856             return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_SE;
857         die("impossible kraken direction");
858     }
859 
860     // Okay, neither head nor next are submerged.
861     // Compare all three positions.
862 
863     // Straight lines first: Vertical.
864     if (north && south)
865         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N_S;
866     // Horizontal.
867     if (east && west)
868         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_W;
869     // Diagonals.
870     if (north_west && south_east)
871         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NW_SE;
872     if (north_east && south_west)
873         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NE_SW;
874 
875     // Curved segments.
876     if (east && north)
877         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_N;
878     if (east && south)
879         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_S;
880     if (south && west)
881         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_S_W;
882     if (north && west)
883         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N_W;
884     if (north_east && north_west)
885         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NE_NW;
886     if (south_east && south_west)
887         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_SE_SW;
888     if (north_west && south_west)
889         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NW_SW;
890     if (north_east && south_east)
891         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NE_SE;
892 
893     // Connect corners and edges.
894     if (north && south_west)
895         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N_SW;
896     if (north && south_east)
897         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N_SE;
898     if (south && north_west)
899         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_S_NW;
900     if (south && north_east)
901         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_S_NE;
902     if (west && north_east)
903         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W_NE;
904     if (west && south_east)
905         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W_SE;
906     if (east && north_west)
907         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_NW;
908     if (east && south_west)
909         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_SW;
910 
911     // Connections at acute angles; can currently only happen for vines.
912     if (north && north_west)
913         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N_NW;
914     if (north && north_east)
915         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N_NE;
916     if (east && north_east)
917         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_NE;
918     if (east && south_east)
919         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_SE;
920     if (south && south_east)
921         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_S_SE;
922     if (south && south_west)
923         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_S_SW;
924     if (west && south_west)
925         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W_SW;
926     if (west && north_west)
927         return TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W_NW;
928 
929     return TILEP_MONS_PROGRAM_BUG;
930 }
931 
tileidx_out_of_bounds(int branch)932 tileidx_t tileidx_out_of_bounds(int branch)
933 {
934     if (branch == BRANCH_SHOALS)
935         return TILE_DNGN_OPEN_SEA | TILE_FLAG_UNSEEN;
936     else
937         return TILE_DNGN_UNSEEN | TILE_FLAG_UNSEEN;
938 }
939 
940 #ifdef USE_TILE
tileidx_out_of_los(tileidx_t * fg,tileidx_t * bg,tileidx_t * cloud,const coord_def & gc)941 void tileidx_out_of_los(tileidx_t *fg, tileidx_t *bg, tileidx_t *cloud, const coord_def& gc)
942 {
943     // Player memory.
944     tileidx_t mem_fg = tile_env.bk_fg(gc);
945     tileidx_t mem_bg = tile_env.bk_bg(gc);
946     tileidx_t mem_cloud = tile_env.bk_cloud(gc);
947 
948     // Detected info is just stored in map_knowledge and doesn't get
949     // written to what the player remembers. We'll feather that in here.
950 
951     // save any rays, which will get overwritten by mapped terrain
952     auto rays = *bg & (TILE_FLAG_RAY_MULTI | TILE_FLAG_RAY_OOR | TILE_FLAG_RAY
953                         | TILE_FLAG_LANDING);
954 
955     const map_cell &cell = env.map_knowledge(gc);
956 
957     // Override terrain for magic mapping.
958     if (!cell.seen() && env.map_knowledge(gc).mapped())
959         *bg = tileidx_feature_base(cell.feat());
960     else
961         *bg = mem_bg;
962     *bg |= tileidx_unseen_flag(gc);
963 
964     // if out-of-los rays are getting shown that shouldn't be, the bug isn't
965     // here -- fix it in the targeter
966     *bg |= rays;
967 
968     // Override foreground for monsters/items
969     if (env.map_knowledge(gc).detected_monster())
970     {
971         ASSERT(cell.monster() == MONS_SENSED);
972         *fg = tileidx_monster_base(cell.monsterinfo()->base_type, 0);
973     }
974     else if (env.map_knowledge(gc).detected_item())
975         *fg = tileidx_item(*cell.item());
976     else
977         *fg = mem_fg;
978 
979     *cloud = mem_cloud;
980 }
981 
_zombie_tile_to_spectral(const tileidx_t z_tile)982 static tileidx_t _zombie_tile_to_spectral(const tileidx_t z_tile)
983 {
984     switch (z_tile)
985     {
986     case TILEP_MONS_ZOMBIE_SMALL:
987     case TILEP_MONS_ZOMBIE_SPRIGGAN:
988     case TILEP_MONS_ZOMBIE_GOBLIN:
989     case TILEP_MONS_ZOMBIE_HOBGOBLIN:
990     case TILEP_MONS_ZOMBIE_GNOLL:
991     case TILEP_MONS_ZOMBIE_KOBOLD:
992     case TILEP_MONS_ZOMBIE_ORC:
993     case TILEP_MONS_ZOMBIE_HUMAN:
994     case TILEP_MONS_ZOMBIE_DRACONIAN:
995     case TILEP_MONS_ZOMBIE_ELF:
996     case TILEP_MONS_ZOMBIE_FAUN:
997     case TILEP_MONS_ZOMBIE_MERFOLK:
998     case TILEP_MONS_ZOMBIE_MINOTAUR:
999     case TILEP_MONS_ZOMBIE_MONKEY:
1000         return TILEP_MONS_SPECTRAL_SMALL;
1001     case TILEP_MONS_ZOMBIE_LARGE:
1002     case TILEP_MONS_ZOMBIE_OGRE:
1003     case TILEP_MONS_ZOMBIE_TROLL:
1004     case TILEP_MONS_ZOMBIE_JUGGERNAUT:
1005     case TILEP_MONS_ZOMBIE_UGLY_THING:
1006         return TILEP_MONS_SPECTRAL_LARGE;
1007     case TILEP_MONS_ZOMBIE_QUADRUPED_SMALL:
1008     case TILEP_MONS_ZOMBIE_RAT:
1009     case TILEP_MONS_ZOMBIE_QUOKKA:
1010     case TILEP_MONS_ZOMBIE_JACKAL:
1011     case TILEP_MONS_ZOMBIE_HOUND:
1012     case TILEP_MONS_ZOMBIE_CRAB:
1013     case TILEP_MONS_ZOMBIE_TURTLE:
1014     case TILEP_MONS_ZOMBIE_BEAR:
1015         return TILEP_MONS_SPECTRAL_QUADRUPED_SMALL;
1016     case TILEP_MONS_ZOMBIE_QUADRUPED_LARGE:
1017     case TILEP_MONS_ZOMBIE_ELEPHANT:
1018     case TILEP_MONS_ZOMBIE_YAK:
1019     case TILEP_MONS_ZOMBIE_QUADRUPED_WINGED:
1020         return TILEP_MONS_SPECTRAL_QUADRUPED_LARGE;
1021     case TILEP_MONS_ZOMBIE_FROG:
1022         return TILEP_MONS_SPECTRAL_FROG;
1023     case TILEP_MONS_ZOMBIE_BAT:
1024     case TILEP_MONS_ZOMBIE_BIRD: /* no bird spectral tile */
1025     case TILEP_MONS_ZOMBIE_HARPY:
1026         return TILEP_MONS_SPECTRAL_BAT;
1027     case TILEP_MONS_ZOMBIE_BEE:
1028     case TILEP_MONS_ZOMBIE_MELIAI:
1029     case TILEP_MONS_ZOMBIE_HORNET:
1030         return TILEP_MONS_SPECTRAL_BEE;
1031     case TILEP_MONS_ZOMBIE_BEETLE:
1032     case TILEP_MONS_ZOMBIE_ROACH:
1033     case TILEP_MONS_ZOMBIE_BUG:
1034         return TILEP_MONS_SPECTRAL_BUG;
1035     case TILEP_MONS_ZOMBIE_FISH:
1036         return TILEP_MONS_SPECTRAL_FISH;
1037     case TILEP_MONS_ZOMBIE_CENTAUR:
1038     case TILEP_MONS_ZOMBIE_YAKTAUR:
1039         return TILEP_MONS_SPECTRAL_CENTAUR;
1040     case TILEP_MONS_ZOMBIE_NAGA:
1041     case TILEP_MONS_ZOMBIE_GUARDIAN_SERPENT:
1042     case TILEP_MONS_ZOMBIE_SALAMANDER:
1043         return TILEP_MONS_SPECTRAL_NAGA;
1044     case TILEP_MONS_ZOMBIE_SNAKE:
1045     case TILEP_MONS_ZOMBIE_ADDER:
1046     case TILEP_MONS_ZOMBIE_WORM:
1047     case TILEP_MONS_ZOMBIE_LINDWURM:
1048         return TILEP_MONS_SPECTRAL_SNAKE;
1049     case TILEP_MONS_ZOMBIE_LIZARD:
1050         return TILEP_MONS_SPECTRAL_LIZARD;
1051     case TILEP_MONS_ZOMBIE_SCORPION:
1052     case TILEP_MONS_ZOMBIE_SPIDER_LARGE:
1053     case TILEP_MONS_ZOMBIE_SPIDER_SMALL:
1054         return TILEP_MONS_SPECTRAL_SPIDER;
1055     case TILEP_MONS_ZOMBIE_DRAGON:
1056     case TILEP_MONS_ZOMBIE_IRON_DRAGON:
1057     case TILEP_MONS_ZOMBIE_GOLDEN_DRAGON:
1058     case TILEP_MONS_ZOMBIE_QUICKSILVER_DRAGON:
1059         return TILEP_MONS_SPECTRAL_DRAGON;
1060     case TILEP_MONS_ZOMBIE_DRAKE:
1061     case TILEP_MONS_ZOMBIE_WYVERN:
1062         return TILEP_MONS_SPECTRAL_DRAKE;
1063     case TILEP_MONS_ZOMBIE_KRAKEN:
1064         return TILEP_MONS_SPECTRAL_KRAKEN;
1065     default:
1066         if (tile_player_basetile(z_tile) == TILEP_MONS_ZOMBIE_HYDRA)
1067         {
1068             return TILEP_MONS_SPECTRAL_HYDRA
1069                    + (z_tile - TILEP_MONS_ZOMBIE_HYDRA);
1070         }
1071     }
1072     return TILEP_MONS_SPECTRAL_SMALL;
1073 }
1074 
_zombie_tile_to_simulacrum(const tileidx_t z_tile)1075 static tileidx_t _zombie_tile_to_simulacrum(const tileidx_t z_tile)
1076 {
1077     switch (z_tile)
1078     {
1079     case TILEP_MONS_ZOMBIE_SMALL:
1080     case TILEP_MONS_ZOMBIE_SPRIGGAN:
1081     case TILEP_MONS_ZOMBIE_GOBLIN:
1082     case TILEP_MONS_ZOMBIE_HOBGOBLIN:
1083     case TILEP_MONS_ZOMBIE_GNOLL:
1084     case TILEP_MONS_ZOMBIE_KOBOLD:
1085     case TILEP_MONS_ZOMBIE_ORC:
1086     case TILEP_MONS_ZOMBIE_HUMAN:
1087     case TILEP_MONS_ZOMBIE_DRACONIAN:
1088     case TILEP_MONS_ZOMBIE_ELF:
1089     case TILEP_MONS_ZOMBIE_FAUN:
1090     case TILEP_MONS_ZOMBIE_MERFOLK:
1091     case TILEP_MONS_ZOMBIE_MINOTAUR:
1092     case TILEP_MONS_ZOMBIE_MONKEY:
1093         return TILEP_MONS_SIMULACRUM_SMALL;
1094     case TILEP_MONS_ZOMBIE_LARGE:
1095     case TILEP_MONS_ZOMBIE_OGRE:
1096     case TILEP_MONS_ZOMBIE_TROLL:
1097     case TILEP_MONS_ZOMBIE_JUGGERNAUT:
1098     case TILEP_MONS_ZOMBIE_UGLY_THING:
1099         return TILEP_MONS_SIMULACRUM_LARGE;
1100     case TILEP_MONS_ZOMBIE_QUADRUPED_SMALL:
1101     case TILEP_MONS_ZOMBIE_BEAR:
1102     case TILEP_MONS_ZOMBIE_RAT:
1103     case TILEP_MONS_ZOMBIE_QUOKKA:
1104     case TILEP_MONS_ZOMBIE_JACKAL:
1105     case TILEP_MONS_ZOMBIE_HOUND:
1106     case TILEP_MONS_ZOMBIE_CRAB:
1107     case TILEP_MONS_ZOMBIE_TURTLE:
1108         return TILEP_MONS_SIMULACRUM_QUADRUPED_SMALL;
1109     case TILEP_MONS_ZOMBIE_QUADRUPED_LARGE:
1110     case TILEP_MONS_ZOMBIE_FROG:
1111     case TILEP_MONS_ZOMBIE_ELEPHANT:
1112     case TILEP_MONS_ZOMBIE_YAK:
1113     case TILEP_MONS_ZOMBIE_QUADRUPED_WINGED:
1114         return TILEP_MONS_SIMULACRUM_QUADRUPED_LARGE;
1115     case TILEP_MONS_ZOMBIE_BAT:
1116     case TILEP_MONS_ZOMBIE_BIRD: /* no bird simulacrum tile */
1117     case TILEP_MONS_ZOMBIE_HARPY:
1118         return TILEP_MONS_SIMULACRUM_BAT;
1119     case TILEP_MONS_ZOMBIE_BEE:
1120     case TILEP_MONS_ZOMBIE_MELIAI:
1121     case TILEP_MONS_ZOMBIE_HORNET:
1122         return TILEP_MONS_SIMULACRUM_BEE;
1123     case TILEP_MONS_ZOMBIE_BEETLE:
1124     case TILEP_MONS_ZOMBIE_ROACH:
1125     case TILEP_MONS_ZOMBIE_BUG:
1126         return TILEP_MONS_SIMULACRUM_BUG;
1127     case TILEP_MONS_ZOMBIE_FISH:
1128         return TILEP_MONS_SIMULACRUM_FISH;
1129     case TILEP_MONS_ZOMBIE_CENTAUR:
1130     case TILEP_MONS_ZOMBIE_YAKTAUR:
1131         return TILEP_MONS_SIMULACRUM_CENTAUR;
1132     case TILEP_MONS_ZOMBIE_NAGA:
1133     case TILEP_MONS_ZOMBIE_GUARDIAN_SERPENT:
1134     case TILEP_MONS_ZOMBIE_SALAMANDER:
1135         return TILEP_MONS_SIMULACRUM_NAGA;
1136     case TILEP_MONS_ZOMBIE_SNAKE:
1137     case TILEP_MONS_ZOMBIE_ADDER:
1138     case TILEP_MONS_ZOMBIE_WORM:
1139     case TILEP_MONS_ZOMBIE_LINDWURM:
1140         return TILEP_MONS_SIMULACRUM_SNAKE;
1141     case TILEP_MONS_ZOMBIE_LIZARD:
1142         return TILEP_MONS_SIMULACRUM_LIZARD;
1143     case TILEP_MONS_ZOMBIE_SCORPION:
1144     case TILEP_MONS_ZOMBIE_SPIDER_LARGE:
1145     case TILEP_MONS_ZOMBIE_SPIDER_SMALL:
1146         return TILEP_MONS_SIMULACRUM_SPIDER;
1147     case TILEP_MONS_ZOMBIE_DRAGON:
1148     case TILEP_MONS_ZOMBIE_IRON_DRAGON:
1149     case TILEP_MONS_ZOMBIE_GOLDEN_DRAGON:
1150     case TILEP_MONS_ZOMBIE_QUICKSILVER_DRAGON:
1151         return TILEP_MONS_SIMULACRUM_DRAGON;
1152     case TILEP_MONS_ZOMBIE_DRAKE:
1153     case TILEP_MONS_ZOMBIE_WYVERN:
1154         return TILEP_MONS_SIMULACRUM_DRAKE;
1155     case TILEP_MONS_ZOMBIE_KRAKEN:
1156         return TILEP_MONS_SIMULACRUM_KRAKEN;
1157     default:
1158         if (tile_player_basetile(z_tile) == TILEP_MONS_ZOMBIE_HYDRA)
1159         {
1160             return TILEP_MONS_SIMULACRUM_HYDRA
1161                    + (z_tile - TILEP_MONS_ZOMBIE_HYDRA);
1162         }
1163     }
1164     return TILEP_MONS_SIMULACRUM_SMALL;
1165 }
1166 
_zombie_tile_to_skeleton(const tileidx_t z_tile)1167 static tileidx_t _zombie_tile_to_skeleton(const tileidx_t z_tile)
1168 {
1169     switch (z_tile)
1170     {
1171     case TILEP_MONS_ZOMBIE_SMALL:
1172     case TILEP_MONS_ZOMBIE_SPRIGGAN:
1173     case TILEP_MONS_ZOMBIE_GOBLIN:
1174     case TILEP_MONS_ZOMBIE_KOBOLD:
1175     case TILEP_MONS_ZOMBIE_MONKEY:
1176         return TILEP_MONS_SKELETON_SMALL;
1177     case TILEP_MONS_ZOMBIE_HOBGOBLIN:
1178     case TILEP_MONS_ZOMBIE_GNOLL:
1179     case TILEP_MONS_ZOMBIE_ORC:
1180     case TILEP_MONS_ZOMBIE_HUMAN:
1181     case TILEP_MONS_ZOMBIE_ELF:
1182     case TILEP_MONS_ZOMBIE_MERFOLK:
1183     case TILEP_MONS_ZOMBIE_MINOTAUR:
1184     case TILEP_MONS_ZOMBIE_FAUN:
1185         return TILEP_MONS_SKELETON_MEDIUM;
1186     case TILEP_MONS_ZOMBIE_TROLL:
1187         return TILEP_MONS_SKELETON_TROLL;
1188     case TILEP_MONS_ZOMBIE_LARGE:
1189     case TILEP_MONS_ZOMBIE_OGRE:
1190     case TILEP_MONS_ZOMBIE_JUGGERNAUT:
1191         return TILEP_MONS_SKELETON_LARGE;
1192     case TILEP_MONS_ZOMBIE_QUADRUPED_SMALL:
1193     case TILEP_MONS_ZOMBIE_RAT:
1194     case TILEP_MONS_ZOMBIE_QUOKKA:
1195     case TILEP_MONS_ZOMBIE_JACKAL:
1196     case TILEP_MONS_ZOMBIE_HOUND:
1197     case TILEP_MONS_ZOMBIE_BEETLE:
1198     case TILEP_MONS_ZOMBIE_ROACH:
1199     case TILEP_MONS_ZOMBIE_BEAR:
1200     case TILEP_MONS_ZOMBIE_BUG:
1201         return TILEP_MONS_SKELETON_QUADRUPED_SMALL;
1202     case TILEP_MONS_ZOMBIE_LIZARD:
1203     case TILEP_MONS_ZOMBIE_CRAB:
1204         return TILEP_MONS_SKELETON_LIZARD;
1205     case TILEP_MONS_ZOMBIE_TURTLE:
1206         return TILEP_MONS_SKELETON_TURTLE;
1207     case TILEP_MONS_ZOMBIE_QUADRUPED_LARGE:
1208     case TILEP_MONS_ZOMBIE_ELEPHANT:
1209     case TILEP_MONS_ZOMBIE_YAK:
1210         return TILEP_MONS_SKELETON_QUADRUPED_LARGE;
1211     case TILEP_MONS_ZOMBIE_FROG:
1212         return TILEP_MONS_SKELETON_FROG;
1213     case TILEP_MONS_ZOMBIE_QUADRUPED_WINGED:
1214         return TILEP_MONS_SKELETON_QUADRUPED_WINGED;
1215     case TILEP_MONS_ZOMBIE_BAT:
1216         return TILEP_MONS_SKELETON_BAT;
1217     case TILEP_MONS_ZOMBIE_HARPY:
1218     case TILEP_MONS_ZOMBIE_BIRD:
1219         return TILEP_MONS_SKELETON_BIRD;
1220     case TILEP_MONS_ZOMBIE_FISH:
1221         return TILEP_MONS_SKELETON_FISH;
1222     case TILEP_MONS_ZOMBIE_CENTAUR:
1223     case TILEP_MONS_ZOMBIE_YAKTAUR:
1224         return TILEP_MONS_SKELETON_CENTAUR;
1225     case TILEP_MONS_ZOMBIE_NAGA:
1226     case TILEP_MONS_ZOMBIE_GUARDIAN_SERPENT:
1227     case TILEP_MONS_ZOMBIE_SALAMANDER:
1228         return TILEP_MONS_SKELETON_NAGA;
1229     case TILEP_MONS_ZOMBIE_SNAKE:
1230     case TILEP_MONS_ZOMBIE_ADDER:
1231     case TILEP_MONS_ZOMBIE_WORM:
1232     case TILEP_MONS_ZOMBIE_LINDWURM:
1233         return TILEP_MONS_SKELETON_SNAKE;
1234     case TILEP_MONS_ZOMBIE_DRAGON:
1235     case TILEP_MONS_ZOMBIE_IRON_DRAGON:
1236     case TILEP_MONS_ZOMBIE_GOLDEN_DRAGON:
1237     case TILEP_MONS_ZOMBIE_QUICKSILVER_DRAGON:
1238         return TILEP_MONS_SKELETON_DRAGON;
1239     case TILEP_MONS_ZOMBIE_DRAKE:
1240     case TILEP_MONS_ZOMBIE_WYVERN:
1241         return TILEP_MONS_SKELETON_DRAKE;
1242     case TILEP_MONS_ZOMBIE_UGLY_THING:
1243         return TILEP_MONS_SKELETON_UGLY_THING;
1244     case TILEP_MONS_ZOMBIE_DRACONIAN:
1245         return TILEP_MONS_SKELETON_DRACONIAN;
1246     default:
1247         if (tile_player_basetile(z_tile) == TILEP_MONS_ZOMBIE_HYDRA)
1248         {
1249             return TILEP_MONS_SKELETON_HYDRA
1250                    + (z_tile - TILEP_MONS_ZOMBIE_HYDRA);
1251         }
1252     }
1253     return TILEP_MONS_SKELETON_SMALL;
1254 }
1255 
1256 /**
1257  * For a given monster, what tile is appropriate for that monster if it's a
1258  * zombie?
1259  *
1260  * If it's another kind of derived undead (e.g. a skeleton), the actual tile to
1261  * be used will be derived from the zombie tile we return here.
1262  *
1263  * @param mon   The monster in question.
1264  * @return      An appropriate zombie tile; e.g. TILEP_MONS_ZOMBIE_DRAGON.
1265  */
_mon_to_zombie_tile(const monster_info & mon)1266 static tileidx_t _mon_to_zombie_tile(const monster_info &mon)
1267 {
1268     const monster_type subtype = mon.base_type;
1269 
1270     // hydras get special casing
1271 
1272     if (subtype == MONS_LERNAEAN_HYDRA && mon.type == MONS_ZOMBIE)
1273     {
1274         // Step down the number of heads to get the appropriate tile:
1275         // for the last five heads, use tiles 1-5, for greater amounts
1276         // use the next tile for every 5 more heads.
1277         return tileidx_mon_clamp(TILEP_MONS_LERNAEAN_HYDRA_ZOMBIE,
1278                                  mon.number <= 5 ?
1279                                  mon.number - 1 :
1280                                  4 + (mon.number - 1)/5);
1281     }
1282     if (mons_genus(subtype) == MONS_HYDRA)
1283         return TILEP_MONS_ZOMBIE_HYDRA + min(mon.num_heads, 5) - 1;
1284 
1285     // specific per-species zombies - use to override genuses
1286     static const map<monster_type, tileidx_t> species_tiles = {
1287         { MONS_JUGGERNAUT,              TILEP_MONS_ZOMBIE_JUGGERNAUT },
1288         { MONS_ACID_DRAGON,             TILEP_MONS_ZOMBIE_DRAKE },
1289         { MONS_STEAM_DRAGON,            TILEP_MONS_ZOMBIE_DRAKE },
1290         { MONS_JACKAL,                  TILEP_MONS_ZOMBIE_JACKAL },
1291         { MONS_ADDER,                   TILEP_MONS_ZOMBIE_ADDER },
1292         { MONS_WOLF_SPIDER,             TILEP_MONS_ZOMBIE_SPIDER_LARGE },
1293         { MONS_EMPEROR_SCORPION,        TILEP_MONS_ZOMBIE_SPIDER_LARGE },
1294         { MONS_HOWLER_MONKEY,           TILEP_MONS_ZOMBIE_MONKEY },
1295         { MONS_IRON_DRAGON,             TILEP_MONS_ZOMBIE_IRON_DRAGON },
1296         { MONS_GOLDEN_DRAGON,           TILEP_MONS_ZOMBIE_GOLDEN_DRAGON },
1297         { MONS_QUICKSILVER_DRAGON,      TILEP_MONS_ZOMBIE_QUICKSILVER_DRAGON },
1298         { MONS_LINDWURM,                TILEP_MONS_ZOMBIE_LINDWURM, },
1299         { MONS_MELIAI,                  TILEP_MONS_ZOMBIE_MELIAI, },
1300         { MONS_HORNET,                  TILEP_MONS_ZOMBIE_HORNET, },
1301     };
1302     // per-genus zombies - use by default
1303     static const map<monster_type, tileidx_t> genus_tiles = {
1304         { MONS_GOBLIN,                  TILEP_MONS_ZOMBIE_GOBLIN },
1305         { MONS_HOBGOBLIN,               TILEP_MONS_ZOMBIE_HOBGOBLIN },
1306         { MONS_GNOLL,                   TILEP_MONS_ZOMBIE_GNOLL },
1307         { MONS_HUMAN,                   TILEP_MONS_ZOMBIE_HUMAN },
1308         { MONS_GHOUL,                   TILEP_MONS_ZOMBIE_HUMAN }, // for skel
1309         { MONS_KOBOLD,                  TILEP_MONS_ZOMBIE_KOBOLD },
1310         { MONS_ORC,                     TILEP_MONS_ZOMBIE_ORC },
1311         { MONS_TROLL,                   TILEP_MONS_ZOMBIE_TROLL },
1312         { MONS_OGRE,                    TILEP_MONS_ZOMBIE_OGRE },
1313         { MONS_HARPY,                   TILEP_MONS_ZOMBIE_HARPY },
1314         { MONS_DRACONIAN,               TILEP_MONS_ZOMBIE_DRACONIAN },
1315         { MONS_DRAGON,                  TILEP_MONS_ZOMBIE_DRAGON },
1316         { MONS_WYVERN,                  TILEP_MONS_ZOMBIE_WYVERN },
1317         { MONS_DRAKE,                   TILEP_MONS_ZOMBIE_DRAKE },
1318         { MONS_GIANT_LIZARD,            TILEP_MONS_ZOMBIE_LIZARD },
1319         { MONS_RAT,                     TILEP_MONS_ZOMBIE_RAT },
1320         { MONS_QUOKKA,                  TILEP_MONS_ZOMBIE_QUOKKA },
1321         { MONS_HOUND,                   TILEP_MONS_ZOMBIE_HOUND },
1322         { MONS_FROG,                    TILEP_MONS_ZOMBIE_FROG },
1323         { MONS_CRAB,                    TILEP_MONS_ZOMBIE_CRAB },
1324         { MONS_SNAPPING_TURTLE,         TILEP_MONS_ZOMBIE_TURTLE },
1325         { MONS_WORM,                    TILEP_MONS_ZOMBIE_WORM },
1326         { MONS_GIANT_COCKROACH,         TILEP_MONS_ZOMBIE_ROACH },
1327         { MONS_SCORPION,                TILEP_MONS_ZOMBIE_SCORPION },
1328         { MONS_KRAKEN,                  TILEP_MONS_ZOMBIE_KRAKEN },
1329         { MONS_OCTOPODE,                TILEP_MONS_ZOMBIE_OCTOPODE },
1330         { MONS_UGLY_THING,              TILEP_MONS_ZOMBIE_UGLY_THING },
1331         { MONS_ELEPHANT,                TILEP_MONS_ZOMBIE_ELEPHANT },
1332         { MONS_ELF,                     TILEP_MONS_ZOMBIE_ELF },
1333         { MONS_FAUN,                    TILEP_MONS_ZOMBIE_FAUN },
1334         { MONS_SATYR,                   TILEP_MONS_ZOMBIE_FAUN },
1335         { MONS_GUARDIAN_SERPENT,        TILEP_MONS_ZOMBIE_GUARDIAN_SERPENT, },
1336         { MONS_MERFOLK,                 TILEP_MONS_ZOMBIE_MERFOLK, },
1337         { MONS_MINOTAUR,                TILEP_MONS_ZOMBIE_MINOTAUR, },
1338         { MONS_SALAMANDER,              TILEP_MONS_ZOMBIE_SALAMANDER, },
1339         { MONS_SPRIGGAN,                TILEP_MONS_ZOMBIE_SPRIGGAN, },
1340         { MONS_YAKTAUR,                 TILEP_MONS_ZOMBIE_YAKTAUR, },
1341         { MONS_YAK,                     TILEP_MONS_ZOMBIE_YAK, },
1342         { MONS_BEAR,                    TILEP_MONS_ZOMBIE_BEAR, },
1343     };
1344 
1345     struct shape_size_tiles
1346     {
1347         tileidx_t small; ///< Z_SMALL and default tile
1348         tileidx_t big;   ///< Z_BIG tile
1349     };
1350     const shape_size_tiles GENERIC_ZOMBIES = { TILEP_MONS_ZOMBIE_SMALL,
1351                                                TILEP_MONS_ZOMBIE_LARGE };
1352     static const map<mon_body_shape, shape_size_tiles> shape_tiles = {
1353         { MON_SHAPE_CENTAUR,            {TILEP_MONS_ZOMBIE_CENTAUR} },
1354         { MON_SHAPE_NAGA,               {TILEP_MONS_ZOMBIE_NAGA} },
1355         { MON_SHAPE_QUADRUPED_WINGED,   {TILEP_MONS_ZOMBIE_QUADRUPED_WINGED} },
1356         { MON_SHAPE_BAT,                {TILEP_MONS_ZOMBIE_BAT} },
1357         { MON_SHAPE_BIRD,               {TILEP_MONS_ZOMBIE_BIRD} },
1358         { MON_SHAPE_SNAKE,              {TILEP_MONS_ZOMBIE_SNAKE} },
1359         { MON_SHAPE_SNAIL,              {TILEP_MONS_ZOMBIE_SNAKE} },
1360         { MON_SHAPE_FISH,               {TILEP_MONS_ZOMBIE_FISH} },
1361         { MON_SHAPE_INSECT,             {TILEP_MONS_ZOMBIE_BUG} },
1362         { MON_SHAPE_CENTIPEDE,          {TILEP_MONS_ZOMBIE_BUG} },
1363         { MON_SHAPE_INSECT_WINGED,      {TILEP_MONS_ZOMBIE_BEE} },
1364         { MON_SHAPE_ARACHNID,           {TILEP_MONS_ZOMBIE_SPIDER_SMALL} },
1365         { MON_SHAPE_QUADRUPED_TAILLESS, {TILEP_MONS_ZOMBIE_QUADRUPED_SMALL,
1366                                          TILEP_MONS_ZOMBIE_QUADRUPED_LARGE} },
1367         { MON_SHAPE_QUADRUPED,          {TILEP_MONS_ZOMBIE_QUADRUPED_SMALL,
1368                                          TILEP_MONS_ZOMBIE_QUADRUPED_LARGE} },
1369         { MON_SHAPE_HUMANOID,           GENERIC_ZOMBIES },
1370         { MON_SHAPE_HUMANOID_WINGED,    GENERIC_ZOMBIES },
1371         { MON_SHAPE_HUMANOID_TAILED,    GENERIC_ZOMBIES },
1372         { MON_SHAPE_HUMANOID_WINGED_TAILED,   GENERIC_ZOMBIES },
1373     };
1374 
1375     const tileidx_t *subtype_tile = map_find(species_tiles, subtype);
1376     if (subtype_tile)
1377         return *subtype_tile;
1378 
1379     const tileidx_t *genus_tile = map_find(genus_tiles, mons_genus(subtype));
1380     if (genus_tile)
1381         return *genus_tile;
1382 
1383     const int z_size = mons_zombie_size(subtype);
1384     const shape_size_tiles *shape_tile_pair
1385         = map_find(shape_tiles, get_mon_shape(subtype));
1386     if (shape_tile_pair)
1387     {
1388         if (z_size == Z_BIG && shape_tile_pair->big)
1389             return shape_tile_pair->big;
1390         return shape_tile_pair->small;
1391     }
1392 
1393     return TILEP_ERROR;
1394 }
1395 
1396 /// What tile should be used for a given derived undead monster?
_tileidx_monster_zombified(const monster_info & mon)1397 static tileidx_t _tileidx_monster_zombified(const monster_info& mon)
1398 {
1399     const tileidx_t zombie_tile = _mon_to_zombie_tile(mon);
1400     switch (mon.type)
1401     {
1402         case MONS_SKELETON:
1403             return _zombie_tile_to_skeleton(zombie_tile);
1404         case MONS_SPECTRAL_THING:
1405             return _zombie_tile_to_spectral(zombie_tile);
1406         case MONS_SIMULACRUM:
1407             return _zombie_tile_to_simulacrum(zombie_tile);
1408         default:
1409             return zombie_tile;
1410     }
1411 }
1412 
1413 // Special case for *taurs which have a different tile
1414 // for when they have a bow.
_bow_offset(const monster_info & mon)1415 static bool _bow_offset(const monster_info& mon)
1416 {
1417     if (!mon.inv[MSLOT_WEAPON])
1418         return true;
1419 
1420     switch (mon.inv[MSLOT_WEAPON]->sub_type)
1421     {
1422     case WPN_SHORTBOW:
1423     case WPN_LONGBOW:
1424     case WPN_ARBALEST:
1425         return false;
1426     default:
1427         return true;
1428     }
1429 }
1430 #endif
1431 
_mon_mod(tileidx_t tile,int offset)1432 static tileidx_t _mon_mod(tileidx_t tile, int offset)
1433 {
1434     int count = tile_player_count(tile);
1435     return tile + offset % count;
1436 }
1437 
tileidx_mon_clamp(tileidx_t tile,int offset)1438 tileidx_t tileidx_mon_clamp(tileidx_t tile, int offset)
1439 {
1440     int count = tile_player_count(tile);
1441     return tile + min(max(offset, 0), count - 1);
1442 }
1443 
1444 #ifdef USE_TILE
1445 // actually, a triangle wave, but it's up to the actual tiles
_mon_sinus(tileidx_t tile)1446 static tileidx_t _mon_sinus(tileidx_t tile)
1447 {
1448     int count = tile_player_count(tile);
1449     ASSERT(count > 0);
1450     ASSERT(count > 1); // technically, staying put would work
1451     int n = you.frame_no % (2 * count - 2);
1452     return (n < count) ? (tile + n) : (tile + 2 * count - 2 - n);
1453 }
1454 #endif
1455 
_mon_cycle(tileidx_t tile,int offset)1456 static tileidx_t _mon_cycle(tileidx_t tile, int offset)
1457 {
1458     int count = tile_player_count(tile);
1459     return tile + ((offset + you.frame_no) % count);
1460 }
1461 
_modrng(int mod,tileidx_t first,tileidx_t last)1462 static tileidx_t _modrng(int mod, tileidx_t first, tileidx_t last)
1463 {
1464     return first + mod % (last - first + 1);
1465 }
1466 
1467 // This function allows for getting a monster from "just" the type.
1468 // To avoid needless duplication of a cases in tileidx_monster, some
1469 // extra parameters that have reasonable defaults for monsters where
1470 // only the type is known are pushed here.
tileidx_monster_base(int type,int mon_id,bool in_water,int colour,int number,int tile_num_prop,bool vary)1471 tileidx_t tileidx_monster_base(int type, int mon_id, bool in_water, int colour,
1472                                int number, int tile_num_prop, bool vary)
1473 {
1474     switch (type)
1475     {
1476     case MONS_UGLY_THING:
1477     case MONS_VERY_UGLY_THING:
1478     {
1479         const tileidx_t ugly_tile = (type == MONS_VERY_UGLY_THING) ?
1480             TILEP_MONS_VERY_UGLY_THING : TILEP_MONS_UGLY_THING;
1481         int colour_offset = ugly_thing_colour_offset(colour);
1482         return tileidx_mon_clamp(ugly_tile, colour_offset);
1483     }
1484 
1485     case MONS_HYDRA:
1486         // Number of heads
1487         return tileidx_mon_clamp(TILEP_MONS_HYDRA, number - 1);
1488     case MONS_SLIME_CREATURE:
1489     case MONS_MERGED_SLIME_CREATURE:
1490         return tileidx_mon_clamp(TILEP_MONS_SLIME_CREATURE, number - 1);
1491     case MONS_LERNAEAN_HYDRA:
1492         // Step down the number of heads to get the appropriate tile:
1493         // For the last five heads, use tiles 1-5, for greater amounts
1494         // use the next tile for every 5 more heads.
1495         return tileidx_mon_clamp(TILEP_MONS_LERNAEAN_HYDRA,
1496                                  number <= 5 ?
1497                                  number - 1 : 4 + (number - 1)/5);
1498 
1499     // draconian ('d')
1500     case MONS_TIAMAT:
1501     {
1502         int offset = 0;
1503         switch (colour)
1504         {
1505         case BLUE:          offset = 0; break;
1506         case YELLOW:        offset = 1; break;
1507         case GREEN:         offset = 2; break;
1508         case LIGHTGREY:     offset = 3; break;
1509         case LIGHTMAGENTA:  offset = 4; break;
1510         case CYAN:          offset = 5; break;
1511         case MAGENTA:       offset = 6; break;
1512         case LIGHTRED:      offset = 7; break;
1513         case WHITE:         offset = 8; break;
1514         }
1515 
1516         return TILEP_MONS_TIAMAT + offset;
1517     }
1518     }
1519 
1520     const monster_type mtype = static_cast<monster_type>(type);
1521     const tileidx_t base_tile = get_mon_base_tile(mtype);
1522     const mon_type_tile_variation vary_type = vary ? get_mon_tile_variation(mtype) : TVARY_NONE;
1523     switch (vary_type)
1524     {
1525     case TVARY_NONE:
1526         return base_tile;
1527     case TVARY_MOD:
1528         return _mon_mod(base_tile, tile_num_prop);
1529     case TVARY_CYCLE:
1530         return _mon_cycle(base_tile, tile_num_prop);
1531     case TVARY_RANDOM:
1532         return _mon_random(base_tile, mon_id);
1533     case TVARY_WATER:
1534         return base_tile + (in_water ? 1 : 0);
1535     default:
1536         die("Unknown tile variation type %d for mon %d!", vary_type, mtype);
1537     }
1538 }
1539 
1540 enum class main_dir
1541 {
1542     north = 0,
1543     east,
1544     south,
1545     west
1546 };
1547 
1548 enum class tentacle_type
1549 {
1550     kraken = 0,
1551     eldritch = 1,
1552     starspawn = 2,
1553     vine = 3,
1554     zombie_kraken = 4,
1555     simulacrum_kraken = 5,
1556     spectral_kraken = 6,
1557 };
1558 
1559 #ifdef USE_TILE
_add_tentacle_overlay(const coord_def pos,const main_dir dir,tentacle_type type)1560 static void _add_tentacle_overlay(const coord_def pos,
1561                                   const main_dir dir,
1562                                   tentacle_type type)
1563 {
1564     /* This adds the corner overlays; e.g. in the following situation:
1565          .#
1566          #.
1567         we need to add corners to the floor tiles since the tentacle
1568         will otherwise look weird. So when placing the upper tentacle
1569         tile, this function is called with dir main_dir::west, so the upper
1570         floor tile gets a corner in the south-east; and similarly,
1571         when placing the lower tentacle tile, we get called with dir
1572         main_dir::east to give the lower floor tile a NW overlay.
1573      */
1574     coord_def next = pos;
1575     switch (dir)
1576     {
1577         case main_dir::north: next += coord_def( 0, -1); break;
1578         case main_dir::east:  next += coord_def( 1,  0); break;
1579         case main_dir::south: next += coord_def( 0,  1); break;
1580         case main_dir::west:  next += coord_def(-1,  0); break;
1581         default:
1582             die("invalid direction");
1583     }
1584     if (!in_bounds(next))
1585         return;
1586 
1587     const coord_def next_showpos(grid2show(next));
1588     if (!show_bounds(next_showpos))
1589         return;
1590 
1591     tile_flags flag;
1592     switch (dir)
1593     {
1594         case main_dir::north: flag = TILE_FLAG_TENTACLE_SW; break;
1595         case main_dir::east: flag = TILE_FLAG_TENTACLE_NW; break;
1596         case main_dir::south: flag = TILE_FLAG_TENTACLE_NE; break;
1597         case main_dir::west: flag = TILE_FLAG_TENTACLE_SE; break;
1598         default: die("invalid direction");
1599     }
1600     tile_env.bg(next_showpos) |= flag;
1601 
1602     switch (type)
1603     {
1604         case tentacle_type::eldritch: flag = TILE_FLAG_TENTACLE_ELDRITCH; break;
1605         case tentacle_type::starspawn: flag = TILE_FLAG_TENTACLE_STARSPAWN; break;
1606         case tentacle_type::vine: flag = TILE_FLAG_TENTACLE_VINE; break;
1607         case tentacle_type::zombie_kraken: flag = TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN; break;
1608         case tentacle_type::simulacrum_kraken: flag = TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN; break;
1609         case tentacle_type::spectral_kraken: flag = TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN; break;
1610         default: flag = TILE_FLAG_TENTACLE_KRAKEN;
1611     }
1612     tile_env.bg(next_showpos) |= flag;
1613 }
1614 
_handle_tentacle_overlay(const coord_def pos,const tileidx_t tile,tentacle_type type)1615 static void _handle_tentacle_overlay(const coord_def pos,
1616                                      const tileidx_t tile,
1617                                      tentacle_type type)
1618 {
1619     switch (tile)
1620     {
1621     case TILEP_MONS_KRAKEN_TENTACLE_NW:
1622     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NW:
1623     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_S_NW:
1624     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_NW:
1625         _add_tentacle_overlay(pos, main_dir::north, type);
1626         break;
1627     case TILEP_MONS_KRAKEN_TENTACLE_NE:
1628     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NE:
1629     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_S_NE:
1630     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W_NE:
1631         _add_tentacle_overlay(pos, main_dir::east, type);
1632         break;
1633     case TILEP_MONS_KRAKEN_TENTACLE_SE:
1634     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_SE:
1635     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N_SE:
1636     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W_SE:
1637         _add_tentacle_overlay(pos, main_dir::south, type);
1638         break;
1639     case TILEP_MONS_KRAKEN_TENTACLE_SW:
1640     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_SW:
1641     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N_SW:
1642     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_E_SW:
1643         _add_tentacle_overlay(pos, main_dir::west, type);
1644         break;
1645     // diagonals
1646     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NW_SE:
1647         _add_tentacle_overlay(pos, main_dir::north, type);
1648         _add_tentacle_overlay(pos, main_dir::south, type);
1649         break;
1650     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NE_SW:
1651         _add_tentacle_overlay(pos, main_dir::east, type);
1652         _add_tentacle_overlay(pos, main_dir::west, type);
1653         break;
1654     // other
1655     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NE_NW:
1656         _add_tentacle_overlay(pos, main_dir::north, type);
1657         _add_tentacle_overlay(pos, main_dir::east, type);
1658         break;
1659     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NE_SE:
1660         _add_tentacle_overlay(pos, main_dir::east, type);
1661         _add_tentacle_overlay(pos, main_dir::south, type);
1662         break;
1663     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_SE_SW:
1664         _add_tentacle_overlay(pos, main_dir::south, type);
1665         _add_tentacle_overlay(pos, main_dir::west, type);
1666         break;
1667     case TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_NW_SW:
1668         _add_tentacle_overlay(pos, main_dir::north, type);
1669         _add_tentacle_overlay(pos, main_dir::west, type);
1670         break;
1671     }
1672 }
1673 
_get_tentacle_type(const monster_info & mon)1674 static tentacle_type _get_tentacle_type(const monster_info& mon)
1675 {
1676     switch (mon.type)
1677     {
1678         case MONS_KRAKEN_TENTACLE:
1679         case MONS_KRAKEN_TENTACLE_SEGMENT:
1680             switch (mon.base_type)
1681             {
1682                 case MONS_ZOMBIE:
1683                     return tentacle_type::zombie_kraken;
1684                 case MONS_SIMULACRUM:
1685                     return tentacle_type::simulacrum_kraken;
1686                 case MONS_SPECTRAL_THING:
1687                     return tentacle_type::spectral_kraken;
1688                 default:
1689                     return tentacle_type::kraken;
1690             }
1691         case MONS_ELDRITCH_TENTACLE:
1692         case MONS_ELDRITCH_TENTACLE_SEGMENT:
1693             return tentacle_type::eldritch;
1694         case MONS_STARSPAWN_TENTACLE:
1695         case MONS_STARSPAWN_TENTACLE_SEGMENT:
1696             return tentacle_type::starspawn;
1697         case MONS_SNAPLASHER_VINE:
1698         case MONS_SNAPLASHER_VINE_SEGMENT:
1699             return tentacle_type::vine;
1700 
1701         default:
1702             die("Invalid tentacle type!");
1703             return tentacle_type::kraken; // Silence a warning
1704     }
1705 }
1706 
_tentacle_tile_not_flying(tileidx_t tile)1707 static bool _tentacle_tile_not_flying(tileidx_t tile)
1708 {
1709     // All tiles between these two enums feature tentacles
1710     // emerging from water.
1711     return tile >= TILEP_FIRST_TENTACLE_IN_WATER
1712            && tile <= TILEP_LAST_TENTACLE_IN_WATER
1713         || tile >= TILEP_FIRST_ZOMBIE_TENTACLE_IN_WATER
1714            && tile <= TILEP_LAST_ZOMBIE_TENTACLE_IN_WATER
1715         || tile >= TILEP_FIRST_SIMULACRUM_TENTACLE_IN_WATER
1716            && tile <= TILEP_LAST_SIMULACRUM_TENTACLE_IN_WATER
1717         || tile >= TILEP_FIRST_SPECTRAL_TENTACLE_IN_WATER
1718            && tile <= TILEP_LAST_SPECTRAL_TENTACLE_IN_WATER;
1719 }
1720 
_tileidx_monster_no_props(const monster_info & mon)1721 static tileidx_t _tileidx_monster_no_props(const monster_info& mon)
1722 {
1723     const bool in_water = feat_is_water(env.map_knowledge(mon.pos).feat());
1724 
1725     // Show only base class for detected monsters.
1726     if (mons_class_is_zombified(mon.type))
1727         return _tileidx_monster_zombified(mon);
1728 
1729     if (mon.props.exists("monster_tile"))
1730     {
1731         tileidx_t t = mon.props["monster_tile"].get_short();
1732         if (t == TILEP_MONS_HELL_WIZARD)
1733             return _mon_sinus(t);
1734         return t;
1735     }
1736 
1737     int tile_num = 0;
1738     if (mon.props.exists(TILE_NUM_KEY))
1739         tile_num = mon.props[TILE_NUM_KEY].get_short();
1740 
1741     bool vary = !(mon.props.exists("fake") && mon.props["fake"].get_bool());
1742     const tileidx_t base = tileidx_monster_base(mon.type,
1743                                                 mon.pos.y*GXM + mon.pos.x,
1744                                                 in_water, mon.colour(true),
1745                                                 mon.number, tile_num, vary);
1746 
1747     switch (mon.type)
1748     {
1749         // use a different tile not using a standard ranged weapon.
1750         case MONS_CENTAUR:
1751         case MONS_CENTAUR_WARRIOR:
1752         case MONS_YAKTAUR:
1753         case MONS_YAKTAUR_CAPTAIN:
1754             return base + (_bow_offset(mon) ? 1 : 0);
1755 
1756         case MONS_CEREBOV:
1757             return base + (mon.inv[MSLOT_WEAPON] ? 0 : 1);
1758 
1759         case MONS_BALLISTOMYCETE:
1760             return base + (mon.is_active ? 1 : 0);
1761 
1762         case MONS_DUVESSA:
1763         case MONS_DOWAN:
1764             return mon.props.exists(ELVEN_IS_ENERGIZED_KEY) ? base + 1 : base;
1765 
1766         case MONS_ARACHNE:
1767         {
1768             // Arachne normally is drawn with her staff wielded two-handed,
1769             // but will use a regular stance if she picks up a shield
1770             // (enhancer staves are compatible with those).
1771             const item_def* weapon = mon.inv[MSLOT_WEAPON].get();
1772             if (!mon.inv[MSLOT_SHIELD] && weapon
1773                 && (weapon->is_type(OBJ_STAVES, STAFF_POISON)
1774                     || is_unrandom_artefact(*weapon, UNRAND_OLGREB)))
1775             {
1776                 return base;
1777             }
1778             else
1779                 return base + 1;
1780         }
1781 
1782         case MONS_AGNES:
1783         {
1784             // For if Agnes loses her lajatang
1785             const item_def * const weapon = mon.inv[MSLOT_WEAPON].get();
1786             if (weapon && weapon->is_type(OBJ_WEAPONS, WPN_LAJATANG))
1787                 return TILEP_MONS_AGNES;
1788             else
1789                 return TILEP_MONS_AGNES_STAVELESS;
1790         }
1791 
1792         case MONS_EDMUND:
1793         {
1794             // For if Edmund loses his weapon
1795             const item_def * const weapon = mon.inv[MSLOT_WEAPON].get();
1796             if (weapon && (weapon->is_type(OBJ_WEAPONS, WPN_DIRE_FLAIL)
1797                             || weapon->is_type(OBJ_WEAPONS, WPN_FLAIL)))
1798             {
1799                 return TILEP_MONS_EDMUND;
1800             }
1801             else
1802                 return TILEP_MONS_EDMUND_WEAPONLESS;
1803         }
1804 
1805         case MONS_ERICA:
1806         {
1807             // For if Erica loses her flaming scimitar
1808             const item_def * const weapon = mon.inv[MSLOT_WEAPON].get();
1809             if (weapon
1810                 && weapon->is_type(OBJ_WEAPONS, WPN_SCIMITAR)
1811                 && get_weapon_brand(*weapon) == SPWPN_FLAMING)
1812             {
1813                 return TILEP_MONS_ERICA;
1814             }
1815             else
1816                 return TILEP_MONS_ERICA_SWORDLESS;
1817         }
1818 
1819         case MONS_BUSH:
1820             if (env.map_knowledge(mon.pos).cloud() == CLOUD_FIRE)
1821                 return TILEP_MONS_BUSH_BURNING;
1822             return base;
1823 
1824         case MONS_BOULDER_BEETLE:
1825             return mon.is(MB_ROLLING)
1826                    ? _mon_random(TILEP_MONS_BOULDER_BEETLE_ROLLING, mon.number)
1827                    : base;
1828 
1829         case MONS_ANIMATED_ARMOUR:
1830             return base | TILE_FLAG_ANIM_OBJ;
1831 
1832         case MONS_DANCING_WEAPON:
1833         {
1834             // Use item tile.
1835             const item_def& item = *mon.inv[MSLOT_WEAPON];
1836             return tileidx_item(item) | TILE_FLAG_ANIM_OBJ;
1837         }
1838 
1839         case MONS_SPECTRAL_WEAPON:
1840         {
1841             // TODO: it would be good to show the TILE_FLAG_ANIM_OBJ icon with
1842             // these too, but most are oriented NW-SE and it looks bad
1843             if (!mon.inv[MSLOT_WEAPON])
1844                 return TILEP_MONS_SPECTRAL_SBL;
1845 
1846             // Tiles exist for each class of weapon.
1847             const item_def& item = *mon.inv[MSLOT_WEAPON];
1848             switch (item_attack_skill(item))
1849             {
1850             case SK_LONG_BLADES:
1851                 return TILEP_MONS_SPECTRAL_LBL;
1852             case SK_AXES:
1853                 return TILEP_MONS_SPECTRAL_AXE;
1854             case SK_POLEARMS:
1855                 return TILEP_MONS_SPECTRAL_SPEAR;
1856             case SK_STAVES:
1857                 return TILEP_MONS_SPECTRAL_STAFF;
1858             case SK_MACES_FLAILS:
1859                 {
1860                     const weapon_type wt = (weapon_type)item.sub_type;
1861                     return (wt == WPN_WHIP || wt == WPN_FLAIL
1862                             || wt == WPN_DIRE_FLAIL || wt == WPN_DEMON_WHIP
1863                             || wt == WPN_SACRED_SCOURGE)
1864                         ? TILEP_MONS_SPECTRAL_WHIP
1865                         : TILEP_MONS_SPECTRAL_MACE;
1866                 }
1867             default:
1868                 return TILEP_MONS_SPECTRAL_SBL;
1869             }
1870         }
1871 
1872         case MONS_KRAKEN_TENTACLE:
1873         case MONS_KRAKEN_TENTACLE_SEGMENT:
1874         case MONS_ELDRITCH_TENTACLE:
1875         case MONS_ELDRITCH_TENTACLE_SEGMENT:
1876         case MONS_STARSPAWN_TENTACLE:
1877         case MONS_STARSPAWN_TENTACLE_SEGMENT:
1878         case MONS_SNAPLASHER_VINE:
1879         case MONS_SNAPLASHER_VINE_SEGMENT:
1880         {
1881             tileidx_t tile = tileidx_tentacle(mon);
1882             _handle_tentacle_overlay(mon.pos, tile, _get_tentacle_type(mon));
1883 
1884             if (!_mons_is_kraken_tentacle(mon.type)
1885                 && tile >= TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N
1886                 && (tile <= TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W_SE
1887                     || tile <= TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_W_NW &&
1888                        mon.type == MONS_SNAPLASHER_VINE_SEGMENT))
1889             {
1890                 tile += TILEP_MONS_ELDRITCH_TENTACLE_PORTAL_N;
1891                 tile -= TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N;
1892 
1893                 if (mon.type == MONS_STARSPAWN_TENTACLE
1894                     || mon.type == MONS_STARSPAWN_TENTACLE_SEGMENT)
1895                 {
1896                     tile += TILEP_MONS_STARSPAWN_TENTACLE_N;
1897                     tile -= TILEP_MONS_ELDRITCH_TENTACLE_N;
1898                 }
1899                 else if (mon.type == MONS_SNAPLASHER_VINE
1900                          || mon.type == MONS_SNAPLASHER_VINE_SEGMENT)
1901                 {
1902                     tile += TILEP_MONS_VINE_N;
1903                     tile -= TILEP_MONS_ELDRITCH_TENTACLE_N;
1904                 }
1905             }
1906 
1907             if (_mons_is_kraken_tentacle(mon.type) && mon.base_type == MONS_ZOMBIE)
1908             {
1909                 tile += TILEP_MONS_KRAKEN_ZOMBIE_TENTACLE_SEGMENT_N;
1910                 tile -= TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N;
1911             }
1912             if (_mons_is_kraken_tentacle(mon.type) && mon.base_type == MONS_SIMULACRUM)
1913             {
1914                 tile += TILEP_MONS_KRAKEN_SIMULACRUM_TENTACLE_SEGMENT_N;
1915                 tile -= TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N;
1916             }
1917             if (_mons_is_kraken_tentacle(mon.type) && mon.base_type == MONS_SPECTRAL_THING)
1918             {
1919                 tile += TILEP_MONS_KRAKEN_SPECTRAL_TENTACLE_SEGMENT_N;
1920                 tile -= TILEP_MONS_KRAKEN_TENTACLE_SEGMENT_N;
1921             }
1922 
1923             return tile;
1924         }
1925 
1926         case MONS_SENSED:
1927         {
1928             // Should be always out of LOS, though...
1929             if (base == TILEP_MONS_PROGRAM_BUG)
1930                 return TILE_UNSEEN_MONSTER;
1931             return base;
1932         }
1933 
1934         default:
1935             return base;
1936     }
1937 }
1938 
tileidx_monster(const monster_info & mons)1939 tileidx_t tileidx_monster(const monster_info& mons)
1940 {
1941     tileidx_t ch = _tileidx_monster_no_props(mons);
1942 
1943     if ((!mons.ground_level() && !_tentacle_tile_not_flying(ch)))
1944         ch |= TILE_FLAG_FLYING;
1945     if (mons.is(MB_CAUGHT))
1946         ch |= TILE_FLAG_NET;
1947     if (mons.is(MB_WEBBED))
1948         ch |= TILE_FLAG_WEB;
1949     if (mons.is(MB_POISONED))
1950         ch |= TILE_FLAG_POISON;
1951     else if (mons.is(MB_MORE_POISONED))
1952         ch |= TILE_FLAG_MORE_POISON;
1953     else if (mons.is(MB_MAX_POISONED))
1954         ch |= TILE_FLAG_MAX_POISON;
1955     if (mons.is(MB_BURNING))
1956         ch |= TILE_FLAG_STICKY_FLAME;
1957     if (mons.is(MB_INNER_FLAME))
1958         ch |= TILE_FLAG_INNER_FLAME;
1959     if (!mons.constrictor_name.empty())
1960         ch |= TILE_FLAG_CONSTRICTED;
1961     if (mons.is(MB_BERSERK))
1962         ch |= TILE_FLAG_BERSERK;
1963     if (mons.is(MB_GLOWING))
1964         ch |= TILE_FLAG_GLOWING;
1965     if (mons.is(MB_SLOWED))
1966         ch |= TILE_FLAG_SLOWED;
1967     if (mons.is(MB_MIRROR_DAMAGE))
1968         ch |= TILE_FLAG_PAIN_MIRROR;
1969     if (mons.is(MB_HASTED))
1970         ch |= TILE_FLAG_HASTED;
1971     if (mons.is(MB_STRONG))
1972         ch |= TILE_FLAG_MIGHT;
1973     if (mons.is(MB_PETRIFYING))
1974         ch |= TILE_FLAG_PETRIFYING;
1975     if (mons.is(MB_PETRIFIED))
1976         ch |= TILE_FLAG_PETRIFIED;
1977     if (mons.is(MB_BLIND))
1978         ch |= TILE_FLAG_BLIND;
1979     if (mons.is(MB_SUMMONED))
1980         ch |= TILE_FLAG_SUMMONED;
1981     if (mons.is(MB_PERM_SUMMON))
1982         ch |= TILE_FLAG_PERM_SUMMON;
1983     if (mons.is(MB_WORD_OF_RECALL))
1984         ch |= TILE_FLAG_RECALL;
1985     if (mons.is(MB_LIGHTLY_DRAINED) || mons.is(MB_HEAVILY_DRAINED))
1986         ch |= TILE_FLAG_DRAIN;
1987     if (mons.is(MB_IDEALISED))
1988         ch |= TILE_FLAG_IDEALISED;
1989     if (mons.is(MB_BOUND_SOUL))
1990         ch |= TILE_FLAG_BOUND_SOUL;
1991     if (mons.is(MB_INFESTATION))
1992         ch |= TILE_FLAG_INFESTED;
1993     if (mons.is(MB_CORROSION))
1994         ch |= TILE_FLAG_CORRODED;
1995     if (mons.is(MB_SWIFT))
1996         ch |= TILE_FLAG_SWIFT;
1997     if (mons.is(MB_VILE_CLUTCH))
1998         ch |= TILE_FLAG_VILE_CLUTCH;
1999     if (mons.is(MB_POSSESSABLE))
2000         ch |= TILE_FLAG_POSSESSABLE;
2001     if (mons.is(MB_WITHERING) || mons.is(MB_CRUMBLING))
2002         ch |= TILE_FLAG_SLOWLY_DYING;
2003 
2004     if (mons.attitude == ATT_FRIENDLY)
2005         ch |= TILE_FLAG_PET;
2006     else if (mons.attitude == ATT_GOOD_NEUTRAL)
2007         ch |= TILE_FLAG_GD_NEUTRAL;
2008     else if (mons.neutral())
2009         ch |= TILE_FLAG_NEUTRAL;
2010     else
2011         switch (mons.threat)
2012         {
2013         case MTHRT_TRIVIAL:
2014             if (Options.tile_show_threat_levels.find("trivial") != string::npos)
2015                 ch |= TILE_FLAG_TRIVIAL;
2016             break;
2017         case MTHRT_EASY:
2018             if (Options.tile_show_threat_levels.find("easy") != string::npos)
2019                 ch |= TILE_FLAG_EASY;
2020             break;
2021         case MTHRT_TOUGH:
2022             if (Options.tile_show_threat_levels.find("tough") != string::npos)
2023                 ch |= TILE_FLAG_TOUGH;
2024             break;
2025         case MTHRT_NASTY:
2026             if (Options.tile_show_threat_levels.find("nasty") != string::npos)
2027                 ch |= TILE_FLAG_NASTY;
2028             break;
2029         default:
2030             break;
2031         }
2032 
2033     if (mons.is(MB_FLEEING))
2034         ch |= TILE_FLAG_FLEEING;
2035     else if (mons.is(MB_STABBABLE) || mons.is(MB_SLEEPING)
2036              || mons.is(MB_DORMANT))
2037     {
2038         // XXX: should we have different tile flags for "stabbable" versus
2039         // "sleeping"?
2040         ch |= TILE_FLAG_STAB;
2041     }
2042     // Should petrify show the '?' symbol?
2043     else if (mons.is(MB_DISTRACTED) && !mons.is(MB_PETRIFYING)
2044             || mons.attitude == ATT_FRIENDLY && mons.is(MB_CONFUSED))
2045     {
2046         ch |= TILE_FLAG_MAY_STAB;
2047     }
2048 
2049     mon_dam_level_type damage_level = mons.dam;
2050 
2051     switch (damage_level)
2052     {
2053     case MDAM_DEAD:
2054     case MDAM_ALMOST_DEAD:
2055         ch |= TILE_FLAG_MDAM_ADEAD;
2056         break;
2057     case MDAM_SEVERELY_DAMAGED:
2058         ch |= TILE_FLAG_MDAM_SEV;
2059         break;
2060     case MDAM_HEAVILY_DAMAGED:
2061         ch |= TILE_FLAG_MDAM_HEAVY;
2062         break;
2063     case MDAM_MODERATELY_DAMAGED:
2064         ch |= TILE_FLAG_MDAM_MOD;
2065         break;
2066     case MDAM_LIGHTLY_DAMAGED:
2067         ch |= TILE_FLAG_MDAM_LIGHT;
2068         break;
2069     case MDAM_OKAY:
2070     default:
2071         // no flag for okay.
2072         break;
2073     }
2074 
2075 #ifdef USE_TILE_LOCAL
2076     // handled on client side in WebTiles
2077     if (Options.tile_show_demon_tier)
2078     {
2079 #endif
2080         // FIXME: non-linear bits suck, should be a simple addition
2081         switch (mons_demon_tier(mons.type))
2082         {
2083         case 1:
2084             ch |= TILE_FLAG_DEMON_1;
2085             break;
2086         case 2:
2087             ch |= TILE_FLAG_DEMON_2;
2088             break;
2089         case 3:
2090             ch |= TILE_FLAG_DEMON_3;
2091             break;
2092         case 4:
2093             ch |= TILE_FLAG_DEMON_4;
2094             break;
2095         case 5:
2096             ch |= TILE_FLAG_DEMON_5;
2097             break;
2098         }
2099 #ifdef USE_TILE_LOCAL
2100     }
2101 #endif
2102 
2103     return ch;
2104 }
2105 #endif
2106 
tileidx_draco_base(monster_type draco)2107 static tileidx_t tileidx_draco_base(monster_type draco)
2108 {
2109     return TILEP_DRACO_BASE + (draco - MONS_DRACONIAN);
2110 }
2111 
tileidx_draco_base(const monster_info & mon)2112 tileidx_t tileidx_draco_base(const monster_info& mon)
2113 {
2114     return tileidx_draco_base(mon.draco_or_demonspawn_subspecies());
2115 }
2116 
tileidx_draco_job(const monster_info & mon)2117 tileidx_t tileidx_draco_job(const monster_info& mon)
2118 {
2119     if (mons_is_draconian_job(mon.type))
2120         return get_mon_base_tile(mon.type);
2121     return 0;
2122 }
2123 
tileidx_demonspawn_base(const monster_info & mon)2124 tileidx_t tileidx_demonspawn_base(const monster_info& mon)
2125 {
2126     return get_mon_base_tile(mon.draco_or_demonspawn_subspecies());
2127 }
2128 
tileidx_demonspawn_job(const monster_info & mon)2129 tileidx_t tileidx_demonspawn_job(const monster_info& mon)
2130 {
2131     if (mons_is_demonspawn_job(mon.type))
2132         return get_mon_base_tile(mon.type);
2133     return 0;
2134 }
2135 
2136 #ifdef USE_TILE
2137 /**
2138  * Return the monster tile used for the player based on a monster type.
2139  *
2140  * When using the player species monster or a monster in general instead of an
2141  * explicit tile name, this function cleans up the tiles for certain monsters
2142  * where there's an alternate tile that's better than the base one for doll
2143  * purposes.
2144  * @returns The tile id of the tile that will be used.
2145 */
tileidx_player_mons()2146 tileidx_t tileidx_player_mons()
2147 {
2148     ASSERT(Options.tile_use_monster != MONS_0);
2149 
2150     monster_type mons;
2151     if (Options.tile_player_tile)
2152         return Options.tile_player_tile;
2153 
2154     if (Options.tile_use_monster == MONS_PLAYER)
2155         mons = player_mons(false);
2156     else
2157         mons = Options.tile_use_monster;
2158 
2159     if (mons_is_base_draconian(mons))
2160         return tileidx_draco_base(mons);
2161 
2162     switch (mons)
2163     {
2164     case MONS_CENTAUR:         return TILEP_MONS_CENTAUR_MELEE;
2165     case MONS_CENTAUR_WARRIOR: return TILEP_MONS_CENTAUR_WARRIOR_MELEE;
2166     case MONS_YAKTAUR:         return TILEP_MONS_YAKTAUR_MELEE;
2167     case MONS_YAKTAUR_CAPTAIN: return TILEP_MONS_YAKTAUR_CAPTAIN_MELEE;
2168     default:                   return tileidx_monster_base(mons, 0);
2169     }
2170 }
2171 #endif
2172 
_tileidx_unrand_artefact(int idx)2173 static tileidx_t _tileidx_unrand_artefact(int idx)
2174 {
2175     const tileidx_t tile = unrandart_to_tile(idx);
2176     return tile ? tile : tileidx_t{TILE_TODO};
2177 }
2178 
_tileidx_wyrmbane(int plus)2179 static tileidx_t _tileidx_wyrmbane(int plus)
2180 {
2181     if (plus < 10)
2182         return TILE_UNRAND_WYRMBANE;
2183     else if (plus < 12)
2184         return TILE_UNRAND_WYRMBANE1;
2185     else if (plus < 15)
2186         return TILE_UNRAND_WYRMBANE2;
2187     else if (plus < 18)
2188         return TILE_UNRAND_WYRMBANE3;
2189     else
2190         return TILE_UNRAND_WYRMBANE4;
2191 }
2192 
_tileidx_weapon_base(const item_def & item)2193 static tileidx_t _tileidx_weapon_base(const item_def &item)
2194 {
2195     switch (item.sub_type)
2196     {
2197     case WPN_DAGGER:                return TILE_WPN_DAGGER;
2198     case WPN_SHORT_SWORD:           return TILE_WPN_SHORT_SWORD;
2199     case WPN_QUICK_BLADE:           return TILE_WPN_QUICK_BLADE;
2200     case WPN_RAPIER:                return TILE_WPN_RAPIER;
2201     case WPN_FALCHION:              return TILE_WPN_FALCHION;
2202     case WPN_LONG_SWORD:            return TILE_WPN_LONG_SWORD;
2203     case WPN_GREAT_SWORD:           return TILE_WPN_GREAT_SWORD;
2204     case WPN_SCIMITAR:              return TILE_WPN_SCIMITAR;
2205     case WPN_DOUBLE_SWORD:          return TILE_WPN_DOUBLE_SWORD;
2206     case WPN_TRIPLE_SWORD:          return TILE_WPN_TRIPLE_SWORD;
2207     case WPN_HAND_AXE:              return TILE_WPN_HAND_AXE;
2208     case WPN_WAR_AXE:               return TILE_WPN_WAR_AXE;
2209     case WPN_BROAD_AXE:             return TILE_WPN_BROAD_AXE;
2210     case WPN_BATTLEAXE:             return TILE_WPN_BATTLEAXE;
2211     case WPN_EXECUTIONERS_AXE:      return TILE_WPN_EXECUTIONERS_AXE;
2212 #if TAG_MAJOR_VERSION == 34
2213     case WPN_BLOWGUN:               return TILE_WPN_BLOWGUN;
2214 #endif
2215     case WPN_HUNTING_SLING:         return TILE_WPN_HUNTING_SLING;
2216     case WPN_FUSTIBALUS:            return TILE_WPN_FUSTIBALUS;
2217     case WPN_SHORTBOW:              return TILE_WPN_SHORTBOW;
2218     case WPN_HAND_CROSSBOW:         return TILE_WPN_HAND_CROSSBOW;
2219     case WPN_ARBALEST:              return TILE_WPN_ARBALEST;
2220     case WPN_TRIPLE_CROSSBOW:       return TILE_WPN_TRIPLE_CROSSBOW;
2221     case WPN_SPEAR:                 return TILE_WPN_SPEAR;
2222     case WPN_TRIDENT:               return TILE_WPN_TRIDENT;
2223     case WPN_HALBERD:               return TILE_WPN_HALBERD;
2224     case WPN_SCYTHE:                return TILE_WPN_SCYTHE;
2225     case WPN_GLAIVE:                return TILE_WPN_GLAIVE;
2226 #if TAG_MAJOR_VERSION == 34
2227     case WPN_STAFF:                 return TILE_WPN_STAFF;
2228 #endif
2229     case WPN_QUARTERSTAFF:          return TILE_WPN_QUARTERSTAFF;
2230     case WPN_CLUB:                  return TILE_WPN_CLUB;
2231     case WPN_MACE:                  return TILE_WPN_MACE;
2232     case WPN_FLAIL:                 return TILE_WPN_FLAIL;
2233     case WPN_GREAT_MACE:            return TILE_WPN_GREAT_MACE;
2234     case WPN_DIRE_FLAIL:            return TILE_WPN_DIRE_FLAIL;
2235     case WPN_MORNINGSTAR:           return TILE_WPN_MORNINGSTAR;
2236     case WPN_EVENINGSTAR:           return TILE_WPN_EVENINGSTAR;
2237     case WPN_GIANT_CLUB:            return TILE_WPN_GIANT_CLUB;
2238     case WPN_GIANT_SPIKED_CLUB:     return TILE_WPN_GIANT_SPIKED_CLUB;
2239     case WPN_WHIP:                  return TILE_WPN_WHIP;
2240     case WPN_DEMON_BLADE:           return TILE_WPN_DEMON_BLADE;
2241     case WPN_EUDEMON_BLADE:         return TILE_WPN_BLESSED_BLADE;
2242     case WPN_DEMON_WHIP:            return TILE_WPN_DEMON_WHIP;
2243     case WPN_SACRED_SCOURGE:        return TILE_WPN_SACRED_SCOURGE;
2244     case WPN_DEMON_TRIDENT:         return TILE_WPN_DEMON_TRIDENT;
2245     case WPN_TRISHULA:              return TILE_WPN_TRISHULA;
2246     case WPN_LONGBOW:               return TILE_WPN_LONGBOW;
2247     case WPN_LAJATANG:              return TILE_WPN_LAJATANG;
2248     case WPN_BARDICHE:              return TILE_WPN_BARDICHE;
2249     }
2250 
2251     return TILE_ERROR;
2252 }
2253 
_tileidx_weapon(const item_def & item)2254 static tileidx_t _tileidx_weapon(const item_def &item)
2255 {
2256     tileidx_t tile = _tileidx_weapon_base(item);
2257     return tileidx_enchant_equ(item, tile);
2258 }
2259 
_tileidx_missile_base(const item_def & item)2260 static tileidx_t _tileidx_missile_base(const item_def &item)
2261 {
2262     int brand = item.brand;
2263     // 0 indicates no ego at all
2264 
2265     switch (item.sub_type)
2266     {
2267     case MI_STONE:        return TILE_MI_STONE;
2268     case MI_LARGE_ROCK:   return TILE_MI_LARGE_ROCK;
2269     case MI_THROWING_NET: return TILE_MI_THROWING_NET;
2270     case MI_BOOMERANG:
2271         switch (brand)
2272         {
2273         default:             return TILE_MI_BOOMERANG + 1;
2274         case 0:              return TILE_MI_BOOMERANG;
2275         case SPMSL_SILVER:   return TILE_MI_BOOMERANG_SILVER;
2276         }
2277 
2278     case MI_DART:
2279         switch (brand)
2280         {
2281         default:             return TILE_MI_DART + 1;
2282         case 0:              return TILE_MI_DART;
2283         case SPMSL_POISONED: return TILE_MI_DART_POISONED;
2284         case SPMSL_CURARE:   return TILE_MI_DART_CURARE;
2285         case SPMSL_BLINDING: return TILE_MI_DART_BLINDING;
2286         case SPMSL_FRENZY:   return TILE_MI_DART_FRENZY;
2287         }
2288 
2289     case MI_ARROW:
2290         switch (brand)
2291         {
2292         default:             return TILE_MI_ARROW + 1;
2293         case 0:              return TILE_MI_ARROW;
2294 #if TAG_MAJOR_VERSION == 34
2295         case SPMSL_STEEL:    return TILE_MI_ARROW_STEEL;
2296 #endif
2297         case SPMSL_SILVER:   return TILE_MI_ARROW_SILVER;
2298         }
2299 
2300     case MI_BOLT:
2301         switch (brand)
2302         {
2303         default:             return TILE_MI_BOLT + 1;
2304         case 0:              return TILE_MI_BOLT;
2305 #if TAG_MAJOR_VERSION == 34
2306         case SPMSL_STEEL:    return TILE_MI_BOLT_STEEL;
2307 #endif
2308         case SPMSL_SILVER:   return TILE_MI_BOLT_SILVER;
2309         }
2310 
2311     case MI_SLING_BULLET:
2312         switch (brand)
2313         {
2314         default:             return TILE_MI_SLING_BULLET + 1;
2315         case 0:              return TILE_MI_SLING_BULLET;
2316 #if TAG_MAJOR_VERSION == 34
2317         case SPMSL_STEEL:    return TILE_MI_SLING_BULLET_STEEL;
2318 #endif
2319         case SPMSL_SILVER:   return TILE_MI_SLING_BULLET_SILVER;
2320         }
2321 
2322     case MI_JAVELIN:
2323         switch (brand)
2324         {
2325         default:             return TILE_MI_JAVELIN + 1;
2326         case 0:              return TILE_MI_JAVELIN;
2327 #if TAG_MAJOR_VERSION == 34
2328         case SPMSL_STEEL:    return TILE_MI_JAVELIN_STEEL;
2329 #endif
2330         case SPMSL_SILVER:   return TILE_MI_JAVELIN_SILVER;
2331         }
2332     }
2333 
2334     return TILE_ERROR;
2335 }
2336 
_tileidx_missile(const item_def & item)2337 static tileidx_t _tileidx_missile(const item_def &item)
2338 {
2339     int tile = _tileidx_missile_base(item);
2340     return tileidx_enchant_equ(item, tile);
2341 }
2342 
_tileidx_armour_base(const item_def & item)2343 static tileidx_t _tileidx_armour_base(const item_def &item)
2344 {
2345     int type  = item.sub_type;
2346     switch (type)
2347     {
2348     case ARM_ROBE:
2349         return TILE_ARM_ROBE;
2350 
2351     case ARM_LEATHER_ARMOUR:
2352         return TILE_ARM_LEATHER_ARMOUR;
2353 
2354     case ARM_RING_MAIL:
2355         return TILE_ARM_RING_MAIL;
2356 
2357     case ARM_SCALE_MAIL:
2358         return TILE_ARM_SCALE_MAIL;
2359 
2360     case ARM_CHAIN_MAIL:
2361         return TILE_ARM_CHAIN_MAIL;
2362 
2363     case ARM_PLATE_ARMOUR:
2364         return TILE_ARM_PLATE_ARMOUR;
2365 
2366     case ARM_CRYSTAL_PLATE_ARMOUR:
2367         return TILE_ARM_CRYSTAL_PLATE_ARMOUR;
2368 
2369     case ARM_KITE_SHIELD:
2370         return TILE_ARM_KITE_SHIELD;
2371 
2372     case ARM_CLOAK:
2373         return TILE_ARM_CLOAK;
2374 
2375     case ARM_SCARF:
2376         return TILE_ARM_SCARF;
2377 
2378     case ARM_HAT:
2379         return TILE_THELM_HAT;
2380 
2381 #if TAG_MAJOR_VERSION == 34
2382     case ARM_CAP:
2383         return TILE_THELM_CAP;
2384 #endif
2385 
2386     case ARM_HELMET:
2387         return TILE_THELM_HELM;
2388 
2389     case ARM_GLOVES:
2390         return TILE_ARM_GLOVES;
2391 
2392     case ARM_BOOTS:
2393         return TILE_ARM_BOOTS;
2394 
2395     case ARM_BUCKLER:
2396         return TILE_ARM_BUCKLER;
2397 
2398     case ARM_TOWER_SHIELD:
2399         return TILE_ARM_TOWER_SHIELD;
2400 
2401     case ARM_BARDING:
2402         return TILE_ARM_BARDING;
2403 
2404     case ARM_ANIMAL_SKIN:
2405         return TILE_ARM_ANIMAL_SKIN;
2406 
2407     case ARM_TROLL_LEATHER_ARMOUR:
2408         return TILE_ARM_TROLL_LEATHER_ARMOUR;
2409 
2410     case ARM_FIRE_DRAGON_ARMOUR:
2411         return TILE_ARM_FIRE_DRAGON_ARMOUR;
2412 
2413     case ARM_ICE_DRAGON_ARMOUR:
2414         return TILE_ARM_ICE_DRAGON_ARMOUR;
2415 
2416     case ARM_STEAM_DRAGON_ARMOUR:
2417         return TILE_ARM_STEAM_DRAGON_ARMOUR;
2418 
2419     case ARM_ACID_DRAGON_ARMOUR:
2420         return TILE_ARM_ACID_DRAGON_ARMOUR;
2421 
2422     case ARM_QUICKSILVER_DRAGON_ARMOUR:
2423         return TILE_ARM_QUICKSILVER_DRAGON_ARMOUR;
2424 
2425     case ARM_STORM_DRAGON_ARMOUR:
2426         return TILE_ARM_STORM_DRAGON_ARMOUR;
2427 
2428     case ARM_SHADOW_DRAGON_ARMOUR:
2429         return TILE_ARM_SHADOW_DRAGON_ARMOUR;
2430 
2431     case ARM_GOLD_DRAGON_ARMOUR:
2432         return TILE_ARM_GOLD_DRAGON_ARMOUR;
2433 
2434     case ARM_PEARL_DRAGON_ARMOUR:
2435         return TILE_ARM_PEARL_DRAGON_ARMOUR;
2436 
2437     case ARM_SWAMP_DRAGON_ARMOUR:
2438         return TILE_ARM_SWAMP_DRAGON_ARMOUR;
2439     }
2440 
2441     return TILE_ERROR;
2442 }
2443 
_tileidx_armour(const item_def & item)2444 static tileidx_t _tileidx_armour(const item_def &item)
2445 {
2446     tileidx_t tile = _tileidx_armour_base(item);
2447     return tileidx_enchant_equ(item, tile);
2448 }
2449 
2450 // Returns index of skeleton tiles.
2451 // Parameter item holds the skeleton.
_tileidx_bone(const item_def & item)2452 static tileidx_t _tileidx_bone(const item_def &item)
2453 {
2454     const monster_type mc = item.mon_type;
2455     const size_type st = get_monster_data(mc)->size;
2456     int cs = 0;
2457 
2458     switch (st)
2459     {
2460     default:
2461         cs = 0; break;
2462     case SIZE_MEDIUM:
2463         cs = 1; break;
2464     case SIZE_LARGE:
2465     case SIZE_BIG:
2466         cs = 2; break;
2467     case SIZE_GIANT:
2468         cs = 3; break;
2469     }
2470 
2471     switch (get_mon_shape(item.mon_type))
2472     {
2473     case MON_SHAPE_HUMANOID:
2474     case MON_SHAPE_HUMANOID_TAILED:
2475     case MON_SHAPE_HUMANOID_WINGED:
2476     case MON_SHAPE_HUMANOID_WINGED_TAILED:
2477         return TILE_FOOD_BONE_HUMANOID + cs;
2478     default:
2479         return TILE_FOOD_BONE + cs;
2480     }
2481 }
2482 
2483 // Returns index of corpse tiles.
2484 // Parameter item holds the corpse.
_tileidx_corpse(const item_def & item)2485 static tileidx_t _tileidx_corpse(const item_def &item)
2486 {
2487     const int type = item.plus;
2488     const tileidx_t base = get_mon_base_corpse_tile((monster_type)type);
2489 
2490     switch (type)
2491     {
2492     case MONS_KILLER_KLOWN:
2493     {
2494         const int count = tile_main_count(TILE_CORPSE_KILLER_KLOWN);
2495         return base + ui_random(count);
2496     }
2497 
2498     case MONS_UGLY_THING:
2499     case MONS_VERY_UGLY_THING:
2500     {
2501         int colour_offset = ugly_thing_colour_offset(item.get_colour());
2502         if (colour_offset == -1)
2503             colour_offset = 0;
2504         return base + colour_offset;
2505     }
2506 
2507     default:
2508         return base;
2509     }
2510 }
2511 
_tileidx_uncollected_rune(const item_def & item)2512 static tileidx_t _tileidx_uncollected_rune(const item_def &item)
2513 {
2514     switch (item.sub_type)
2515     {
2516     // the hell runes:
2517     case RUNE_DIS:         return TILE_UNCOLLECTED_RUNE_DIS;
2518     case RUNE_GEHENNA:     return TILE_UNCOLLECTED_RUNE_GEHENNA;
2519     case RUNE_COCYTUS:     return TILE_UNCOLLECTED_RUNE_COCYTUS;
2520     case RUNE_TARTARUS:    return TILE_UNCOLLECTED_RUNE_TARTARUS;
2521 
2522     // special pandemonium runes:
2523     case RUNE_MNOLEG:      return TILE_UNCOLLECTED_RUNE_MNOLEG;
2524     case RUNE_LOM_LOBON:   return TILE_UNCOLLECTED_RUNE_LOM_LOBON;
2525     case RUNE_CEREBOV:     return TILE_UNCOLLECTED_RUNE_CEREBOV;
2526     case RUNE_GLOORX_VLOQ: return TILE_UNCOLLECTED_RUNE_GLOORX_VLOQ;
2527 
2528     case RUNE_DEMONIC:     return TILE_UNCOLLECTED_RUNE_DEMONIC;
2529     case RUNE_ABYSSAL:     return TILE_UNCOLLECTED_RUNE_ABYSS;
2530 
2531     case RUNE_SNAKE:       return TILE_UNCOLLECTED_RUNE_SNAKE;
2532     case RUNE_SPIDER:      return TILE_UNCOLLECTED_RUNE_SPIDER;
2533     case RUNE_SLIME:       return TILE_UNCOLLECTED_RUNE_SLIME;
2534     case RUNE_VAULTS:      return TILE_UNCOLLECTED_RUNE_VAULTS;
2535     case RUNE_TOMB:        return TILE_UNCOLLECTED_RUNE_TOMB;
2536     case RUNE_SWAMP:       return TILE_UNCOLLECTED_RUNE_SWAMP;
2537     case RUNE_SHOALS:      return TILE_UNCOLLECTED_RUNE_SHOALS;
2538     case RUNE_ELF:         return TILE_UNCOLLECTED_RUNE_ELVEN;
2539 
2540     case RUNE_FOREST:
2541     default:               return TILE_MISC_UNCOLLECTED_RUNE_OF_ZOT;
2542     }
2543 }
2544 
_tileidx_rune(const item_def & item)2545 static tileidx_t _tileidx_rune(const item_def &item)
2546 {
2547     switch (item.sub_type)
2548     {
2549     // the hell runes:
2550     case RUNE_DIS:         return TILE_RUNE_DIS;
2551     case RUNE_GEHENNA:     return TILE_RUNE_GEHENNA;
2552     case RUNE_COCYTUS:     return TILE_RUNE_COCYTUS;
2553     case RUNE_TARTARUS:    return TILE_RUNE_TARTARUS;
2554 
2555     // special pandemonium runes:
2556     case RUNE_MNOLEG:      return TILE_RUNE_MNOLEG;
2557     case RUNE_LOM_LOBON:   return TILE_RUNE_LOM_LOBON;
2558     case RUNE_CEREBOV:     return TILE_RUNE_CEREBOV;
2559     case RUNE_GLOORX_VLOQ: return TILE_RUNE_GLOORX_VLOQ;
2560 
2561     case RUNE_DEMONIC:     return TILE_RUNE_DEMONIC
2562         + ((uint32_t)item.rnd) % tile_main_count(TILE_RUNE_DEMONIC);
2563     case RUNE_ABYSSAL:     return TILE_RUNE_ABYSS;
2564 
2565     case RUNE_SNAKE:       return TILE_RUNE_SNAKE;
2566     case RUNE_SPIDER:      return TILE_RUNE_SPIDER;
2567     case RUNE_SLIME:       return TILE_RUNE_SLIME;
2568     case RUNE_VAULTS:      return TILE_RUNE_VAULTS;
2569     case RUNE_TOMB:        return TILE_RUNE_TOMB;
2570     case RUNE_SWAMP:       return TILE_RUNE_SWAMP;
2571     case RUNE_SHOALS:      return TILE_RUNE_SHOALS;
2572     case RUNE_ELF:         return TILE_RUNE_ELVEN;
2573 
2574     case RUNE_FOREST:
2575     default:               return TILE_MISC_RUNE_OF_ZOT;
2576     }
2577 }
2578 
_tileidx_misc(const item_def & item)2579 static tileidx_t _tileidx_misc(const item_def &item)
2580 {
2581     switch (item.sub_type)
2582     {
2583 #if TAG_MAJOR_VERSION == 34
2584     case MISC_BOTTLED_EFREET:
2585         return TILE_MISC_BOTTLED_EFREET;
2586 
2587     case MISC_FAN_OF_GALES:
2588         return TILE_MISC_FAN_OF_GALES_INERT;
2589 
2590     case MISC_LAMP_OF_FIRE:
2591         return TILE_MISC_LAMP_OF_FIRE_INERT;
2592 
2593     case MISC_STONE_OF_TREMORS:
2594         return TILE_MISC_STONE_OF_TREMORS_INERT;
2595 #endif
2596 
2597     case MISC_PHIAL_OF_FLOODS:
2598         return evoker_charges(item.sub_type) ? TILE_MISC_PHIAL_OF_FLOODS
2599                                              : TILE_MISC_PHIAL_OF_FLOODS_INERT;
2600 
2601     case MISC_TIN_OF_TREMORSTONES:
2602         return TILE_MISC_TIN_OF_TREMORSTONES;
2603 
2604     case MISC_CONDENSER_VANE:
2605             return evoker_charges(item.sub_type) ? TILE_MISC_CONDENSER_VANE
2606                                                  : TILE_MISC_CONDENSER_VANE_INERT;
2607 
2608     case MISC_XOMS_CHESSBOARD:
2609             return _modrng(item.rnd, TILE_MISC_CHESSPIECE_FIRST, TILE_MISC_CHESSPIECE_LAST);
2610 
2611 #if TAG_MAJOR_VERSION == 34
2612     case MISC_BUGGY_LANTERN_OF_SHADOWS:
2613         return TILE_MISC_LANTERN_OF_SHADOWS;
2614 #endif
2615 
2616     case MISC_HORN_OF_GERYON:
2617         return TILE_MISC_HORN_OF_GERYON;
2618 
2619     case MISC_BOX_OF_BEASTS:
2620         return TILE_MISC_BOX_OF_BEASTS;
2621 
2622 #if TAG_MAJOR_VERSION == 34
2623     case MISC_CRYSTAL_BALL_OF_ENERGY:
2624         return TILE_MISC_CRYSTAL_BALL_OF_ENERGY;
2625 #endif
2626 
2627     case MISC_LIGHTNING_ROD:
2628         return evoker_charges(item.sub_type) ? TILE_MISC_LIGHTNING_ROD
2629                                              : TILE_MISC_LIGHTNING_ROD_INERT;
2630 
2631 #if TAG_MAJOR_VERSION == 34
2632     case MISC_SACK_OF_SPIDERS:
2633         return TILE_MISC_SACK_OF_SPIDERS;
2634 #endif
2635 
2636     // Default for summary menus
2637     case NUM_MISCELLANY:
2638     case MISC_PHANTOM_MIRROR:
2639         return TILE_MISC_PHANTOM_MIRROR;
2640 
2641     case MISC_ZIGGURAT:
2642         return TILE_MISC_ZIGGURAT;
2643 
2644     case MISC_QUAD_DAMAGE:
2645         return TILE_MISC_QUAD_DAMAGE;
2646     }
2647 
2648     return TILE_ERROR;
2649 }
2650 
_tileidx_gold(const item_def & item)2651 static tileidx_t _tileidx_gold(const item_def &item)
2652 {
2653     if (item.quantity >= 1 && item.quantity <= 10)
2654         return TILE_GOLD01 + item.quantity - 1;
2655     if (item.quantity < 20)
2656         return TILE_GOLD16;
2657     if (item.quantity < 30)
2658         return TILE_GOLD19;
2659     if (item.quantity < 100)
2660         return TILE_GOLD23;
2661     return TILE_GOLD25;
2662 }
2663 
tileidx_item(const item_def & item)2664 tileidx_t tileidx_item(const item_def &item)
2665 {
2666     if (item.props.exists("item_tile"))
2667         return item.props["item_tile"].get_short();
2668 
2669     const int clas        = item.base_type;
2670     const int type        = item.sub_type;
2671     const int subtype_rnd = item.subtype_rnd;
2672     const int rnd         = item.rnd;
2673 
2674     switch (clas)
2675     {
2676     case OBJ_WEAPONS:
2677         if (is_unrandom_artefact(item, UNRAND_WYRMBANE))
2678             return _tileidx_wyrmbane(item.plus);
2679         else if (is_unrandom_artefact(item))
2680             return _tileidx_unrand_artefact(find_unrandart_index(item));
2681         else
2682             return _tileidx_weapon(item);
2683 
2684     case OBJ_MISSILES:
2685         return _tileidx_missile(item);
2686 
2687     case OBJ_ARMOUR:
2688         if (is_unrandom_artefact(item))
2689             return _tileidx_unrand_artefact(find_unrandart_index(item));
2690         else
2691             return _tileidx_armour(item);
2692 
2693     case OBJ_WANDS:
2694         if (item.flags & ISFLAG_KNOW_TYPE)
2695             return TILE_WAND_ID_FIRST + type;
2696         else
2697             return TILE_WAND_OFFSET + subtype_rnd % NDSC_WAND_PRI;
2698 
2699     case OBJ_SCROLLS:
2700         if (item.flags & ISFLAG_KNOW_TYPE)
2701             return TILE_SCR_ID_FIRST + type;
2702         return TILE_SCROLL;
2703 
2704     case OBJ_GOLD:
2705         return _tileidx_gold(item);
2706 
2707     case OBJ_JEWELLERY:
2708         if (is_unrandom_artefact(item))
2709             return _tileidx_unrand_artefact(find_unrandart_index(item));
2710 
2711         // rings
2712         if (!jewellery_is_amulet(item))
2713         {
2714             if (is_artefact(item))
2715             {
2716                 const int offset = item.rnd
2717                                    % tile_main_count(TILE_RING_RANDART_OFFSET);
2718                 return TILE_RING_RANDART_OFFSET + offset;
2719             }
2720 
2721             if (item.flags & ISFLAG_KNOW_TYPE)
2722             {
2723                 return TILE_RING_ID_FIRST + type - RING_FIRST_RING
2724 #if TAG_MAJOR_VERSION == 34
2725                        + 1 // we have a save-compat ring tile before FIRST_RING
2726 #endif
2727                     ;
2728             }
2729 
2730             return TILE_RING_NORMAL_OFFSET + subtype_rnd % NDSC_JEWEL_PRI;
2731         }
2732 
2733         // amulets
2734         if (is_artefact(item))
2735         {
2736             const int offset = item.rnd
2737                                % tile_main_count(TILE_AMU_RANDART_OFFSET);
2738             return TILE_AMU_RANDART_OFFSET + offset;
2739         }
2740 
2741         if (item.flags & ISFLAG_KNOW_TYPE)
2742             return TILE_AMU_ID_FIRST + type - AMU_FIRST_AMULET;
2743         return TILE_AMU_NORMAL_OFFSET + subtype_rnd % NDSC_JEWEL_PRI;
2744 
2745     case OBJ_POTIONS:
2746         if (item.flags & ISFLAG_KNOW_TYPE)
2747             return TILE_POT_ID_FIRST + type;
2748         else
2749             return TILE_POTION_OFFSET + item.subtype_rnd % NDSC_POT_PRI;
2750 
2751     case OBJ_BOOKS:
2752         if (is_random_artefact(item))
2753         {
2754             const int offset = rnd % tile_main_count(TILE_BOOK_RANDART_OFFSET);
2755             return TILE_BOOK_RANDART_OFFSET + offset;
2756         }
2757 
2758         if (item.sub_type == BOOK_MANUAL)
2759             return TILE_BOOK_MANUAL + rnd % tile_main_count(TILE_BOOK_MANUAL);
2760 
2761         return TILE_BOOK_OFFSET
2762                + rnd % tile_main_count(TILE_BOOK_OFFSET);
2763 
2764     case OBJ_STAVES:
2765         if (item.flags & ISFLAG_KNOW_TYPE)
2766             return TILE_STAFF_ID_FIRST + type;
2767 
2768         return TILE_STAFF_OFFSET
2769                + (subtype_rnd / NDSC_STAVE_PRI) % NDSC_STAVE_SEC;
2770 
2771 #if TAG_MAJOR_VERSION == 34
2772     case OBJ_RODS:
2773         return TILE_ROD + item.rnd % tile_main_count(TILE_ROD);
2774 #endif
2775 
2776     case OBJ_CORPSES:
2777         if (item.sub_type == CORPSE_SKELETON)
2778             return _tileidx_bone(item);
2779         else
2780             return _tileidx_corpse(item);
2781 
2782     case OBJ_ORBS:
2783         if (item.quantity <= 0)
2784             return TILE_UNCOLLECTED_ORB;
2785         return TILE_ORB + ui_random(tile_main_count(TILE_ORB));
2786 
2787     case OBJ_MISCELLANY:
2788         return _tileidx_misc(item);
2789 
2790     case OBJ_RUNES:
2791         if (item.quantity <= 0)
2792             return _tileidx_uncollected_rune(item);
2793         return _tileidx_rune(item);
2794 
2795     case OBJ_DETECTED:
2796         return TILE_UNSEEN_ITEM;
2797 
2798     default:
2799         return TILE_ERROR;
2800     }
2801 }
2802 
2803 //  Determine Octant of missile direction
2804 //   .---> X+
2805 //   |
2806 //   |  701
2807 //   Y  6O2
2808 //   +  543
2809 //
2810 // The octant boundary slope tan(pi/8)=sqrt(2)-1 = 0.414 is approximated by 2/5.
_tile_bolt_dir(int dx,int dy)2811 static int _tile_bolt_dir(int dx, int dy)
2812 {
2813     int ax = abs(dx);
2814     int ay = abs(dy);
2815 
2816     if (5*ay < 2*ax)
2817         return (dx > 0) ? 2 : 6;
2818     else if (5*ax < 2*ay)
2819         return (dy > 0) ? 4 : 0;
2820     else if (dx > 0)
2821         return (dy > 0) ? 3 : 1;
2822     else
2823         return (dy > 0) ? 5: 7;
2824 }
2825 
tileidx_item_throw(const item_def & item,int dx,int dy)2826 tileidx_t tileidx_item_throw(const item_def &item, int dx, int dy)
2827 {
2828     if (item.base_type == OBJ_MISSILES)
2829     {
2830         int ch = -1;
2831         int dir = _tile_bolt_dir(dx, dy);
2832 
2833         // Thrown items with multiple directions
2834         switch (item.sub_type)
2835         {
2836             case MI_ARROW:
2837                 ch = TILE_MI_ARROW0;
2838                 break;
2839             case MI_BOLT:
2840                 ch = TILE_MI_BOLT0;
2841                 break;
2842             case MI_DART:
2843                 ch = TILE_MI_DART0;
2844                 break;
2845             case MI_JAVELIN:
2846                 ch = TILE_MI_JAVELIN0;
2847                 break;
2848             case MI_THROWING_NET:
2849                 ch = TILE_MI_THROWING_NET0;
2850                 break;
2851             default:
2852                 break;
2853         }
2854         if (ch != -1)
2855             return ch + dir;
2856 
2857         // Thrown items with a single direction
2858         switch (item.sub_type)
2859         {
2860             case MI_STONE:
2861                 ch = TILE_MI_STONE0;
2862                 break;
2863             case MI_SLING_BULLET:
2864                 switch (item.brand)
2865                 {
2866                 default:
2867                     ch = TILE_MI_SLING_BULLET0;
2868                     break;
2869 #if TAG_MAJOR_VERSION == 34
2870                 case SPMSL_STEEL:
2871                     ch = TILE_MI_SLING_BULLET_STEEL0;
2872                     break;
2873 #endif
2874                 case SPMSL_SILVER:
2875                     ch = TILE_MI_SLING_BULLET_SILVER0;
2876                     break;
2877                 }
2878                 break;
2879             case MI_LARGE_ROCK:
2880                 ch = TILE_MI_LARGE_ROCK0;
2881                 break;
2882             case MI_THROWING_NET:
2883                 ch = TILE_MI_THROWING_NET0;
2884                 break;
2885             case MI_BOOMERANG:
2886                 ch = TILE_MI_BOOMERANG0;
2887             default:
2888                 break;
2889         }
2890         if (ch != -1)
2891             return tileidx_enchant_equ(item, ch);
2892     }
2893 
2894     // If not a special case, just return the default tile.
2895     return tileidx_item(item);
2896 }
2897 
2898 // For items with randomized descriptions, only the overlay label is
2899 // placed in the tile page. This function looks up what the base item
2900 // is based on the randomized description. It returns 0 if there is none.
tileidx_known_base_item(tileidx_t label)2901 tileidx_t tileidx_known_base_item(tileidx_t label)
2902 {
2903     if (label >= TILE_POT_ID_FIRST && label <= TILE_POT_ID_LAST)
2904     {
2905         int type = label - TILE_POT_ID_FIRST;
2906         int desc = you.item_description[IDESC_POTIONS][type] % NDSC_POT_PRI;
2907 
2908         if (!get_ident_type(OBJ_POTIONS, type))
2909             return TILE_UNSEEN_POTION;
2910         else
2911             return TILE_POTION_OFFSET + desc;
2912     }
2913 
2914     if (label >= TILE_RING_ID_FIRST && label <= TILE_RING_ID_LAST)
2915     {
2916         int type = label - TILE_RING_ID_FIRST + RING_FIRST_RING
2917 #if TAG_MAJOR_VERSION == 34
2918                    - 1 // we have a save-compat ring tile before FIRST_RING
2919 #endif
2920             ;
2921         int desc = you.item_description[IDESC_RINGS][type] % NDSC_JEWEL_PRI;
2922 
2923         if (!get_ident_type(OBJ_JEWELLERY, type))
2924             return TILE_UNSEEN_RING;
2925         else
2926             return TILE_RING_NORMAL_OFFSET + desc;
2927     }
2928 
2929     if (label >= TILE_AMU_ID_FIRST && label <= TILE_AMU_ID_LAST)
2930     {
2931         int type = label - TILE_AMU_ID_FIRST + AMU_FIRST_AMULET;
2932         int desc = you.item_description[IDESC_RINGS][type] % NDSC_JEWEL_PRI;
2933 
2934         if (!get_ident_type(OBJ_JEWELLERY, type))
2935             return TILE_UNSEEN_AMULET;
2936         else
2937             return TILE_AMU_NORMAL_OFFSET + desc;
2938     }
2939 
2940     if (label >= TILE_SCR_ID_FIRST && label <= TILE_SCR_ID_LAST)
2941         return TILE_SCROLL;
2942 
2943     if (label >= TILE_WAND_ID_FIRST && label <= TILE_WAND_ID_LAST)
2944     {
2945         int type = label - TILE_WAND_ID_FIRST;
2946         int desc = you.item_description[IDESC_WANDS][type] % NDSC_WAND_PRI;
2947 
2948         if (!get_ident_type(OBJ_WANDS, type))
2949             return TILE_UNSEEN_WAND;
2950         else
2951             return TILE_WAND_OFFSET + desc;
2952     }
2953 
2954     if (label >= TILE_STAFF_ID_FIRST && label <= TILE_STAFF_ID_LAST)
2955     {
2956         int type = label - TILE_STAFF_ID_FIRST;
2957         int desc = you.item_description[IDESC_STAVES][type];
2958         desc = (desc / NDSC_STAVE_PRI) % NDSC_STAVE_SEC;
2959 
2960         if (!get_ident_type(OBJ_STAVES, type))
2961             return TILE_UNSEEN_STAFF;
2962         else
2963             return TILE_STAFF_OFFSET + desc;
2964     }
2965 
2966     return 0;
2967 }
2968 
tileidx_cloud(const cloud_info & cl)2969 tileidx_t tileidx_cloud(const cloud_info &cl)
2970 {
2971     const cloud_type type  = cl.type;
2972     const int colour = cl.colour;
2973     const unsigned int dur = cl.duration;
2974 
2975     tileidx_t ch = cl.tile;
2976 
2977     if (ch == 0)
2978     {
2979         const cloud_tile_info &tile_info = cloud_type_tile_info(type);
2980 
2981         switch (tile_info.variation)
2982         {
2983             case CTVARY_NONE:
2984                 ch = tile_info.base;
2985                 break;
2986             case CTVARY_DUR:
2987                 ch = tile_info.base + min(dur,
2988                                           tile_main_count(tile_info.base) - 1);
2989                 break;
2990             case CTVARY_RANDOM:
2991                 ch = tile_info.base + hash_with_seed(
2992                         tile_main_count(tile_info.base),
2993                         cl.pos.y * GXM + cl.pos.x, you.frame_no);
2994                 break;
2995         }
2996 
2997         if (!ch || ch == TILE_ERROR)
2998             ch = TILE_CLOUD_GREY_SMOKE;
2999 
3000         switch (type)
3001         {
3002             case CLOUD_MUTAGENIC:
3003                 ch = (dur == 0 ? TILE_CLOUD_MUTAGENIC_0 :
3004                       dur == 1 ? TILE_CLOUD_MUTAGENIC_1
3005                                : TILE_CLOUD_MUTAGENIC_2);
3006                 ch += ui_random(tile_main_count(ch));
3007                 break;
3008 
3009             case CLOUD_VORTEX:
3010                 ch = get_vortex_phase(cl.pos) ? TILE_CLOUD_FREEZING_WINDS_0
3011                                                : TILE_CLOUD_FREEZING_WINDS_1;
3012                 break;
3013 
3014             default:
3015                 break;
3016         }
3017     }
3018 
3019     if (colour != -1)
3020         ch = tile_main_coloured(ch, colour);
3021 
3022     return ch;
3023 }
3024 
tileidx_bolt(const bolt & bolt)3025 tileidx_t tileidx_bolt(const bolt &bolt)
3026 {
3027     const int col = bolt.colour;
3028     const coord_def diff = bolt.target - bolt.source;
3029     const int dir = _tile_bolt_dir(diff.x, diff.y);
3030 
3031     switch (col)
3032     {
3033     case WHITE:
3034         if (bolt.name == "crystal spear")
3035             return TILE_BOLT_CRYSTAL_SPEAR + dir;
3036         else if (bolt.name == "puff of frost")
3037             return TILE_BOLT_FROST;
3038         else if (bolt.name == "shard of ice")
3039             return TILE_BOLT_ICICLE + dir;
3040         else if (bolt.name == "searing ray")
3041             return TILE_BOLT_SEARING_RAY;
3042         break;
3043 
3044     case LIGHTCYAN:
3045         if (bolt.name == "iron shot")
3046             return TILE_BOLT_IRON_SHOT + dir;
3047         else if (bolt.name == "zap")
3048             return TILE_BOLT_ZAP + dir % tile_main_count(TILE_BOLT_ZAP);
3049         break;
3050 
3051     case RED:
3052         if (bolt.name == "puff of flame")
3053             return TILE_BOLT_FLAME;
3054         break;
3055 
3056     case LIGHTRED:
3057         if (bolt.name.find("damnation") != string::npos)
3058             return TILE_BOLT_DAMNATION;
3059         break;
3060 
3061     case LIGHTMAGENTA:
3062         if (bolt.name == "magic dart")
3063             return TILE_BOLT_MAGIC_DART;
3064         break;
3065 
3066     case BROWN:
3067         if (bolt.name == "blast of sand")
3068             return TILE_BOLT_SANDBLAST;
3069         else if (bolt.name == "klown pie")
3070             return TILE_BOLT_PIE + dir;
3071         break;
3072 
3073     case GREEN:
3074         if (bolt.name == "sting")
3075             return TILE_BOLT_POISON_ARROW + dir;
3076         break;
3077 
3078     case LIGHTGREEN:
3079         if (bolt.name == "poison arrow")
3080             return TILE_BOLT_POISON_ARROW + dir;
3081         break;
3082 
3083     case LIGHTGREY:
3084         if (bolt.name == "stone arrow")
3085             return TILE_BOLT_STONE_ARROW + dir;
3086         break;
3087 
3088     case DARKGREY:
3089         if (bolt.name == "bolt of negative energy")
3090             return TILE_BOLT_DRAIN;
3091         break;
3092 
3093     case MAGENTA:
3094         break;
3095 
3096     case CYAN:
3097         if (bolt.name == "slug dart")
3098             return TILE_BOLT_STONE_ARROW + dir;
3099         break;
3100 
3101     case ETC_MUTAGENIC:
3102         if (bolt.name == "irradiate" || bolt.name == "unravelling")
3103             return TILE_BOLT_IRRADIATE;
3104         break;
3105     }
3106 
3107     return tileidx_zap(col);
3108 }
3109 
vary_bolt_tile(tileidx_t tile,int dist)3110 tileidx_t vary_bolt_tile(tileidx_t tile, int dist)
3111 {
3112     switch (tile)
3113     {
3114     case TILE_BOLT_FROST:
3115     case TILE_BOLT_MAGIC_DART:
3116     case TILE_BOLT_SANDBLAST:
3117     case TILE_BOLT_STING:
3118         return tile + dist % tile_main_count(tile);
3119     case TILE_BOLT_FLAME:
3120     case TILE_BOLT_IRRADIATE:
3121         return tile + ui_random(tile_main_count(tile));
3122     case TILE_MI_BOOMERANG0:
3123         return tile + ui_random(4);
3124     default:
3125         return tile;
3126     }
3127 }
3128 
tileidx_zap(int colour)3129 tileidx_t tileidx_zap(int colour)
3130 {
3131     switch (colour)
3132     {
3133     case ETC_HOLY:
3134         colour = YELLOW;
3135         break;
3136     default:
3137         colour = element_colour(colour);
3138         break;
3139     }
3140 
3141     if (colour < 1)
3142         colour = 7;
3143     else if (colour > 8)
3144         colour -= 8;
3145 
3146     return TILE_SYM_BOLT_OFS - 1 + colour;
3147 }
3148 
tileidx_spell(spell_type spell)3149 tileidx_t tileidx_spell(spell_type spell)
3150 {
3151     if (spell == NUM_SPELLS)
3152         return TILEG_MEMORISE; // XXX: Hack!
3153     return get_spell_tile(spell);
3154 }
3155 
3156 /**
3157  * Get the appropriate tile for the given skill @ the given training level.
3158  *
3159  * @param skill     The skill in question; e.g. SK_FIGHTING.
3160  * @param train     The training_status to render at; e.g. TRAINING_DISABLED.
3161  * @return          An appropriate tile; e.g. TILEG_FIGHTING_OFF>
3162  */
tileidx_skill(skill_type skill,int train)3163 tileidx_t tileidx_skill(skill_type skill, int train)
3164 {
3165     tileidx_t ch;
3166     switch (skill)
3167     {
3168     case SK_FIGHTING:       ch = TILEG_FIGHTING_ON; break;
3169     case SK_SHORT_BLADES:   ch = TILEG_SHORT_BLADES_ON; break;
3170     case SK_LONG_BLADES:    ch = TILEG_LONG_BLADES_ON; break;
3171     case SK_AXES:           ch = TILEG_AXES_ON; break;
3172     case SK_MACES_FLAILS:   ch = TILEG_MACES_FLAILS_ON; break;
3173     case SK_POLEARMS:       ch = TILEG_POLEARMS_ON; break;
3174     case SK_STAVES:         ch = TILEG_STAVES_ON; break;
3175     case SK_SLINGS:         ch = TILEG_SLINGS_ON; break;
3176     case SK_BOWS:           ch = TILEG_BOWS_ON; break;
3177     case SK_CROSSBOWS:      ch = TILEG_CROSSBOWS_ON; break;
3178     case SK_THROWING:       ch = TILEG_THROWING_ON; break;
3179     case SK_ARMOUR:         ch = TILEG_ARMOUR_ON; break;
3180     case SK_DODGING:        ch = TILEG_DODGING_ON; break;
3181     case SK_STEALTH:        ch = TILEG_STEALTH_ON; break;
3182     case SK_SHIELDS:        ch = TILEG_SHIELDS_ON; break;
3183     case SK_UNARMED_COMBAT:
3184         {
3185             const string hand = you.hand_name(false);
3186             if (hand == "hand")
3187                 ch = TILEG_UNARMED_COMBAT_ON;
3188             else if (hand == "paw")
3189                 ch = TILEG_UNARMED_COMBAT_PAW_ON;
3190             else if (hand == "tentacle")
3191                 ch = TILEG_UNARMED_COMBAT_TENTACLE_ON;
3192             else
3193                 ch = TILEG_UNARMED_COMBAT_CLAW_ON;
3194         }
3195         break;
3196     case SK_SPELLCASTING:   ch = TILEG_SPELLCASTING_ON; break;
3197     case SK_CONJURATIONS:   ch = TILEG_CONJURATIONS_ON; break;
3198     case SK_HEXES:          ch = TILEG_HEXES_ON; break;
3199     case SK_SUMMONINGS:     ch = TILEG_SUMMONINGS_ON; break;
3200     case SK_NECROMANCY:
3201         ch = you.religion == GOD_KIKUBAAQUDGHA ? TILEG_NECROMANCY_K_ON
3202                                                : TILEG_NECROMANCY_ON; break;
3203     case SK_TRANSLOCATIONS: ch = TILEG_TRANSLOCATIONS_ON; break;
3204     case SK_TRANSMUTATIONS: ch = TILEG_TRANSMUTATIONS_ON; break;
3205     case SK_FIRE_MAGIC:     ch = TILEG_FIRE_MAGIC_ON; break;
3206     case SK_ICE_MAGIC:      ch = TILEG_ICE_MAGIC_ON; break;
3207     case SK_AIR_MAGIC:      ch = TILEG_AIR_MAGIC_ON; break;
3208     case SK_EARTH_MAGIC:    ch = TILEG_EARTH_MAGIC_ON; break;
3209     case SK_POISON_MAGIC:   ch = TILEG_POISON_MAGIC_ON; break;
3210     case SK_EVOCATIONS:     ch = TILEG_EVOCATIONS_ON; break;
3211     case SK_INVOCATIONS:
3212         {
3213             switch (you.religion)
3214             {
3215             // Gods who use invo get a unique tile.
3216             case GOD_SHINING_ONE:
3217                 ch = TILEG_INVOCATIONS_1_ON; break;
3218             case GOD_BEOGH:
3219                 ch = TILEG_INVOCATIONS_B_ON; break;
3220             case GOD_CHEIBRIADOS:
3221                 ch = TILEG_INVOCATIONS_C_ON; break;
3222             case GOD_DITHMENOS:
3223                 ch = TILEG_INVOCATIONS_D_ON; break;
3224             case GOD_ELYVILON:
3225                 ch = TILEG_INVOCATIONS_E_ON; break;
3226             case GOD_FEDHAS:
3227                 ch = TILEG_INVOCATIONS_F_ON; break;
3228             case GOD_HEPLIAKLQANA:
3229                 ch = TILEG_INVOCATIONS_H_ON; break;
3230             case GOD_LUGONU:
3231                 ch = TILEG_INVOCATIONS_L_ON; break;
3232             case GOD_MAKHLEB:
3233                 ch = TILEG_INVOCATIONS_M_ON; break;
3234             case GOD_NEMELEX_XOBEH:
3235                 ch = TILEG_INVOCATIONS_N_ON; break;
3236             case GOD_OKAWARU:
3237                 ch = TILEG_INVOCATIONS_O_ON; break;
3238             case GOD_QAZLAL:
3239                 ch = TILEG_INVOCATIONS_Q_ON; break;
3240             case GOD_SIF_MUNA:
3241                 ch = TILEG_INVOCATIONS_S_ON; break;
3242             case GOD_USKAYAW:
3243                 ch = TILEG_INVOCATIONS_U_ON; break;
3244             case GOD_YREDELEMNUL:
3245                 ch = TILEG_INVOCATIONS_Y_ON; break;
3246             case GOD_ZIN:
3247                 ch = TILEG_INVOCATIONS_Z_ON; break;
3248             default:
3249                 ch = TILEG_INVOCATIONS_ON;
3250             }
3251         }
3252         break;
3253     default:                return TILEG_TODO;
3254     }
3255 
3256     switch (train)
3257     {
3258     case TRAINING_DISABLED:
3259         return ch + TILEG_FIGHTING_OFF - TILEG_FIGHTING_ON;
3260     case TRAINING_INACTIVE:
3261         return ch + TILEG_FIGHTING_INACTIVE - TILEG_FIGHTING_ON;
3262     case TRAINING_ENABLED:
3263         return ch;
3264     case TRAINING_FOCUSED:
3265         return ch + TILEG_FIGHTING_FOCUS - TILEG_FIGHTING_ON;
3266     case TRAINING_MASTERED:
3267         return ch + TILEG_FIGHTING_MAX - TILEG_FIGHTING_ON;
3268     default:
3269         die("invalid skill tile type");
3270     }
3271 
3272 }
3273 
tileidx_command(const command_type cmd)3274 tileidx_t tileidx_command(const command_type cmd)
3275 {
3276     switch (cmd)
3277     {
3278     case CMD_REST:
3279         return TILEG_CMD_REST;
3280     case CMD_EXPLORE:
3281         return TILEG_CMD_EXPLORE;
3282     case CMD_INTERLEVEL_TRAVEL:
3283         return TILEG_CMD_INTERLEVEL_TRAVEL;
3284     case CMD_AUTOFIGHT:
3285         return TILEG_CMD_AUTOFIGHT;
3286     case CMD_WAIT:
3287         return TILEG_CMD_WAIT;
3288     case CMD_USE_ABILITY:
3289         return TILEG_CMD_USE_ABILITY;
3290     case CMD_SEARCH_STASHES:
3291         return TILEG_CMD_SEARCH_STASHES;
3292     case CMD_REPLAY_MESSAGES:
3293         return TILEG_CMD_REPLAY_MESSAGES;
3294     case CMD_RESISTS_SCREEN:
3295         return TILEG_CMD_RESISTS_SCREEN;
3296     case CMD_DISPLAY_OVERMAP:
3297         return TILEG_CMD_DISPLAY_OVERMAP;
3298     case CMD_DISPLAY_RELIGION:
3299         return TILEG_CMD_DISPLAY_RELIGION;
3300     case CMD_DISPLAY_MUTATIONS:
3301         return TILEG_CMD_DISPLAY_MUTATIONS;
3302     case CMD_MACRO_ADD: // this tile is a fairly generic + despite the name
3303     case CMD_MACRO_MENU:
3304     case CMD_DISPLAY_SKILLS:
3305         return TILEG_CMD_DISPLAY_SKILLS;
3306     case CMD_SHOW_CHARACTER_DUMP:
3307     case CMD_DISPLAY_CHARACTER_STATUS:
3308         return TILEG_CMD_DISPLAY_CHARACTER_STATUS;
3309     case CMD_DISPLAY_KNOWN_OBJECTS:
3310         return TILEG_CMD_KNOWN_ITEMS;
3311     case CMD_SAVE_GAME_NOW:
3312     case CMD_SAVE_GAME:
3313         return TILEG_CMD_SAVE_GAME_NOW;
3314 #ifdef USE_TILE
3315     case CMD_EDIT_PLAYER_TILE:
3316         return TILEG_CMD_EDIT_PLAYER_TILE;
3317 #endif
3318     case CMD_DISPLAY_COMMANDS:
3319         return TILEG_CMD_DISPLAY_COMMANDS;
3320     case CMD_LOOKUP_HELP:
3321         return TILEG_CMD_LOOKUP_HELP;
3322     case CMD_CHARACTER_DUMP:
3323         return TILEG_CMD_CHARACTER_DUMP;
3324     case CMD_DISPLAY_INVENTORY:
3325         return TILEG_CMD_DISPLAY_INVENTORY;
3326     case CMD_CAST_SPELL:
3327         return TILEG_CMD_CAST_SPELL;
3328     case CMD_MEMORISE_SPELL:
3329         return TILEG_CMD_MEMORISE_SPELL;
3330     case CMD_DROP:
3331         return TILEG_CMD_DROP;
3332     case CMD_DISPLAY_MAP:
3333         return TILEG_CMD_DISPLAY_MAP;
3334     case CMD_MAP_GOTO_TARGET:
3335         return TILEG_CMD_MAP_GOTO_TARGET;
3336     case CMD_MAP_NEXT_LEVEL:
3337         return TILEG_CMD_MAP_NEXT_LEVEL;
3338     case CMD_MAP_PREV_LEVEL:
3339         return TILEG_CMD_MAP_PREV_LEVEL;
3340     case CMD_MAP_GOTO_LEVEL:
3341         return TILEG_CMD_MAP_GOTO_LEVEL;
3342     case CMD_MAP_EXCLUDE_AREA:
3343         return TILEG_CMD_MAP_EXCLUDE_AREA;
3344     case CMD_MAP_FIND_EXCLUDED:
3345         return TILEG_CMD_MAP_FIND_EXCLUDED;
3346     case CMD_MAP_CLEAR_EXCLUDES:
3347         return TILEG_CMD_MAP_CLEAR_EXCLUDES;
3348     case CMD_MAP_ADD_WAYPOINT:
3349         return TILEG_CMD_MAP_ADD_WAYPOINT;
3350     case CMD_MAP_FIND_WAYPOINT:
3351         return TILEG_CMD_MAP_FIND_WAYPOINT;
3352     case CMD_MAP_FIND_UPSTAIR:
3353         return TILEG_CMD_MAP_FIND_UPSTAIR;
3354     case CMD_MAP_FIND_DOWNSTAIR:
3355         return TILEG_CMD_MAP_FIND_DOWNSTAIR;
3356     case CMD_MAP_FIND_YOU:
3357         return TILEG_CMD_MAP_FIND_YOU;
3358     case CMD_MAP_FIND_PORTAL:
3359         return TILEG_CMD_MAP_FIND_PORTAL;
3360     case CMD_MAP_FIND_TRAP:
3361         return TILEG_CMD_MAP_FIND_TRAP;
3362     case CMD_MAP_FIND_ALTAR:
3363         return TILEG_CMD_MAP_FIND_ALTAR;
3364     case CMD_MAP_FIND_STASH:
3365         return TILEG_CMD_MAP_FIND_STASH;
3366     case CMD_QUIT:
3367         return TILEG_SYMBOL_OF_TORMENT;
3368     case CMD_GAME_MENU:
3369         return TILEG_STARTUP_STONESOUP;
3370 #ifdef TOUCH_UI
3371     case CMD_SHOW_KEYBOARD:
3372         return TILEG_CMD_KEYBOARD;
3373 #endif
3374     default:
3375         return TILEG_TODO;
3376     }
3377 }
3378 
tileidx_gametype(const game_type gtype)3379 tileidx_t tileidx_gametype(const game_type gtype)
3380 {
3381     switch (gtype)
3382     {
3383     case GAME_TYPE_NORMAL:
3384     case GAME_TYPE_CUSTOM_SEED:
3385         return TILEG_STARTUP_STONESOUP;
3386     case GAME_TYPE_TUTORIAL:
3387         return TILEG_STARTUP_TUTORIAL;
3388     case GAME_TYPE_HINTS:
3389         return TILEG_STARTUP_HINTS;
3390     case GAME_TYPE_SPRINT:
3391         return TILEG_STARTUP_SPRINT;
3392     case GAME_TYPE_INSTRUCTIONS:
3393         return TILEG_STARTUP_INSTRUCTIONS;
3394     case GAME_TYPE_ARENA:
3395         return TILEG_STARTUP_ARENA;
3396     case GAME_TYPE_HIGH_SCORES:
3397         return TILEG_STARTUP_HIGH_SCORES;
3398     default:
3399         return TILEG_ERROR;
3400     }
3401 }
3402 
tileidx_ability(const ability_type ability)3403 tileidx_t tileidx_ability(const ability_type ability)
3404 {
3405     switch (ability)
3406     {
3407     // Innate abilities and (Demonspaw) mutations.
3408     case ABIL_SPIT_POISON:
3409         return TILEG_ABILITY_SPIT_POISON;
3410     case ABIL_BREATHE_FIRE:
3411         return TILEG_ABILITY_BREATHE_FIRE;
3412     case ABIL_BREATHE_FROST:
3413         return TILEG_ABILITY_BREATHE_FROST;
3414     case ABIL_BREATHE_POISON:
3415         return TILEG_ABILITY_BREATHE_POISON;
3416     case ABIL_BREATHE_LIGHTNING:
3417         return TILEG_ABILITY_BREATHE_LIGHTNING;
3418     case ABIL_BREATHE_POWER:
3419         return TILEG_ABILITY_BREATHE_ENERGY;
3420     case ABIL_BREATHE_STEAM:
3421         return TILEG_ABILITY_BREATHE_STEAM;
3422     case ABIL_BREATHE_MEPHITIC:
3423         return TILEG_ABILITY_BREATHE_MEPHITIC;
3424     case ABIL_BREATHE_ACID:
3425         return TILEG_ABILITY_BREATHE_ACID;
3426 #if TAG_MAJOR_VERSION == 34
3427     case ABIL_BLINK:
3428         return TILEG_ABILITY_BLINK;
3429 #endif
3430     case ABIL_HOP:
3431         return TILEG_ABILITY_HOP;
3432     case ABIL_ROLLING_CHARGE:
3433         return TILEG_ABILITY_ROLL;
3434     case ABIL_BLINKBOLT:
3435         return TILEG_ABILITY_BLINKBOLT;
3436 
3437     // Others
3438     case ABIL_END_TRANSFORMATION:
3439         return TILEG_ABILITY_END_TRANSFORMATION;
3440     case ABIL_STOP_RECALL:
3441         return TILEG_ABILITY_STOP_RECALL;
3442 
3443     // Species-specific abilities.
3444     // Demonspawn-only
3445     case ABIL_DAMNATION:
3446         return TILEG_ABILITY_HURL_DAMNATION;
3447     case ABIL_WORD_OF_CHAOS:
3448         return TILEG_ABILITY_WORD_OF_CHAOS;
3449     // Vampires
3450     case ABIL_TRAN_BAT:
3451         return TILEG_ABILITY_BAT_FORM;
3452     case ABIL_EXSANGUINATE:
3453         return TILEG_ABILITY_EXSANGUINATE;
3454     case ABIL_REVIVIFY:
3455         return TILEG_ABILITY_REVIVIFY;
3456     // Deep Dwarves
3457     case ABIL_HEAL_WOUNDS:
3458         return TILEG_ABILITY_HEAL_WOUNDS;
3459     // Formicids
3460     case ABIL_DIG:
3461         return TILEG_ABILITY_DIG;
3462     case ABIL_SHAFT_SELF:
3463         return TILEG_ABILITY_SHAFT_SELF;
3464 
3465     // Evoking items.
3466     case ABIL_EVOKE_BERSERK:
3467         return TILEG_ABILITY_EVOKE_BERSERK;
3468     case ABIL_EVOKE_BLINK:
3469         return TILEG_ABILITY_BLINK;
3470     case ABIL_EVOKE_TURN_INVISIBLE:
3471         return TILEG_ABILITY_EVOKE_INVISIBILITY;
3472     case ABIL_EVOKE_THUNDER:
3473         return TILEG_ABILITY_EVOKE_THUNDER;
3474 
3475     // Divine abilities
3476     // Zin
3477     case ABIL_ZIN_SUSTENANCE:
3478         return TILEG_TODO;
3479     case ABIL_ZIN_RECITE:
3480         return TILEG_ABILITY_ZIN_RECITE;
3481     case ABIL_ZIN_VITALISATION:
3482         return TILEG_ABILITY_ZIN_VITALISATION;
3483     case ABIL_ZIN_IMPRISON:
3484         return TILEG_ABILITY_ZIN_IMPRISON;
3485     case ABIL_ZIN_SANCTUARY:
3486         return TILEG_ABILITY_ZIN_SANCTUARY;
3487     case ABIL_ZIN_DONATE_GOLD:
3488         return TILEG_ABILITY_ZIN_DONATE_GOLD;
3489     // TSO
3490     case ABIL_TSO_DIVINE_SHIELD:
3491         return TILEG_ABILITY_TSO_DIVINE_SHIELD;
3492     case ABIL_TSO_CLEANSING_FLAME:
3493         return TILEG_ABILITY_TSO_CLEANSING_FLAME;
3494     case ABIL_TSO_SUMMON_DIVINE_WARRIOR:
3495         return TILEG_ABILITY_TSO_DIVINE_WARRIOR;
3496     case ABIL_TSO_BLESS_WEAPON:
3497         return TILEG_ABILITY_TSO_BLESS_WEAPON;
3498     // Kiku
3499     case ABIL_KIKU_RECEIVE_CORPSES:
3500         return TILEG_ABILITY_KIKU_RECEIVE_CORPSES;
3501     case ABIL_KIKU_TORMENT:
3502         return TILEG_ABILITY_KIKU_TORMENT;
3503     case ABIL_KIKU_BLESS_WEAPON:
3504         return TILEG_ABILITY_KIKU_BLESS_WEAPON;
3505     case ABIL_KIKU_GIFT_CAPSTONE_SPELLS:
3506         return TILEG_ABILITY_KIKU_NECRONOMICON;
3507     // Yredelemnul
3508     case ABIL_YRED_INJURY_MIRROR:
3509         return TILEG_ABILITY_YRED_INJURY_MIRROR;
3510     case ABIL_YRED_ANIMATE_REMAINS:
3511         return TILEG_ABILITY_YRED_ANIMATE_REMAINS;
3512     case ABIL_YRED_RECALL_UNDEAD_SLAVES:
3513         return TILEG_ABILITY_YRED_RECALL;
3514     case ABIL_YRED_ANIMATE_DEAD:
3515         return TILEG_ABILITY_YRED_ANIMATE_DEAD;
3516     case ABIL_YRED_DRAIN_LIFE:
3517         return TILEG_ABILITY_YRED_DRAIN_LIFE;
3518     case ABIL_YRED_ENSLAVE_SOUL:
3519         return TILEG_ABILITY_YRED_ENSLAVE_SOUL;
3520     // Xom, Vehumet = 90
3521     // Okawaru
3522     case ABIL_OKAWARU_HEROISM:
3523         return TILEG_ABILITY_OKAWARU_HEROISM;
3524     case ABIL_OKAWARU_FINESSE:
3525         return TILEG_ABILITY_OKAWARU_FINESSE;
3526     // Makhleb
3527     case ABIL_MAKHLEB_MINOR_DESTRUCTION:
3528         return TILEG_ABILITY_MAKHLEB_MINOR_DESTRUCTION;
3529     case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB:
3530         return TILEG_ABILITY_MAKHLEB_LESSER_SERVANT;
3531     case ABIL_MAKHLEB_MAJOR_DESTRUCTION:
3532         return TILEG_ABILITY_MAKHLEB_MAJOR_DESTRUCTION;
3533     case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB:
3534         return TILEG_ABILITY_MAKHLEB_GREATER_SERVANT;
3535     // Sif Muna
3536     case ABIL_SIF_MUNA_CHANNEL_ENERGY:
3537         return TILEG_ABILITY_SIF_MUNA_CHANNEL;
3538     case ABIL_SIF_MUNA_FORGET_SPELL:
3539         return TILEG_ABILITY_SIF_MUNA_AMNESIA;
3540     case ABIL_SIF_MUNA_DIVINE_EXEGESIS:
3541         return TILEG_ABILITY_SIF_MUNA_EXEGESIS;
3542     // Trog
3543     case ABIL_TROG_BERSERK:
3544         return TILEG_ABILITY_TROG_BERSERK;
3545     case ABIL_TROG_HAND:
3546         return TILEG_ABILITY_TROG_HAND;
3547     case ABIL_TROG_BROTHERS_IN_ARMS:
3548         return TILEG_ABILITY_TROG_BROTHERS_IN_ARMS;
3549     // Elyvilon
3550     case ABIL_ELYVILON_LIFESAVING:
3551         return TILEG_ABILITY_ELYVILON_DIVINE_PROTECTION;
3552     case ABIL_ELYVILON_LESSER_HEALING:
3553         return TILEG_ABILITY_ELYVILON_LESSER_HEALING;
3554     case ABIL_ELYVILON_PURIFICATION:
3555         return TILEG_ABILITY_ELYVILON_PURIFICATION;
3556     case ABIL_ELYVILON_GREATER_HEALING:
3557         return TILEG_ABILITY_ELYVILON_GREATER_HEALING;
3558     case ABIL_ELYVILON_HEAL_OTHER:
3559         return TILEG_ABILITY_ELYVILON_HEAL_OTHER;
3560     case ABIL_ELYVILON_DIVINE_VIGOUR:
3561         return TILEG_ABILITY_ELYVILON_DIVINE_VIGOUR;
3562     // Lugonu
3563     case ABIL_LUGONU_ABYSS_EXIT:
3564         return TILEG_ABILITY_LUGONU_EXIT_ABYSS;
3565     case ABIL_LUGONU_BEND_SPACE:
3566         return TILEG_ABILITY_LUGONU_BEND_SPACE;
3567     case ABIL_LUGONU_BANISH:
3568         return TILEG_ABILITY_LUGONU_BANISH;
3569     case ABIL_LUGONU_CORRUPT:
3570         return TILEG_ABILITY_LUGONU_CORRUPT;
3571     case ABIL_LUGONU_ABYSS_ENTER:
3572         return TILEG_ABILITY_LUGONU_ENTER_ABYSS;
3573     case ABIL_LUGONU_BLESS_WEAPON:
3574         return TILEG_ABILITY_LUGONU_BLESS_WEAPON;
3575     // Nemelex
3576     case ABIL_NEMELEX_TRIPLE_DRAW:
3577         return TILEG_ABILITY_NEMELEX_TRIPLE_DRAW;
3578     case ABIL_NEMELEX_DEAL_FOUR:
3579         return TILEG_ABILITY_NEMELEX_DEAL_FOUR;
3580     case ABIL_NEMELEX_STACK_FIVE:
3581         return TILEG_ABILITY_NEMELEX_STACK_FIVE;
3582     case ABIL_NEMELEX_DRAW_ESCAPE:
3583         return TILEG_ABILITY_NEMELEX_DRAW_ESCAPE;
3584     case ABIL_NEMELEX_DRAW_DESTRUCTION:
3585         return TILEG_ABILITY_NEMELEX_DRAW_DESTRUCTION;
3586     case ABIL_NEMELEX_DRAW_SUMMONING:
3587         return TILEG_ABILITY_NEMELEX_DRAW_SUMMONING;
3588     case ABIL_NEMELEX_DRAW_STACK:
3589         return TILEG_ABILITY_NEMELEX_DRAW_STACK;
3590     // Beogh
3591     case ABIL_BEOGH_GIFT_ITEM:
3592         return TILEG_ABILITY_BEOGH_GIFT_ITEM;
3593     case ABIL_BEOGH_SMITING:
3594         return TILEG_ABILITY_BEOGH_SMITE;
3595     case ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS:
3596         return TILEG_ABILITY_BEOGH_RECALL;
3597     case ABIL_CONVERT_TO_BEOGH:
3598         return TILEG_ABILITY_CONVERT_TO_BEOGH;
3599     case ABIL_BEOGH_RESURRECTION:
3600         return TILEG_ABILITY_BEOGH_RESURRECTION;
3601     // Jiyva
3602     case ABIL_JIYVA_CALL_JELLY:
3603         return TILEG_ABILITY_JIYVA_REQUEST_JELLY;
3604     case ABIL_JIYVA_SLIMIFY:
3605         return TILEG_ABILITY_JIYVA_SLIMIFY;
3606     case ABIL_JIYVA_CURE_BAD_MUTATION:
3607         return TILEG_ABILITY_JIYVA_CURE_BAD_MUTATIONS;
3608     // Fedhas
3609     case ABIL_FEDHAS_WALL_OF_BRIARS:
3610         return TILEG_ABILITY_FEDHAS_WALL_OF_BRIARS;
3611     case ABIL_FEDHAS_GROW_BALLISTOMYCETE:
3612         return TILEG_ABILITY_FEDHAS_GROW_BALLISTOMYCETE;
3613     case ABIL_FEDHAS_OVERGROW:
3614         return TILEG_ABILITY_FEDHAS_OVERGROW;
3615     case ABIL_FEDHAS_GROW_OKLOB:
3616         return TILEG_ABILITY_FEDHAS_GROW_OKLOB;
3617     // Cheibriados
3618     case ABIL_CHEIBRIADOS_TIME_STEP:
3619         return TILEG_ABILITY_CHEIBRIADOS_TIME_STEP;
3620     case ABIL_CHEIBRIADOS_TIME_BEND:
3621         return TILEG_ABILITY_CHEIBRIADOS_BEND_TIME;
3622     case ABIL_CHEIBRIADOS_SLOUCH:
3623         return TILEG_ABILITY_CHEIBRIADOS_SLOUCH;
3624     case ABIL_CHEIBRIADOS_DISTORTION:
3625         return TILEG_ABILITY_CHEIBRIADOS_TEMPORAL_DISTORTION;
3626     // Ashenzari
3627     case ABIL_ASHENZARI_CURSE:
3628         return TILEG_ABILITY_ASHENZARI_CURSE;
3629     case ABIL_ASHENZARI_UNCURSE:
3630         return TILEG_ABILITY_ASHENZARI_UNCURSE;
3631     // Dithmenos
3632     case ABIL_DITHMENOS_SHADOW_STEP:
3633         return TILEG_ABILITY_DITHMENOS_SHADOW_STEP;
3634     case ABIL_DITHMENOS_SHADOW_FORM:
3635         return TILEG_ABILITY_DITHMENOS_SHADOW_FORM;
3636     // Gozag
3637     case ABIL_GOZAG_POTION_PETITION:
3638         return TILEG_ABILITY_GOZAG_POTION_PETITION;
3639     case ABIL_GOZAG_CALL_MERCHANT:
3640         return TILEG_ABILITY_GOZAG_CALL_MERCHANT;
3641     case ABIL_GOZAG_BRIBE_BRANCH:
3642         return TILEG_ABILITY_GOZAG_BRIBE_BRANCH;
3643     // Qazlal
3644     case ABIL_QAZLAL_UPHEAVAL:
3645         return TILEG_ABILITY_QAZLAL_UPHEAVAL;
3646     case ABIL_QAZLAL_ELEMENTAL_FORCE:
3647         return TILEG_ABILITY_QAZLAL_ELEMENTAL_FORCE;
3648     case ABIL_QAZLAL_DISASTER_AREA:
3649         return TILEG_ABILITY_QAZLAL_DISASTER_AREA;
3650     // Ru
3651     case ABIL_RU_DRAW_OUT_POWER:
3652         return TILEG_ABILITY_RU_DRAW_OUT_POWER;
3653     case ABIL_RU_POWER_LEAP:
3654         return TILEG_ABILITY_RU_POWER_LEAP;
3655     case ABIL_RU_APOCALYPSE:
3656         return TILEG_ABILITY_RU_APOCALYPSE;
3657 
3658     case ABIL_RU_SACRIFICE_PURITY:
3659         return TILEG_ABILITY_RU_SACRIFICE_PURITY;
3660     case ABIL_RU_SACRIFICE_WORDS:
3661         return TILEG_ABILITY_RU_SACRIFICE_WORDS;
3662     case ABIL_RU_SACRIFICE_DRINK:
3663         return TILEG_ABILITY_RU_SACRIFICE_DRINK;
3664     case ABIL_RU_SACRIFICE_ESSENCE:
3665         return TILEG_ABILITY_RU_SACRIFICE_ESSENCE;
3666     case ABIL_RU_SACRIFICE_HEALTH:
3667         return TILEG_ABILITY_RU_SACRIFICE_HEALTH;
3668     case ABIL_RU_SACRIFICE_STEALTH:
3669         return TILEG_ABILITY_RU_SACRIFICE_STEALTH;
3670     case ABIL_RU_SACRIFICE_ARTIFICE:
3671         return TILEG_ABILITY_RU_SACRIFICE_ARTIFICE;
3672     case ABIL_RU_SACRIFICE_LOVE:
3673         return TILEG_ABILITY_RU_SACRIFICE_LOVE;
3674     case ABIL_RU_SACRIFICE_COURAGE:
3675         return TILEG_ABILITY_RU_SACRIFICE_COURAGE;
3676     case ABIL_RU_SACRIFICE_ARCANA:
3677         return TILEG_ABILITY_RU_SACRIFICE_ARCANA;
3678     case ABIL_RU_SACRIFICE_NIMBLENESS:
3679         return TILEG_ABILITY_RU_SACRIFICE_NIMBLENESS;
3680     case ABIL_RU_SACRIFICE_DURABILITY:
3681         return TILEG_ABILITY_RU_SACRIFICE_DURABILITY;
3682     case ABIL_RU_SACRIFICE_HAND:
3683         return TILEG_ABILITY_RU_SACRIFICE_HAND;
3684     case ABIL_RU_SACRIFICE_EXPERIENCE:
3685         return TILEG_ABILITY_RU_SACRIFICE_EXPERIENCE;
3686     case ABIL_RU_SACRIFICE_SKILL:
3687         return TILEG_ABILITY_RU_SACRIFICE_SKILL;
3688     case ABIL_RU_SACRIFICE_EYE:
3689         return TILEG_ABILITY_RU_SACRIFICE_EYE;
3690     case ABIL_RU_SACRIFICE_RESISTANCE:
3691         return TILEG_ABILITY_RU_SACRIFICE_RESISTANCE;
3692     case ABIL_RU_REJECT_SACRIFICES:
3693         return TILEG_ABILITY_RU_REJECT_SACRIFICES;
3694     // Hepliaklqana
3695     case ABIL_HEPLIAKLQANA_RECALL:
3696         return TILEG_ABILITY_HEP_RECALL;
3697     case ABIL_HEPLIAKLQANA_IDEALISE:
3698         return TILEG_ABILITY_HEP_IDEALISE;
3699     case ABIL_HEPLIAKLQANA_TRANSFERENCE:
3700         return TILEG_ABILITY_HEP_TRANSFERENCE;
3701     case ABIL_HEPLIAKLQANA_IDENTITY:
3702         return TILEG_ABILITY_HEP_IDENTITY;
3703     case ABIL_HEPLIAKLQANA_TYPE_KNIGHT:
3704         return TILEG_ABILITY_HEP_KNIGHT;
3705     case ABIL_HEPLIAKLQANA_TYPE_BATTLEMAGE:
3706         return TILEG_ABILITY_HEP_BATTLEMAGE;
3707     case ABIL_HEPLIAKLQANA_TYPE_HEXER:
3708         return TILEG_ABILITY_HEP_HEXER;
3709     // usk
3710    case ABIL_USKAYAW_STOMP:
3711         return TILEG_ABILITY_USKAYAW_STOMP;
3712    case ABIL_USKAYAW_LINE_PASS:
3713         return TILEG_ABILITY_USKAYAW_LINE_PASS;
3714    case ABIL_USKAYAW_GRAND_FINALE:
3715         return TILEG_ABILITY_USKAYAW_GRAND_FINALE;
3716      // Wu Jian
3717     case ABIL_WU_JIAN_WALLJUMP:
3718         return TILEG_ABILITY_WU_JIAN_WALL_JUMP;
3719     case ABIL_WU_JIAN_SERPENTS_LASH:
3720         return TILEG_ABILITY_WU_JIAN_SERPENTS_LASH;
3721     case ABIL_WU_JIAN_HEAVENLY_STORM:
3722         return TILEG_ABILITY_WU_JIAN_HEAVENLY_STORM;
3723 
3724     // General divine (pseudo) abilities.
3725     case ABIL_RENOUNCE_RELIGION:
3726         return TILEG_ABILITY_RENOUNCE_RELIGION;
3727 
3728     default:
3729         return TILEG_ERROR;
3730     }
3731 }
3732 
tileidx_branch(const branch_type br)3733 tileidx_t tileidx_branch(const branch_type br)
3734 {
3735     switch (br)
3736     {
3737     case BRANCH_DUNGEON:
3738         return TILE_DNGN_EXIT_DUNGEON;
3739     case BRANCH_TEMPLE:
3740         return TILE_DNGN_ENTER_TEMPLE;
3741     case BRANCH_ORC:
3742         return TILE_DNGN_ENTER_ORC;
3743     case BRANCH_ELF:
3744         return TILE_DNGN_ENTER_ELF;
3745     case BRANCH_LAIR:
3746         return TILE_DNGN_ENTER_LAIR;
3747     case BRANCH_SWAMP:
3748         return TILE_DNGN_ENTER_SWAMP;
3749     case BRANCH_SHOALS:
3750         return TILE_DNGN_ENTER_SHOALS;
3751     case BRANCH_SNAKE:
3752         return TILE_DNGN_ENTER_SNAKE;
3753     case BRANCH_SPIDER:
3754         return TILE_DNGN_ENTER_SPIDER;
3755     case BRANCH_SLIME:
3756         return TILE_DNGN_ENTER_SLIME;
3757     case BRANCH_VAULTS:
3758         return TILE_DNGN_ENTER_VAULTS_OPEN;
3759     case BRANCH_CRYPT:
3760         return TILE_DNGN_ENTER_CRYPT;
3761     case BRANCH_TOMB:
3762         return TILE_DNGN_ENTER_TOMB;
3763     case BRANCH_DEPTHS:
3764         return TILE_DNGN_ENTER_DEPTHS;
3765     case BRANCH_VESTIBULE:
3766         return TILE_DNGN_ENTER_HELL;
3767     case BRANCH_DIS:
3768         return TILE_DNGN_ENTER_DIS;
3769     case BRANCH_GEHENNA:
3770         return TILE_DNGN_ENTER_GEHENNA;
3771     case BRANCH_COCYTUS:
3772         return TILE_DNGN_ENTER_COCYTUS;
3773     case BRANCH_TARTARUS:
3774         return TILE_DNGN_ENTER_TARTARUS;
3775     case BRANCH_ZOT:
3776         return TILE_DNGN_ENTER_ZOT_OPEN;
3777     case BRANCH_ABYSS:
3778         return TILE_DNGN_ENTER_ABYSS;
3779     case BRANCH_PANDEMONIUM:
3780         return TILE_DNGN_ENTER_PANDEMONIUM;
3781     case BRANCH_ZIGGURAT:
3782         return TILE_DNGN_PORTAL_ZIGGURAT;
3783     case BRANCH_GAUNTLET:
3784         return TILE_DNGN_PORTAL_GAUNTLET;
3785     case BRANCH_BAZAAR:
3786         return TILE_DNGN_PORTAL_BAZAAR;
3787     case BRANCH_TROVE:
3788         return TILE_DNGN_PORTAL_TROVE;
3789     case BRANCH_SEWER:
3790         return TILE_DNGN_PORTAL_SEWER;
3791     case BRANCH_OSSUARY:
3792         return TILE_DNGN_PORTAL_OSSUARY;
3793     case BRANCH_BAILEY:
3794         return TILE_DNGN_PORTAL_BAILEY;
3795     case BRANCH_ICE_CAVE:
3796         return TILE_DNGN_PORTAL_ICE_CAVE;
3797     case BRANCH_VOLCANO:
3798         return TILE_DNGN_PORTAL_VOLCANO;
3799     case BRANCH_WIZLAB:
3800         return TILE_DNGN_PORTAL_WIZARD_LAB_7; /* I like this colour */
3801     case BRANCH_DESOLATION:
3802         return TILE_DNGN_PORTAL_DESOLATION;
3803 
3804     default:
3805         return TILEG_ERROR;
3806     }
3807 }
3808 
_tileidx_player_job_base(const job_type job)3809 static tileidx_t _tileidx_player_job_base(const job_type job)
3810 {
3811     switch (job)
3812     {
3813         case JOB_FIGHTER:
3814             return TILEG_JOB_FIGHTER;
3815         case JOB_WIZARD:
3816             return TILEG_JOB_WIZARD;
3817         case JOB_GLADIATOR:
3818             return TILEG_JOB_GLADIATOR;
3819         case JOB_NECROMANCER:
3820             return TILEG_JOB_NECROMANCER;
3821         case JOB_BRIGAND:
3822             return TILEG_JOB_BRIGAND;
3823         case JOB_BERSERKER:
3824             return TILEG_JOB_BERSERKER;
3825         case JOB_HUNTER:
3826             return TILEG_JOB_HUNTER;
3827         case JOB_CONJURER:
3828             return TILEG_JOB_CONJURER;
3829         case JOB_ENCHANTER:
3830             return TILEG_JOB_ENCHANTER;
3831         case JOB_FIRE_ELEMENTALIST:
3832             return TILEG_JOB_FIRE_ELEMENTALIST;
3833         case JOB_ICE_ELEMENTALIST:
3834             return TILEG_JOB_ICE_ELEMENTALIST;
3835         case JOB_SUMMONER:
3836             return TILEG_JOB_SUMMONER;
3837         case JOB_AIR_ELEMENTALIST:
3838             return TILEG_JOB_AIR_ELEMENTALIST;
3839         case JOB_EARTH_ELEMENTALIST:
3840             return TILEG_JOB_EARTH_ELEMENTALIST;
3841         case JOB_VENOM_MAGE:
3842             return TILEG_JOB_VENOM_MAGE;
3843         case JOB_CHAOS_KNIGHT:
3844             return TILEG_JOB_CHAOS_KNIGHT;
3845         case JOB_TRANSMUTER:
3846             return TILEG_JOB_TRANSMUTER;
3847         case JOB_MONK:
3848             return TILEG_JOB_MONK;
3849         case JOB_WARPER:
3850             return TILEG_JOB_WARPER;
3851         case JOB_WANDERER:
3852             return TILEG_JOB_WANDERER;
3853         case JOB_ARTIFICER:
3854             return TILEG_JOB_ARTIFICER;
3855         case JOB_DELVER:
3856             return TILEG_JOB_DELVER;
3857         case JOB_ARCANE_MARKSMAN:
3858             return TILEG_JOB_ARCANE_MARKSMAN;
3859         case JOB_ABYSSAL_KNIGHT:
3860             return TILEG_JOB_ABYSSAL_KNIGHT;
3861         default:
3862             return TILEG_ERROR;
3863     }
3864 }
3865 
_tileidx_player_species_base(const species_type species)3866 static tileidx_t _tileidx_player_species_base(const species_type species)
3867 {
3868     switch (species)
3869     {
3870         case SP_HUMAN:
3871             return TILEG_SP_HUMAN;
3872         case SP_DEEP_ELF:
3873             return TILEG_SP_DEEP_ELF;
3874         case SP_HILL_ORC:
3875             return TILEG_SP_HILL_ORC;
3876         case SP_KOBOLD:
3877             return TILEG_SP_KOBOLD;
3878         case SP_MUMMY:
3879             return TILEG_SP_MUMMY;
3880         case SP_NAGA:
3881             return TILEG_SP_NAGA;
3882         case SP_OGRE:
3883             return TILEG_SP_OGRE;
3884         case SP_TROLL:
3885             return TILEG_SP_TROLL;
3886         case SP_BASE_DRACONIAN:
3887             return TILEG_SP_DRACONIAN;
3888         case SP_PALENTONGA:
3889             return TILEG_SP_PALENTONGA;
3890         case SP_DEMIGOD:
3891             return TILEG_SP_DEMIGOD;
3892         case SP_SPRIGGAN:
3893             return TILEG_SP_SPRIGGAN;
3894         case SP_MINOTAUR:
3895             return TILEG_SP_MINOTAUR;
3896         case SP_DEMONSPAWN:
3897             return TILEG_SP_DEMONSPAWN;
3898         case SP_GHOUL:
3899             return TILEG_SP_GHOUL;
3900         case SP_TENGU:
3901             return TILEG_SP_TENGU;
3902         case SP_MERFOLK:
3903             return TILEG_SP_MERFOLK;
3904         case SP_VAMPIRE:
3905             return TILEG_SP_VAMPIRE;
3906         case SP_DEEP_DWARF:
3907             return TILEG_SP_DEEP_DWARF;
3908         case SP_FELID:
3909             return TILEG_SP_FELID;
3910         case SP_OCTOPODE:
3911             return TILEG_SP_OCTOPODE;
3912         case SP_GARGOYLE:
3913             return TILEG_SP_GARGOYLE;
3914         case SP_FORMICID:
3915             return TILEG_SP_FORMICID;
3916         case SP_VINE_STALKER:
3917             return TILEG_SP_VINE_STALKER;
3918         case SP_BARACHI:
3919             return TILEG_SP_BARACHI;
3920         case SP_GNOLL:
3921             return TILEG_SP_GNOLL;
3922         case SP_DJINNI:
3923             return TILEG_SP_DJINNI;
3924         default:
3925             return TILEP_ERROR;
3926     }
3927 }
3928 
tileidx_player_species(const species_type species,bool recommended)3929 tileidx_t tileidx_player_species(const species_type species, bool recommended)
3930 {
3931     tileidx_t off = recommended ? -TILEG_LAST_SPECIES+TILEG_LAST_RECOMMENDED_SPECIES: 0;
3932     return _tileidx_player_species_base(species) + off;
3933 }
3934 
tileidx_player_job(const job_type job,bool recommended)3935 tileidx_t tileidx_player_job(const job_type job, bool recommended)
3936 {
3937     tileidx_t off = recommended ? -TILEG_LAST_JOB+TILEG_LAST_RECOMMENDED_JOB: 0;
3938     return _tileidx_player_job_base(job) + off;
3939 }
3940 
tileidx_known_brand(const item_def & item)3941 tileidx_t tileidx_known_brand(const item_def &item)
3942 {
3943     if (!item_type_known(item))
3944         return 0;
3945 
3946     if (item.base_type == OBJ_WEAPONS)
3947     {
3948         const int brand = get_weapon_brand(item);
3949         if (brand != SPWPN_NORMAL)
3950             return TILE_BRAND_WEP_FIRST + get_weapon_brand(item) - 1;
3951     }
3952     else if (item.base_type == OBJ_ARMOUR)
3953     {
3954         const int brand = get_armour_ego_type(item);
3955         if (brand != SPARM_NORMAL)
3956             return TILE_BRAND_ARM_FIRST + get_armour_ego_type(item) - 1;
3957     }
3958     else if (item.base_type == OBJ_MISSILES)
3959     {
3960         switch (get_ammo_brand(item))
3961         {
3962 #if TAG_MAJOR_VERSION == 34
3963         case SPMSL_FLAME:
3964             return TILE_BRAND_FLAME;
3965         case SPMSL_FROST:
3966             return TILE_BRAND_FROST;
3967 #endif
3968         case SPMSL_POISONED:
3969             return TILE_BRAND_POISONED;
3970         case SPMSL_CURARE:
3971             return TILE_BRAND_CURARE;
3972 #if TAG_MAJOR_VERSION == 34
3973         case SPMSL_RETURNING:
3974             return TILE_BRAND_RETURNING;
3975 #endif
3976         case SPMSL_CHAOS:
3977             return TILE_BRAND_CHAOS;
3978 #if TAG_MAJOR_VERSION == 34
3979         case SPMSL_PENETRATION:
3980             return TILE_BRAND_PENETRATION;
3981 #endif
3982         case SPMSL_DISPERSAL:
3983             return TILE_BRAND_DISPERSAL;
3984         case SPMSL_EXPLODING:
3985             return TILE_BRAND_EXPLOSION;
3986 #if TAG_MAJOR_VERSION == 34
3987         case SPMSL_CONFUSION:
3988             return TILE_BRAND_CONFUSION;
3989         case SPMSL_PARALYSIS:
3990             return TILE_BRAND_PARALYSIS;
3991         case SPMSL_SLOW:
3992             return TILE_BRAND_SLOWING;
3993         case SPMSL_SICKNESS:
3994             return TILE_BRAND_SICKNESS;
3995         case SPMSL_SLEEP:
3996             return TILE_BRAND_SLEEP;
3997 #endif
3998         case SPMSL_FRENZY:
3999             return TILE_BRAND_FRENZY;
4000         case SPMSL_BLINDING:
4001             return TILE_BRAND_BLINDING;
4002         default:
4003             break;
4004         }
4005     }
4006 #if TAG_MAJOR_VERSION == 34
4007     else if (item.base_type == OBJ_RODS)
4008     {
4009         // Technically not a brand, but still handled here
4010         return TILE_ROD_ID_FIRST + item.sub_type;
4011     }
4012 #endif
4013     return 0;
4014 }
4015 
tileidx_corpse_brand(const item_def & item)4016 tileidx_t tileidx_corpse_brand(const item_def &item)
4017 {
4018     if (item.base_type != OBJ_CORPSES || item.sub_type != CORPSE_BODY)
4019         return 0;
4020 
4021     return 0;
4022 }
4023 
tileidx_unseen_flag(const coord_def & gc)4024 tileidx_t tileidx_unseen_flag(const coord_def &gc)
4025 {
4026     if (!map_bounds(gc))
4027         return TILE_FLAG_UNSEEN;
4028     else if (env.map_knowledge(gc).known()
4029                 && !env.map_knowledge(gc).seen()
4030              || env.map_knowledge(gc).detected_item()
4031              || env.map_knowledge(gc).detected_monster()
4032            )
4033     {
4034         return TILE_FLAG_MM_UNSEEN;
4035     }
4036     else
4037         return TILE_FLAG_UNSEEN;
4038 }
4039 
enchant_to_int(const item_def & item)4040 int enchant_to_int(const item_def &item)
4041 {
4042     if (is_random_artefact(item))
4043         return 4;
4044 
4045     switch (item.flags & ISFLAG_COSMETIC_MASK)
4046     {
4047         default:
4048             return 0;
4049         case ISFLAG_EMBROIDERED_SHINY:
4050             return 1;
4051         case ISFLAG_RUNED:
4052             return 2;
4053         case ISFLAG_GLOWING:
4054             return 3;
4055     }
4056 }
4057 
tileidx_enchant_equ(const item_def & item,tileidx_t tile,bool player)4058 tileidx_t tileidx_enchant_equ(const item_def &item, tileidx_t tile, bool player)
4059 {
4060     static const int etable[5][5] =
4061     {
4062       {0, 0, 0, 0, 0},  // all variants look the same
4063       {0, 1, 1, 1, 1},  // normal, ego/randart
4064       {0, 1, 1, 1, 2},  // normal, ego, randart
4065       {0, 1, 1, 2, 3},  // normal, ego (shiny/runed), ego (glowing), randart
4066       {0, 1, 2, 3, 4}   // normal, shiny, runed, glowing, randart
4067     };
4068 
4069     const int etype = enchant_to_int(item);
4070 
4071     // XXX: only helmets, robes and boots have variants, but it would be nice
4072     // if this weren't hardcoded.
4073     if (tile == TILE_THELM_HELM)
4074     {
4075         switch (etype)
4076         {
4077             case 1:
4078             case 2:
4079             case 3:
4080                 tile = _modrng(item.rnd, TILE_THELM_EGO_FIRST, TILE_THELM_EGO_LAST);
4081                 break;
4082             case 4:
4083                 tile = _modrng(item.rnd, TILE_THELM_ART_FIRST, TILE_THELM_ART_LAST);
4084                 break;
4085             default:
4086                 tile = _modrng(item.rnd, TILE_THELM_FIRST, TILE_THELM_LAST);
4087         }
4088         return tile;
4089     }
4090 
4091     if (tile == TILE_ARM_ROBE)
4092     {
4093         switch (etype)
4094         {
4095             case 1:
4096             case 2:
4097             case 3:
4098                 tile = _modrng(item.rnd, TILE_ARM_ROBE_EGO_FIRST, TILE_ARM_ROBE_EGO_LAST);
4099                 break;
4100             case 4:
4101                 tile = _modrng(item.rnd, TILE_ARM_ROBE_ART_FIRST, TILE_ARM_ROBE_ART_LAST);
4102                 break;
4103             default:
4104                 tile = _modrng(item.rnd, TILE_ARM_ROBE_FIRST, TILE_ARM_ROBE_LAST);
4105         }
4106         return tile;
4107     }
4108 
4109     if (tile == TILE_ARM_BOOTS)
4110     {
4111         switch (etype)
4112         {
4113             case 1:
4114             case 2:
4115             case 3:
4116                 tile = _modrng(item.rnd, TILE_ARM_BOOTS_EGO_FIRST, TILE_ARM_BOOTS_EGO_LAST);
4117                 break;
4118             case 4:
4119                 tile = _modrng(item.rnd, TILE_ARM_BOOTS_ART_FIRST, TILE_ARM_BOOTS_ART_LAST);
4120                 break;
4121             default:
4122                 tile = _modrng(item.rnd, TILE_ARM_BOOTS_FIRST, TILE_ARM_BOOTS_LAST);
4123         }
4124         return tile;
4125     }
4126 
4127     int idx;
4128     if (player)
4129         idx = tile_player_count(tile) - 1;
4130     else
4131         idx = tile_main_count(tile) - 1;
4132     ASSERT(idx < 5);
4133 
4134     tile += etable[idx][etype];
4135 
4136     return tile;
4137 }
4138 
4139 #ifdef USE_TILE
tile_debug_string(tileidx_t fg,tileidx_t bg,char prefix)4140 string tile_debug_string(tileidx_t fg, tileidx_t bg, char prefix)
4141 {
4142     tileidx_t fg_idx = fg & TILE_FLAG_MASK;
4143     tileidx_t bg_idx = bg & TILE_FLAG_MASK;
4144 
4145     string fg_name;
4146     if (fg_idx < TILE_FLOOR_MAX)
4147         fg_name = tile_floor_name(fg_idx);
4148     else if (fg_idx < TILE_WALL_MAX)
4149         fg_name = tile_wall_name(fg_idx);
4150     else if (fg_idx < TILE_FEAT_MAX)
4151         fg_name = tile_feat_name(fg_idx);
4152     else if (fg_idx < TILE_DNGN_MAX)
4153         fg_name = tile_dngn_name(fg_idx);
4154     else if (fg_idx < TILE_MAIN_MAX)
4155         fg_name = tile_main_name(fg_idx);
4156     else if (fg_idx < TILEP_MCACHE_START)
4157         fg_name = (tile_player_name(fg_idx));
4158     else
4159     {
4160         fg_name = "mc:";
4161         mcache_entry *entry = mcache.get(fg_idx);
4162         if (entry)
4163         {
4164             tile_draw_info dinfo[mcache_entry::MAX_INFO_COUNT];
4165             unsigned int count = entry->info(&dinfo[0]);
4166             for (unsigned int i = 0; i < count; ++i)
4167             {
4168                 tileidx_t mc_idx = dinfo[i].idx;
4169                 if (mc_idx < TILE_MAIN_MAX)
4170                     fg_name += tile_main_name(mc_idx);
4171                 else if (mc_idx < TILEP_PLAYER_MAX)
4172                     fg_name += tile_player_name(mc_idx);
4173                 else
4174                     fg_name += "[invalid index]";
4175 
4176                 if (i < count - 1)
4177                     fg_name += ", ";
4178             }
4179         }
4180         else
4181             fg_name += "[not found]";
4182     }
4183 
4184     string tile_string = make_stringf(
4185         "%cFG: %4" PRIu64" | 0x%8" PRIx64" (%s)\n"
4186         "%cBG: %4" PRIu64" | 0x%8" PRIx64" (%s)\n",
4187         prefix,
4188         fg_idx,
4189         fg & ~TILE_FLAG_MASK,
4190         fg_name.c_str(),
4191         prefix,
4192         bg_idx,
4193         bg & ~TILE_FLAG_MASK,
4194         tile_dngn_name(bg_idx));
4195 
4196     return tile_string;
4197 }
4198 #endif
4199 
bind_item_tile(item_def & item)4200 void bind_item_tile(item_def &item)
4201 {
4202     if (item.props.exists("item_tile_name"))
4203     {
4204         string tile = item.props["item_tile_name"].get_string();
4205         dprf("Binding non-worn item tile: \"%s\".", tile.c_str());
4206         tileidx_t index;
4207         if (!tile_main_index(tile.c_str(), &index))
4208         {
4209             // If invalid tile name, complain and discard the props.
4210             dprf("bad tile name: \"%s\".", tile.c_str());
4211             item.props.erase("item_tile_name");
4212             item.props.erase("item_tile");
4213         }
4214         else
4215             item.props["item_tile"] = short(index);
4216     }
4217 
4218     if (item.props.exists("worn_tile_name"))
4219     {
4220         string tile = item.props["worn_tile_name"].get_string();
4221         dprf("Binding worn item tile: \"%s\".", tile.c_str());
4222         tileidx_t index;
4223         if (!tile_player_index(tile.c_str(), &index))
4224         {
4225             // If invalid tile name, complain and discard the props.
4226             dprf("bad tile name: \"%s\".", tile.c_str());
4227             item.props.erase("worn_tile_name");
4228             item.props.erase("worn_tile");
4229         }
4230         else
4231             item.props["worn_tile"] = short(index);
4232     }
4233 }
4234 
tile_init_props(monster * mon)4235 void tile_init_props(monster* mon)
4236 {
4237     // Only monsters using mon_mod or mon_cycle need a tile_num.
4238     switch (mon->type)
4239     {
4240         case MONS_TOADSTOOL:
4241         case MONS_FUNGUS:
4242         case MONS_PLANT:
4243         case MONS_BUSH:
4244         case MONS_FIRE_VORTEX:
4245         case MONS_TWISTER:
4246         case MONS_SPATIAL_VORTEX:
4247         case MONS_SPATIAL_MAELSTROM:
4248         case MONS_ABOMINATION_SMALL:
4249         case MONS_ABOMINATION_LARGE:
4250         case MONS_BLOCK_OF_ICE:
4251         case MONS_BUTTERFLY:
4252         case MONS_HUMAN:
4253         case MONS_DEEP_ELF_ELEMENTALIST:
4254             break;
4255         default:
4256             return;
4257     }
4258 
4259     // Already overridden or set.
4260     if (mon->props.exists("monster_tile") || mon->props.exists(TILE_NUM_KEY))
4261         return;
4262 
4263     mon->props[TILE_NUM_KEY] = short(random2(256));
4264 }
4265