1 #include "spell-kind/spells-sight.h"
2 #include "avatar/avatar.h"
3 #include "core/stuff-handler.h"
4 #include "core/window-redrawer.h"
5 #include "effect/attribute-types.h"
6 #include "effect/effect-characteristics.h"
7 #include "effect/effect-processor.h"
8 #include "floor/cave.h"
9 #include "game-option/birth-options.h"
10 #include "game-option/map-screen-options.h"
11 #include "grid/grid.h"
12 #include "io/cursor.h"
13 #include "io/input-key-acceptor.h"
14 #include "locale/english.h"
15 #include "lore/lore-store.h"
16 #include "monster-race/monster-kind-mask.h"
17 #include "monster-race/monster-race.h"
18 #include "monster-race/race-flags3.h"
19 #include "monster/monster-describer.h"
20 #include "monster/monster-description-types.h"
21 #include "monster/monster-flag-types.h"
22 #include "monster/monster-info.h"
23 #include "monster/monster-status-setter.h"
24 #include "monster/monster-status.h"
25 #include "monster/smart-learn-types.h"
26 #include "system/floor-type-definition.h"
27 #include "system/monster-entity.h"
28 #include "system/monster-race-info.h"
29 #include "system/player-type-definition.h"
30 #include "system/redrawing-flags-updater.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, Virtue::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, Virtue::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!"));
255 if (player_ptr->riding) {
256 RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
261 * @brief パニック・モンスター効果(プレイヤー視界範囲内) / Confuse monsters
262 * @param player_ptr プレイヤーへの参照ポインタ
264 * @return 作用が実際にあった場合TRUEを返す
266 bool confuse_monsters(PlayerType *player_ptr, int dam)
268 return project_all_los(player_ptr, AttributeType::OLD_CONF, dam);
272 * @brief チャーム・モンスター効果(プレイヤー視界範囲内) / Charm monsters
273 * @param player_ptr プレイヤーへの参照ポインタ
275 * @return 作用が実際にあった場合TRUEを返す
277 bool charm_monsters(PlayerType *player_ptr, int dam)
279 return project_all_los(player_ptr, AttributeType::CHARM, dam);
283 * @brief 動物魅了効果(プレイヤー視界範囲内) / Charm Animals
284 * @param player_ptr プレイヤーへの参照ポインタ
286 * @return 作用が実際にあった場合TRUEを返す
288 bool charm_animals(PlayerType *player_ptr, int dam)
290 return project_all_los(player_ptr, AttributeType::CONTROL_ANIMAL, dam);
294 * @brief モンスター朦朧効果(プレイヤー視界範囲内) / Stun monsters
295 * @param player_ptr プレイヤーへの参照ポインタ
297 * @return 作用が実際にあった場合TRUEを返す
299 bool stun_monsters(PlayerType *player_ptr, int dam)
301 return project_all_los(player_ptr, AttributeType::STUN, dam);
305 * @brief モンスター停止効果(プレイヤー視界範囲内) / Stasis monsters
306 * @param player_ptr プレイヤーへの参照ポインタ
308 * @return 作用が実際にあった場合TRUEを返す
310 bool stasis_monsters(PlayerType *player_ptr, int dam)
312 return project_all_los(player_ptr, AttributeType::STASIS, dam);
316 * @brief モンスター精神攻撃効果(プレイヤー視界範囲内) / Mindblast monsters
317 * @param player_ptr プレイヤーへの参照ポインタ
319 * @return 作用が実際にあった場合TRUEを返す
321 bool mindblast_monsters(PlayerType *player_ptr, int dam)
323 return project_all_los(player_ptr, AttributeType::PSI, dam);
327 * @brief モンスター追放効果(プレイヤー視界範囲内) / Banish all monsters
328 * @param player_ptr プレイヤーへの参照ポインタ
330 * @return 作用が実際にあった場合TRUEを返す
332 bool banish_monsters(PlayerType *player_ptr, int dist)
334 return project_all_los(player_ptr, AttributeType::AWAY_ALL, dist);
338 * @brief 邪悪退散効果(プレイヤー視界範囲内) / Turn evil
339 * @param player_ptr プレイヤーへの参照ポインタ
341 * @return 作用が実際にあった場合TRUEを返す
343 bool turn_evil(PlayerType *player_ptr, int dam)
345 return project_all_los(player_ptr, AttributeType::TURN_EVIL, dam);
349 * @brief 全モンスター退散効果(プレイヤー視界範囲内) / Turn everyone
350 * @param player_ptr プレイヤーへの参照ポインタ
352 * @return 作用が実際にあった場合TRUEを返す
354 bool turn_monsters(PlayerType *player_ptr, int dam)
356 return project_all_los(player_ptr, AttributeType::TURN_ALL, dam);
360 * @brief 死の光線(プレイヤー視界範囲内) / Death-ray all monsters (note: OBSCENELY powerful)
361 * @param player_ptr プレイヤーへの参照ポインタ
362 * @return 作用が実際にあった場合TRUEを返す
364 bool deathray_monsters(PlayerType *player_ptr)
366 return project_all_los(player_ptr, AttributeType::DEATH_RAY, player_ptr->lev * 200);
370 * @brief 調査したモンスターの情報を表示する
371 * @param player_ptr プレイヤー情報への参照ポインタ
372 * @param m_ptr モンスター情報への参照ポインタ
373 * @param r_ptr モンスター種族への参照ポインタ
374 * @return 調査結果 善悪アライメント、最大HP、残りHP、AC、速度、ステータス
376 std::string probed_monster_info(PlayerType *player_ptr, MonsterEntity *m_ptr, MonsterRaceInfo *r_ptr)
378 if (!m_ptr->is_original_ap()) {
379 if (m_ptr->mflag2.has(MonsterConstantFlagType::KAGE)) {
380 m_ptr->mflag2.reset(MonsterConstantFlagType::KAGE);
383 m_ptr->ap_r_idx = m_ptr->r_idx;
384 lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
387 const auto m_name = monster_desc(player_ptr, m_ptr, MD_IGNORE_HALLU | MD_INDEF_HIDDEN);
390 if (r_ptr->kind_flags.has_all_of(alignment_mask)) {
391 align = _("善悪", "good&evil");
392 } else if (r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
393 align = _("邪悪", "evil");
394 } else if (r_ptr->kind_flags.has(MonsterKindType::GOOD)) {
395 align = _("善良", "good");
396 } else if ((m_ptr->sub_align & (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) == (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) {
397 align = _("中立(善悪)", "neutral(good&evil)");
398 } else if (m_ptr->sub_align & SUB_ALIGN_EVIL) {
399 align = _("中立(邪悪)", "neutral(evil)");
400 } else if (m_ptr->sub_align & SUB_ALIGN_GOOD) {
401 align = _("中立(善良)", "neutral(good)");
403 align = _("中立", "neutral");
406 const auto speed = m_ptr->get_temporary_speed() - STANDARD_SPEED;
407 constexpr auto mes = _("%s ... 属性:%s HP:%d/%d AC:%d 速度:%s%d 経験:", "%s ... align:%s HP:%d/%d AC:%d speed:%s%d exp:");
408 auto result = format(mes, m_name.data(), align, (int)m_ptr->hp, (int)m_ptr->maxhp, r_ptr->ac, (speed > 0) ? "+" : "", speed);
410 if (MonsterRace(r_ptr->next_r_idx).is_valid()) {
411 result.append(format("%d/%d ", m_ptr->exp, r_ptr->next_exp));
413 result.append("xxx ");
416 if (m_ptr->is_asleep()) {
417 result.append(_("睡眠 ", "sleeping "));
419 if (m_ptr->is_stunned()) {
420 result.append(_("朦朧 ", "stunned "));
422 if (m_ptr->is_fearful()) {
423 result.append(_("恐怖 ", "scared "));
425 if (m_ptr->is_confused()) {
426 result.append(_("混乱 ", "confused "));
428 if (m_ptr->is_invulnerable()) {
429 result.append(_("無敵 ", "invulnerable "));
435 * @brief 周辺モンスターを調査する / Probe nearby monsters
436 * @return 効力があった場合TRUEを返す
438 bool probing(PlayerType *player_ptr)
440 bool cu = game_term->scr->cu;
441 bool cv = game_term->scr->cv;
442 game_term->scr->cu = 0;
443 game_term->scr->cv = 1;
445 auto &rfu = RedrawingFlagsUpdater::get_instance();
447 for (int i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
448 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
449 auto *r_ptr = &monraces_info[m_ptr->r_idx];
450 if (!m_ptr->is_valid()) {
453 if (!player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx)) {
461 msg_print(_("調査中...", "Probing..."));
465 const auto probe_result = probed_monster_info(player_ptr, m_ptr, r_ptr);
466 prt(probe_result, 0, 0);
468 message_add(probe_result);
469 rfu.set_flag(SubWindowRedrawingFlag::MESSAGE);
470 handle_stuff(player_ptr);
471 move_cursor_relative(m_ptr->fy, m_ptr->fx);
473 term_erase(0, 0, 255);
474 if (lore_do_probe(player_ptr, m_ptr->r_idx)) {
476 msg_format("%sについてさらに詳しくなった気がする。", r_ptr->name.data());
478 std::string nm = r_ptr->name;
479 /* Leave room for making it plural. */
480 nm.resize(r_ptr->name.length() + 16);
481 plural_aux(nm.data());
482 msg_format("You now know more about %s.", nm.data());
490 game_term->scr->cu = cu;
491 game_term->scr->cv = cv;
495 chg_virtue(player_ptr, Virtue::KNOWLEDGE, 1);
496 msg_print(_("これで全部です。", "That's all."));