Apply the new ground_level method.
[crawl.git] / crawl-ref / source / tileview.cc
blob21f644f8cb3fea40085bf240cdba633b95e99629
1 #include "AppHdr.h"
3 #ifdef USE_TILE
4 #include "tileview.h"
6 #include "areas.h"
7 #include "cloud.h"
8 #include "coord.h"
9 #include "coordit.h"
10 #include "env.h"
11 #include "fprop.h"
12 #include "items.h"
13 #include "kills.h"
14 #include "mon-stuff.h"
15 #include "mon-util.h"
16 #include "options.h"
17 #include "player.h"
18 #include "showsymb.h"
19 #include "stuff.h"
20 #include "terrain.h"
21 #include "tiledef-dngn.h"
22 #include "tilemcache.h"
23 #include "tilepick.h"
24 #include "traps.h"
25 #include "travel.h"
26 #include "viewgeom.h"
28 void tile_new_level(bool first_time, bool init_unseen)
30 tiles.clear_minimap();
32 for (unsigned int x = 0; x < GXM; x++)
33 for (unsigned int y = 0; y < GYM; y++)
34 tiles.update_minimap(coord_def(x, y));
36 if (first_time)
37 tile_init_flavour();
39 if (!player_in_mappable_area() || init_unseen)
41 for (unsigned int x = 0; x < GXM; x++)
42 for (unsigned int y = 0; y < GYM; y++)
44 env.tile_bk_fg[x][y] = 0;
45 env.tile_bk_bg[x][y] = TILE_DNGN_UNSEEN;
49 // Fix up stair markers. The travel information isn't hooked up
50 // until after we change levels. So, look through all of the stairs
51 // on this level and check if they still need the stair flag.
52 for (unsigned int x = 0; x < GXM; x++)
53 for (unsigned int y = 0; y < GYM; y++)
55 unsigned int tile = env.tile_bk_bg[x][y];
56 if (!(tile & TILE_FLAG_NEW_STAIR))
57 continue;
58 if (!is_unknown_stair(coord_def(x,y)))
59 env.tile_bk_bg[x][y] &= ~TILE_FLAG_NEW_STAIR;
63 void tile_init_default_flavour()
65 tile_default_flv(you.level_type, you.where_are_you, env.tile_default);
68 void tile_default_flv(level_area_type lev, branch_type br, tile_flavour &flv)
70 flv.wall = TILE_WALL_NORMAL;
71 flv.floor = TILE_FLOOR_NORMAL;
72 flv.special = 0;
74 if (lev == LEVEL_PANDEMONIUM)
76 flv.floor = TILE_FLOOR_TOMB;
77 switch (random2(7))
79 default:
80 case 0: flv.wall = TILE_WALL_ZOT_BLUE; break;
81 case 1: flv.wall = TILE_WALL_ZOT_RED; break;
82 case 2: flv.wall = TILE_WALL_ZOT_MAGENTA; break;
83 case 3: flv.wall = TILE_WALL_ZOT_GREEN; break;
84 case 4: flv.wall = TILE_WALL_ZOT_CYAN; break;
85 case 5: flv.wall = TILE_WALL_ZOT_YELLOW; break;
86 case 6: flv.wall = TILE_WALL_ZOT_WHITE; break;
89 if (one_chance_in(3))
90 flv.wall = TILE_WALL_FLESH;
91 if (one_chance_in(3))
92 flv.floor = TILE_FLOOR_NERVES;
94 return;
96 else if (lev == LEVEL_ABYSS)
98 flv.floor = TILE_FLOOR_NERVES;
99 switch (random2(6))
101 default:
102 case 0: flv.wall = TILE_WALL_HIVE; break;
103 case 1: flv.wall = TILE_WALL_PEBBLE_RED; break;
104 case 2: flv.wall = TILE_WALL_SLIME; break;
105 case 3: flv.wall = TILE_WALL_ICE; break;
106 case 4: flv.wall = TILE_WALL_HALL; break;
107 case 5: flv.wall = TILE_WALL_UNDEAD; break;
109 return;
111 else if (lev == LEVEL_LABYRINTH)
113 flv.wall = TILE_WALL_UNDEAD;
114 flv.floor = TILE_FLOOR_TOMB;
115 return;
117 else if (lev == LEVEL_PORTAL_VAULT)
119 // These should be handled in the respective lua files.
120 flv.wall = TILE_WALL_NORMAL;
121 flv.floor = TILE_FLOOR_NORMAL;
122 return;
125 switch (br)
127 case BRANCH_MAIN_DUNGEON:
128 flv.wall = TILE_WALL_NORMAL;
129 flv.floor = TILE_FLOOR_NORMAL;
130 return;
132 case BRANCH_HIVE:
133 flv.wall = TILE_WALL_HIVE;
134 flv.floor = TILE_FLOOR_HIVE;
135 return;
137 case BRANCH_VAULTS:
138 flv.wall = TILE_WALL_VAULT;
139 flv.floor = TILE_FLOOR_VAULT;
140 return;
142 case BRANCH_ECUMENICAL_TEMPLE:
143 flv.wall = TILE_WALL_VINES;
144 flv.floor = TILE_FLOOR_VINES;
145 return;
147 case BRANCH_DWARVEN_HALL:
148 case BRANCH_ELVEN_HALLS:
149 case BRANCH_HALL_OF_BLADES:
150 flv.wall = TILE_WALL_HALL;
151 flv.floor = TILE_FLOOR_HALL;
152 return;
154 case BRANCH_TARTARUS:
155 case BRANCH_CRYPT:
156 case BRANCH_VESTIBULE_OF_HELL:
157 flv.wall = TILE_WALL_UNDEAD;
158 flv.floor = TILE_FLOOR_TOMB;
159 return;
161 case BRANCH_TOMB:
162 flv.wall = TILE_WALL_TOMB;
163 flv.floor = TILE_FLOOR_TOMB;
164 return;
166 case BRANCH_DIS:
167 flv.wall = TILE_WALL_ZOT_CYAN;
168 flv.floor = TILE_FLOOR_TOMB;
169 return;
171 case BRANCH_GEHENNA:
172 flv.wall = TILE_WALL_ZOT_RED;
173 flv.floor = TILE_FLOOR_ROUGH_RED;
174 return;
176 case BRANCH_COCYTUS:
177 flv.wall = TILE_WALL_ICE;
178 flv.floor = TILE_FLOOR_ICE;
179 return;
181 case BRANCH_ORCISH_MINES:
182 flv.wall = TILE_WALL_ORC;
183 flv.floor = TILE_FLOOR_ORC;
184 return;
186 case BRANCH_LAIR:
187 case BRANCH_FOREST:
188 case BRANCH_SPIDER_NEST:
189 flv.wall = TILE_WALL_LAIR;
190 flv.floor = TILE_FLOOR_LAIR;
191 return;
193 case BRANCH_SLIME_PITS:
194 flv.wall = TILE_WALL_SLIME;
195 flv.floor = TILE_FLOOR_SLIME;
196 return;
198 case BRANCH_SNAKE_PIT:
199 flv.wall = TILE_WALL_SNAKE;
200 flv.floor = TILE_FLOOR_SNAKE;
201 return;
203 case BRANCH_SWAMP:
204 flv.wall = TILE_WALL_SWAMP;
205 flv.floor = TILE_FLOOR_SWAMP;
206 return;
208 case BRANCH_SHOALS:
209 flv.wall = TILE_WALL_YELLOW_ROCK;
210 flv.floor = TILE_FLOOR_SAND_STONE;
211 return;
213 case BRANCH_HALL_OF_ZOT:
214 flv.wall = TILE_WALL_ZOT_YELLOW;
215 flv.floor = TILE_FLOOR_TOMB;
216 return;
218 case NUM_BRANCHES:
219 break;
223 void tile_clear_flavour()
225 for (rectangle_iterator ri(0); ri; ++ri)
227 env.tile_flv(*ri).floor = 0;
228 env.tile_flv(*ri).wall = 0;
229 env.tile_flv(*ri).feat = 0;
230 env.tile_flv(*ri).special = 0;
234 // For floors and walls that have not already been set to a particular tile,
235 // set them to a random instance of the default floor and wall tileset.
236 void tile_init_flavour()
238 for (rectangle_iterator ri(0); ri; ++ri)
239 tile_init_flavour(*ri);
242 static tileidx_t _pick_random_dngn_tile(tileidx_t idx, int value = -1)
244 ASSERT(idx >= 0 && idx < TILE_DNGN_MAX);
245 const int count = tile_dngn_count(idx);
246 if (count == 1)
247 return (idx);
249 const int total = tile_dngn_probs(idx + count - 1);
250 const int rand = (value == -1 ? random2(total) : value % total);
252 for (int i = 0; i < count; ++i)
254 tileidx_t curr = idx + i;
255 if (rand < tile_dngn_probs(curr))
256 return (curr);
259 return (idx);
262 void tile_init_flavour(const coord_def &gc)
264 if (!map_bounds(gc))
265 return;
267 if (!env.tile_flv(gc).floor)
269 tileidx_t floor_base = env.tile_default.floor;
270 int colour = env.grid_colours(gc);
271 if (colour)
272 floor_base = tile_dngn_coloured(floor_base, colour);
273 env.tile_flv(gc).floor = _pick_random_dngn_tile(floor_base);
276 if (!env.tile_flv(gc).wall)
278 tileidx_t wall_base = env.tile_default.wall;
279 int colour = env.grid_colours(gc);
280 if (colour)
281 wall_base = tile_dngn_coloured(wall_base, colour);
282 env.tile_flv(gc).wall = _pick_random_dngn_tile(wall_base);
285 if (feat_is_door(grd(gc)))
287 // Check for horizontal gates.
289 const coord_def left(gc.x - 1, gc.y);
290 const coord_def right(gc.x + 1, gc.y);
292 bool door_left = (grd(left) == grd(gc));
293 bool door_right = (grd(right) == grd(gc));
295 if (door_left || door_right)
297 tileidx_t target;
298 if (door_left && door_right)
299 target = TILE_DNGN_GATE_CLOSED_MIDDLE;
300 else if (door_left)
301 target = TILE_DNGN_GATE_CLOSED_RIGHT;
302 else
303 target = TILE_DNGN_GATE_CLOSED_LEFT;
305 // NOTE: This requires that closed gates and open gates
306 // are positioned in the tile set relative to their
307 // door counterpart.
308 env.tile_flv(gc).special = target - TILE_DNGN_CLOSED_DOOR;
310 else
311 env.tile_flv(gc).special = 0;
313 else if (feat_is_secret_door(grd(gc)))
314 env.tile_flv(gc).special = 0;
315 else if (!env.tile_flv(gc).special)
316 env.tile_flv(gc).special = random2(256);
319 enum SpecialIdx
321 SPECIAL_N = 0,
322 SPECIAL_NE = 1,
323 SPECIAL_E = 2,
324 SPECIAL_SE = 3,
325 SPECIAL_S = 4,
326 SPECIAL_SW = 5,
327 SPECIAL_W = 6,
328 SPECIAL_NW = 7,
329 SPECIAL_FULL = 8,
332 static int _jitter(SpecialIdx i)
334 return (i + random_range(-1, 1) + 8) % 8;
337 static bool _adjacent_target(dungeon_feature_type target, int x, int y)
339 for (adjacent_iterator ai(coord_def(x, y), false); ai; ++ai)
341 if (!map_bounds(*ai))
342 continue;
343 if (grd(*ai) == target)
344 return (true);
347 return (false);
350 void tile_floor_halo(dungeon_feature_type target, tileidx_t tile)
352 for (int x = 0; x < GXM; x++)
354 for (int y = 0; y < GYM; y++)
356 if (grd[x][y] < DNGN_FLOOR_MIN)
357 continue;
358 if (!_adjacent_target(target, x, y))
359 continue;
361 bool l_flr = (x > 0 && grd[x-1][y] >= DNGN_FLOOR_MIN);
362 bool r_flr = (x < GXM - 1 && grd[x+1][y] >= DNGN_FLOOR_MIN);
363 bool u_flr = (y > 0 && grd[x][y-1] >= DNGN_FLOOR_MIN);
364 bool d_flr = (y < GYM - 1 && grd[x][y+1] >= DNGN_FLOOR_MIN);
366 bool l_target = _adjacent_target(target, x-1, y);
367 bool r_target = _adjacent_target(target, x+1, y);
368 bool u_target = _adjacent_target(target, x, y-1);
369 bool d_target = _adjacent_target(target, x, y+1);
371 // The special tiles contains part floor and part special, so
372 // if there are adjacent floor or special tiles, we should
373 // do our best to "connect" them appropriately. If there are
374 // are other tiles there (walls, doors, whatever...) then it
375 // doesn't matter.
376 bool l_nrm = (l_flr && !l_target);
377 bool r_nrm = (r_flr && !r_target);
378 bool u_nrm = (u_flr && !u_target);
379 bool d_nrm = (d_flr && !d_target);
381 bool l_spc = (l_flr && l_target);
382 bool r_spc = (r_flr && r_target);
383 bool u_spc = (u_flr && u_target);
384 bool d_spc = (d_flr && d_target);
386 if (l_nrm && r_nrm || u_nrm && d_nrm)
388 // Not much to do here...
389 env.tile_flv[x][y].floor = tile + SPECIAL_FULL;
391 else if (l_nrm)
393 if (u_nrm)
394 env.tile_flv[x][y].floor = tile + SPECIAL_NW;
395 else if (d_nrm)
396 env.tile_flv[x][y].floor = tile + SPECIAL_SW;
397 else if (u_spc && d_spc)
398 env.tile_flv[x][y].floor = tile + SPECIAL_W;
399 else if (u_spc && r_spc)
400 env.tile_flv[x][y].floor = tile + SPECIAL_SW;
401 else if (d_spc && r_spc)
402 env.tile_flv[x][y].floor = tile + SPECIAL_NW;
403 else if (u_spc)
405 env.tile_flv[x][y].floor = tile + (coinflip() ?
406 SPECIAL_W : SPECIAL_SW);
408 else if (d_spc)
410 env.tile_flv[x][y].floor = tile + (coinflip() ?
411 SPECIAL_W : SPECIAL_NW);
413 else
414 env.tile_flv[x][y].floor = tile + _jitter(SPECIAL_W);
416 else if (r_nrm)
418 if (u_nrm)
419 env.tile_flv[x][y].floor = tile + SPECIAL_NE;
420 else if (d_nrm)
421 env.tile_flv[x][y].floor = tile + SPECIAL_SE;
422 else if (u_spc && d_spc)
423 env.tile_flv[x][y].floor = tile + SPECIAL_E;
424 else if (u_spc && l_spc)
425 env.tile_flv[x][y].floor = tile + SPECIAL_SE;
426 else if (d_spc && l_spc)
427 env.tile_flv[x][y].floor = tile + SPECIAL_NE;
428 else if (u_spc)
429 env.tile_flv[x][y].floor = tile + (coinflip() ?
430 SPECIAL_E : SPECIAL_SE);
431 else if (d_spc)
432 env.tile_flv[x][y].floor = tile + (coinflip() ?
433 SPECIAL_E : SPECIAL_NE);
434 else
435 env.tile_flv[x][y].floor = tile + _jitter(SPECIAL_E);
437 else if (u_nrm)
439 if (r_spc && l_spc)
440 env.tile_flv[x][y].floor = tile + SPECIAL_N;
441 else if (r_spc && d_spc)
442 env.tile_flv[x][y].floor = tile + SPECIAL_NW;
443 else if (l_spc && d_spc)
444 env.tile_flv[x][y].floor = tile + SPECIAL_NE;
445 else if (r_spc)
447 env.tile_flv[x][y].floor = tile + (coinflip() ?
448 SPECIAL_N : SPECIAL_NW);
450 else if (l_spc)
452 env.tile_flv[x][y].floor = tile + (coinflip() ?
453 SPECIAL_N : SPECIAL_NE);
455 else
456 env.tile_flv[x][y].floor = tile + _jitter(SPECIAL_N);
458 else if (d_nrm)
460 if (r_spc && l_spc)
461 env.tile_flv[x][y].floor = tile + SPECIAL_S;
462 else if (r_spc && u_spc)
463 env.tile_flv[x][y].floor = tile + SPECIAL_SW;
464 else if (l_spc && u_spc)
465 env.tile_flv[x][y].floor = tile + SPECIAL_SE;
466 else if (r_spc)
468 env.tile_flv[x][y].floor = tile + (coinflip() ?
469 SPECIAL_S : SPECIAL_SW);
471 else if (l_spc)
473 env.tile_flv[x][y].floor = tile + (coinflip() ?
474 SPECIAL_S : SPECIAL_SE);
476 else
477 env.tile_flv[x][y].floor = tile + _jitter(SPECIAL_S);
479 else if (u_spc && d_spc)
481 // We know this value is already initialised and
482 // is necessarily in bounds.
483 tileidx_t t = env.tile_flv[x][y-1].floor - tile;
484 if (t == SPECIAL_NE || t == SPECIAL_E)
485 env.tile_flv[x][y].floor = tile + SPECIAL_E;
486 else if (t == SPECIAL_NW || t == SPECIAL_W)
487 env.tile_flv[x][y].floor = tile + SPECIAL_W;
488 else
489 env.tile_flv[x][y].floor = tile + SPECIAL_FULL;
491 else if (r_spc && l_spc)
493 // We know this value is already initialised and
494 // is necessarily in bounds.
495 tileidx_t t = env.tile_flv[x-1][y].floor - tile;
496 if (t == SPECIAL_NW || t == SPECIAL_N)
497 env.tile_flv[x][y].floor = tile + SPECIAL_N;
498 else if (t == SPECIAL_SW || t == SPECIAL_S)
499 env.tile_flv[x][y].floor = tile + SPECIAL_S;
500 else
501 env.tile_flv[x][y].floor = tile + SPECIAL_FULL;
503 else if (u_spc && l_spc)
505 env.tile_flv[x][y].floor = tile + SPECIAL_SE;
507 else if (u_spc && r_spc)
509 env.tile_flv[x][y].floor = tile + SPECIAL_SW;
511 else if (d_spc && l_spc)
513 env.tile_flv[x][y].floor = tile + SPECIAL_NE;
515 else if (d_spc && r_spc)
517 env.tile_flv[x][y].floor = tile + SPECIAL_NW;
519 else
521 env.tile_flv[x][y].floor = tile + SPECIAL_FULL;
526 // Second pass for clean up. The only bad part about the above
527 // algorithm is that it could turn a block of floor like this:
529 // N4NN
530 // 3125
531 // NN6N
533 // (KEY: N = normal floor, # = special floor)
535 // Into these flavours:
536 // 1 - SPECIAL_S
537 // 2 - SPECIAL_N
538 // 3-6, not important
540 // Generally the tiles don't fit with a north to the right or left
541 // of a south tile. What we really want to do is to separate the
542 // two regions, by making 1 a SPECIAL_SE and 2 a SPECIAL_NW tile.
543 for (int y = 0; y < GYM - 1; ++y)
544 for (int x = 0; x < GXM - 1; ++x)
546 int this_spc = env.tile_flv[x][y].floor - tile;
547 if (this_spc < 0 || this_spc > 8)
548 continue;
550 if (this_spc != SPECIAL_N && this_spc != SPECIAL_S
551 && this_spc != SPECIAL_E && this_spc != SPECIAL_W)
553 continue;
556 int right_spc = x < GXM - 1 ? env.tile_flv[x+1][y].floor - tile
557 : SPECIAL_FULL;
558 int down_spc = y < GYM - 1 ? env.tile_flv[x][y+1].floor - tile
559 : SPECIAL_FULL;
561 if (this_spc == SPECIAL_N && right_spc == SPECIAL_S)
563 env.tile_flv[x][y].floor = tile + SPECIAL_NE;
564 env.tile_flv[x+1][y].floor = tile + SPECIAL_SW;
566 else if (this_spc == SPECIAL_S && right_spc == SPECIAL_N)
568 env.tile_flv[x][y].floor = tile + SPECIAL_SE;
569 env.tile_flv[x+1][y].floor = tile + SPECIAL_NW;
571 else if (this_spc == SPECIAL_E && down_spc == SPECIAL_W)
573 env.tile_flv[x][y].floor = tile + SPECIAL_SE;
574 env.tile_flv[x][y+1].floor = tile + SPECIAL_NW;
576 else if (this_spc == SPECIAL_W && down_spc == SPECIAL_E)
578 env.tile_flv[x][y].floor = tile + SPECIAL_NE;
579 env.tile_flv[x][y+1].floor = tile + SPECIAL_SW;
584 void tile_draw_floor()
586 for (int cy = 0; cy < env.tile_fg.height(); cy++)
587 for (int cx = 0; cx < env.tile_fg.width(); cx++)
589 const coord_def ep(cx, cy);
590 const coord_def gc = show2grid(ep);
592 tileidx_t bg = TILE_DNGN_UNSEEN | tileidx_unseen_flag(gc);
594 if (you.see_cell(gc))
596 bg = tileidx_feature(gc);
598 dungeon_feature_type feat = grid_appearance(gc);
599 if (feat == DNGN_DETECTED_SECRET_DOOR)
600 bg |= TILE_FLAG_WAS_SECRET;
601 else if (is_unknown_stair(gc))
602 bg |= TILE_FLAG_NEW_STAIR;
606 // init tiles
607 env.tile_bg(ep) = bg;
608 env.tile_fg(ep) = 0;
612 // Called from item() in view.cc
613 void tile_place_item(const coord_def &gc, const item_def &item)
615 if (env.tile_fg(gc))
616 return;
618 tileidx_t t = tileidx_item(item);
619 if (item.link != NON_ITEM)
620 t |= TILE_FLAG_S_UNDER;
622 env.tile_fg(gc) = t;
624 if (item_needs_autopickup(item))
625 env.tile_bg(gc) |= TILE_FLAG_CURSOR3;
628 // Called from item() in view.cc
629 void tile_place_item_marker(const coord_def &gc, const item_def &item)
631 env.tile_fg(gc) |= TILE_FLAG_S_UNDER;
633 if (item_needs_autopickup(item))
634 env.tile_bg(gc) |= TILE_FLAG_CURSOR3;
637 // Called from show_def::_update_monster() in show.cc
638 void tile_place_monster(const coord_def &gc, const monster* mon)
640 if (!mon)
641 return;
643 const coord_def ep = grid2show(gc);
645 tileidx_t t = tileidx_monster(mon);
646 tileidx_t t0 = t & TILE_FLAG_MASK;
647 tileidx_t flag = t & (~TILE_FLAG_MASK);
649 if (mons_is_item_mimic(mon->type))
651 if (mons_is_unknown_mimic(mon))
653 // If necessary add item brand.
654 if (you.visible_igrd(gc) != NON_ITEM)
655 t |= TILE_FLAG_S_UNDER;
657 if (item_needs_autopickup(get_mimic_item(mon)))
658 env.tile_bg(ep) |= TILE_FLAG_CURSOR3;
661 else if (mons_is_stationary(mon) && mon->type != MONS_TRAINING_DUMMY)
663 // If necessary add item brand.
664 if (you.visible_igrd(gc) != NON_ITEM)
665 t |= TILE_FLAG_S_UNDER;
667 else
669 tileidx_t mcache_idx = mcache.register_monster(mon);
670 t = flag | (mcache_idx ? mcache_idx : t0);
673 // Add name tags.
674 env.tile_fg(ep) = t;
676 if (!mon->visible_to(&you)
677 || mons_is_lurking(mon)
678 || mons_is_unknown_mimic(mon)
679 || mons_class_flag(mon->type, M_NO_EXP_GAIN))
681 return;
684 const tag_pref pref = Options.tile_tag_pref;
685 if (pref == TAGPREF_NONE)
686 return;
687 else if (pref == TAGPREF_TUTORIAL)
689 const int kills = you.kills->num_kills(mon);
690 const int limit = 0;
692 if (!mon->is_named() && kills > limit)
693 return;
695 else if (!mon->is_named())
696 return;
698 if (pref != TAGPREF_NAMED && mon->friendly())
699 return;
701 // HACK. Large-tile monsters don't interact well with name tags.
702 if (mon->type == MONS_PANDEMONIUM_DEMON
703 || mon->type == MONS_LERNAEAN_HYDRA)
705 return;
707 tiles.add_text_tag(TAG_NAMED_MONSTER, mon);
710 void tile_place_cloud(const coord_def &gc, const cloud_struct &cl)
712 const coord_def ep = grid2show(gc);
713 if (env.tile_fg(ep) != 0)
714 return;
716 const monster* mon = monster_at(gc);
717 bool disturbance = false;
719 if (mon && !mon->visible_to(&you) && you.see_cell(gc)
720 && is_opaque_cloud(env.cgrid(gc))
721 && !mon->is_insubstantial())
723 disturbance = true;
726 // In the Shoals, ink is handled differently. (jpeg)
727 // I'm not sure it is even possible anywhere else, but just to be safe...
728 if (cl.type != CLOUD_INK || !player_in_branch(BRANCH_SHOALS))
729 env.tile_fg(ep) = tileidx_cloud(cl, disturbance);
732 unsigned int num_tile_rays = 0;
733 struct tile_ray
735 coord_def ep;
736 bool in_range;
738 FixedVector<tile_ray, 30> tile_ray_vec;
740 void tile_place_ray(const coord_def &gc, bool in_range)
742 // Record rays for later. The curses version just applies
743 // rays directly to the screen. The tiles version doesn't have
744 // (nor want) such direct access. So, it batches up all of the
745 // rays and applies them in viewwindow(...).
746 if (num_tile_rays < tile_ray_vec.size() - 1)
748 tile_ray_vec[num_tile_rays].in_range = in_range;
749 tile_ray_vec[num_tile_rays++].ep = grid2show(gc);
753 void tile_draw_rays(bool reset_count)
755 for (unsigned int i = 0; i < num_tile_rays; i++)
757 tileidx_t flag = tile_ray_vec[i].in_range ? TILE_FLAG_RAY
758 : TILE_FLAG_RAY_OOR;
759 env.tile_bg(tile_ray_vec[i].ep) |= flag;
762 if (reset_count)
763 num_tile_rays = 0;
766 void tile_wizmap_terrain(const coord_def &gc)
768 env.tile_bk_bg(gc) = tileidx_feature(gc);
771 // Updates the "flavour" of tiles that are animated.
772 // Unfortunately, these are all hard-coded for now.
773 void tile_apply_animations(tileidx_t bg, tile_flavour *flv)
775 tileidx_t bg_idx = bg & TILE_FLAG_MASK;
776 if (bg_idx >= TILE_DNGN_LAVA && bg_idx < TILE_BLOOD)
778 flv->special = random2(256);
780 else if (bg_idx == TILE_DNGN_PORTAL_WIZARD_LAB
781 || bg_idx == TILE_DNGN_ALTAR_CHEIBRIADOS)
783 flv->special = (flv->special + 1) % tile_dngn_count(bg_idx);
785 else if (bg_idx == TILE_WALL_NORMAL
786 && flv->wall >= TILE_WALL_BRICK_TORCH_START
787 && flv->wall <= TILE_WALL_BRICK_TORCH_END)
789 flv->wall += 1;
790 if (flv->wall > TILE_WALL_BRICK_TORCH_END)
791 flv->wall = TILE_WALL_BRICK_TORCH_START;
795 static bool _suppress_blood(const coord_def pos)
797 if (!you.see_cell(pos))
798 return (true);
800 const dungeon_feature_type feat = grd(pos);
801 if (feat == DNGN_TREE || feat == DNGN_SWAMP_TREE)
802 return (true);
804 if (feat >= DNGN_FOUNTAIN_BLUE && feat <= DNGN_PERMADRY_FOUNTAIN)
805 return (true);
807 if (feat_is_altar(feat))
808 return (true);
810 if (feat_stair_direction(feat) != CMD_NO_CMD)
811 return (true);
813 if (feat == DNGN_TEMP_PORTAL)
814 return (true);
816 const trap_def *trap = find_trap(pos);
817 if (trap && trap->type == TRAP_SHAFT && trap->is_known())
818 return (true);
820 return (false);
823 static bool _suppress_blood(tileidx_t bg_idx)
825 return (bg_idx >= TILE_WALL_BRICK_TORCH_START
826 && bg_idx <= TILE_WALL_BRICK_TORCH_END);
829 // Specifically for vault-overwritten doors. We have three "sets" of tiles that
830 // can be dealt with. The tile sets should be 2, 3, 8 and 9 respectively. They
831 // are:
832 // 2. Closed, open.
833 // 3. Detected, closed, open.
834 // 8. Closed, open, gate left closed, gate middle closed, gate right closed,
835 // gate left open, gate middle open, gate right open.
836 // 9. Detected, closed, open, gate left closed, gate middle closed, gate right
837 // closed, gate left open, gate middle open, gate right open.
838 static int _get_door_offset(tileidx_t base_tile, bool opened = false,
839 bool detected = false, int gateway_type = 0)
841 int count = tile_dngn_count(base_tile);
842 if (count == 1)
843 return 0;
845 // The location of the default "closed" tile.
846 int offset = 0;
848 switch (count)
850 case 2:
851 return ((opened) ? 1: 0);
852 case 3:
853 if (opened)
854 return 2;
855 else if (detected)
856 return 0;
857 else
858 return 1;
859 case 8:
860 // But is BASE_TILE for others.
861 offset = 0;
862 break;
863 case 9:
864 // It's located at BASE_TILE+1 for tile sets with detected doors
865 offset = 1;
866 break;
867 default:
868 // Passed a non-door tile base, pig out now.
869 die("non-door tile");
872 // If we've reached this point, we're dealing with a gate.
873 // Don't believe gateways deal differently with detection.
874 if (detected)
875 return 0;
877 if (!opened && !detected && gateway_type == 0)
878 return 0;
880 return offset + gateway_type;
883 static inline void _apply_variations(const tile_flavour &flv, tileidx_t *bg,
884 const coord_def &gc)
886 tileidx_t orig = (*bg) & TILE_FLAG_MASK;
887 tileidx_t flag = (*bg) & (~TILE_FLAG_MASK);
889 // TODO enne - expose this as an option, so ziggurat can use it too.
890 // Alternatively, allow the stone type to be set.
892 // Hack: Swap rock/stone in crypt and tomb, because there are
893 // only stone walls.
894 if ((you.where_are_you == BRANCH_CRYPT || you.where_are_you == BRANCH_TOMB)
895 && orig == TILE_DNGN_STONE_WALL)
897 orig = TILE_WALL_NORMAL;
900 if (orig == TILE_FLOOR_NORMAL)
901 *bg = flv.floor;
902 else if (orig == TILE_WALL_NORMAL)
903 *bg = flv.wall;
904 else if (orig == TILE_DNGN_CLOSED_DOOR || orig == TILE_DNGN_OPEN_DOOR)
906 tileidx_t override = flv.feat;
907 // Setting an override on a door specifically for undetected secret
908 // doors causes issues if there are a number of variants for that tile.
909 // In these instances, append "last_tile" and have the tile specifier
910 // for the door in question on its own line, and it should bypass any
911 // asserts or weird visual issues. Somewhat hackish. The following code
912 // assumes that if there is an override on a door location and that
913 // has no variations, that the override is not actually a door tile but
914 // the aforementioned secret door thing. {due}
915 if (override && tile_dngn_count(override) > 1)
917 // XXX: This doesn't deal properly with detected doors.
918 bool opened = (orig == TILE_DNGN_OPEN_DOOR);
919 int offset = _get_door_offset(override, opened, false, flv.special);
920 *bg = override + offset;
922 else
923 *bg = orig + std::min((int)flv.special, 3);
925 if (feature_mimic_at(gc))
927 dungeon_feature_type feat = get_mimic_feat(monster_at(gc));
928 if (feat == DNGN_CLOSED_DOOR)
929 *bg = orig;
932 else if (orig == TILE_DNGN_PORTAL_WIZARD_LAB
933 || orig == TILE_DNGN_ALTAR_CHEIBRIADOS)
935 *bg = orig + flv.special % tile_dngn_count(orig);
937 else if (orig < TILE_DNGN_MAX)
939 *bg = _pick_random_dngn_tile(orig, flv.special);
942 *bg |= flag;
945 // If the top tile is a corpse, don't draw blood underneath.
946 static bool _top_item_is_corpse(const coord_def &gc)
948 if (!in_bounds(gc))
949 return (false);
951 const int item_idx = igrd(gc);
952 // No item.
953 if (item_idx == NON_ITEM)
954 return (false);
956 item_def& item = mitm[item_idx];
957 return (item.base_type == OBJ_CORPSES
958 && item.sub_type == CORPSE_BODY);
961 void tile_apply_properties(const coord_def &gc, packed_cell &cell)
963 if (is_excluded(gc))
965 if (is_exclude_root(gc))
966 cell.bg |= TILE_FLAG_EXCL_CTR;
967 else
968 cell.bg |= TILE_FLAG_TRAV_EXCL;
971 if (!map_bounds(gc))
972 return;
974 _apply_variations(env.tile_flv(gc), &cell.bg, gc);
976 bool print_blood = true;
977 if (haloed(gc))
979 monster* mon = monster_at(gc);
980 if (you.see_cell(gc) && mon)
982 if (!mons_class_flag(mon->type, M_NO_EXP_GAIN)
983 && (!mons_is_mimic(mon->type)
984 || testbits(mon->flags, MF_KNOWN_MIMIC)))
986 cell.is_haloed = true;
987 print_blood = false;
991 else
992 cell.is_haloed = false;
994 if (print_blood && (_suppress_blood(gc)
995 || _suppress_blood((cell.bg) & TILE_FLAG_MASK)))
997 print_blood = false;
1000 // Mold has the same restrictions as blood
1001 // but mold takes precendence over blood.
1002 if (print_blood)
1004 if (is_moldy(gc))
1005 cell.is_moldy = true;
1006 else if (is_bloodcovered(gc) && !_top_item_is_corpse(gc))
1007 cell.is_bloody = true;
1010 const dungeon_feature_type feat = grd(gc);
1011 if (feat_is_water(feat) || feat == DNGN_LAVA)
1012 cell.bg |= TILE_FLAG_WATER;
1014 if (is_sanctuary(gc))
1015 cell.is_sanctuary = true;
1017 if (silenced(gc))
1018 cell.is_silenced = true;
1020 if (grd(gc) == DNGN_SWAMP_TREE)
1021 cell.swamp_tree_water = true;
1024 void tile_clear_map(const coord_def& gc)
1026 env.tile_bk_fg(gc) = 0;
1027 tiles.update_minimap(gc);
1030 void tile_forget_map(const coord_def &gc)
1032 env.tile_bk_fg(gc) = 0;
1033 env.tile_bk_bg(gc) = 0;
1034 tiles.update_minimap(gc);
1037 #endif