1 #include "spell-kind/spells-detection.h"
2 #include "dungeon/dungeon.h"
3 #include "floor/floor-save.h"
4 #include "floor/floor.h"
7 #include "monster-race/monster-race.h"
8 #include "monster-race/race-flags2.h"
9 #include "monster-race/race-flags3.h"
10 #include "monster-race/monster-race-hook.h"
11 #include "monster/monster-flag-types.h"
12 #include "monster/monster-info.h"
13 #include "monster/monster-status.h"
14 #include "monster/monster-update.h"
15 #include "object-hook/hook-checker.h"
16 #include "object/object-hook.h"
17 #include "object/object-mark-types.h"
18 #include "realm/realm-song-numbers.h"
19 #include "realm/realm-song.h"
20 #include "util/bit-flags-calculator.h"
21 #include "util/string-processor.h"
22 #include "view/display-messages.h"
25 * @brief プレイヤー周辺の地形を感知する
26 * @param caster_ptr プレーヤーへの参照ポインタ
29 * @param known 地形から危険フラグを外すならTRUE
30 * @return 効力があった場合TRUEを返す
32 static bool detect_feat_flag(player_type *caster_ptr, POSITION range, int flag, bool known)
34 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
39 for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++) {
40 for (POSITION x = 1; x <= caster_ptr->current_floor_ptr->width - 1; x++) {
41 int dist = distance(caster_ptr->y, caster_ptr->x, y, x);
44 g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
45 if (flag == FF_TRAP) {
46 /* Mark as detected */
47 if (dist <= range && known) {
48 if (dist <= range - 1)
49 g_ptr->info |= (CAVE_IN_DETECT);
51 g_ptr->info &= ~(CAVE_UNSAFE);
53 lite_spot(caster_ptr, y, x);
57 if (cave_have_flag_grid(g_ptr, flag)) {
58 disclose_grid(caster_ptr, y, x);
59 g_ptr->info |= (CAVE_MARK);
60 lite_spot(caster_ptr, y, x);
70 * @brief プレイヤー周辺のトラップを感知する / Detect all traps on current panel
71 * @param caster_ptr プレーヤーへの参照ポインタ
73 * @param known 感知外範囲を超える警告フラグを立てる場合TRUEを返す
74 * @return 効力があった場合TRUEを返す
76 bool detect_traps(player_type *caster_ptr, POSITION range, bool known)
78 bool detect = detect_feat_flag(caster_ptr, range, FF_TRAP, known);
81 caster_ptr->dtrap = TRUE;
83 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
86 msg_print(_("トラップの存在を感じとった!", "You sense the presence of traps!"));
93 * @brief プレイヤー周辺のドアを感知する / Detect all doors on current panel
94 * @param caster_ptr プレーヤーへの参照ポインタ
96 * @return 効力があった場合TRUEを返す
98 bool detect_doors(player_type *caster_ptr, POSITION range)
100 bool detect = detect_feat_flag(caster_ptr, range, FF_DOOR, TRUE);
102 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
105 msg_print(_("ドアの存在を感じとった!", "You sense the presence of doors!"));
112 * @brief プレイヤー周辺の階段を感知する / Detect all stairs on current panel
113 * @param caster_ptr プレーヤーへの参照ポインタ
115 * @return 効力があった場合TRUEを返す
117 bool detect_stairs(player_type *caster_ptr, POSITION range)
119 bool detect = detect_feat_flag(caster_ptr, range, FF_STAIRS, TRUE);
121 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
124 msg_print(_("階段の存在を感じとった!", "You sense the presence of stairs!"));
131 * @brief プレイヤー周辺の地形財宝を感知する / Detect any treasure on the current panel
132 * @param caster_ptr プレーヤーへの参照ポインタ
134 * @return 効力があった場合TRUEを返す
136 bool detect_treasure(player_type *caster_ptr, POSITION range)
138 bool detect = detect_feat_flag(caster_ptr, range, FF_HAS_GOLD, TRUE);
140 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
143 msg_print(_("埋蔵された財宝の存在を感じとった!", "You sense the presence of buried treasure!"));
149 * @brief プレイヤー周辺のアイテム財宝を感知する / Detect all "gold" objects on the current panel
150 * @param caster_ptr プレーヤーへの参照ポインタ
152 * @return 効力があった場合TRUEを返す
154 bool detect_objects_gold(player_type *caster_ptr, POSITION range)
156 POSITION range2 = range;
157 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
163 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
164 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
166 if (!object_is_valid(o_ptr))
168 if (object_is_held_monster(o_ptr))
173 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range2)
176 if (o_ptr->tval == TV_GOLD) {
177 o_ptr->marked |= OM_FOUND;
178 lite_spot(caster_ptr, y, x);
183 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
186 msg_print(_("財宝の存在を感じとった!", "You sense the presence of treasure!"));
189 if (detect_monsters_string(caster_ptr, range, "$")) {
197 * @brief 通常のアイテムオブジェクトを感知する / Detect all "normal" objects on the current panel
198 * @param caster_ptr プレーヤーへの参照ポインタ
200 * @return 効力があった場合TRUEを返す
202 bool detect_objects_normal(player_type *caster_ptr, POSITION range)
204 POSITION range2 = range;
205 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
209 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
210 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
212 if (!object_is_valid(o_ptr))
214 if (object_is_held_monster(o_ptr))
217 POSITION y = o_ptr->iy;
218 POSITION x = o_ptr->ix;
220 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range2)
223 if (o_ptr->tval != TV_GOLD) {
224 o_ptr->marked |= OM_FOUND;
225 lite_spot(caster_ptr, y, x);
230 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
233 msg_print(_("アイテムの存在を感じとった!", "You sense the presence of objects!"));
236 if (detect_monsters_string(caster_ptr, range, "!=?|/`")) {
244 * @brief 魔法効果のあるのアイテムオブジェクトを感知する / Detect all "magic" objects on the current panel.
245 * @param caster_ptr プレーヤーへの参照ポインタ
247 * @return 効力があった場合TRUEを返す
250 * This will light up all spaces with "magic" items, including artifacts,
251 * ego-items, potions, scrolls, books, rods, wands, staffs, amulets, rings,
252 * and "enchanted" items of the "good" variety.
254 * It can probably be argued that this function is now too powerful.
257 bool detect_objects_magic(player_type *caster_ptr, POSITION range)
259 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
264 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
265 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
267 if (!object_is_valid(o_ptr))
269 if (object_is_held_monster(o_ptr))
272 POSITION y = o_ptr->iy;
273 POSITION x = o_ptr->ix;
275 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
279 if (object_is_artifact(o_ptr) || object_is_ego(o_ptr) || (tv == TV_WHISTLE) || (tv == TV_AMULET) || (tv == TV_RING) || (tv == TV_STAFF)
280 || (tv == TV_WAND) || (tv == TV_ROD) || (tv == TV_SCROLL) || (tv == TV_POTION) || (tv == TV_LIFE_BOOK) || (tv == TV_SORCERY_BOOK)
281 || (tv == TV_NATURE_BOOK) || (tv == TV_CHAOS_BOOK) || (tv == TV_DEATH_BOOK) || (tv == TV_TRUMP_BOOK) || (tv == TV_ARCANE_BOOK)
282 || (tv == TV_CRAFT_BOOK) || (tv == TV_DAEMON_BOOK) || (tv == TV_CRUSADE_BOOK) || (tv == TV_MUSIC_BOOK) || (tv == TV_HISSATSU_BOOK)
283 || (tv == TV_HEX_BOOK) || ((o_ptr->to_a > 0) || (o_ptr->to_h + o_ptr->to_d > 0))) {
284 o_ptr->marked |= OM_FOUND;
285 lite_spot(caster_ptr, y, x);
291 msg_print(_("魔法のアイテムの存在を感じとった!", "You sense the presence of magic objects!"));
298 * @brief 一般のモンスターを感知する / Detect all "normal" monsters on the current panel
299 * @param caster_ptr プレーヤーへの参照ポインタ
301 * @return 効力があった場合TRUEを返す
303 bool detect_monsters_normal(player_type *caster_ptr, POSITION range)
305 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
309 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
310 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
311 monster_race *r_ptr = &r_info[m_ptr->r_idx];
312 if (!monster_is_valid(m_ptr))
315 POSITION y = m_ptr->fy;
316 POSITION x = m_ptr->fx;
317 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
320 if (!(r_ptr->flags2 & RF2_INVISIBLE) || caster_ptr->see_inv) {
321 repair_monsters = TRUE;
322 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
323 update_monster(caster_ptr, i, FALSE);
328 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
331 msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!"));
338 * @brief 不可視のモンスターを感知する / Detect all "invisible" monsters around the player
339 * @param caster_ptr プレーヤーへの参照ポインタ
341 * @return 効力があった場合TRUEを返す
343 bool detect_monsters_invis(player_type *caster_ptr, POSITION range)
345 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
349 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
350 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
351 monster_race *r_ptr = &r_info[m_ptr->r_idx];
353 if (!monster_is_valid(m_ptr))
356 POSITION y = m_ptr->fy;
357 POSITION x = m_ptr->fx;
359 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
362 if (r_ptr->flags2 & RF2_INVISIBLE) {
363 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
364 caster_ptr->window |= (PW_MONSTER);
367 repair_monsters = TRUE;
368 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
369 update_monster(caster_ptr, i, FALSE);
374 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
377 msg_print(_("透明な生物の存在を感じとった!", "You sense the presence of invisible creatures!"));
384 * @brief 邪悪なモンスターを感知する / Detect all "evil" monsters on current panel
385 * @param caster_ptr プレーヤーへの参照ポインタ
387 * @return 効力があった場合TRUEを返す
389 bool detect_monsters_evil(player_type *caster_ptr, POSITION range)
391 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
395 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
396 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
397 monster_race *r_ptr = &r_info[m_ptr->r_idx];
398 if (!monster_is_valid(m_ptr))
401 POSITION y = m_ptr->fy;
402 POSITION x = m_ptr->fx;
404 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
407 if (r_ptr->flags3 & RF3_EVIL) {
408 if (is_original_ap(m_ptr)) {
409 r_ptr->r_flags3 |= (RF3_EVIL);
410 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
411 caster_ptr->window |= (PW_MONSTER);
415 repair_monsters = TRUE;
416 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
417 update_monster(caster_ptr, i, FALSE);
423 msg_print(_("邪悪なる生物の存在を感じとった!", "You sense the presence of evil creatures!"));
430 * @brief 無生命のモンスターを感知する(アンデッド、悪魔系を含む) / Detect all "nonliving", "undead" or "demonic" monsters on current panel
431 * @param caster_ptr プレーヤーへの参照ポインタ
433 * @return 効力があった場合TRUEを返す
435 bool detect_monsters_nonliving(player_type *caster_ptr, POSITION range)
437 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
441 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
442 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
443 if (!monster_is_valid(m_ptr))
446 POSITION y = m_ptr->fy;
447 POSITION x = m_ptr->fx;
448 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
451 if (!monster_living(m_ptr->r_idx)) {
452 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
453 caster_ptr->window |= (PW_MONSTER);
456 repair_monsters = TRUE;
457 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
458 update_monster(caster_ptr, i, FALSE);
464 msg_print(_("自然でないモンスターの存在を感じた!", "You sense the presence of unnatural beings!"));
471 * @brief 精神のあるモンスターを感知する / Detect all monsters it has mind on current panel
472 * @param caster_ptr プレーヤーへの参照ポインタ
474 * @return 効力があった場合TRUEを返す
476 bool detect_monsters_mind(player_type *caster_ptr, POSITION range)
478 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
482 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
483 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
484 monster_race *r_ptr = &r_info[m_ptr->r_idx];
485 if (!monster_is_valid(m_ptr))
488 POSITION y = m_ptr->fy;
489 POSITION x = m_ptr->fx;
491 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
494 if (!(r_ptr->flags2 & RF2_EMPTY_MIND)) {
495 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
496 caster_ptr->window |= (PW_MONSTER);
499 repair_monsters = TRUE;
500 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
501 update_monster(caster_ptr, i, FALSE);
507 msg_print(_("殺気を感じとった!", "You sense the presence of someone's mind!"));
514 * @brief 該当シンボルのモンスターを感知する / Detect all (string) monsters on current panel
515 * @param caster_ptr プレーヤーへの参照ポインタ
517 * @param Match 対応シンボルの混じったモンスター文字列(複数指定化)
518 * @return 効力があった場合TRUEを返す
520 bool detect_monsters_string(player_type *caster_ptr, POSITION range, concptr Match)
522 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
526 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
527 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
528 monster_race *r_ptr = &r_info[m_ptr->r_idx];
529 if (!monster_is_valid(m_ptr))
532 POSITION y = m_ptr->fy;
533 POSITION x = m_ptr->fx;
535 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
538 if (angband_strchr(Match, r_ptr->d_char)) {
539 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
540 caster_ptr->window |= (PW_MONSTER);
543 repair_monsters = TRUE;
544 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
545 update_monster(caster_ptr, i, FALSE);
550 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
553 msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!"));
560 * @brief flags3に対応するモンスターを感知する / A "generic" detect monsters routine, tagged to flags3
561 * @param caster_ptr プレーヤーへの参照ポインタ
563 * @param match_flag 感知フラグ
564 * @return 効力があった場合TRUEを返す
566 bool detect_monsters_xxx(player_type *caster_ptr, POSITION range, u32b match_flag)
568 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
572 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
573 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
574 monster_race *r_ptr = &r_info[m_ptr->r_idx];
575 if (!monster_is_valid(m_ptr))
578 POSITION y = m_ptr->fy;
579 POSITION x = m_ptr->fx;
581 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
584 if (r_ptr->flags3 & (match_flag)) {
585 if (is_original_ap(m_ptr)) {
586 r_ptr->r_flags3 |= (match_flag);
587 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
588 caster_ptr->window |= (PW_MONSTER);
592 repair_monsters = TRUE;
593 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
594 update_monster(caster_ptr, i, FALSE);
599 concptr desc_monsters = _("変なモンスター", "weird monsters");
601 switch (match_flag) {
603 desc_monsters = _("デーモン", "demons");
606 desc_monsters = _("アンデッド", "the undead");
610 msg_format(_("%sの存在を感じとった!", "You sense the presence of %s!"), desc_monsters);
618 * @brief 全感知処理 / Detect everything
619 * @param caster_ptr プレーヤーへの参照ポインタ
621 * @return 効力があった場合TRUEを返す
623 bool detect_all(player_type *caster_ptr, POSITION range)
626 if (detect_traps(caster_ptr, range, TRUE))
628 if (detect_doors(caster_ptr, range))
630 if (detect_stairs(caster_ptr, range))
632 if (detect_objects_gold(caster_ptr, range))
634 if (detect_objects_normal(caster_ptr, range))
636 if (detect_monsters_invis(caster_ptr, range))
638 if (detect_monsters_normal(caster_ptr, range))