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