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/floor-save.h"
6 #include "floor/floor.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/bit-flags-calculator.h"
26 #include "util/string-processor.h"
27 #include "view/display-messages.h"
30 * @brief プレイヤー周辺の地形を感知する
31 * @param caster_ptr プレーヤーへの参照ポインタ
34 * @param known 地形から危険フラグを外すならTRUE
35 * @return 効力があった場合TRUEを返す
37 static bool detect_feat_flag(player_type *caster_ptr, POSITION range, int flag, bool known)
39 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
44 for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++) {
45 for (POSITION x = 1; x <= caster_ptr->current_floor_ptr->width - 1; x++) {
46 int dist = distance(caster_ptr->y, caster_ptr->x, y, x);
49 g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
50 if (flag == FF_TRAP) {
51 /* Mark as detected */
52 if (dist <= range && known) {
53 if (dist <= range - 1)
54 g_ptr->info |= (CAVE_IN_DETECT);
56 g_ptr->info &= ~(CAVE_UNSAFE);
58 lite_spot(caster_ptr, y, x);
62 if (cave_have_flag_grid(g_ptr, flag)) {
63 disclose_grid(caster_ptr, y, x);
64 g_ptr->info |= (CAVE_MARK);
65 lite_spot(caster_ptr, y, x);
75 * @brief プレイヤー周辺のトラップを感知する / Detect all traps on current panel
76 * @param caster_ptr プレーヤーへの参照ポインタ
78 * @param known 感知外範囲を超える警告フラグを立てる場合TRUEを返す
79 * @return 効力があった場合TRUEを返す
81 bool detect_traps(player_type *caster_ptr, POSITION range, bool known)
83 bool detect = detect_feat_flag(caster_ptr, range, FF_TRAP, known);
86 caster_ptr->dtrap = TRUE;
88 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
91 msg_print(_("トラップの存在を感じとった!", "You sense the presence of traps!"));
98 * @brief プレイヤー周辺のドアを感知する / Detect all doors on current panel
99 * @param caster_ptr プレーヤーへの参照ポインタ
101 * @return 効力があった場合TRUEを返す
103 bool detect_doors(player_type *caster_ptr, POSITION range)
105 bool detect = detect_feat_flag(caster_ptr, range, FF_DOOR, TRUE);
107 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
110 msg_print(_("ドアの存在を感じとった!", "You sense the presence of doors!"));
117 * @brief プレイヤー周辺の階段を感知する / Detect all stairs on current panel
118 * @param caster_ptr プレーヤーへの参照ポインタ
120 * @return 効力があった場合TRUEを返す
122 bool detect_stairs(player_type *caster_ptr, POSITION range)
124 bool detect = detect_feat_flag(caster_ptr, range, FF_STAIRS, TRUE);
126 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
129 msg_print(_("階段の存在を感じとった!", "You sense the presence of stairs!"));
136 * @brief プレイヤー周辺の地形財宝を感知する / Detect any treasure on the current panel
137 * @param caster_ptr プレーヤーへの参照ポインタ
139 * @return 効力があった場合TRUEを返す
141 bool detect_treasure(player_type *caster_ptr, POSITION range)
143 bool detect = detect_feat_flag(caster_ptr, range, FF_HAS_GOLD, TRUE);
145 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
148 msg_print(_("埋蔵された財宝の存在を感じとった!", "You sense the presence of buried treasure!"));
154 * @brief プレイヤー周辺のアイテム財宝を感知する / Detect all "gold" objects on the current panel
155 * @param caster_ptr プレーヤーへの参照ポインタ
157 * @return 効力があった場合TRUEを返す
159 bool detect_objects_gold(player_type *caster_ptr, POSITION range)
161 POSITION range2 = range;
162 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
168 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
169 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
171 if (!object_is_valid(o_ptr))
173 if (object_is_held_monster(o_ptr))
178 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range2)
181 if (o_ptr->tval == TV_GOLD) {
182 o_ptr->marked |= OM_FOUND;
183 lite_spot(caster_ptr, y, x);
188 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
191 msg_print(_("財宝の存在を感じとった!", "You sense the presence of treasure!"));
194 if (detect_monsters_string(caster_ptr, range, "$")) {
202 * @brief 通常のアイテムオブジェクトを感知する / Detect all "normal" objects on the current panel
203 * @param caster_ptr プレーヤーへの参照ポインタ
205 * @return 効力があった場合TRUEを返す
207 bool detect_objects_normal(player_type *caster_ptr, POSITION range)
209 POSITION range2 = range;
210 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
214 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
215 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
217 if (!object_is_valid(o_ptr))
219 if (object_is_held_monster(o_ptr))
222 POSITION y = o_ptr->iy;
223 POSITION x = o_ptr->ix;
225 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range2)
228 if (o_ptr->tval != TV_GOLD) {
229 o_ptr->marked |= OM_FOUND;
230 lite_spot(caster_ptr, y, x);
235 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
238 msg_print(_("アイテムの存在を感じとった!", "You sense the presence of objects!"));
241 if (detect_monsters_string(caster_ptr, range, "!=?|/`")) {
249 * @brief 魔法効果のあるのアイテムオブジェクトを感知する / Detect all "magic" objects on the current panel.
250 * @param caster_ptr プレーヤーへの参照ポインタ
252 * @return 効力があった場合TRUEを返す
255 * This will light up all spaces with "magic" items, including artifacts,
256 * ego-items, potions, scrolls, books, rods, wands, staffs, amulets, rings,
257 * and "enchanted" items of the "good" variety.
259 * It can probably be argued that this function is now too powerful.
262 bool detect_objects_magic(player_type *caster_ptr, POSITION range)
264 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
269 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
270 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
272 if (!object_is_valid(o_ptr))
274 if (object_is_held_monster(o_ptr))
277 POSITION y = o_ptr->iy;
278 POSITION x = o_ptr->ix;
280 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
284 if (object_is_artifact(o_ptr) || object_is_ego(o_ptr) || (tv == TV_WHISTLE) || (tv == TV_AMULET) || (tv == TV_RING) || (tv == TV_STAFF)
285 || (tv == TV_WAND) || (tv == TV_ROD) || (tv == TV_SCROLL) || (tv == TV_POTION) || (tv == TV_LIFE_BOOK) || (tv == TV_SORCERY_BOOK)
286 || (tv == TV_NATURE_BOOK) || (tv == TV_CHAOS_BOOK) || (tv == TV_DEATH_BOOK) || (tv == TV_TRUMP_BOOK) || (tv == TV_ARCANE_BOOK)
287 || (tv == TV_CRAFT_BOOK) || (tv == TV_DEMON_BOOK) || (tv == TV_CRUSADE_BOOK) || (tv == TV_MUSIC_BOOK) || (tv == TV_HISSATSU_BOOK)
288 || (tv == TV_HEX_BOOK) || ((o_ptr->to_a > 0) || (o_ptr->to_h + o_ptr->to_d > 0))) {
289 o_ptr->marked |= OM_FOUND;
290 lite_spot(caster_ptr, y, x);
296 msg_print(_("魔法のアイテムの存在を感じとった!", "You sense the presence of magic objects!"));
303 * @brief 一般のモンスターを感知する / Detect all "normal" monsters on the current panel
304 * @param caster_ptr プレーヤーへの参照ポインタ
306 * @return 効力があった場合TRUEを返す
308 bool detect_monsters_normal(player_type *caster_ptr, POSITION range)
310 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
314 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
315 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
316 monster_race *r_ptr = &r_info[m_ptr->r_idx];
317 if (!monster_is_valid(m_ptr))
320 POSITION y = m_ptr->fy;
321 POSITION x = m_ptr->fx;
322 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
325 if (!(r_ptr->flags2 & RF2_INVISIBLE) || caster_ptr->see_inv) {
326 repair_monsters = TRUE;
327 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
328 update_monster(caster_ptr, i, FALSE);
333 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
336 msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!"));
343 * @brief 不可視のモンスターを感知する / Detect all "invisible" monsters around the player
344 * @param caster_ptr プレーヤーへの参照ポインタ
346 * @return 効力があった場合TRUEを返す
348 bool detect_monsters_invis(player_type *caster_ptr, POSITION range)
350 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
354 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
355 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
356 monster_race *r_ptr = &r_info[m_ptr->r_idx];
358 if (!monster_is_valid(m_ptr))
361 POSITION y = m_ptr->fy;
362 POSITION x = m_ptr->fx;
364 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
367 if (r_ptr->flags2 & RF2_INVISIBLE) {
368 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
369 caster_ptr->window |= (PW_MONSTER);
372 repair_monsters = TRUE;
373 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
374 update_monster(caster_ptr, i, FALSE);
379 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
382 msg_print(_("透明な生物の存在を感じとった!", "You sense the presence of invisible creatures!"));
389 * @brief 邪悪なモンスターを感知する / Detect all "evil" monsters on current panel
390 * @param caster_ptr プレーヤーへの参照ポインタ
392 * @return 効力があった場合TRUEを返す
394 bool detect_monsters_evil(player_type *caster_ptr, POSITION range)
396 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
400 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
401 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
402 monster_race *r_ptr = &r_info[m_ptr->r_idx];
403 if (!monster_is_valid(m_ptr))
406 POSITION y = m_ptr->fy;
407 POSITION x = m_ptr->fx;
409 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
412 if (r_ptr->flags3 & RF3_EVIL) {
413 if (is_original_ap(m_ptr)) {
414 r_ptr->r_flags3 |= (RF3_EVIL);
415 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
416 caster_ptr->window |= (PW_MONSTER);
420 repair_monsters = TRUE;
421 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
422 update_monster(caster_ptr, i, FALSE);
428 msg_print(_("邪悪なる生物の存在を感じとった!", "You sense the presence of evil creatures!"));
435 * @brief 無生命のモンスターを感知する(アンデッド、悪魔系を含む) / Detect all "nonliving", "undead" or "demonic" monsters on current panel
436 * @param caster_ptr プレーヤーへの参照ポインタ
438 * @return 効力があった場合TRUEを返す
440 bool detect_monsters_nonliving(player_type *caster_ptr, POSITION range)
442 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
446 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
447 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
448 if (!monster_is_valid(m_ptr))
451 POSITION y = m_ptr->fy;
452 POSITION x = m_ptr->fx;
453 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
456 if (!monster_living(m_ptr->r_idx)) {
457 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
458 caster_ptr->window |= (PW_MONSTER);
461 repair_monsters = TRUE;
462 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
463 update_monster(caster_ptr, i, FALSE);
469 msg_print(_("自然でないモンスターの存在を感じた!", "You sense the presence of unnatural beings!"));
476 * @brief 精神のあるモンスターを感知する / Detect all monsters it has mind on current panel
477 * @param caster_ptr プレーヤーへの参照ポインタ
479 * @return 効力があった場合TRUEを返す
481 bool detect_monsters_mind(player_type *caster_ptr, POSITION range)
483 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
487 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
488 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
489 monster_race *r_ptr = &r_info[m_ptr->r_idx];
490 if (!monster_is_valid(m_ptr))
493 POSITION y = m_ptr->fy;
494 POSITION x = m_ptr->fx;
496 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
499 if (!(r_ptr->flags2 & RF2_EMPTY_MIND)) {
500 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
501 caster_ptr->window |= (PW_MONSTER);
504 repair_monsters = TRUE;
505 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
506 update_monster(caster_ptr, i, FALSE);
512 msg_print(_("殺気を感じとった!", "You sense the presence of someone's mind!"));
519 * @brief 該当シンボルのモンスターを感知する / Detect all (string) monsters on current panel
520 * @param caster_ptr プレーヤーへの参照ポインタ
522 * @param Match 対応シンボルの混じったモンスター文字列(複数指定化)
523 * @return 効力があった場合TRUEを返す
525 bool detect_monsters_string(player_type *caster_ptr, POSITION range, concptr Match)
527 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
531 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
532 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
533 monster_race *r_ptr = &r_info[m_ptr->r_idx];
534 if (!monster_is_valid(m_ptr))
537 POSITION y = m_ptr->fy;
538 POSITION x = m_ptr->fx;
540 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
543 if (angband_strchr(Match, r_ptr->d_char)) {
544 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
545 caster_ptr->window |= (PW_MONSTER);
548 repair_monsters = TRUE;
549 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
550 update_monster(caster_ptr, i, FALSE);
555 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
558 msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!"));
565 * @brief flags3に対応するモンスターを感知する / A "generic" detect monsters routine, tagged to flags3
566 * @param caster_ptr プレーヤーへの参照ポインタ
568 * @param match_flag 感知フラグ
569 * @return 効力があった場合TRUEを返す
571 bool detect_monsters_xxx(player_type *caster_ptr, POSITION range, u32b match_flag)
573 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
577 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
578 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
579 monster_race *r_ptr = &r_info[m_ptr->r_idx];
580 if (!monster_is_valid(m_ptr))
583 POSITION y = m_ptr->fy;
584 POSITION x = m_ptr->fx;
586 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
589 if (r_ptr->flags3 & (match_flag)) {
590 if (is_original_ap(m_ptr)) {
591 r_ptr->r_flags3 |= (match_flag);
592 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
593 caster_ptr->window |= (PW_MONSTER);
597 repair_monsters = TRUE;
598 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
599 update_monster(caster_ptr, i, FALSE);
604 concptr desc_monsters = _("変なモンスター", "weird monsters");
606 switch (match_flag) {
608 desc_monsters = _("デーモン", "demons");
611 desc_monsters = _("アンデッド", "the undead");
615 msg_format(_("%sの存在を感じとった!", "You sense the presence of %s!"), desc_monsters);
623 * @brief 全感知処理 / Detect everything
624 * @param caster_ptr プレーヤーへの参照ポインタ
626 * @return 効力があった場合TRUEを返す
628 bool detect_all(player_type *caster_ptr, POSITION range)
631 if (detect_traps(caster_ptr, range, TRUE))
633 if (detect_doors(caster_ptr, range))
635 if (detect_stairs(caster_ptr, range))
637 if (detect_objects_gold(caster_ptr, range))
639 if (detect_objects_normal(caster_ptr, range))
641 if (detect_monsters_invis(caster_ptr, range))
643 if (detect_monsters_normal(caster_ptr, range))