1 #include "AppHdr.h"
2 
3 #include "tileview.h"
4 
5 #include "areas.h"
6 #include "branch.h"
7 #include "cloud.h"
8 #include "colour.h"
9 #include "coord.h"
10 #include "coordit.h"
11 #include "domino.h"
12 #include "domino-data.h"
13 #include "dungeon.h"
14 #include "env.h"
15 #include "tile-env.h"
16 #include "fprop.h"
17 #include "items.h"
18 #include "kills.h"
19 #include "level-state-type.h"
20 #include "mon-util.h"
21 #include "options.h"
22 #include "pcg.h"
23 #include "player.h"
24 #include "state.h"
25 #include "tag-version.h"
26 #include "terrain.h"
27 #include "tile-flags.h"
28 #include "rltiles/tiledef-dngn.h"
29 #include "rltiles/tiledef-player.h"
30 #include "tilemcache.h"
31 #include "tilepick.h"
32 #include "tiles-build-specific.h"
33 #include "traps.h"
34 #include "travel.h"
35 #include "viewgeom.h"
36 
tile_new_level(bool first_time,bool init_unseen)37 void tile_new_level(bool first_time, bool init_unseen)
38 {
39     if (first_time)
40         tile_init_flavour();
41 
42 #ifdef USE_TILE
43     if (init_unseen)
44     {
45         for (unsigned int x = 0; x < GXM; x++)
46             for (unsigned int y = 0; y < GYM; y++)
47             {
48                 tile_env.bk_fg[x][y] = 0;
49                 tile_env.bk_bg[x][y] = TILE_DNGN_UNSEEN;
50                 tile_env.bk_cloud[x][y] = 0;
51             }
52     }
53 
54     // Fix up stair markers. The travel information isn't hooked up
55     // until after we change levels. So, look through all of the stairs
56     // on this level and check if they still need the stair flag.
57     for (unsigned int x = 0; x < GXM; x++)
58         for (unsigned int y = 0; y < GYM; y++)
59         {
60             unsigned int tile = tile_env.bk_bg[x][y];
61             if ((tile & TILE_FLAG_NEW_STAIR)
62                 && !is_unknown_stair(coord_def(x,y)))
63             {
64                 tile_env.bk_bg[x][y] &= ~TILE_FLAG_NEW_STAIR;
65             }
66             else if ((tile & TILE_FLAG_NEW_TRANSPORTER)
67                      && !is_unknown_transporter(coord_def(x,y)))
68                 tile_env.bk_bg[x][y] &= ~TILE_FLAG_NEW_TRANSPORTER;
69         }
70 
71     tiles.clear_minimap();
72 
73     for (unsigned int x = 0; x < GXM; x++)
74         for (unsigned int y = 0; y < GYM; y++)
75             tiles.update_minimap(coord_def(x, y));
76 #else
77     UNUSED(init_unseen);
78 #endif
79 }
80 
tile_init_default_flavour()81 void tile_init_default_flavour()
82 {
83     tile_default_flv(you.where_are_you, tile_env.default_flavour);
84 }
85 
tile_default_flv(branch_type br,tile_flavour & flv)86 void tile_default_flv(branch_type br, tile_flavour &flv)
87 {
88     flv.wall    = TILE_WALL_NORMAL;
89     flv.floor   = TILE_FLOOR_NORMAL;
90     flv.special = 0;
91 
92     flv.wall_idx = 0;
93     flv.floor_idx = 0;
94 
95     switch (br)
96     {
97     case BRANCH_DUNGEON:
98         flv.wall  = TILE_WALL_NORMAL;
99         flv.floor = TILE_FLOOR_NORMAL;
100         return;
101 
102     case BRANCH_DEPTHS:
103         flv.wall  = TILE_WALL_NORMAL;
104         flv.floor = TILE_FLOOR_GREY_DIRT_B;
105         return;
106 
107     case BRANCH_VAULTS:
108         flv.wall  = TILE_WALL_VAULT;
109         flv.floor = TILE_FLOOR_VAULT;
110         return;
111 
112     case BRANCH_TEMPLE:
113         flv.wall  = TILE_WALL_VINES;
114         flv.floor = TILE_FLOOR_VINES;
115         return;
116 
117 #if TAG_MAJOR_VERSION == 34
118     case BRANCH_DWARF:
119         flv.wall  = TILE_WALL_HALL;
120         flv.floor = TILE_FLOOR_LIMESTONE;
121         return;
122 #endif
123 
124 #if TAG_MAJOR_VERSION == 34
125     case BRANCH_BLADE:
126 #endif
127     case BRANCH_ELF:
128         flv.wall  = TILE_WALL_HALL;
129         flv.floor = TILE_FLOOR_HALL;
130         return;
131 
132     case BRANCH_TARTARUS:
133         flv.wall  = TILE_WALL_COBALT_ROCK;
134         flv.floor = TILE_FLOOR_BLACK_COBALT;
135         return;
136 
137     case BRANCH_CRYPT:
138         flv.wall  = TILE_WALL_BRICK_GRAY;
139         flv.floor = TILE_FLOOR_CRYPT;
140         return;
141 
142     case BRANCH_TOMB:
143         flv.wall  = TILE_WALL_UNDEAD;
144         flv.floor = TILE_FLOOR_TOMB;
145         return;
146 
147     case BRANCH_VESTIBULE:
148         flv.wall  = TILE_WALL_HELL;
149         flv.floor = TILE_FLOOR_CAGE;
150         return;
151 
152     case BRANCH_DIS:
153         flv.wall  = TILE_WALL_ZOT_CYAN;
154         flv.floor = TILE_FLOOR_IRON;
155         return;
156 
157     case BRANCH_GEHENNA:
158         flv.wall  = TILE_WALL_ZOT_RED;
159         flv.floor = TILE_FLOOR_ROUGH_RED;
160         return;
161 
162     case BRANCH_COCYTUS:
163         flv.wall  = TILE_WALL_ICE;
164         flv.floor = TILE_FLOOR_FROZEN;
165         return;
166 
167     case BRANCH_ORC:
168         flv.wall  = TILE_WALL_ORC;
169         flv.floor = TILE_FLOOR_ORC;
170         return;
171 
172     case BRANCH_LAIR:
173         flv.wall  = TILE_WALL_LAIR;
174         flv.floor = TILE_FLOOR_LAIR;
175         return;
176 
177     case BRANCH_SLIME:
178         flv.wall  = TILE_WALL_SLIME;
179         flv.floor = TILE_FLOOR_SLIME;
180         return;
181 
182     case BRANCH_SNAKE:
183         flv.wall  = TILE_WALL_SNAKE;
184         flv.floor = TILE_FLOOR_MOSAIC;
185         return;
186 
187     case BRANCH_SWAMP:
188         flv.wall  = TILE_WALL_SWAMP;
189         flv.floor = TILE_FLOOR_SWAMP;
190         return;
191 
192     case BRANCH_SHOALS:
193         flv.wall  = TILE_WALL_SHOALS;
194         flv.floor = TILE_FLOOR_SAND;
195         return;
196 
197     case BRANCH_SPIDER:
198         flv.wall  = TILE_WALL_SPIDER;
199         flv.floor = TILE_FLOOR_SPIDER;
200         return;
201 
202     case BRANCH_ZOT:
203         flv.wall  = TILE_WALL_ZOT_YELLOW;
204         flv.floor = TILE_FLOOR_TOMB;
205         return;
206 
207 #if TAG_MAJOR_VERSION == 34
208     case BRANCH_FOREST:
209         flv.wall  = TILE_WALL_LAIR;
210         flv.floor = TILE_FLOOR_GRASS;
211         return;
212 #endif
213     case BRANCH_ABYSS:
214         flv.floor = tile_dngn_coloured(TILE_FLOOR_NERVES, env.floor_colour);
215         switch (random2(6))
216         {
217         default:
218         case 0:
219         case 1:
220         case 2:
221             flv.wall = tile_dngn_coloured(TILE_WALL_ABYSS, env.rock_colour);
222             break;
223         case 3:
224             flv.wall = tile_dngn_coloured(TILE_WALL_PEBBLE, env.rock_colour);
225             break;
226         case 4:
227             flv.wall = tile_dngn_coloured(TILE_WALL_HALL, env.rock_colour);
228             break;
229         case 5:
230             flv.wall = tile_dngn_coloured(TILE_WALL_UNDEAD, env.rock_colour);
231             break;
232         }
233         return;
234 
235     case BRANCH_PANDEMONIUM:
236         flv.floor = tile_dngn_coloured(TILE_FLOOR_DEMONIC, env.floor_colour);
237         if (env.rock_colour == LIGHTRED)
238             flv.wall = TILE_WALL_FLESH;
239         else
240             flv.wall = tile_dngn_coloured(TILE_WALL_BARS, env.rock_colour);
241         break;
242 
243     case BRANCH_ZIGGURAT:
244     case BRANCH_BAZAAR:
245     case BRANCH_TROVE:
246         flv.wall  = TILE_WALL_VAULT;
247         flv.floor = TILE_FLOOR_VAULT;
248         return;
249 
250 #if TAG_MAJOR_VERSION == 34
251     case BRANCH_LABYRINTH:
252 #endif
253     case BRANCH_GAUNTLET:
254         flv.wall  = TILE_WALL_LAB_ROCK;
255         flv.floor = TILE_FLOOR_GAUNTLET;
256         return;
257 
258     case BRANCH_SEWER:
259         flv.wall  = TILE_WALL_PEBBLE_GREEN;
260         flv.floor = TILE_FLOOR_SLIME;
261         return;
262 
263     case BRANCH_OSSUARY:
264         flv.wall  = TILE_WALL_SANDSTONE;
265         flv.floor = TILE_FLOOR_SANDSTONE;
266         return;
267 
268     case BRANCH_BAILEY:
269         flv.wall  = TILE_WALL_BRICK_BROWN;
270         flv.floor = TILE_FLOOR_COBBLE_BLOOD;
271         return;
272 
273     case BRANCH_ICE_CAVE:
274         flv.wall  = TILE_WALL_ICE_BLOCK;
275         flv.floor = TILE_FLOOR_ICE;
276         return;
277 
278     case BRANCH_VOLCANO:
279         flv.wall  = TILE_WALL_VOLCANIC;
280         flv.floor = TILE_FLOOR_ROUGH_RED;
281         return;
282 
283     case BRANCH_WIZLAB:
284         flv.wall  = TILE_WALL_NORMAL;
285         flv.floor = TILE_FLOOR_NORMAL;
286         return;
287 
288     case BRANCH_DESOLATION:
289         flv.floor = TILE_FLOOR_SALT;
290         flv.wall = TILE_WALL_DESOLATION;
291         return;
292 
293     case NUM_BRANCHES:
294     case GLOBAL_BRANCH_INFO:
295         break;
296     }
297 }
298 
tile_clear_flavour(const coord_def & p)299 void tile_clear_flavour(const coord_def &p)
300 {
301     tile_env.flv(p).floor     = 0;
302     tile_env.flv(p).wall      = 0;
303     tile_env.flv(p).feat      = 0;
304     tile_env.flv(p).floor_idx = 0;
305     tile_env.flv(p).wall_idx  = 0;
306     tile_env.flv(p).feat_idx  = 0;
307     tile_env.flv(p).special   = 0;
308 }
309 
tile_clear_flavour()310 void tile_clear_flavour()
311 {
312     for (rectangle_iterator ri(0); ri; ++ri)
313         tile_clear_flavour(*ri);
314 }
315 
_level_uses_dominoes()316 static bool _level_uses_dominoes()
317 {
318     return you.where_are_you == BRANCH_CRYPT;
319 }
320 
321 // For floors and walls that have not already been set to a particular tile,
322 // set them to a random instance of the default floor and wall tileset.
tile_init_flavour()323 void tile_init_flavour()
324 {
325     if (_level_uses_dominoes())
326     {
327         vector<unsigned int> output;
328 
329         {
330             rng::subgenerator sub_rng(
331                 static_cast<uint64_t>(you.where_are_you ^ you.game_seed),
332                 static_cast<uint64_t>(you.depth));
333             output.reserve(X_WIDTH * Y_WIDTH);
334             domino::DominoSet<domino::EdgeDomino> dominoes(domino::cohen_set, 8);
335             // TODO: don't pass a PcgRNG object
336             dominoes.Generate(X_WIDTH, Y_WIDTH, output,
337                                                     rng::current_generator());
338         }
339 
340         for (rectangle_iterator ri(0); ri; ++ri)
341             tile_init_flavour(*ri, output[ri->x + ri->y * GXM]);
342     }
343     else
344         for (rectangle_iterator ri(0); ri; ++ri)
345             tile_init_flavour(*ri, 0);
346 }
347 
348 // 11111333333   55555555
349 //   222222444444   6666666666
_get_dungeon_wall_tiles_by_depth(int depth,vector<tileidx_t> & t)350 static void _get_dungeon_wall_tiles_by_depth(int depth, vector<tileidx_t>& t)
351 {
352     if (crawl_state.game_is_sprint() || crawl_state.game_is_arena())
353     {
354         t.push_back(TILE_WALL_CATACOMBS);
355         return;
356     }
357     if (depth <= 5)
358         t.push_back(TILE_WALL_BRICK_DARK_1);
359     if (depth > 2 && depth <= 8)
360     {
361         t.push_back(TILE_WALL_BRICK_DARK_2);
362         t.push_back(TILE_WALL_BRICK_DARK_2_TORCH);
363     }
364     if (depth > 5 && depth <= 11)
365         t.push_back(TILE_WALL_BRICK_DARK_3);
366     if (depth > 8)
367     {
368         t.push_back(TILE_WALL_BRICK_DARK_4);
369         t.push_back(TILE_WALL_BRICK_DARK_4_TORCH);
370     }
371     if (depth == brdepth[BRANCH_DUNGEON])
372         t.push_back(TILE_WALL_BRICK_DARK_4_TORCH);  // torches are more common on D:14...
373 }
374 
_get_depths_wall_tiles_by_depth(int depth,vector<tileidx_t> & t)375 static void _get_depths_wall_tiles_by_depth(int depth, vector<tileidx_t>& t)
376 {
377     t.push_back(TILE_WALL_BRICK_DARK_6_TORCH);
378     if (depth <= 3)
379         t.push_back(TILE_WALL_BRICK_DARK_5);
380     if (depth > 3)
381         t.push_back(TILE_WALL_BRICK_DARK_6);
382     if (depth == brdepth[BRANCH_DEPTHS])
383         t.push_back(TILE_WALL_BRICK_DARK_6_TORCH);  // ...and on Depths:$
384 }
385 
_find_variants(tileidx_t idx,int variant,vector<int> & out)386 static int _find_variants(tileidx_t idx, int variant, vector<int> &out)
387 {
388     const int count = tile_dngn_count(idx);
389     out.reserve(count);
390     if (count == 1)
391     {
392         out.push_back(1);
393         return 1;
394     }
395 
396     int total = 0;
397     int curr_prob = 0;
398     for (int i = 0; i < count; ++i)
399     {
400         int last_prob = curr_prob;
401         curr_prob = tile_dngn_probs(idx + i);
402         if (tile_dngn_dominoes(idx + i) == variant)
403         {
404             int weight = curr_prob - last_prob;
405             total += weight;
406             out.push_back(weight);
407         }
408         else
409             out.push_back(0);
410     }
411     if (!total)
412     {
413         out.clear();
414         out.push_back(tile_dngn_probs(idx));
415         for (int i = 1; i < count; ++i)
416             out.push_back(tile_dngn_probs(idx + i) - tile_dngn_probs(idx + i - 1));
417         return tile_dngn_probs(idx + count - 1);
418     }
419     return total;
420 }
421 
pick_dngn_tile(tileidx_t idx,int value,int domino)422 tileidx_t pick_dngn_tile(tileidx_t idx, int value, int domino)
423 {
424     ASSERT_LESS(idx, TILE_DNGN_MAX);
425     static vector<int> weights;
426     weights.clear();
427 
428     int total = _find_variants(idx, domino, weights);
429     if (weights.size() == 1)
430         return idx;
431     int rand = value % total;
432 
433     for (size_t i = 0; i < weights.size(); ++i)
434     {
435         rand -= weights[i];
436         if (rand < 0) return idx + i;
437     }
438 
439     return idx;
440 }
441 
_pick_dngn_tile_multi(vector<tileidx_t> candidates,int value)442 static tileidx_t _pick_dngn_tile_multi(vector<tileidx_t> candidates, int value)
443 {
444     ASSERT(!candidates.empty());
445 
446     int total = 0;
447     for (tileidx_t tidx : candidates)
448     {
449         const unsigned int count = tile_dngn_count(tidx);
450         total += tile_dngn_probs(tidx + count - 1);
451     }
452     int rand = value % total;
453 
454     for (tileidx_t tidx : candidates)
455     {
456         const unsigned int count = tile_dngn_count(tidx);
457         for (unsigned int j = 0; j < count; ++j)
458         {
459             if (rand < tile_dngn_probs(tidx + j))
460                 return tidx + j;
461         }
462         rand -= tile_dngn_probs(tidx + count - 1);
463     }
464 
465     // Should never reach this place
466     ASSERT(false);
467 }
468 
_same_door_at(dungeon_feature_type feat,const coord_def & gc)469 static bool _same_door_at(dungeon_feature_type feat, const coord_def &gc)
470 {
471     const dungeon_feature_type door = env.grid(gc);
472 
473     return door == feat
474 #if TAG_MAJOR_VERSION == 34
475         || map_masked(gc, MMT_WAS_DOOR_MIMIC)
476 #endif
477         || feat_is_closed_door(door)
478            && feat_is_opaque(feat) == feat_is_opaque(door)
479            && (feat_is_sealed(feat) || feat_is_sealed(door));
480 }
481 
tile_init_flavour(const coord_def & gc,const int domino)482 void tile_init_flavour(const coord_def &gc, const int domino)
483 {
484     if (!map_bounds(gc))
485         return;
486 
487     uint32_t seed = you.birth_time + you.where_are_you +
488         (you.depth << 8) + (gc.x << 16) + (gc.y << 24);
489 
490     int rand1 = hash_with_seed(INT_MAX, seed, 0);
491     int rand2 = hash_with_seed(INT_MAX, seed, 1);
492 
493     if (!tile_env.flv(gc).floor)
494     {
495         tileidx_t floor_base = tile_env.default_flavour.floor;
496         int colour = env.grid_colours(gc);
497         if (colour)
498             floor_base = tile_dngn_coloured(floor_base, colour);
499         tile_env.flv(gc).floor = pick_dngn_tile(floor_base, rand1, domino);
500     }
501     else if (tile_env.flv(gc).floor != TILE_HALO_GRASS
502              && tile_env.flv(gc).floor != TILE_HALO_GRASS2
503              && tile_env.flv(gc).floor != TILE_HALO_VAULT
504              && tile_env.flv(gc).floor != TILE_HALO_DIRT)
505     {
506         tile_env.flv(gc).floor = pick_dngn_tile(tile_env.flv(gc).floor, rand1);
507     }
508 
509     if (!tile_env.flv(gc).wall)
510     {
511         if ((player_in_branch(BRANCH_DUNGEON) || player_in_branch(BRANCH_DEPTHS))
512             && tile_env.default_flavour.wall == TILE_WALL_NORMAL)
513         {
514             vector<tileidx_t> tile_candidates;
515             if (player_in_branch(BRANCH_DEPTHS))
516                 _get_depths_wall_tiles_by_depth(you.depth, tile_candidates);
517             else
518                 _get_dungeon_wall_tiles_by_depth(you.depth, tile_candidates);
519             tile_env.flv(gc).wall = _pick_dngn_tile_multi(tile_candidates, rand2);
520         }
521         else
522         {
523             tileidx_t wall_base = tile_env.default_flavour.wall;
524             int colour = env.grid_colours(gc);
525             if (colour)
526                 wall_base = tile_dngn_coloured(wall_base, colour);
527             tile_env.flv(gc).wall = pick_dngn_tile(wall_base, rand2);
528         }
529     }
530     else
531         tile_env.flv(gc).wall = pick_dngn_tile(tile_env.flv(gc).wall, rand2);
532 
533     if (feat_is_stone_stair(env.grid(gc)) && player_in_branch(BRANCH_SHOALS))
534     {
535         const bool up = feat_stair_direction(env.grid(gc)) == CMD_GO_UPSTAIRS;
536         tile_env.flv(gc).feat = up ? TILE_DNGN_SHOALS_STAIRS_UP
537                                    : TILE_DNGN_SHOALS_STAIRS_DOWN;
538     }
539 
540     if (feat_is_escape_hatch(env.grid(gc)) && player_in_branch(BRANCH_TOMB))
541     {
542         const bool up = feat_stair_direction(env.grid(gc)) == CMD_GO_UPSTAIRS;
543         tile_env.flv(gc).feat = up ? TILE_DNGN_ONE_WAY_STAIRS_UP
544                                    : TILE_DNGN_ONE_WAY_STAIRS_DOWN;
545     }
546 
547     if (feat_is_door(env.grid(gc)))
548     {
549         // Check for gates.
550         bool door_left  = _same_door_at(env.grid(gc), coord_def(gc.x - 1, gc.y));
551         bool door_right = _same_door_at(env.grid(gc), coord_def(gc.x + 1, gc.y));
552         bool door_up    = _same_door_at(env.grid(gc), coord_def(gc.x, gc.y - 1));
553         bool door_down  = _same_door_at(env.grid(gc), coord_def(gc.x, gc.y + 1));
554 
555         if (door_left || door_right || door_up || door_down)
556         {
557             tileidx_t target;
558             if (door_left && door_right)
559                 target = TILE_DNGN_GATE_CLOSED_MIDDLE;
560             else if (door_up && door_down)
561                 target = TILE_DNGN_VGATE_CLOSED_MIDDLE;
562             else if (door_left)
563                 target = TILE_DNGN_GATE_CLOSED_RIGHT;
564             else if (door_right)
565                 target = TILE_DNGN_GATE_CLOSED_LEFT;
566             else if (door_up)
567                 target = TILE_DNGN_VGATE_CLOSED_DOWN;
568             else
569                 target = TILE_DNGN_VGATE_CLOSED_UP;
570 
571             // NOTE: This requires that closed gates and open gates
572             // are positioned in the tile set relative to their
573             // door counterpart.
574             tile_env.flv(gc).special = target - TILE_DNGN_CLOSED_DOOR;
575         }
576         else
577             tile_env.flv(gc).special = 0;
578     }
579     else if (!tile_env.flv(gc).special)
580         tile_env.flv(gc).special = hash_with_seed(256, seed, 10);
581 }
582 
583 enum SpecialIdx
584 {
585     SPECIAL_N    = 0,
586     SPECIAL_NE   = 1,
587     SPECIAL_E    = 2,
588     SPECIAL_SE   = 3,
589     SPECIAL_S    = 4,
590     SPECIAL_SW   = 5,
591     SPECIAL_W    = 6,
592     SPECIAL_NW   = 7,
593     SPECIAL_FULL = 8,
594 };
595 
_jitter(SpecialIdx i)596 static int _jitter(SpecialIdx i)
597 {
598     return (i + random_range(-1, 1) + 8) % 8;
599 }
600 
_adjacent_target(dungeon_feature_type target,int x,int y)601 static bool _adjacent_target(dungeon_feature_type target, int x, int y)
602 {
603     for (adjacent_iterator ai(coord_def(x, y), false); ai; ++ai)
604     {
605         if (!map_bounds(*ai))
606             continue;
607         if (env.grid(*ai) == target)
608             return true;
609     }
610 
611     return false;
612 }
613 
tile_floor_halo(dungeon_feature_type target,tileidx_t tile)614 void tile_floor_halo(dungeon_feature_type target, tileidx_t tile)
615 {
616     for (int x = 0; x < GXM; x++)
617     {
618         for (int y = 0; y < GYM; y++)
619         {
620             if (!feat_has_dry_floor(env.grid[x][y]))
621                 continue;
622             if (!_adjacent_target(target, x, y))
623                 continue;
624 
625             bool l_flr = (x > 0 && feat_has_dry_floor(env.grid[x-1][y]));
626             bool r_flr = (x < GXM - 1 && feat_has_dry_floor(env.grid[x+1][y]));
627             bool u_flr = (y > 0 && feat_has_dry_floor(env.grid[x][y-1]));
628             bool d_flr = (y < GYM - 1 && feat_has_dry_floor(env.grid[x][y+1]));
629 
630             bool l_target = _adjacent_target(target, x-1, y);
631             bool r_target = _adjacent_target(target, x+1, y);
632             bool u_target = _adjacent_target(target, x, y-1);
633             bool d_target = _adjacent_target(target, x, y+1);
634 
635             // The special tiles contains part floor and part special, so
636             // if there are adjacent floor or special tiles, we should
637             // do our best to "connect" them appropriately. If there are
638             // are other tiles there (walls, doors, whatever...) then it
639             // doesn't matter.
640             bool l_nrm = (l_flr && !l_target);
641             bool r_nrm = (r_flr && !r_target);
642             bool u_nrm = (u_flr && !u_target);
643             bool d_nrm = (d_flr && !d_target);
644 
645             bool l_spc = (l_flr && l_target);
646             bool r_spc = (r_flr && r_target);
647             bool u_spc = (u_flr && u_target);
648             bool d_spc = (d_flr && d_target);
649 
650             if (l_nrm && r_nrm || u_nrm && d_nrm)
651             {
652                 // Not much to do here...
653                 tile_env.flv[x][y].floor = tile + SPECIAL_FULL;
654             }
655             else if (l_nrm)
656             {
657                 if (u_nrm)
658                     tile_env.flv[x][y].floor = tile + SPECIAL_NW;
659                 else if (d_nrm)
660                     tile_env.flv[x][y].floor = tile + SPECIAL_SW;
661                 else if (u_spc && d_spc)
662                     tile_env.flv[x][y].floor = tile + SPECIAL_W;
663                 else if (u_spc && r_spc)
664                     tile_env.flv[x][y].floor = tile + SPECIAL_SW;
665                 else if (d_spc && r_spc)
666                     tile_env.flv[x][y].floor = tile + SPECIAL_NW;
667                 else if (u_spc)
668                 {
669                     tile_env.flv[x][y].floor = tile + (coinflip() ?
670                         SPECIAL_W : SPECIAL_SW);
671                 }
672                 else if (d_spc)
673                 {
674                     tile_env.flv[x][y].floor = tile + (coinflip() ?
675                         SPECIAL_W : SPECIAL_NW);
676                 }
677                 else
678                     tile_env.flv[x][y].floor = tile + _jitter(SPECIAL_W);
679             }
680             else if (r_nrm)
681             {
682                 if (u_nrm)
683                     tile_env.flv[x][y].floor = tile + SPECIAL_NE;
684                 else if (d_nrm)
685                     tile_env.flv[x][y].floor = tile + SPECIAL_SE;
686                 else if (u_spc && d_spc)
687                     tile_env.flv[x][y].floor = tile + SPECIAL_E;
688                 else if (u_spc && l_spc)
689                     tile_env.flv[x][y].floor = tile + SPECIAL_SE;
690                 else if (d_spc && l_spc)
691                     tile_env.flv[x][y].floor = tile + SPECIAL_NE;
692                 else if (u_spc)
693                     tile_env.flv[x][y].floor = tile + (coinflip() ?
694                         SPECIAL_E : SPECIAL_SE);
695                 else if (d_spc)
696                     tile_env.flv[x][y].floor = tile + (coinflip() ?
697                         SPECIAL_E : SPECIAL_NE);
698                 else
699                     tile_env.flv[x][y].floor = tile + _jitter(SPECIAL_E);
700             }
701             else if (u_nrm)
702             {
703                 if (r_spc && l_spc)
704                     tile_env.flv[x][y].floor = tile + SPECIAL_N;
705                 else if (r_spc && d_spc)
706                     tile_env.flv[x][y].floor = tile + SPECIAL_NW;
707                 else if (l_spc && d_spc)
708                     tile_env.flv[x][y].floor = tile + SPECIAL_NE;
709                 else if (r_spc)
710                 {
711                     tile_env.flv[x][y].floor = tile + (coinflip() ?
712                         SPECIAL_N : SPECIAL_NW);
713                 }
714                 else if (l_spc)
715                 {
716                     tile_env.flv[x][y].floor = tile + (coinflip() ?
717                         SPECIAL_N : SPECIAL_NE);
718                 }
719                 else
720                     tile_env.flv[x][y].floor = tile + _jitter(SPECIAL_N);
721             }
722             else if (d_nrm)
723             {
724                 if (r_spc && l_spc)
725                     tile_env.flv[x][y].floor = tile + SPECIAL_S;
726                 else if (r_spc && u_spc)
727                     tile_env.flv[x][y].floor = tile + SPECIAL_SW;
728                 else if (l_spc && u_spc)
729                     tile_env.flv[x][y].floor = tile + SPECIAL_SE;
730                 else if (r_spc)
731                 {
732                     tile_env.flv[x][y].floor = tile + (coinflip() ?
733                         SPECIAL_S : SPECIAL_SW);
734                 }
735                 else if (l_spc)
736                 {
737                     tile_env.flv[x][y].floor = tile + (coinflip() ?
738                         SPECIAL_S : SPECIAL_SE);
739                 }
740                 else
741                     tile_env.flv[x][y].floor = tile + _jitter(SPECIAL_S);
742             }
743             else if (u_spc && d_spc)
744             {
745                 // We know this value is already initialised and
746                 // is necessarily in bounds.
747                 tileidx_t t = tile_env.flv[x][y-1].floor - tile;
748                 if (t == SPECIAL_NE || t == SPECIAL_E)
749                     tile_env.flv[x][y].floor = tile + SPECIAL_E;
750                 else if (t == SPECIAL_NW || t == SPECIAL_W)
751                     tile_env.flv[x][y].floor = tile + SPECIAL_W;
752                 else
753                     tile_env.flv[x][y].floor = tile + SPECIAL_FULL;
754             }
755             else if (r_spc && l_spc)
756             {
757                 // We know this value is already initialised and
758                 // is necessarily in bounds.
759                 tileidx_t t = tile_env.flv[x-1][y].floor - tile;
760                 if (t == SPECIAL_NW || t == SPECIAL_N)
761                     tile_env.flv[x][y].floor = tile + SPECIAL_N;
762                 else if (t == SPECIAL_SW || t == SPECIAL_S)
763                     tile_env.flv[x][y].floor = tile + SPECIAL_S;
764                 else
765                     tile_env.flv[x][y].floor = tile + SPECIAL_FULL;
766             }
767             else if (u_spc && l_spc)
768                 tile_env.flv[x][y].floor = tile + SPECIAL_SE;
769             else if (u_spc && r_spc)
770                 tile_env.flv[x][y].floor = tile + SPECIAL_SW;
771             else if (d_spc && l_spc)
772                 tile_env.flv[x][y].floor = tile + SPECIAL_NE;
773             else if (d_spc && r_spc)
774                 tile_env.flv[x][y].floor = tile + SPECIAL_NW;
775             else
776                 tile_env.flv[x][y].floor = tile + SPECIAL_FULL;
777         }
778     }
779 
780     // Second pass for clean up. The only bad part about the above
781     // algorithm is that it could turn a block of floor like this:
782     //
783     // N4NN
784     // 3125
785     // NN6N
786     //
787     // (KEY: N = normal floor, # = special floor)
788     //
789     // Into these flavours:
790     // 1 - SPECIAL_S
791     // 2 - SPECIAL_N
792     // 3-6, not important
793     //
794     // Generally the tiles don't fit with a north to the right or left
795     // of a south tile. What we really want to do is to separate the
796     // two regions, by making 1 a SPECIAL_SE and 2 a SPECIAL_NW tile.
797     for (int y = 0; y < GYM - 1; ++y)
798         for (int x = 0; x < GXM - 1; ++x)
799         {
800             int this_spc = tile_env.flv[x][y].floor - tile;
801             if (this_spc < 0 || this_spc > 8)
802                 continue;
803 
804             if (this_spc != SPECIAL_N && this_spc != SPECIAL_S
805                 && this_spc != SPECIAL_E && this_spc != SPECIAL_W)
806             {
807                 continue;
808             }
809 
810             // TODO: these conditions are guaranteed?
811             int right_spc = x < GXM - 1 ? tile_env.flv[x+1][y].floor - tile
812                                         : int{SPECIAL_FULL};
813             int down_spc  = y < GYM - 1 ? tile_env.flv[x][y+1].floor - tile
814                                         : int{SPECIAL_FULL};
815 
816             if (this_spc == SPECIAL_N && right_spc == SPECIAL_S)
817             {
818                 tile_env.flv[x][y].floor = tile + SPECIAL_NE;
819                 tile_env.flv[x+1][y].floor = tile + SPECIAL_SW;
820             }
821             else if (this_spc == SPECIAL_S && right_spc == SPECIAL_N)
822             {
823                 tile_env.flv[x][y].floor = tile + SPECIAL_SE;
824                 tile_env.flv[x+1][y].floor = tile + SPECIAL_NW;
825             }
826             else if (this_spc == SPECIAL_E && down_spc == SPECIAL_W)
827             {
828                 tile_env.flv[x][y].floor = tile + SPECIAL_SE;
829                 tile_env.flv[x][y+1].floor = tile + SPECIAL_NW;
830             }
831             else if (this_spc == SPECIAL_W && down_spc == SPECIAL_E)
832             {
833                 tile_env.flv[x][y].floor = tile + SPECIAL_NE;
834                 tile_env.flv[x][y+1].floor = tile + SPECIAL_SW;
835             }
836         }
837 }
838 
839 #ifdef USE_TILE
840 
tile_draw_map_cells()841 void tile_draw_map_cells()
842 {
843     if (crawl_state.game_is_arena())
844         for (rectangle_iterator ri(crawl_view.vgrdc, LOS_MAX_RANGE); ri; ++ri)
845         {
846             tile_draw_map_cell(*ri, true);
847 #ifdef USE_TILE_WEB
848             tiles.mark_for_redraw(*ri);
849 #endif
850         }
851     else
852         for (radius_iterator ri(you.pos(), LOS_NONE); ri; ++ri)
853         {
854             tile_draw_map_cell(*ri, true);
855 #ifdef USE_TILE_WEB
856             tiles.mark_for_redraw(*ri);
857 #endif
858         }
859 }
860 
_get_floor_bg(const coord_def & gc)861 static tileidx_t _get_floor_bg(const coord_def& gc)
862 {
863     tileidx_t bg = TILE_DNGN_UNSEEN | tileidx_unseen_flag(gc);
864 
865     if (map_bounds(gc))
866     {
867         bg = tileidx_feature(gc);
868 
869         if (is_unknown_stair(gc)
870             && env.map_knowledge(gc).feat() != DNGN_ENTER_ZOT
871             && !(player_in_hell()
872                  && env.map_knowledge(gc).feat() == DNGN_ENTER_HELL))
873         {
874             bg |= TILE_FLAG_NEW_STAIR;
875         }
876         else if (is_unknown_transporter(gc))
877             bg |= TILE_FLAG_NEW_TRANSPORTER;
878     }
879 
880     return bg;
881 }
882 
tile_draw_floor()883 void tile_draw_floor()
884 {
885     for (int cy = 0; cy < tile_env.fg.height(); cy++)
886         for (int cx = 0; cx < tile_env.fg.width(); cx++)
887         {
888             const coord_def ep(cx, cy);
889             const coord_def gc = show2grid(ep);
890 
891             tileidx_t bg = _get_floor_bg(gc);
892 
893             // init tiles
894             tile_env.bg(ep) = bg;
895             tile_env.fg(ep) = 0;
896             tile_env.cloud(ep) = 0;
897         }
898 }
899 
tile_clear_map(const coord_def & gc)900 void tile_clear_map(const coord_def& gc)
901 {
902     tile_env.bk_fg(gc) = 0;
903     tile_env.bk_cloud(gc) = 0;
904     tiles.update_minimap(gc);
905 }
906 
tile_forget_map(const coord_def & gc)907 void tile_forget_map(const coord_def &gc)
908 {
909     tile_env.bk_fg(gc) = 0;
910     tile_env.bk_bg(gc) = 0;
911     tile_env.bk_cloud(gc) = 0;
912     // This may have changed the explore horizon, so update adjacent minimap
913     // squares as well.
914     for (adjacent_iterator ai(gc, false); ai; ++ai)
915         tiles.update_minimap(*ai);
916 }
917 
_tile_place_item(const coord_def & gc,const item_def & item,bool more_items)918 static void _tile_place_item(const coord_def &gc, const item_def &item,
919                              bool more_items)
920 {
921     tileidx_t t = tileidx_item(item);
922     if (more_items)
923         t |= TILE_FLAG_S_UNDER;
924 
925     if (you.see_cell(gc))
926     {
927         const coord_def ep = crawl_view.grid2show(gc);
928         if (tile_env.fg(ep))
929             return;
930 
931         tile_env.fg(ep) = t;
932 
933         if (item_needs_autopickup(item))
934             tile_env.bg(ep) |= TILE_FLAG_CURSOR3;
935     }
936     else
937     {
938         tile_env.bk_fg(gc) = t;
939 
940         if (item_needs_autopickup(item))
941             tile_env.bk_bg(gc) |= TILE_FLAG_CURSOR3;
942     }
943 }
944 
_tile_place_item_marker(const coord_def & gc,const item_def & item)945 static void _tile_place_item_marker(const coord_def &gc, const item_def &item)
946 {
947     if (you.see_cell(gc))
948     {
949         const coord_def ep = crawl_view.grid2show(gc);
950         tile_env.fg(ep) |= TILE_FLAG_S_UNDER;
951 
952         if (item_needs_autopickup(item))
953             tile_env.bg(ep) |= TILE_FLAG_CURSOR3;
954     }
955     else
956     {
957         tile_env.bk_fg(gc) = ((tileidx_t) tile_env.bk_fg(gc)) | TILE_FLAG_S_UNDER;
958 
959         if (item_needs_autopickup(item))
960             tile_env.bk_bg(gc) |= TILE_FLAG_CURSOR3;
961     }
962 }
963 
964 /**
965  * Place the tile for an unseen monster's disturbance.
966  *
967  * @param gc    The disturbance's map position.
968 **/
_tile_place_invisible_monster(const coord_def & gc)969 static void _tile_place_invisible_monster(const coord_def &gc)
970 {
971     const coord_def ep = grid2show(gc);
972     const map_cell& cell = env.map_knowledge(gc);
973 
974     // Shallow water has its own modified tile for disturbances
975     // see tileidx_feature
976     // That tile is hidden by clouds though
977     if (cell.feat() != DNGN_SHALLOW_WATER || cell.cloud() != CLOUD_NONE)
978     {
979         if (you.see_cell(gc))
980             tile_env.fg(ep) = TILE_UNSEEN_MONSTER;
981         else
982             tile_env.bk_fg(gc) = TILE_UNSEEN_MONSTER;
983     }
984 
985     if (env.map_knowledge(gc).item())
986         _tile_place_item_marker(gc, *env.map_knowledge(gc).item());
987 }
988 
_tile_place_monster(const coord_def & gc,const monster_info & mon)989 static void _tile_place_monster(const coord_def &gc, const monster_info& mon)
990 {
991     const coord_def ep = grid2show(gc);
992 
993     tileidx_t t    = tileidx_monster(mon);
994     tileidx_t t0   = t & TILE_FLAG_MASK;
995     tileidx_t flag = t & (~TILE_FLAG_MASK);
996 
997     if (mons_class_is_stationary(mon.type)
998         && mon.type != MONS_TRAINING_DUMMY)
999     {
1000         // If necessary add item brand.
1001         if (env.map_knowledge(gc).item())
1002         {
1003             t |= TILE_FLAG_S_UNDER;
1004 
1005             if (item_needs_autopickup(*env.map_knowledge(gc).item()))
1006             {
1007                 if (you.see_cell(gc))
1008                     tile_env.bg(ep) |= TILE_FLAG_CURSOR3;
1009                 else
1010                     tile_env.bk_bg(gc) |= TILE_FLAG_CURSOR3;
1011             }
1012         }
1013     }
1014     else
1015     {
1016         tileidx_t mcache_idx = mcache.register_monster(mon);
1017         t = flag | (mcache_idx ? mcache_idx : t0);
1018     }
1019 
1020     if (!you.see_cell(gc))
1021     {
1022         tile_env.bk_fg(gc) = t;
1023         return;
1024     }
1025     tile_env.fg(ep) = t;
1026 
1027     // Add name tags.
1028     if (!mons_class_gives_xp(mon.type))
1029         return;
1030 
1031     const tag_pref pref = Options.tile_tag_pref;
1032     if (pref == TAGPREF_NONE)
1033         return;
1034     else if (pref == TAGPREF_TUTORIAL)
1035     {
1036         const int kills = you.kills.num_kills(mon);
1037         const int limit  = 0;
1038 
1039         if (!mon.is_named() && kills > limit)
1040             return;
1041     }
1042     else if (!mon.is_named())
1043         return;
1044 
1045     if (pref != TAGPREF_NAMED && mon.attitude == ATT_FRIENDLY)
1046         return;
1047 
1048     tiles.add_text_tag(TAG_NAMED_MONSTER, mon);
1049 }
1050 
tile_reset_fg(const coord_def & gc)1051 void tile_reset_fg(const coord_def &gc)
1052 {
1053     // remove autopickup cursor, it will be added back if necessary
1054     tile_env.bk_bg(gc) &= ~TILE_FLAG_CURSOR3;
1055     tile_draw_map_cell(gc, true);
1056     tiles.update_minimap(gc);
1057 }
1058 
tile_reset_feat(const coord_def & gc)1059 void tile_reset_feat(const coord_def &gc)
1060 {
1061     tile_env.bk_bg(gc) = tileidx_feature(gc);
1062 }
1063 
_tile_place_cloud(const coord_def & gc,const cloud_info & cl)1064 static void _tile_place_cloud(const coord_def &gc, const cloud_info &cl)
1065 {
1066     if (you.see_cell(gc))
1067     {
1068         const coord_def ep = grid2show(gc);
1069         tile_env.cloud(ep) = tileidx_cloud(cl);
1070     }
1071     else
1072         tile_env.bk_cloud(gc) = tileidx_cloud(cl);
1073 }
1074 
tile_draw_map_cell(const coord_def & gc,bool foreground_only)1075 void tile_draw_map_cell(const coord_def& gc, bool foreground_only)
1076 {
1077     if (!foreground_only)
1078         tile_env.bk_bg(gc) = _get_floor_bg(gc);
1079 
1080     if (you.see_cell(gc))
1081     {
1082         tile_env.fg(grid2show(gc)) = 0;
1083         tile_env.cloud(grid2show(gc)) = 0;
1084     }
1085 
1086     const map_cell& cell = env.map_knowledge(gc);
1087 
1088     if (cell.invisible_monster())
1089         _tile_place_invisible_monster(gc);
1090     else if (cell.monsterinfo())
1091         _tile_place_monster(gc, *cell.monsterinfo());
1092     else if (cell.item())
1093     {
1094         if (feat_is_stair(cell.feat()))
1095             _tile_place_item_marker(gc, *cell.item());
1096         else
1097             _tile_place_item(gc, *cell.item(), (cell.flags & MAP_MORE_ITEMS) != 0);
1098     }
1099     else
1100         tile_env.bk_fg(gc) = 0;
1101 
1102     // Always place clouds now they have their own layer
1103     if (cell.cloud() != CLOUD_NONE)
1104         _tile_place_cloud(gc, *cell.cloudinfo());
1105     else
1106         tile_env.bk_cloud(gc) = 0;
1107 }
1108 
tile_wizmap_terrain(const coord_def & gc)1109 void tile_wizmap_terrain(const coord_def &gc)
1110 {
1111     tile_env.bk_bg(gc) = tileidx_feature(gc);
1112 }
1113 
_is_torch(tileidx_t basetile)1114 static bool _is_torch(tileidx_t basetile)
1115 {
1116     return basetile == TILE_WALL_BRICK_DARK_2_TORCH
1117            || basetile == TILE_WALL_BRICK_DARK_4_TORCH
1118            || basetile == TILE_WALL_BRICK_DARK_6_TORCH;
1119 }
1120 
1121 // Updates the "flavour" of tiles that are animated.
1122 // Unfortunately, these are all hard-coded for now.
tile_apply_animations(tileidx_t bg,tile_flavour * flv)1123 void tile_apply_animations(tileidx_t bg, tile_flavour *flv)
1124 {
1125 #ifndef USE_TILE_WEB
1126     tileidx_t bg_idx = bg & TILE_FLAG_MASK;
1127     if (bg_idx == TILE_DNGN_PORTAL_WIZARD_LAB && Options.tile_misc_anim)
1128         flv->special = (flv->special + 1) % tile_dngn_count(bg_idx);
1129     else if (bg_idx == TILE_DNGN_LAVA && Options.tile_water_anim)
1130     {
1131         // Lava tiles are four sets of four tiles (the second and fourth
1132         // sets are the same). This cycles between the four sets, picking
1133         // a random element from each set.
1134         flv->special = ((flv->special - ((flv->special % 4)))
1135                         + 4 + random2(4)) % tile_dngn_count(bg_idx);
1136     }
1137     else if (bg_idx > TILE_DNGN_LAVA && bg_idx < TILE_FLOOR_MAX
1138              && Options.tile_water_anim)
1139     {
1140         flv->special = random2(256);
1141     }
1142     else if (bg_idx >= TILE_DNGN_ENTER_ZOT_CLOSED && bg_idx < TILE_BLOOD
1143              && Options.tile_misc_anim)
1144     {
1145         flv->special = random2(256);
1146     }
1147     else if (bg_idx == TILE_WALL_NORMAL && Options.tile_misc_anim)
1148     {
1149         tileidx_t basetile = tile_dngn_basetile(flv->wall);
1150         if (_is_torch(basetile))
1151             flv->wall = basetile + (flv->wall - basetile + 1) % tile_dngn_count(basetile);
1152     }
1153 #else
1154     UNUSED(bg, flv);
1155 #endif
1156 }
1157 
_suppress_blood(tileidx_t bg_idx)1158 static bool _suppress_blood(tileidx_t bg_idx)
1159 {
1160     tileidx_t basetile = tile_dngn_basetile(bg_idx);
1161     return _is_torch(basetile);
1162 }
1163 
1164 // Specifically for vault-overwritten doors. We have three "sets" of tiles that
1165 // can be dealt with. The tile sets should have size 2, 3, 8, or 9. They are:
1166 //  2. Closed, open.
1167 //  3. Runed, closed, open.
1168 //  8. Closed, open, gate left closed, gate middle closed, gate right closed,
1169 //     gate left open, gate middle open, gate right open.
1170 //  9. Runed, closed, open, gate left closed, gate middle closed, gate right
1171 //     closed, gate left open, gate middle open, gate right open.
_get_door_offset(tileidx_t base_tile,bool opened,bool runed,int gateway_type)1172 static int _get_door_offset(tileidx_t base_tile, bool opened, bool runed,
1173                             int gateway_type)
1174 {
1175     int count = tile_dngn_count(base_tile);
1176     if (count == 1)
1177         return 0;
1178 
1179     // The location of the default "closed" tile.
1180     int offset = 0;
1181 
1182     switch (count)
1183     {
1184     case 2:
1185         ASSERT(!runed);
1186         return opened ? 1: 0;
1187     case 3:
1188         if (opened)
1189             return 2;
1190         else if (runed)
1191             return 0;
1192         else
1193             return 1;
1194     case 8:
1195         ASSERT(!runed);
1196         // The closed door is at BASE_TILE for sets without runed doors
1197         offset = 0;
1198         break;
1199     case 9:
1200         // But is at BASE_TILE+1 for sets with them.
1201         offset = 1;
1202         break;
1203     default:
1204         // Passed a non-door tile base, pig out now.
1205         die("non-door tile");
1206     }
1207 
1208     // If we've reached this point, we're dealing with a gate.
1209     if (runed)
1210         return 0;
1211 
1212     if (!opened && !runed && gateway_type == 0)
1213         return 0;
1214 
1215     return offset + gateway_type;
1216 }
1217 
apply_variations(const tile_flavour & flv,tileidx_t * bg,const coord_def & gc)1218 void apply_variations(const tile_flavour &flv, tileidx_t *bg,
1219                       const coord_def &gc)
1220 {
1221     // TODO: there's an awful lot of hardcoding going on here...
1222     tileidx_t orig = (*bg) & TILE_FLAG_MASK;
1223     tileidx_t flag = (*bg) & (~TILE_FLAG_MASK);
1224 
1225     // TODO: allow the stone type to be set in a cleaner way.
1226     if (player_in_branch(BRANCH_GAUNTLET))
1227     {
1228         if (orig == TILE_DNGN_STONE_WALL)
1229             orig = TILE_WALL_LAB_STONE;
1230         else if (orig == TILE_DNGN_METAL_WALL)
1231             orig = TILE_WALL_LAB_METAL;
1232         else if (orig == TILE_WALL_PERMAROCK)
1233             orig = TILE_WALL_PERMAROCK_BROWN;
1234     }
1235     else if (player_in_branch(BRANCH_CRYPT))
1236     {
1237         if (orig == TILE_DNGN_STONE_WALL)
1238             orig = TILE_WALL_CRYPT;
1239         else if (orig == TILE_DNGN_METAL_WALL)
1240             orig = TILE_WALL_CRYPT_METAL;
1241         else if (orig == TILE_DNGN_OPEN_DOOR)
1242             orig = TILE_DNGN_OPEN_DOOR_CRYPT;
1243         else if (orig == TILE_DNGN_CLOSED_DOOR)
1244             orig = TILE_DNGN_CLOSED_DOOR_CRYPT;
1245     }
1246     else if (player_in_branch(BRANCH_TOMB))
1247     {
1248         if (orig == TILE_DNGN_STONE_WALL)
1249             orig = TILE_WALL_TOMB;
1250     }
1251     else if (player_in_branch(BRANCH_DIS))
1252     {
1253         if (orig == TILE_DNGN_METAL_WALL)
1254             orig = TILE_DNGN_METAL_IRON;
1255         else if (orig == TILE_DNGN_CRYSTAL)
1256             orig = TILE_WALL_EMERALD;
1257     }
1258     else if (player_in_branch(BRANCH_COCYTUS))
1259     {
1260         if (orig == TILE_DNGN_STONE_WALL)
1261             orig = TILE_WALL_ICY_STONE;
1262     }
1263     else if (player_in_branch(BRANCH_TARTARUS))
1264     {
1265         if (orig == TILE_DNGN_STONE_WALL)
1266             orig = TILE_WALL_COBALT_STONE;
1267         else if (orig == TILE_DNGN_CRYSTAL)
1268             orig = TILE_WALL_EMERALD;
1269         else if (orig == TILE_DNGN_METAL_WALL)
1270             orig = TILE_DNGN_METAL_WALL_DARKGRAY;
1271     }
1272     else if (player_in_branch(BRANCH_GEHENNA))
1273     {
1274         if (orig == TILE_DNGN_STONE_WALL)
1275             orig = TILE_DNGN_STONE_WALL_RED;
1276         if (orig == TILE_DNGN_METAL_WALL)
1277             orig = TILE_DNGN_METAL_WALL_RED;
1278     }
1279     else if (player_in_branch(BRANCH_BAILEY))
1280     {
1281         if (orig == TILE_DNGN_STONE_WALL)
1282             orig = TILE_WALL_STONE_SMOOTH;
1283     }
1284     else if (player_in_branch(BRANCH_OSSUARY))
1285     {
1286         if (orig == TILE_DNGN_STONE_WALL)
1287             orig = TILE_DNGN_STONE_WALL_BROWN;
1288     }
1289     else if (player_in_branch(BRANCH_SLIME))
1290     {
1291         if (orig == TILE_DNGN_STONE_WALL)
1292             orig = TILE_STONE_WALL_SLIME;
1293     }
1294     else if (player_in_branch(BRANCH_VAULTS))
1295     {
1296         if (orig == TILE_DNGN_STONE_WALL)
1297             orig = TILE_STONE_WALL_VAULT;
1298     }
1299 
1300     if (orig == TILE_FLOOR_NORMAL)
1301         *bg = flv.floor;
1302     else if (orig == TILE_WALL_NORMAL)
1303         *bg = flv.wall;
1304     else if (orig == TILE_DNGN_STONE_WALL
1305              || orig == TILE_DNGN_CRYSTAL_WALL
1306              || orig == TILE_WALL_PERMAROCK
1307              || orig == TILE_WALL_PERMAROCK_CLEAR
1308              || orig == TILE_DNGN_METAL_WALL
1309              || orig == TILE_DNGN_TREE)
1310     {
1311         // TODO: recoloring vaults stone walls from corruption?
1312         *bg = pick_dngn_tile(tile_dngn_coloured(orig, env.grid_colours(gc)),
1313                              flv.special);
1314     }
1315     else if (is_door_tile(orig))
1316     {
1317         tileidx_t override = flv.feat;
1318         // For vaults overriding door tiles, like Cigotuvi's Fleshworks.
1319         if (is_door_tile(override))
1320         {
1321             bool opened = (orig == TILE_DNGN_OPEN_DOOR);
1322             bool runed = (orig == TILE_DNGN_RUNED_DOOR);
1323             int offset = _get_door_offset(override, opened, runed, flv.special);
1324             *bg = override + offset;
1325         }
1326         else
1327             *bg = orig + min((int)flv.special, 6);
1328     }
1329     else if (orig == TILE_DNGN_PORTAL_WIZARD_LAB)
1330         *bg = orig + flv.special % tile_dngn_count(orig);
1331     else if ((orig == TILE_SHOALS_SHALLOW_WATER
1332               || orig == TILE_SHOALS_DEEP_WATER)
1333              && element_colour(ETC_WAVES, 0, gc) == LIGHTCYAN)
1334     {
1335         *bg = orig + 6 + flv.special % 6;
1336     }
1337     else if (orig < TILE_DNGN_MAX)
1338         *bg = pick_dngn_tile(orig, flv.special);
1339 
1340     *bg |= flag;
1341 }
1342 
1343 // If the top tile is a corpse, don't draw blood underneath.
_top_item_is_corpse(const map_cell & mc)1344 static bool _top_item_is_corpse(const map_cell& mc)
1345 {
1346     const item_def* item = mc.item();
1347     return item && item->is_type(OBJ_CORPSES, CORPSE_BODY);
1348 }
1349 
_get_direction_index(const coord_def & delta)1350 static uint8_t _get_direction_index(const coord_def& delta)
1351 {
1352     if (delta.x ==  0 && delta.y ==  1) return 1;
1353     if (delta.x == -1 && delta.y ==  1) return 2;
1354     if (delta.x == -1 && delta.y ==  0) return 3;
1355     if (delta.x == -1 && delta.y == -1) return 4;
1356     if (delta.x ==  0 && delta.y == -1) return 5;
1357     if (delta.x ==  1 && delta.y == -1) return 6;
1358     if (delta.x ==  1 && delta.y ==  0) return 7;
1359     if (delta.x ==  1 && delta.y ==  1) return 8;
1360     return 0;
1361 }
1362 
tile_apply_properties(const coord_def & gc,packed_cell & cell)1363 void tile_apply_properties(const coord_def &gc, packed_cell &cell)
1364 {
1365     if (is_excluded(gc))
1366     {
1367         if (is_exclude_root(gc))
1368             cell.bg |= TILE_FLAG_EXCL_CTR;
1369         else
1370             cell.bg |= TILE_FLAG_TRAV_EXCL;
1371     }
1372 
1373     if (!map_bounds(gc))
1374         return;
1375 
1376     apply_variations(tile_env.flv(gc), &cell.bg, gc);
1377 
1378     const map_cell& mc = env.map_knowledge(gc);
1379 
1380     bool print_blood = true;
1381     if (mc.flags & MAP_UMBRAED)
1382         cell.halo = HALO_UMBRA;
1383     else if (mc.flags & MAP_HALOED)
1384         cell.halo = HALO_RANGE;
1385     else
1386         cell.halo = HALO_NONE;
1387 
1388     if (mc.flags & MAP_LIQUEFIED)
1389         cell.is_liquefied = true;
1390     else if (print_blood && (feat_suppress_blood(mc.feat())
1391                              || _suppress_blood((cell.bg) & TILE_FLAG_MASK)))
1392     {
1393         print_blood = false;
1394     }
1395 
1396     if (print_blood)
1397     {
1398         // Corpses have a blood puddle of their own.
1399         if (mc.flags & MAP_BLOODY && !_top_item_is_corpse(mc))
1400         {
1401             cell.is_bloody = true;
1402             cell.blood_rotation = blood_rotation(gc);
1403             cell.old_blood = bool(env.pgrid(gc) & FPROP_OLD_BLOOD);
1404         }
1405     }
1406 
1407     const dungeon_feature_type feat = mc.feat();
1408     if (feat_is_water(feat) || feat == DNGN_LAVA)
1409         cell.bg |= TILE_FLAG_WATER;
1410 
1411     if ((mc.flags & MAP_SANCTUARY_1) || (mc.flags & MAP_SANCTUARY_2))
1412         cell.is_sanctuary = true;
1413 
1414     if (mc.flags & MAP_SILENCED)
1415         cell.is_silenced = true;
1416 
1417     if (feat == DNGN_MANGROVE)
1418         cell.mangrove_water = true;
1419     cell.awakened_forest = feat_is_tree(feat) && env.forest_awoken_until;
1420 
1421     if (mc.flags & MAP_ORB_HALOED)
1422         cell.orb_glow = get_orb_phase(gc) ? 2 : 1;
1423 
1424 #if TAG_MAJOR_VERSION == 34
1425     if (mc.flags & MAP_HOT)
1426         cell.heat_aura = 1 + random2(3);
1427 #endif
1428 
1429     if (mc.flags & MAP_QUAD_HALOED)
1430         cell.quad_glow = true;
1431 
1432     if (mc.flags & MAP_DISJUNCT)
1433         cell.disjunct = get_disjunct_phase(gc);
1434 
1435     if (Options.show_travel_trail)
1436     {
1437         int tt_idx = travel_trail_index(gc);
1438         if (tt_idx >= 0 && tt_idx < (int) env.travel_trail.size() - 1)
1439         {
1440             if (tt_idx > 0)
1441             {
1442                 coord_def delta = gc - env.travel_trail[tt_idx-1];
1443                 cell.travel_trail = _get_direction_index(delta);
1444             }
1445             if (tt_idx < (int) env.travel_trail.size() - 1)
1446             {
1447                 coord_def delta = gc - env.travel_trail[tt_idx+1];
1448                 cell.travel_trail |= _get_direction_index(delta) << 4;
1449             }
1450         }
1451     }
1452 
1453     cell.flv = tile_env.flv(gc);
1454 
1455     if (env.level_state & LSTATE_SLIMY_WALL)
1456     {
1457         for (adjacent_iterator ai(gc); ai; ++ai)
1458             if (env.map_knowledge(*ai).feat() == DNGN_SLIMY_WALL)
1459             {
1460                 cell.flv.floor = TILE_FLOOR_SLIME_ACIDIC;
1461                 break;
1462             }
1463     }
1464     else if (env.level_state & LSTATE_ICY_WALL)
1465     {
1466         for (adjacent_iterator ai(gc); ai; ++ai)
1467         {
1468             if (feat_is_wall(env.map_knowledge(*ai).feat())
1469                 && env.map_knowledge(*ai).flags & MAP_ICY)
1470             {
1471                 cell.flv.floor = TILE_FLOOR_ICY;
1472                 break;
1473             }
1474         }
1475     }
1476 }
1477 #endif
1478