1 #include "spell-kind/spells-sight.h"
2 #include "avatar/avatar.h"
3 #include "core/player-update-types.h"
4 #include "core/stuff-handler.h"
5 #include "core/window-redrawer.h"
6 #include "effect/attribute-types.h"
7 #include "effect/effect-characteristics.h"
8 #include "effect/effect-processor.h"
9 #include "floor/cave.h"
10 #include "game-option/birth-options.h"
11 #include "game-option/map-screen-options.h"
12 #include "grid/grid.h"
13 #include "io/cursor.h"
14 #include "io/input-key-acceptor.h"
15 #include "locale/english.h"
16 #include "lore/lore-store.h"
17 #include "monster-race/monster-kind-mask.h"
18 #include "monster-race/monster-race.h"
19 #include "monster-race/race-flags3.h"
20 #include "monster/monster-describer.h"
21 #include "monster/monster-description-types.h"
22 #include "monster/monster-flag-types.h"
23 #include "monster/monster-info.h"
24 #include "monster/monster-status-setter.h"
25 #include "monster/monster-status.h"
26 #include "monster/smart-learn-types.h"
27 #include "system/floor-type-definition.h"
28 #include "system/monster-race-definition.h"
29 #include "system/monster-type-definition.h"
30 #include "system/player-type-definition.h"
31 #include "target/projection-path-calculator.h"
32 #include "term/screen-processor.h"
33 #include "view/display-messages.h"
36 * @brief 視界内モンスターに魔法効果を与える / Apply a "project()" directly to all viewable monsters
39 * @return 効力があった場合TRUEを返す
42 * Note that affected monsters are NOT auto-tracked by this usage.
44 * To avoid misbehavior when monster deaths have side-effects,
45 * this is done in two passes. -- JDL
48 bool project_all_los(PlayerType *player_ptr, AttributeType typ, int dam)
50 for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
51 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
52 if (!m_ptr->is_valid()) {
56 POSITION y = m_ptr->fy;
57 POSITION x = m_ptr->fx;
58 if (!player_has_los_bold(player_ptr, y, x) || !projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
62 m_ptr->mflag.set(MonsterTemporaryFlagType::LOS);
65 BIT_FLAGS flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE;
67 for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
68 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
69 if (m_ptr->mflag.has_not(MonsterTemporaryFlagType::LOS)) {
73 m_ptr->mflag.reset(MonsterTemporaryFlagType::LOS);
74 POSITION y = m_ptr->fy;
75 POSITION x = m_ptr->fx;
77 if (project(player_ptr, 0, 0, y, x, dam, typ, flg).notice) {
86 * @brief 視界内モンスターを加速する処理 / Speed monsters
87 * @param player_ptr プレイヤーへの参照ポインタ
88 * @return 効力があった場合TRUEを返す
90 bool speed_monsters(PlayerType *player_ptr)
92 return project_all_los(player_ptr, AttributeType::OLD_SPEED, player_ptr->lev);
96 * @brief 視界内モンスターを加速する処理 / Slow monsters
97 * @param player_ptr プレイヤーへの参照ポインタ
98 * @return 効力があった場合TRUEを返す
100 bool slow_monsters(PlayerType *player_ptr, int power)
102 return project_all_los(player_ptr, AttributeType::OLD_SLOW, power);
106 * @brief 視界内モンスターを眠らせる処理 / Sleep monsters
107 * @param player_ptr プレイヤーへの参照ポインタ
108 * @return 効力があった場合TRUEを返す
110 bool sleep_monsters(PlayerType *player_ptr, int power)
112 return project_all_los(player_ptr, AttributeType::OLD_SLEEP, power);
116 * @brief 視界内の邪悪なモンスターをテレポート・アウェイさせる処理 / Banish evil monsters
117 * @param player_ptr プレイヤーへの参照ポインタ
118 * @return 効力があった場合TRUEを返す
120 bool banish_evil(PlayerType *player_ptr, int dist)
122 return project_all_los(player_ptr, AttributeType::AWAY_EVIL, dist);
126 * @brief 視界内のアンデッド・モンスターを恐怖させる処理 / Turn undead
127 * @return 効力があった場合TRUEを返す
129 bool turn_undead(PlayerType *player_ptr)
131 bool tester = (project_all_los(player_ptr, AttributeType::TURN_UNDEAD, player_ptr->lev));
133 chg_virtue(player_ptr, V_UNLIFE, -1);
139 * @brief 視界内のアンデッド・モンスターにダメージを与える処理 / Dispel undead monsters
140 * @param player_ptr プレイヤーへの参照ポインタ
141 * @return 効力があった場合TRUEを返す
143 bool dispel_undead(PlayerType *player_ptr, int dam)
145 bool tester = (project_all_los(player_ptr, AttributeType::DISP_UNDEAD, dam));
147 chg_virtue(player_ptr, V_UNLIFE, -2);
153 * @brief 視界内の邪悪なモンスターにダメージを与える処理 / Dispel evil monsters
154 * @param player_ptr プレイヤーへの参照ポインタ
155 * @return 効力があった場合TRUEを返す
157 bool dispel_evil(PlayerType *player_ptr, int dam)
159 return project_all_los(player_ptr, AttributeType::DISP_EVIL, dam);
163 * @brief 視界内の善良なモンスターにダメージを与える処理 / Dispel good monsters
164 * @param player_ptr プレイヤーへの参照ポインタ
165 * @return 効力があった場合TRUEを返す
167 bool dispel_good(PlayerType *player_ptr, int dam)
169 return project_all_los(player_ptr, AttributeType::DISP_GOOD, dam);
173 * @brief 視界内のあらゆるモンスターにダメージを与える処理 / Dispel all monsters
174 * @param player_ptr プレイヤーへの参照ポインタ
175 * @return 効力があった場合TRUEを返す
177 bool dispel_monsters(PlayerType *player_ptr, int dam)
179 return project_all_los(player_ptr, AttributeType::DISP_ALL, dam);
183 * @brief 視界内の生命のあるモンスターにダメージを与える処理 / Dispel 'living' monsters
184 * @param player_ptr プレイヤーへの参照ポインタ
185 * @return 効力があった場合TRUEを返す
187 bool dispel_living(PlayerType *player_ptr, int dam)
189 return project_all_los(player_ptr, AttributeType::DISP_LIVING, dam);
193 * @brief 視界内の悪魔系モンスターにダメージを与える処理 / Dispel 'living' monsters
194 * @param player_ptr プレイヤーへの参照ポインタ
195 * @return 効力があった場合TRUEを返す
197 bool dispel_demons(PlayerType *player_ptr, int dam)
199 return project_all_los(player_ptr, AttributeType::DISP_DEMON, dam);
203 * @brief 視界内のモンスターに「聖戦」効果を与える処理
204 * @param player_ptr プレイヤーへの参照ポインタ
205 * @return 効力があった場合TRUEを返す
207 bool crusade(PlayerType *player_ptr)
209 return project_all_los(player_ptr, AttributeType::CRUSADE, player_ptr->lev * 4);
213 * @brief 視界内モンスターを怒らせる処理 / Wake up all monsters, and speed up "los" monsters.
214 * @param player_ptr プレイヤーへの参照ポインタ
215 * @param who 怒らせる原因を起こしたモンスター(0ならばプレイヤー)
217 void aggravate_monsters(PlayerType *player_ptr, MONSTER_IDX who)
221 for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
222 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
223 if (!m_ptr->is_valid()) {
230 if (m_ptr->cdis < MAX_PLAYER_SIGHT * 2) {
231 if (m_ptr->is_asleep()) {
232 (void)set_monster_csleep(player_ptr, i, 0);
236 if (!m_ptr->is_pet()) {
237 m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
241 if (player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx)) {
242 if (!m_ptr->is_pet()) {
243 (void)set_monster_fast(player_ptr, i, m_ptr->get_remaining_acceleration() + 100);
250 msg_print(_("付近で何かが突如興奮したような感じを受けた!", "You feel a sudden stirring nearby!"));
252 msg_print(_("何かが突如興奮したような騒々しい音が遠くに聞こえた!", "You hear a sudden stirring in the distance!"));
254 if (player_ptr->riding) {
255 player_ptr->update |= PU_BONUS;
260 * @brief パニック・モンスター効果(プレイヤー視界範囲内) / Confuse monsters
261 * @param player_ptr プレイヤーへの参照ポインタ
263 * @return 作用が実際にあった場合TRUEを返す
265 bool confuse_monsters(PlayerType *player_ptr, int dam)
267 return project_all_los(player_ptr, AttributeType::OLD_CONF, dam);
271 * @brief チャーム・モンスター効果(プレイヤー視界範囲内) / Charm monsters
272 * @param player_ptr プレイヤーへの参照ポインタ
274 * @return 作用が実際にあった場合TRUEを返す
276 bool charm_monsters(PlayerType *player_ptr, int dam)
278 return project_all_los(player_ptr, AttributeType::CHARM, dam);
282 * @brief 動物魅了効果(プレイヤー視界範囲内) / Charm Animals
283 * @param player_ptr プレイヤーへの参照ポインタ
285 * @return 作用が実際にあった場合TRUEを返す
287 bool charm_animals(PlayerType *player_ptr, int dam)
289 return project_all_los(player_ptr, AttributeType::CONTROL_ANIMAL, dam);
293 * @brief モンスター朦朧効果(プレイヤー視界範囲内) / Stun monsters
294 * @param player_ptr プレイヤーへの参照ポインタ
296 * @return 作用が実際にあった場合TRUEを返す
298 bool stun_monsters(PlayerType *player_ptr, int dam)
300 return project_all_los(player_ptr, AttributeType::STUN, dam);
304 * @brief モンスター停止効果(プレイヤー視界範囲内) / Stasis monsters
305 * @param player_ptr プレイヤーへの参照ポインタ
307 * @return 作用が実際にあった場合TRUEを返す
309 bool stasis_monsters(PlayerType *player_ptr, int dam)
311 return project_all_los(player_ptr, AttributeType::STASIS, dam);
315 * @brief モンスター精神攻撃効果(プレイヤー視界範囲内) / Mindblast monsters
316 * @param player_ptr プレイヤーへの参照ポインタ
318 * @return 作用が実際にあった場合TRUEを返す
320 bool mindblast_monsters(PlayerType *player_ptr, int dam)
322 return project_all_los(player_ptr, AttributeType::PSI, dam);
326 * @brief モンスター追放効果(プレイヤー視界範囲内) / Banish all monsters
327 * @param player_ptr プレイヤーへの参照ポインタ
329 * @return 作用が実際にあった場合TRUEを返す
331 bool banish_monsters(PlayerType *player_ptr, int dist)
333 return project_all_los(player_ptr, AttributeType::AWAY_ALL, dist);
337 * @brief 邪悪退散効果(プレイヤー視界範囲内) / Turn evil
338 * @param player_ptr プレイヤーへの参照ポインタ
340 * @return 作用が実際にあった場合TRUEを返す
342 bool turn_evil(PlayerType *player_ptr, int dam)
344 return project_all_los(player_ptr, AttributeType::TURN_EVIL, dam);
348 * @brief 全モンスター退散効果(プレイヤー視界範囲内) / Turn everyone
349 * @param player_ptr プレイヤーへの参照ポインタ
351 * @return 作用が実際にあった場合TRUEを返す
353 bool turn_monsters(PlayerType *player_ptr, int dam)
355 return project_all_los(player_ptr, AttributeType::TURN_ALL, dam);
359 * @brief 死の光線(プレイヤー視界範囲内) / Death-ray all monsters (note: OBSCENELY powerful)
360 * @param player_ptr プレイヤーへの参照ポインタ
361 * @return 作用が実際にあった場合TRUEを返す
363 bool deathray_monsters(PlayerType *player_ptr)
365 return project_all_los(player_ptr, AttributeType::DEATH_RAY, player_ptr->lev * 200);
369 * @brief 調査したモンスターの情報を表示する
370 * @param player_ptr プレイヤー情報への参照ポインタ
371 * @param m_ptr モンスター情報への参照ポインタ
372 * @param r_ptr モンスター種族への参照ポインタ
374 void probed_monster_info(char *buf, PlayerType *player_ptr, MonsterEntity *m_ptr, MonsterRaceInfo *r_ptr)
376 if (!m_ptr->is_original_ap()) {
377 if (m_ptr->mflag2.has(MonsterConstantFlagType::KAGE)) {
378 m_ptr->mflag2.reset(MonsterConstantFlagType::KAGE);
381 m_ptr->ap_r_idx = m_ptr->r_idx;
382 lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
385 GAME_TEXT m_name[MAX_NLEN];
386 monster_desc(player_ptr, m_name, m_ptr, MD_IGNORE_HALLU | MD_INDEF_HIDDEN);
389 if (r_ptr->kind_flags.has_all_of(alignment_mask)) {
390 align = _("善悪", "good&evil");
391 } else if (r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
392 align = _("邪悪", "evil");
393 } else if (r_ptr->kind_flags.has(MonsterKindType::GOOD)) {
394 align = _("善良", "good");
395 } else if ((m_ptr->sub_align & (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) == (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) {
396 align = _("中立(善悪)", "neutral(good&evil)");
397 } else if (m_ptr->sub_align & SUB_ALIGN_EVIL) {
398 align = _("中立(邪悪)", "neutral(evil)");
399 } else if (m_ptr->sub_align & SUB_ALIGN_GOOD) {
400 align = _("中立(善良)", "neutral(good)");
402 align = _("中立", "neutral");
405 const auto speed = m_ptr->get_temporary_speed() - STANDARD_SPEED;
406 sprintf(buf, _("%s ... 属性:%s HP:%d/%d AC:%d 速度:%s%d 経験:", "%s ... align:%s HP:%d/%d AC:%d speed:%s%d exp:"), m_name, align, (int)m_ptr->hp,
407 (int)m_ptr->maxhp, r_ptr->ac, (speed > 0) ? "+" : "", speed);
409 if (MonsterRace(r_ptr->next_r_idx).is_valid()) {
410 strcat(buf, format("%d/%d ", m_ptr->exp, r_ptr->next_exp));
415 if (m_ptr->is_asleep()) {
416 strcat(buf, _("睡眠 ", "sleeping "));
418 if (m_ptr->is_stunned()) {
419 strcat(buf, _("朦朧 ", "stunned "));
421 if (m_ptr->is_fearful()) {
422 strcat(buf, _("恐怖 ", "scared "));
424 if (m_ptr->is_confused()) {
425 strcat(buf, _("混乱 ", "confused "));
427 if (m_ptr->is_invulnerable()) {
428 strcat(buf, _("無敵 ", "invulnerable "));
430 buf[strlen(buf) - 1] = '\0';
434 * @brief 周辺モンスターを調査する / Probe nearby monsters
435 * @return 効力があった場合TRUEを返す
437 bool probing(PlayerType *player_ptr)
439 bool cu = game_term->scr->cu;
440 bool cv = game_term->scr->cv;
441 game_term->scr->cu = 0;
442 game_term->scr->cv = 1;
446 for (int i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
447 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
448 auto *r_ptr = &monraces_info[m_ptr->r_idx];
449 if (!m_ptr->is_valid()) {
452 if (!player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx)) {
460 msg_print(_("調査中...", "Probing..."));
464 probed_monster_info(buf, player_ptr, m_ptr, r_ptr);
468 player_ptr->window_flags |= (PW_MESSAGE);
469 handle_stuff(player_ptr);
470 move_cursor_relative(m_ptr->fy, m_ptr->fx);
472 term_erase(0, 0, 255);
473 if (lore_do_probe(player_ptr, m_ptr->r_idx)) {
474 strcpy(buf, (r_ptr->name.data()));
476 msg_format("%sについてさらに詳しくなった気がする。", buf);
479 msg_format("You now know more about %s.", buf);
487 game_term->scr->cu = cu;
488 game_term->scr->cv = cv;
492 chg_virtue(player_ptr, V_KNOWLEDGE, 1);
493 msg_print(_("これで全部です。", "That's all."));