1 #include "spell/spells-detection.h"
2 #include "core/player-processor.h"
3 #include "dungeon/dungeon.h"
4 #include "floor/floor.h"
7 #include "monster/monster-race-hook.h"
8 #include "monster/monster-status.h"
9 #include "object/object-hook.h"
10 #include "object/object-mark-types.h"
11 #include "realm/realm-song-numbers.h"
12 #include "realm/realm-song.h"
15 * @brief プレイヤー周辺の地形を感知する
16 * @param caster_ptr プレーヤーへの参照ポインタ
19 * @param known 地形から危険フラグを外すならTRUE
20 * @return 効力があった場合TRUEを返す
22 static bool detect_feat_flag(player_type *caster_ptr, POSITION range, int flag, bool known)
24 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
29 for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++) {
30 for (POSITION x = 1; x <= caster_ptr->current_floor_ptr->width - 1; x++) {
31 int dist = distance(caster_ptr->y, caster_ptr->x, y, x);
34 g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
35 if (flag == FF_TRAP) {
36 /* Mark as detected */
37 if (dist <= range && known) {
38 if (dist <= range - 1)
39 g_ptr->info |= (CAVE_IN_DETECT);
41 g_ptr->info &= ~(CAVE_UNSAFE);
43 lite_spot(caster_ptr, y, x);
47 if (cave_have_flag_grid(g_ptr, flag)) {
48 disclose_grid(caster_ptr, y, x);
49 g_ptr->info |= (CAVE_MARK);
50 lite_spot(caster_ptr, y, x);
60 * @brief プレイヤー周辺のトラップを感知する / Detect all traps on current panel
61 * @param caster_ptr プレーヤーへの参照ポインタ
63 * @param known 感知外範囲を超える警告フラグを立てる場合TRUEを返す
64 * @return 効力があった場合TRUEを返す
66 bool detect_traps(player_type *caster_ptr, POSITION range, bool known)
68 bool detect = detect_feat_flag(caster_ptr, range, FF_TRAP, known);
71 caster_ptr->dtrap = TRUE;
73 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
76 msg_print(_("トラップの存在を感じとった!", "You sense the presence of traps!"));
83 * @brief プレイヤー周辺のドアを感知する / Detect all doors on current panel
84 * @param caster_ptr プレーヤーへの参照ポインタ
86 * @return 効力があった場合TRUEを返す
88 bool detect_doors(player_type *caster_ptr, POSITION range)
90 bool detect = detect_feat_flag(caster_ptr, range, FF_DOOR, TRUE);
92 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
95 msg_print(_("ドアの存在を感じとった!", "You sense the presence of doors!"));
102 * @brief プレイヤー周辺の階段を感知する / Detect all stairs on current panel
103 * @param caster_ptr プレーヤーへの参照ポインタ
105 * @return 効力があった場合TRUEを返す
107 bool detect_stairs(player_type *caster_ptr, POSITION range)
109 bool detect = detect_feat_flag(caster_ptr, range, FF_STAIRS, TRUE);
111 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 0)
114 msg_print(_("階段の存在を感じとった!", "You sense the presence of stairs!"));
121 * @brief プレイヤー周辺の地形財宝を感知する / Detect any treasure on the current panel
122 * @param caster_ptr プレーヤーへの参照ポインタ
124 * @return 効力があった場合TRUEを返す
126 bool detect_treasure(player_type *caster_ptr, POSITION range)
128 bool detect = detect_feat_flag(caster_ptr, range, FF_HAS_GOLD, TRUE);
130 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
133 msg_print(_("埋蔵された財宝の存在を感じとった!", "You sense the presence of buried treasure!"));
139 * @brief プレイヤー周辺のアイテム財宝を感知する / Detect all "gold" objects on the current panel
140 * @param caster_ptr プレーヤーへの参照ポインタ
142 * @return 効力があった場合TRUEを返す
144 bool detect_objects_gold(player_type *caster_ptr, POSITION range)
146 POSITION range2 = range;
147 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
153 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
154 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
156 if (!OBJECT_IS_VALID(o_ptr))
158 if (OBJECT_IS_HELD_MONSTER(o_ptr))
163 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range2)
166 if (o_ptr->tval == TV_GOLD) {
167 o_ptr->marked |= OM_FOUND;
168 lite_spot(caster_ptr, y, x);
173 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
176 msg_print(_("財宝の存在を感じとった!", "You sense the presence of treasure!"));
179 if (detect_monsters_string(caster_ptr, range, "$")) {
187 * @brief 通常のアイテムオブジェクトを感知する / Detect all "normal" objects on the current panel
188 * @param caster_ptr プレーヤーへの参照ポインタ
190 * @return 効力があった場合TRUEを返す
192 bool detect_objects_normal(player_type *caster_ptr, POSITION range)
194 POSITION range2 = range;
195 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
199 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
200 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
202 if (!OBJECT_IS_VALID(o_ptr))
204 if (OBJECT_IS_HELD_MONSTER(o_ptr))
207 POSITION y = o_ptr->iy;
208 POSITION x = o_ptr->ix;
210 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range2)
213 if (o_ptr->tval != TV_GOLD) {
214 o_ptr->marked |= OM_FOUND;
215 lite_spot(caster_ptr, y, x);
220 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 6)
223 msg_print(_("アイテムの存在を感じとった!", "You sense the presence of objects!"));
226 if (detect_monsters_string(caster_ptr, range, "!=?|/`")) {
234 * @brief 魔法効果のあるのアイテムオブジェクトを感知する / Detect all "magic" objects on the current panel.
235 * @param caster_ptr プレーヤーへの参照ポインタ
237 * @return 効力があった場合TRUEを返す
240 * This will light up all spaces with "magic" items, including artifacts,
241 * ego-items, potions, scrolls, books, rods, wands, staffs, amulets, rings,
242 * and "enchanted" items of the "good" variety.
244 * It can probably be argued that this function is now too powerful.
247 bool detect_objects_magic(player_type *caster_ptr, POSITION range)
249 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
254 for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
255 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
257 if (!OBJECT_IS_VALID(o_ptr))
259 if (OBJECT_IS_HELD_MONSTER(o_ptr))
262 POSITION y = o_ptr->iy;
263 POSITION x = o_ptr->ix;
265 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
269 if (object_is_artifact(o_ptr) || object_is_ego(o_ptr) || (tv == TV_WHISTLE) || (tv == TV_AMULET) || (tv == TV_RING) || (tv == TV_STAFF)
270 || (tv == TV_WAND) || (tv == TV_ROD) || (tv == TV_SCROLL) || (tv == TV_POTION) || (tv == TV_LIFE_BOOK) || (tv == TV_SORCERY_BOOK)
271 || (tv == TV_NATURE_BOOK) || (tv == TV_CHAOS_BOOK) || (tv == TV_DEATH_BOOK) || (tv == TV_TRUMP_BOOK) || (tv == TV_ARCANE_BOOK)
272 || (tv == TV_CRAFT_BOOK) || (tv == TV_DAEMON_BOOK) || (tv == TV_CRUSADE_BOOK) || (tv == TV_MUSIC_BOOK) || (tv == TV_HISSATSU_BOOK)
273 || (tv == TV_HEX_BOOK) || ((o_ptr->to_a > 0) || (o_ptr->to_h + o_ptr->to_d > 0))) {
274 o_ptr->marked |= OM_FOUND;
275 lite_spot(caster_ptr, y, x);
281 msg_print(_("魔法のアイテムの存在を感じとった!", "You sense the presence of magic objects!"));
288 * @brief 一般のモンスターを感知する / Detect all "normal" monsters on the current panel
289 * @param caster_ptr プレーヤーへの参照ポインタ
291 * @return 効力があった場合TRUEを返す
293 bool detect_monsters_normal(player_type *caster_ptr, POSITION range)
295 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
299 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
300 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
301 monster_race *r_ptr = &r_info[m_ptr->r_idx];
302 if (!monster_is_valid(m_ptr))
305 POSITION y = m_ptr->fy;
306 POSITION x = m_ptr->fx;
307 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
310 if (!(r_ptr->flags2 & RF2_INVISIBLE) || caster_ptr->see_inv) {
311 repair_monsters = TRUE;
312 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
313 update_monster(caster_ptr, i, FALSE);
318 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
321 msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!"));
328 * @brief 不可視のモンスターを感知する / Detect all "invisible" monsters around the player
329 * @param caster_ptr プレーヤーへの参照ポインタ
331 * @return 効力があった場合TRUEを返す
333 bool detect_monsters_invis(player_type *caster_ptr, POSITION range)
335 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
339 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
340 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
341 monster_race *r_ptr = &r_info[m_ptr->r_idx];
343 if (!monster_is_valid(m_ptr))
346 POSITION y = m_ptr->fy;
347 POSITION x = m_ptr->fx;
349 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
352 if (r_ptr->flags2 & RF2_INVISIBLE) {
353 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
354 caster_ptr->window |= (PW_MONSTER);
357 repair_monsters = TRUE;
358 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
359 update_monster(caster_ptr, i, FALSE);
364 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
367 msg_print(_("透明な生物の存在を感じとった!", "You sense the presence of invisible creatures!"));
374 * @brief 邪悪なモンスターを感知する / Detect all "evil" monsters on current panel
375 * @param caster_ptr プレーヤーへの参照ポインタ
377 * @return 効力があった場合TRUEを返す
379 bool detect_monsters_evil(player_type *caster_ptr, POSITION range)
381 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
385 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
386 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
387 monster_race *r_ptr = &r_info[m_ptr->r_idx];
388 if (!monster_is_valid(m_ptr))
391 POSITION y = m_ptr->fy;
392 POSITION x = m_ptr->fx;
394 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
397 if (r_ptr->flags3 & RF3_EVIL) {
398 if (is_original_ap(m_ptr)) {
399 r_ptr->r_flags3 |= (RF3_EVIL);
400 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
401 caster_ptr->window |= (PW_MONSTER);
405 repair_monsters = TRUE;
406 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
407 update_monster(caster_ptr, i, FALSE);
413 msg_print(_("邪悪なる生物の存在を感じとった!", "You sense the presence of evil creatures!"));
420 * @brief 無生命のモンスターを感知する(アンデッド、悪魔系を含む) / Detect all "nonliving", "undead" or "demonic" monsters on current panel
421 * @param caster_ptr プレーヤーへの参照ポインタ
423 * @return 効力があった場合TRUEを返す
425 bool detect_monsters_nonliving(player_type *caster_ptr, POSITION range)
427 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
431 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
432 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
433 if (!monster_is_valid(m_ptr))
436 POSITION y = m_ptr->fy;
437 POSITION x = m_ptr->fx;
438 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
441 if (!monster_living(m_ptr->r_idx)) {
442 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
443 caster_ptr->window |= (PW_MONSTER);
446 repair_monsters = TRUE;
447 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
448 update_monster(caster_ptr, i, FALSE);
454 msg_print(_("自然でないモンスターの存在を感じた!", "You sense the presence of unnatural beings!"));
461 * @brief 精神のあるモンスターを感知する / Detect all monsters it has mind on current panel
462 * @param caster_ptr プレーヤーへの参照ポインタ
464 * @return 効力があった場合TRUEを返す
466 bool detect_monsters_mind(player_type *caster_ptr, POSITION range)
468 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
472 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
473 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
474 monster_race *r_ptr = &r_info[m_ptr->r_idx];
475 if (!monster_is_valid(m_ptr))
478 POSITION y = m_ptr->fy;
479 POSITION x = m_ptr->fx;
481 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
484 if (!(r_ptr->flags2 & RF2_EMPTY_MIND)) {
485 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
486 caster_ptr->window |= (PW_MONSTER);
489 repair_monsters = TRUE;
490 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
491 update_monster(caster_ptr, i, FALSE);
497 msg_print(_("殺気を感じとった!", "You sense the presence of someone's mind!"));
504 * @brief 該当シンボルのモンスターを感知する / Detect all (string) monsters on current panel
505 * @param caster_ptr プレーヤーへの参照ポインタ
507 * @param Match 対応シンボルの混じったモンスター文字列(複数指定化)
508 * @return 効力があった場合TRUEを返す
510 bool detect_monsters_string(player_type *caster_ptr, POSITION range, concptr Match)
512 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
516 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
517 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
518 monster_race *r_ptr = &r_info[m_ptr->r_idx];
519 if (!monster_is_valid(m_ptr))
522 POSITION y = m_ptr->fy;
523 POSITION x = m_ptr->fx;
525 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
528 if (my_strchr(Match, r_ptr->d_char)) {
529 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
530 caster_ptr->window |= (PW_MONSTER);
533 repair_monsters = TRUE;
534 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
535 update_monster(caster_ptr, i, FALSE);
540 if (music_singing(caster_ptr, MUSIC_DETECT) && SINGING_COUNT(caster_ptr) > 3)
543 msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!"));
550 * @brief flags3に対応するモンスターを感知する / A "generic" detect monsters routine, tagged to flags3
551 * @param caster_ptr プレーヤーへの参照ポインタ
553 * @param match_flag 感知フラグ
554 * @return 効力があった場合TRUEを返す
556 bool detect_monsters_xxx(player_type *caster_ptr, POSITION range, u32b match_flag)
558 if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
562 for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
563 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
564 monster_race *r_ptr = &r_info[m_ptr->r_idx];
565 if (!monster_is_valid(m_ptr))
568 POSITION y = m_ptr->fy;
569 POSITION x = m_ptr->fx;
571 if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
574 if (r_ptr->flags3 & (match_flag)) {
575 if (is_original_ap(m_ptr)) {
576 r_ptr->r_flags3 |= (match_flag);
577 if (caster_ptr->monster_race_idx == m_ptr->r_idx) {
578 caster_ptr->window |= (PW_MONSTER);
582 repair_monsters = TRUE;
583 m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
584 update_monster(caster_ptr, i, FALSE);
589 concptr desc_monsters = _("変なモンスター", "weird monsters");
591 switch (match_flag) {
593 desc_monsters = _("デーモン", "demons");
596 desc_monsters = _("アンデッド", "the undead");
600 msg_format(_("%sの存在を感じとった!", "You sense the presence of %s!"), desc_monsters);
608 * @brief 全感知処理 / Detect everything
609 * @param caster_ptr プレーヤーへの参照ポインタ
611 * @return 効力があった場合TRUEを返す
613 bool detect_all(player_type *caster_ptr, POSITION range)
616 if (detect_traps(caster_ptr, range, TRUE))
618 if (detect_doors(caster_ptr, range))
620 if (detect_stairs(caster_ptr, range))
622 if (detect_objects_gold(caster_ptr, range))
624 if (detect_objects_normal(caster_ptr, range))
626 if (detect_monsters_invis(caster_ptr, range))
628 if (detect_monsters_normal(caster_ptr, range))