1 #include "spell-kind/spells-detection.h"
2 #include "core/window-redrawer.h"
3 #include "dungeon/dungeon-flag-types.h"
4 #include "dungeon/dungeon.h"
5 #include "floor/cave.h"
6 #include "floor/floor-save-util.h"
9 #include "monster-race/monster-race.h"
10 #include "monster-race/race-flags2.h"
11 #include "monster-race/race-flags3.h"
12 #include "monster-race/monster-race-hook.h"
13 #include "monster/monster-flag-types.h"
14 #include "monster/monster-info.h"
15 #include "monster/monster-status.h"
16 #include "monster/monster-update.h"
17 #include "object-hook/hook-checker.h"
18 #include "object-hook/hook-enchant.h"
19 #include "object/object-mark-types.h"
20 #include "object/tval-types.h"
21 #include "realm/realm-song-numbers.h"
22 #include "realm/realm-song.h"
23 #include "system/floor-type-definition.h"
24 #include "system/object-type-definition.h"
25 #include "util/string-processor.h"
26 #include "view/display-messages.h"
29 * @brief プレイヤー周辺の地形を感知する
30 * @param caster_ptr プレーヤーへの参照ポインタ
33 * @param known 地形から危険フラグを外すならTRUE
34 * @return 効力があった場合TRUEを返す
36 static bool detect_feat_flag(player_type *caster_ptr, POSITION range, int flag, bool known)
38 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
43 for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++) {
44 for (POSITION x = 1; x <= caster_ptr->current_floor_ptr->width - 1; x++) {
45 int dist = distance(caster_ptr->y, caster_ptr->x, y, x);
48 g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
49 if (flag == FF_TRAP) {
50 /* Mark as detected */
51 if (dist <= range && known) {
52 if (dist <= range - 1)
53 g_ptr->info |= (CAVE_IN_DETECT);
55 g_ptr->info &= ~(CAVE_UNSAFE);
57 lite_spot(caster_ptr, y, x);
61 if (cave_has_flag_grid(g_ptr, flag)) {
62 disclose_grid(caster_ptr, y, x);
63 g_ptr->info |= (CAVE_MARK);
64 lite_spot(caster_ptr, y, x);
74 * @brief プレイヤー周辺のトラップを感知する / Detect all traps on current panel
75 * @param caster_ptr プレーヤーへの参照ポインタ
77 * @param known 感知外範囲を超える警告フラグを立てる場合TRUEを返す
78 * @return 効力があった場合TRUEを返す
80 bool detect_traps(player_type *caster_ptr, POSITION range, bool known)
82 bool detect = detect_feat_flag(caster_ptr, range, FF_TRAP, known);
85 caster_ptr->dtrap = TRUE;
87 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
90 msg_print(_("トラップの存在を感じとった!", "You sense the presence of traps!"));
97 * @brief プレイヤー周辺のドアを感知する / Detect all doors on current panel
98 * @param caster_ptr プレーヤーへの参照ポインタ
100 * @return 効力があった場合TRUEを返す
102 bool detect_doors(player_type *caster_ptr, POSITION range)
104 bool detect = detect_feat_flag(caster_ptr, range, FF_DOOR, TRUE);
106 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
109 msg_print(_("ドアの存在を感じとった!", "You sense the presence of doors!"));
116 * @brief プレイヤー周辺の階段を感知する / Detect all stairs on current panel
117 * @param caster_ptr プレーヤーへの参照ポインタ
119 * @return 効力があった場合TRUEを返す
121 bool detect_stairs(player_type *caster_ptr, POSITION range)
123 bool detect = detect_feat_flag(caster_ptr, range, FF_STAIRS, TRUE);
125 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
128 msg_print(_("階段の存在を感じとった!", "You sense the presence of stairs!"));
135 * @brief プレイヤー周辺の地形財宝を感知する / Detect any treasure on the current panel
136 * @param caster_ptr プレーヤーへの参照ポインタ
138 * @return 効力があった場合TRUEを返す
140 bool detect_treasure(player_type *caster_ptr, POSITION range)
142 bool detect = detect_feat_flag(caster_ptr, range, FF_HAS_GOLD, TRUE);
144 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
147 msg_print(_("埋蔵された財宝の存在を感じとった!", "You sense the presence of buried treasure!"));
153 * @brief プレイヤー周辺のアイテム財宝を感知する / Detect all "gold" objects on the current panel
154 * @param caster_ptr プレーヤーへの参照ポインタ
156 * @return 効力があった場合TRUEを返す
158 bool detect_objects_gold(player_type *caster_ptr, POSITION range)
160 POSITION range2 = range;
161 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
167 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
168 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
170 if (!object_is_valid(o_ptr))
172 if (object_is_held_monster(o_ptr))
177 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range2)
180 if (o_ptr->tval == TV_GOLD) {
181 o_ptr->marked |= OM_FOUND;
182 lite_spot(caster_ptr, y, x);
187 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
190 msg_print(_("財宝の存在を感じとった!", "You sense the presence of treasure!"));
193 if (detect_monsters_string(caster_ptr, range, "$")) {
201 * @brief 通常のアイテムオブジェクトを感知する / Detect all "normal" objects on the current panel
202 * @param caster_ptr プレーヤーへの参照ポインタ
204 * @return 効力があった場合TRUEを返す
206 bool detect_objects_normal(player_type *caster_ptr, POSITION range)
208 POSITION range2 = range;
209 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
213 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
214 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
216 if (!object_is_valid(o_ptr))
218 if (object_is_held_monster(o_ptr))
221 POSITION y = o_ptr->iy;
222 POSITION x = o_ptr->ix;
224 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range2)
227 if (o_ptr->tval != TV_GOLD) {
228 o_ptr->marked |= OM_FOUND;
229 lite_spot(caster_ptr, y, x);
234 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
237 msg_print(_("アイテムの存在を感じとった!", "You sense the presence of objects!"));
240 if (detect_monsters_string(caster_ptr, range, "!=?|/`")) {
248 * @brief 魔法効果のあるのアイテムオブジェクトを感知する / Detect all "magic" objects on the current panel.
249 * @param caster_ptr プレーヤーへの参照ポインタ
251 * @return 効力があった場合TRUEを返す
254 * This will light up all spaces with "magic" items, including artifacts,
255 * ego-items, potions, scrolls, books, rods, wands, staffs, amulets, rings,
256 * and "enchanted" items of the "good" variety.
258 * It can probably be argued that this function is now too powerful.
261 bool detect_objects_magic(player_type *caster_ptr, POSITION range)
263 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
268 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
269 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
271 if (!object_is_valid(o_ptr))
273 if (object_is_held_monster(o_ptr))
276 POSITION y = o_ptr->iy;
277 POSITION x = o_ptr->ix;
279 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
283 if (object_is_artifact(o_ptr) || object_is_ego(o_ptr) || (tv == TV_WHISTLE) || (tv == TV_AMULET) || (tv == TV_RING) || (tv == TV_STAFF)
284 || (tv == TV_WAND) || (tv == TV_ROD) || (tv == TV_SCROLL) || (tv == TV_POTION) || (tv == TV_LIFE_BOOK) || (tv == TV_SORCERY_BOOK)
285 || (tv == TV_NATURE_BOOK) || (tv == TV_CHAOS_BOOK) || (tv == TV_DEATH_BOOK) || (tv == TV_TRUMP_BOOK) || (tv == TV_ARCANE_BOOK)
286 || (tv == TV_CRAFT_BOOK) || (tv == TV_DEMON_BOOK) || (tv == TV_CRUSADE_BOOK) || (tv == TV_MUSIC_BOOK) || (tv == TV_HISSATSU_BOOK)
287 || (tv == TV_HEX_BOOK) || ((o_ptr->to_a > 0) || (o_ptr->to_h + o_ptr->to_d > 0))) {
288 o_ptr->marked |= OM_FOUND;
289 lite_spot(caster_ptr, y, x);
295 msg_print(_("魔法のアイテムの存在を感じとった!", "You sense the presence of magic objects!"));
302 * @brief 一般のモンスターを感知する / Detect all "normal" monsters on the current panel
303 * @param caster_ptr プレーヤーへの参照ポインタ
305 * @return 効力があった場合TRUEを返す
307 bool detect_monsters_normal(player_type *caster_ptr, POSITION range)
309 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
313 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
314 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
315 monster_race *r_ptr = &r_info[m_ptr->r_idx];
316 if (!monster_is_valid(m_ptr))
319 POSITION y = m_ptr->fy;
320 POSITION x = m_ptr->fx;
321 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
324 if (!(r_ptr->flags2 & RF2_INVISIBLE) || caster_ptr->see_inv) {
325 repair_monsters = TRUE;
326 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
327 update_monster(caster_ptr, i, FALSE);
332 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
335 msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!"));
342 * @brief 不可視のモンスターを感知する / Detect all "invisible" monsters around the player
343 * @param caster_ptr プレーヤーへの参照ポインタ
345 * @return 効力があった場合TRUEを返す
347 bool detect_monsters_invis(player_type *caster_ptr, POSITION range)
349 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
353 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
354 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
355 monster_race *r_ptr = &r_info[m_ptr->r_idx];
357 if (!monster_is_valid(m_ptr))
360 POSITION y = m_ptr->fy;
361 POSITION x = m_ptr->fx;
363 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
366 if (r_ptr->flags2 & RF2_INVISIBLE) {
367 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
368 caster_ptr->window_flags |= (PW_MONSTER);
371 repair_monsters = TRUE;
372 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
373 update_monster(caster_ptr, i, FALSE);
378 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
381 msg_print(_("透明な生物の存在を感じとった!", "You sense the presence of invisible creatures!"));
388 * @brief 邪悪なモンスターを感知する / Detect all "evil" monsters on current panel
389 * @param caster_ptr プレーヤーへの参照ポインタ
391 * @return 効力があった場合TRUEを返す
393 bool detect_monsters_evil(player_type *caster_ptr, POSITION range)
395 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
399 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
400 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
401 monster_race *r_ptr = &r_info[m_ptr->r_idx];
402 if (!monster_is_valid(m_ptr))
405 POSITION y = m_ptr->fy;
406 POSITION x = m_ptr->fx;
408 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
411 if (r_ptr->flags3 & RF3_EVIL) {
412 if (is_original_ap(m_ptr)) {
413 r_ptr->r_flags3 |= (RF3_EVIL);
414 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
415 caster_ptr->window_flags |= (PW_MONSTER);
419 repair_monsters = TRUE;
420 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
421 update_monster(caster_ptr, i, FALSE);
427 msg_print(_("邪悪なる生物の存在を感じとった!", "You sense the presence of evil creatures!"));
434 * @brief 無生命のモンスターを感知する(アンデッド、悪魔系を含む) / Detect all "nonliving", "undead" or "demonic" monsters on current panel
435 * @param caster_ptr プレーヤーへの参照ポインタ
437 * @return 効力があった場合TRUEを返す
439 bool detect_monsters_nonliving(player_type *caster_ptr, POSITION range)
441 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
445 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
446 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
447 if (!monster_is_valid(m_ptr))
450 POSITION y = m_ptr->fy;
451 POSITION x = m_ptr->fx;
452 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
455 if (!monster_living(m_ptr->r_idx)) {
456 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
457 caster_ptr->window_flags |= (PW_MONSTER);
460 repair_monsters = TRUE;
461 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
462 update_monster(caster_ptr, i, FALSE);
468 msg_print(_("自然でないモンスターの存在を感じた!", "You sense the presence of unnatural beings!"));
475 * @brief 精神のあるモンスターを感知する / Detect all monsters it has mind on current panel
476 * @param caster_ptr プレーヤーへの参照ポインタ
478 * @return 効力があった場合TRUEを返す
480 bool detect_monsters_mind(player_type *caster_ptr, POSITION range)
482 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
486 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
487 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
488 monster_race *r_ptr = &r_info[m_ptr->r_idx];
489 if (!monster_is_valid(m_ptr))
492 POSITION y = m_ptr->fy;
493 POSITION x = m_ptr->fx;
495 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
498 if (!(r_ptr->flags2 & RF2_EMPTY_MIND)) {
499 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
500 caster_ptr->window_flags |= (PW_MONSTER);
503 repair_monsters = TRUE;
504 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
505 update_monster(caster_ptr, i, FALSE);
511 msg_print(_("殺気を感じとった!", "You sense the presence of someone's mind!"));
518 * @brief 該当シンボルのモンスターを感知する / Detect all (string) monsters on current panel
519 * @param caster_ptr プレーヤーへの参照ポインタ
521 * @param Match 対応シンボルの混じったモンスター文字列(複数指定化)
522 * @return 効力があった場合TRUEを返す
524 bool detect_monsters_string(player_type *caster_ptr, POSITION range, concptr Match)
526 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
530 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
531 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
532 monster_race *r_ptr = &r_info[m_ptr->r_idx];
533 if (!monster_is_valid(m_ptr))
536 POSITION y = m_ptr->fy;
537 POSITION x = m_ptr->fx;
539 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
542 if (angband_strchr(Match, r_ptr->d_char)) {
543 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
544 caster_ptr->window_flags |= (PW_MONSTER);
547 repair_monsters = TRUE;
548 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
549 update_monster(caster_ptr, i, FALSE);
554 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
557 msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!"));
564 * @brief flags3に対応するモンスターを感知する / A "generic" detect monsters routine, tagged to flags3
565 * @param caster_ptr プレーヤーへの参照ポインタ
567 * @param match_flag 感知フラグ
568 * @return 効力があった場合TRUEを返す
570 bool detect_monsters_xxx(player_type *caster_ptr, POSITION range, u32b match_flag)
572 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
576 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
577 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
578 monster_race *r_ptr = &r_info[m_ptr->r_idx];
579 if (!monster_is_valid(m_ptr))
582 POSITION y = m_ptr->fy;
583 POSITION x = m_ptr->fx;
585 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
588 if (r_ptr->flags3 & (match_flag)) {
589 if (is_original_ap(m_ptr)) {
590 r_ptr->r_flags3 |= (match_flag);
591 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
592 caster_ptr->window_flags |= (PW_MONSTER);
596 repair_monsters = TRUE;
597 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
598 update_monster(caster_ptr, i, FALSE);
603 concptr desc_monsters = _("変なモンスター", "weird monsters");
605 switch (match_flag) {
607 desc_monsters = _("デーモン", "demons");
610 desc_monsters = _("アンデッド", "the undead");
614 msg_format(_("%sの存在を感じとった!", "You sense the presence of %s!"), desc_monsters);
622 * @brief 全感知処理 / Detect everything
623 * @param caster_ptr プレーヤーへの参照ポインタ
625 * @return 効力があった場合TRUEを返す
627 bool detect_all(player_type *caster_ptr, POSITION range)
630 if (detect_traps(caster_ptr, range, TRUE))
632 if (detect_doors(caster_ptr, range))
634 if (detect_stairs(caster_ptr, range))
636 if (detect_objects_gold(caster_ptr, range))
638 if (detect_objects_normal(caster_ptr, range))
640 if (detect_monsters_invis(caster_ptr, range))
642 if (detect_monsters_normal(caster_ptr, range))