1 #include "system/angband.h"
2 #include "core/stuff-handler.h"
4 #include "main/sound-definitions-table.h"
7 #include "io/write-diary.h"
8 #include "autopick/autopick-pref-processor.h"
9 #include "cmd/cmd-draw.h"
10 #include "cmd/cmd-dump.h"
11 #include "dungeon/dungeon.h"
12 #include "floor/floor.h"
13 #include "grid/grid.h"
14 #include "monster/monster.h"
15 #include "monster/monster-status.h"
16 #include "spell/monster-spell.h"
17 #include "monster/monster-process.h"
18 #include "spell/spells2.h"
19 #include "spell/spells-summon.h"
20 #include "monster/monsterrace-hook.h"
21 #include "object/object-curse.h"
22 #include "object/artifact.h"
25 #include "player/player-effects.h"
26 #include "player/player-personality.h"
27 #include "view/display-main-window.h"
28 #include "world/world.h"
34 * @brief モンスターIDからPOWERFULフラグの有無を取得する /
35 * @param floor_ptr 現在フロアへの参照ポインタ
36 * @param m_idx モンスターID
37 * @return POWERFULフラグがあればTRUE、なければFALSEを返す。
39 bool monster_is_powerful(floor_type *floor_ptr, MONSTER_IDX m_idx)
41 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
42 monster_race *r_ptr = &r_info[m_ptr->r_idx];
43 bool powerful = r_ptr->flags2 & RF2_POWERFUL ? TRUE : FALSE;
49 * @brief モンスターIDからモンスターのレベルを取得する(ただし最低1を保証する) /
50 * @param m_idx モンスターID
53 DEPTH monster_level_idx(floor_type *floor_ptr, MONSTER_IDX m_idx)
55 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
56 monster_race *r_ptr = &r_info[m_ptr->r_idx];
57 DEPTH rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);
63 * @brief モンスターに与えたダメージの修正処理 /
64 * Modify the physical damage done to the monster.
65 * @param target_ptr プレーヤーへの参照ポインタ
66 * @param m_ptr ダメージを受けるモンスターの構造体参照ポインタ
68 * @param is_psy_spear 攻撃手段が光の剣ならばTRUE
69 * @return 修正を行った結果のダメージ量
72 * (for example when it's invulnerable or shielded)
73 * ToDo: Accept a damage-type to calculate the modified damage from
74 * things like fire, frost, lightning, poison, ... attacks.
75 * "type" is not yet used and should be 0.
78 HIT_POINT mon_damage_mod(player_type *target_ptr, monster_type *m_ptr, HIT_POINT dam, bool is_psy_spear)
80 monster_race *r_ptr = &r_info[m_ptr->r_idx];
82 if ((r_ptr->flagsr & RFR_RES_ALL) && dam > 0)
85 if ((dam == 0) && one_in_(3)) dam = 1;
88 if (MON_INVULNER(m_ptr))
92 if (!target_ptr->blind && is_seen(m_ptr))
94 msg_print(_("バリアを切り裂いた!", "The barrier is penetrated!"));
97 else if (!one_in_(PENETRATE_INVULNERABILITY))
108 * @brief モンスターに与えたダメージを元に経験値を加算する /
109 * Calculate experience point to be get
110 * @param dam 与えたダメージ量
111 * @param m_ptr ダメージを与えたモンスターの構造体参照ポインタ
115 * Even the 64 bit operation is not big enough to avoid overflaw
116 * unless we carefully choose orders of multiplication and division.
117 * Get the coefficient first, and multiply (potentially huge) base
118 * experience point of a monster later.
121 static void get_exp_from_mon(player_type *target_ptr, HIT_POINT dam, monster_type *m_ptr)
123 monster_race *r_ptr = &r_info[m_ptr->r_idx];
125 if (!monster_is_valid(m_ptr)) return;
126 if (is_pet(m_ptr) || target_ptr->phase_out) return;
129 * todo 変数宣言と代入を同時に実行するとコンパイル警告が出る
138 * - Ratio of monster's level to player's level effects
139 * - Varying speed effects
140 * - Get a fraction in proportion of damage point
142 new_exp = r_ptr->level * SPEED_TO_ENERGY(m_ptr->mspeed) * dam;
145 div_l = (target_ptr->max_plv + 2) * SPEED_TO_ENERGY(r_ptr->speed);
147 /* Use (average maxhp * 2) as a denominator */
148 if (!(r_ptr->flags1 & RF1_FORCE_MAXHP))
149 s64b_mul(&div_h, &div_l, 0, r_ptr->hdice * (ironman_nightmare ? 2 : 1) * (r_ptr->hside + 1));
151 s64b_mul(&div_h, &div_l, 0, r_ptr->hdice * (ironman_nightmare ? 2 : 1) * r_ptr->hside * 2);
153 /* Special penalty in the wilderness */
154 if (!target_ptr->current_floor_ptr->dun_level && (!(r_ptr->flags8 & RF8_WILD_ONLY) || !(r_ptr->flags1 & RF1_UNIQUE)))
155 s64b_mul(&div_h, &div_l, 0, 5);
157 /* Do division first to prevent overflaw */
158 s64b_div(&new_exp, &new_exp_frac, div_h, div_l);
160 /* Special penalty for mutiply-monster */
161 if ((r_ptr->flags2 & RF2_MULTIPLY) || (m_ptr->r_idx == MON_DAWN))
163 int monnum_penarty = r_ptr->r_akills / 400;
164 if (monnum_penarty > 8) monnum_penarty = 8;
166 while (monnum_penarty--)
169 s64b_RSHIFT(new_exp, new_exp_frac, 2);
173 /* Special penalty for rest_and_shoot exp scum */
174 if ((m_ptr->dealt_damage > m_ptr->max_maxhp) && (m_ptr->hp >= 0))
176 int over_damage = m_ptr->dealt_damage / m_ptr->max_maxhp;
177 if (over_damage > 32) over_damage = 32;
179 while (over_damage--)
182 s64b_mul(&new_exp, &new_exp_frac, 0, 9);
183 s64b_div(&new_exp, &new_exp_frac, 0, 10);
187 s64b_mul(&new_exp, &new_exp_frac, 0, r_ptr->mexp);
188 gain_exp_64(target_ptr, new_exp, new_exp_frac);
193 * @brief モンスターの時限ステータスを取得する
194 * @param floor_ptr 現在フロアへの参照ポインタ
195 * @return m_idx モンスターの参照ID
196 * @return mproc_type モンスターの時限ステータスID
199 int get_mproc_idx(floor_type *floor_ptr, MONSTER_IDX m_idx, int mproc_type)
201 s16b *cur_mproc_list = floor_ptr->mproc_list[mproc_type];
202 for (int i = floor_ptr->mproc_max[mproc_type] - 1; i >= 0; i--)
204 if (cur_mproc_list[i] == m_idx) return i;
212 * @brief モンスターの時限ステータスリストを追加する
213 * @param floor_ptr 現在フロアへの参照ポインタ
214 * @return m_idx モンスターの参照ID
215 * @return mproc_type 追加したいモンスターの時限ステータスID
218 static void mproc_add(floor_type *floor_ptr, MONSTER_IDX m_idx, int mproc_type)
220 if (floor_ptr->mproc_max[mproc_type] < current_world_ptr->max_m_idx)
222 floor_ptr->mproc_list[mproc_type][floor_ptr->mproc_max[mproc_type]++] = (s16b)m_idx;
228 * @brief モンスターの時限ステータスリストを削除
229 * @param floor_ptr 現在フロアへの参照ポインタ
230 * @return m_idx モンスターの参照ID
231 * @return mproc_type 削除したいモンスターの時限ステータスID
234 static void mproc_remove(floor_type *floor_ptr, MONSTER_IDX m_idx, int mproc_type)
236 int mproc_idx = get_mproc_idx(floor_ptr, m_idx, mproc_type);
239 floor_ptr->mproc_list[mproc_type][mproc_idx] = floor_ptr->mproc_list[mproc_type][--floor_ptr->mproc_max[mproc_type]];
245 * @brief モンスターの時限ステータスリストを初期化する / Initialize monster process
246 * @param floor_ptr 現在フロアへの参照ポインタ
249 void mproc_init(floor_type *floor_ptr)
251 /* Reset "target_ptr->current_floor_ptr->mproc_max[]" */
252 for (int i = 0; i < MAX_MTIMED; i++)
254 floor_ptr->mproc_max[i] = 0;
257 /* Process the monsters (backwards) */
258 for (MONSTER_IDX i = floor_ptr->m_max - 1; i >= 1; i--)
261 m_ptr = &floor_ptr->m_list[i];
263 /* Ignore "dead" monsters */
264 if (!monster_is_valid(m_ptr)) continue;
266 for (int cmi = 0; cmi < MAX_MTIMED; cmi++)
268 if (m_ptr->mtimed[cmi]) mproc_add(floor_ptr, i, cmi);
275 * @brief モンスターの睡眠状態値をセットする。0で起きる。 /
276 * Set "m_ptr->mtimed[MTIMED_CSLEEP]", notice observable changes
277 * @param target_ptr プレーヤーへの参照ポインタ
278 * @param m_idx モンスター参照ID
280 * @return 別途更新処理が必要な場合TRUEを返す
282 bool set_monster_csleep(player_type *target_ptr, MONSTER_IDX m_idx, int v)
284 floor_type *floor_ptr = target_ptr->current_floor_ptr;
285 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
287 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
291 if (!MON_CSLEEP(m_ptr))
293 mproc_add(floor_ptr, m_idx, MTIMED_CSLEEP);
300 if (MON_CSLEEP(m_ptr))
302 mproc_remove(floor_ptr, m_idx, MTIMED_CSLEEP);
308 m_ptr->mtimed[MTIMED_CSLEEP] = (s16b)v;
310 if (!notice) return FALSE;
314 /* Update health bar as needed */
315 if (target_ptr->health_who == m_idx) target_ptr->redraw |= (PR_HEALTH);
316 if (target_ptr->riding == m_idx) target_ptr->redraw |= (PR_UHEALTH);
319 if (r_info[m_ptr->r_idx].flags7 & RF7_HAS_LD_MASK) target_ptr->update |= (PU_MON_LITE);
326 * @brief モンスターの加速状態値をセット /
327 * Set "m_ptr->mtimed[MTIMED_FAST]", notice observable changes
328 * @param target_ptr プレーヤーへの参照ポインタ
329 * @param m_idx モンスター参照ID
331 * @return 別途更新処理が必要な場合TRUEを返す
333 bool set_monster_fast(player_type *target_ptr, MONSTER_IDX m_idx, int v)
335 floor_type *floor_ptr = target_ptr->current_floor_ptr;
336 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
338 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
342 if (!MON_FAST(m_ptr))
344 mproc_add(floor_ptr, m_idx, MTIMED_FAST);
353 mproc_remove(floor_ptr, m_idx, MTIMED_FAST);
359 m_ptr->mtimed[MTIMED_FAST] = (s16b)v;
361 if (!notice) return FALSE;
363 if ((target_ptr->riding == m_idx) && !target_ptr->leaving) target_ptr->update |= (PU_BONUS);
370 * Set "m_ptr->mtimed[MTIMED_SLOW]", notice observable changes
372 bool set_monster_slow(player_type *target_ptr, MONSTER_IDX m_idx, int v)
374 floor_type *floor_ptr = target_ptr->current_floor_ptr;
375 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
377 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
381 if (!MON_SLOW(m_ptr))
383 mproc_add(floor_ptr, m_idx, MTIMED_SLOW);
392 mproc_remove(floor_ptr, m_idx, MTIMED_SLOW);
398 m_ptr->mtimed[MTIMED_SLOW] = (s16b)v;
400 if (!notice) return FALSE;
402 if ((target_ptr->riding == m_idx) && !target_ptr->leaving) target_ptr->update |= (PU_BONUS);
409 * @brief モンスターの朦朧状態値をセット /
410 * Set "m_ptr->mtimed[MTIMED_STUNNED]", notice observable changes
411 * @param target_ptr プレーヤーへの参照ポインタ
412 * @param m_idx モンスター参照ID
414 * @return 別途更新処理が必要な場合TRUEを返す
416 bool set_monster_stunned(player_type *target_ptr, MONSTER_IDX m_idx, int v)
418 floor_type *floor_ptr = target_ptr->current_floor_ptr;
419 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
421 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
425 if (!MON_STUNNED(m_ptr))
427 mproc_add(floor_ptr, m_idx, MTIMED_STUNNED);
434 if (MON_STUNNED(m_ptr))
436 mproc_remove(floor_ptr, m_idx, MTIMED_STUNNED);
442 m_ptr->mtimed[MTIMED_STUNNED] = (s16b)v;
449 * @brief モンスターの混乱状態値をセット /
450 * Set "m_ptr->mtimed[MTIMED_CONFUSED]", notice observable changes
451 * @param target_ptr プレーヤーへの参照ポインタ
452 * @param m_idx モンスター参照ID
454 * @return 別途更新処理が必要な場合TRUEを返す
456 bool set_monster_confused(player_type *target_ptr, MONSTER_IDX m_idx, int v)
458 floor_type *floor_ptr = target_ptr->current_floor_ptr;
459 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
461 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
465 if (!MON_CONFUSED(m_ptr))
467 mproc_add(floor_ptr, m_idx, MTIMED_CONFUSED);
474 if (MON_CONFUSED(m_ptr))
476 mproc_remove(floor_ptr, m_idx, MTIMED_CONFUSED);
482 m_ptr->mtimed[MTIMED_CONFUSED] = (s16b)v;
489 * @brief モンスターの恐慌状態値をセット /
490 * Set "m_ptr->mtimed[MTIMED_MONFEAR]", notice observable changes
491 * @param target_ptr プレーヤーへの参照ポインタ
492 * @param m_idx モンスター参照ID
494 * @return 別途更新処理が必要な場合TRUEを返す
496 bool set_monster_monfear(player_type *target_ptr, MONSTER_IDX m_idx, int v)
498 floor_type *floor_ptr = target_ptr->current_floor_ptr;
499 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
501 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
505 if (!MON_MONFEAR(m_ptr))
507 mproc_add(floor_ptr, m_idx, MTIMED_MONFEAR);
514 if (MON_MONFEAR(m_ptr))
516 mproc_remove(floor_ptr, m_idx, MTIMED_MONFEAR);
522 m_ptr->mtimed[MTIMED_MONFEAR] = (s16b)v;
524 if (!notice) return FALSE;
528 /* Update health bar as needed */
529 if (target_ptr->health_who == m_idx) target_ptr->redraw |= (PR_HEALTH);
530 if (target_ptr->riding == m_idx) target_ptr->redraw |= (PR_UHEALTH);
538 * @brief モンスターの無敵状態値をセット /
539 * Set "m_ptr->mtimed[MTIMED_INVULNER]", notice observable changes
540 * @param target_ptr プレーヤーへの参照ポインタ
541 * @param m_idx モンスター参照ID
543 * @param energy_need TRUEならば無敵解除時に行動ターン消費を行う
544 * @return 別途更新処理が必要な場合TRUEを返す
546 bool set_monster_invulner(player_type *target_ptr, MONSTER_IDX m_idx, int v, bool energy_need)
548 floor_type *floor_ptr = target_ptr->current_floor_ptr;
549 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
551 v = (v > 200) ? 200 : (v < 0) ? 0 : v;
555 if (!MON_INVULNER(m_ptr))
557 mproc_add(floor_ptr, m_idx, MTIMED_INVULNER);
564 if (MON_INVULNER(m_ptr))
566 mproc_remove(floor_ptr, m_idx, MTIMED_INVULNER);
567 if (energy_need && !target_ptr->wild_mode) m_ptr->energy_need += ENERGY_NEED();
573 m_ptr->mtimed[MTIMED_INVULNER] = (s16b)v;
575 if (!notice) return FALSE;
579 /* Update health bar as needed */
580 if (target_ptr->health_who == m_idx) target_ptr->redraw |= (PR_HEALTH);
581 if (target_ptr->riding == m_idx) target_ptr->redraw |= (PR_UHEALTH);
588 static u32b csleep_noise;
591 * @brief モンスターの各種状態値を時間経過により更新するサブルーチン
592 * @param floor_ptr 現在フロアへの参照ポインタ
593 * @param m_idx モンスター参照ID
594 * @param mtimed_idx 更新するモンスターの時限ステータスID
597 static void process_monsters_mtimed_aux(player_type *target_ptr, MONSTER_IDX m_idx, int mtimed_idx)
599 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
605 monster_race *r_ptr = &r_info[m_ptr->r_idx];
607 /* Assume does not wake up */
610 /* Hack -- Require proximity */
611 if (m_ptr->cdis < AAF_LIMIT)
613 /* Handle "sensing radius" */
614 if (m_ptr->cdis <= (is_pet(m_ptr) ? ((r_ptr->aaf > MAX_SIGHT) ? MAX_SIGHT : r_ptr->aaf) : r_ptr->aaf))
620 /* Handle "sight" and "aggravation" */
621 else if ((m_ptr->cdis <= MAX_SIGHT) && (player_has_los_bold(target_ptr, m_ptr->fy, m_ptr->fx)))
630 u32b notice = randint0(1024);
632 /* Nightmare monsters are more alert */
633 if (ironman_nightmare) notice /= 2;
635 /* Hack -- See if monster "notices" player */
636 if ((notice * notice * notice) > csleep_noise) break;
638 /* Hack -- amount of "waking" */
639 /* Wake up faster near the player */
640 int d = (m_ptr->cdis < AAF_LIMIT / 2) ? (AAF_LIMIT / m_ptr->cdis) : 1;
642 /* Hack -- amount of "waking" is affected by speed of player */
643 d = (d * SPEED_TO_ENERGY(target_ptr->pspeed)) / 10;
646 /* Monster wakes up "a little bit" */
649 if (!set_monster_csleep(target_ptr, m_idx, MON_CSLEEP(m_ptr) - d))
651 /* Notice the "not waking up" */
652 if (is_original_ap_and_seen(target_ptr, m_ptr))
654 /* Hack -- Count the ignores */
655 if (r_ptr->r_ignore < MAX_UCHAR) r_ptr->r_ignore++;
661 /* Notice the "waking up" */
664 GAME_TEXT m_name[MAX_NLEN];
665 monster_desc(target_ptr, m_name, m_ptr, 0);
666 msg_format(_("%^sが目を覚ました。", "%^s wakes up."), m_name);
669 if (is_original_ap_and_seen(target_ptr, m_ptr))
671 /* Hack -- Count the wakings */
672 if (r_ptr->r_wake < MAX_UCHAR) r_ptr->r_wake++;
679 /* Reduce by one, note if expires */
680 if (set_monster_fast(target_ptr, m_idx, MON_FAST(m_ptr) - 1))
684 GAME_TEXT m_name[MAX_NLEN];
685 monster_desc(target_ptr, m_name, m_ptr, 0);
686 msg_format(_("%^sはもう加速されていない。", "%^s is no longer fast."), m_name);
693 /* Reduce by one, note if expires */
694 if (set_monster_slow(target_ptr, m_idx, MON_SLOW(m_ptr) - 1))
698 GAME_TEXT m_name[MAX_NLEN];
699 monster_desc(target_ptr, m_name, m_ptr, 0);
700 msg_format(_("%^sはもう減速されていない。", "%^s is no longer slow."), m_name);
708 int rlev = r_info[m_ptr->r_idx].level;
710 /* Recover from stun */
711 if (set_monster_stunned(target_ptr, m_idx, (randint0(10000) <= rlev * rlev) ? 0 : (MON_STUNNED(m_ptr) - 1)))
713 /* Message if visible */
716 GAME_TEXT m_name[MAX_NLEN];
717 monster_desc(target_ptr, m_name, m_ptr, 0);
718 msg_format(_("%^sは朦朧状態から立ち直った。", "%^s is no longer stunned."), m_name);
725 case MTIMED_CONFUSED:
727 /* Reduce the confusion */
728 if (!set_monster_confused(target_ptr, m_idx, MON_CONFUSED(m_ptr) - randint1(r_info[m_ptr->r_idx].level / 20 + 1)))
730 /* Message if visible */
733 GAME_TEXT m_name[MAX_NLEN];
734 monster_desc(target_ptr, m_name, m_ptr, 0);
735 msg_format(_("%^sは混乱から立ち直った。", "%^s is no longer confused."), m_name);
743 /* Reduce the fear */
744 if (!set_monster_monfear(target_ptr, m_idx, MON_MONFEAR(m_ptr) - randint1(r_info[m_ptr->r_idx].level / 20 + 1)))
750 GAME_TEXT m_name[MAX_NLEN];
755 /* Acquire the monster possessive */
756 monster_desc(target_ptr, m_poss, m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE);
758 monster_desc(target_ptr, m_name, m_ptr, 0);
760 msg_format("%^sは勇気を取り戻した。", m_name);
762 msg_format("%^s recovers %s courage.", m_name, m_poss);
769 case MTIMED_INVULNER:
771 /* Reduce by one, note if expires */
772 if (!set_monster_invulner(target_ptr, m_idx, MON_INVULNER(m_ptr) - 1, TRUE))
777 GAME_TEXT m_name[MAX_NLEN];
778 monster_desc(target_ptr, m_name, m_ptr, 0);
779 msg_format(_("%^sはもう無敵でない。", "%^s is no longer invulnerable."), m_name);
789 * @brief 全モンスターの各種状態値を時間経過により更新するメインルーチン
790 * @param mtimed_idx 更新するモンスターの時限ステータスID
791 * @param target_ptr プレーヤーへの参照ポインタ
794 * Process the counters of monsters (once per 10 game turns)\n
795 * These functions are to process monsters' counters same as player's.
797 void process_monsters_mtimed(player_type *target_ptr, int mtimed_idx)
799 floor_type *floor_ptr = target_ptr->current_floor_ptr;
800 s16b *cur_mproc_list = floor_ptr->mproc_list[mtimed_idx];
802 /* Hack -- calculate the "player noise" */
803 if (mtimed_idx == MTIMED_CSLEEP) csleep_noise = (1L << (30 - target_ptr->skill_stl));
805 /* Process the monsters (backwards) */
806 for (int i = floor_ptr->mproc_max[mtimed_idx] - 1; i >= 0; i--)
808 process_monsters_mtimed_aux(target_ptr, cur_mproc_list[i], mtimed_idx);
814 * @brief モンスターへの魔力消去処理
815 * @param target_ptr プレーヤーへの参照ポインタ
816 * @param m_idx 魔力消去を受けるモンスターの参照ID
819 void dispel_monster_status(player_type *target_ptr, MONSTER_IDX m_idx)
821 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
822 GAME_TEXT m_name[MAX_NLEN];
824 monster_desc(target_ptr, m_name, m_ptr, 0);
825 if (set_monster_invulner(target_ptr, m_idx, 0, TRUE))
827 if (m_ptr->ml) msg_format(_("%sはもう無敵ではない。", "%^s is no longer invulnerable."), m_name);
830 if (set_monster_fast(target_ptr, m_idx, 0))
832 if (m_ptr->ml) msg_format(_("%sはもう加速されていない。", "%^s is no longer fast."), m_name);
835 if (set_monster_slow(target_ptr, m_idx, 0))
837 if (m_ptr->ml) msg_format(_("%sはもう減速されていない。", "%^s is no longer slow."), m_name);
843 * @brief モンスターの時間停止処理
844 * @param target_ptr プレーヤーへの参照ポインタ
845 * @param num 時間停止を行った敵が行動できる回数
846 * @param who 時間停止処理の主体ID
847 * @param vs_player TRUEならば時間停止開始処理を行う
848 * @return 時間停止が行われている状態ならばTRUEを返す
850 bool set_monster_timewalk(player_type *target_ptr, int num, MONSTER_IDX who, bool vs_player)
852 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[hack_m_idx]; /* the world monster */
854 if (current_world_ptr->timewalk_m_idx) return FALSE;
858 GAME_TEXT m_name[MAX_NLEN];
859 monster_desc(target_ptr, m_name, m_ptr, 0);
862 msg_format(_("「『ザ・ワールド』!時は止まった!」", "%s yells 'The World! Time has stopped!'"), m_name);
864 msg_format(_("「時よ!」", "%s yells 'Time!'"), m_name);
865 else msg_print("hek!");
870 /* This monster cast spells */
871 current_world_ptr->timewalk_m_idx = hack_m_idx;
873 if (vs_player) do_cmd_redraw(target_ptr);
877 if (!monster_is_valid(m_ptr)) break;
878 process_monster(target_ptr, current_world_ptr->timewalk_m_idx);
880 handle_stuff(target_ptr);
882 if (vs_player) Term_xtra(TERM_XTRA_DELAY, 500);
885 target_ptr->redraw |= (PR_MAP);
886 target_ptr->update |= (PU_MONSTERS);
887 target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
889 current_world_ptr->timewalk_m_idx = 0;
890 if (vs_player || (player_has_los_bold(target_ptr, m_ptr->fy, m_ptr->fx) && projectable(target_ptr, target_ptr->y, target_ptr->x, m_ptr->fy, m_ptr->fx)))
892 msg_print(_("「時は動きだす…」", "You feel time flowing around you once more."));
896 handle_stuff(target_ptr);
901 * @brief モンスターの経験値取得処理
902 * @param target_ptr プレーヤーへの参照ポインタ
903 * @param m_idx 経験値を得るモンスターの参照ID
904 * @param s_idx 撃破されたモンスター種族の参照ID
907 void monster_gain_exp(player_type *target_ptr, MONSTER_IDX m_idx, MONRACE_IDX s_idx)
912 if (m_idx <= 0 || s_idx <= 0) return;
914 floor_type *floor_ptr = target_ptr->current_floor_ptr;
915 m_ptr = &floor_ptr->m_list[m_idx];
917 if (!monster_is_valid(m_ptr)) return;
919 r_ptr = &r_info[m_ptr->r_idx];
920 s_ptr = &r_info[s_idx];
922 if (target_ptr->phase_out) return;
924 if (!r_ptr->next_exp) return;
926 int new_exp = s_ptr->mexp * s_ptr->level / (r_ptr->level + 2);
927 if (m_idx == target_ptr->riding) new_exp = (new_exp + 1) / 2;
928 if (!floor_ptr->dun_level) new_exp /= 5;
929 m_ptr->exp += new_exp;
930 if (m_ptr->mflag2 & MFLAG2_CHAMELEON) return;
932 if (m_ptr->exp < r_ptr->next_exp)
934 if (m_idx == target_ptr->riding) target_ptr->update |= PU_BONUS;
938 GAME_TEXT m_name[MAX_NLEN];
939 int old_hp = m_ptr->hp;
940 int old_maxhp = m_ptr->max_maxhp;
941 int old_r_idx = m_ptr->r_idx;
942 byte old_sub_align = m_ptr->sub_align;
944 /* Hack -- Reduce the racial counter of previous monster */
945 real_r_ptr(m_ptr)->cur_num--;
947 monster_desc(target_ptr, m_name, m_ptr, 0);
948 m_ptr->r_idx = r_ptr->next_r_idx;
950 /* Count the monsters on the level */
951 real_r_ptr(m_ptr)->cur_num++;
953 m_ptr->ap_r_idx = m_ptr->r_idx;
954 r_ptr = &r_info[m_ptr->r_idx];
956 if (r_ptr->flags1 & RF1_FORCE_MAXHP)
958 m_ptr->max_maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
962 m_ptr->max_maxhp = damroll(r_ptr->hdice, r_ptr->hside);
964 if (ironman_nightmare)
966 HIT_POINT hp = m_ptr->max_maxhp * 2L;
967 m_ptr->max_maxhp = MIN(30000, hp);
970 m_ptr->maxhp = m_ptr->max_maxhp;
971 m_ptr->hp = old_hp * m_ptr->maxhp / old_maxhp;
973 /* dealt damage is 0 at initial*/
974 m_ptr->dealt_damage = 0;
976 /* Extract the monster base speed */
977 m_ptr->mspeed = get_mspeed(target_ptr, r_ptr);
979 /* Sub-alignment of a monster */
980 if (!is_pet(m_ptr) && !(r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)))
981 m_ptr->sub_align = old_sub_align;
984 m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
985 if (r_ptr->flags3 & RF3_EVIL) m_ptr->sub_align |= SUB_ALIGN_EVIL;
986 if (r_ptr->flags3 & RF3_GOOD) m_ptr->sub_align |= SUB_ALIGN_GOOD;
991 if (is_pet(m_ptr) || m_ptr->ml)
993 if (!ignore_unview || player_can_see_bold(target_ptr, m_ptr->fy, m_ptr->fx))
995 if (target_ptr->image)
997 monster_race *hallu_race;
1001 hallu_race = &r_info[randint1(max_r_idx - 1)];
1002 } while (!hallu_race->name || (hallu_race->flags1 & RF1_UNIQUE));
1003 msg_format(_("%sは%sに進化した。", "%^s evolved into %s."), m_name, r_name + hallu_race->name);
1007 msg_format(_("%sは%sに進化した。", "%^s evolved into %s."), m_name, r_name + r_ptr->name);
1011 if (!target_ptr->image) r_info[old_r_idx].r_xtra1 |= MR1_SINKA;
1013 /* Now you feel very close to this pet. */
1014 m_ptr->parent_m_idx = 0;
1017 update_monster(target_ptr, m_idx, FALSE);
1018 lite_spot(target_ptr, m_ptr->fy, m_ptr->fx);
1020 if (m_idx == target_ptr->riding) target_ptr->update |= PU_BONUS;
1024 * @brief モンスターのHPをダメージに応じて減算する /
1025 * Decreases monsters hit points, handling monster death.
1026 * @param dam 与えたダメージ量
1027 * @param m_idx ダメージを与えたモンスターのID
1028 * @param fear ダメージによってモンスターが恐慌状態に陥ったならばTRUEを返す
1029 * @param note モンスターが倒された際の特別なメッセージ述語
1033 * We return TRUE if the monster has been killed (and deleted).
1034 * We announce monster death (using an optional "death message"
1035 * if given, and a otherwise a generic killed/destroyed message).
1036 * Only "physical attacks" can induce the "You have slain" message.
1037 * Missile and Spell attacks will induce the "dies" message, or
1038 * various "specialized" messages. Note that "You have destroyed"
1039 * and "is destroyed" are synonyms for "You have slain" and "dies".
1040 * Hack -- unseen monsters yield "You have killed it." message.
1041 * Added fear (DGK) and check whether to print fear messages -CWS
1042 * Made name, sex, and capitalization generic -BEN-
1043 * As always, the "ghost" processing is a total hack.
1044 * Hack -- we "delay" fear messages by passing around a "fear" flag.
1045 * Consider decreasing monster experience over time, say,
1046 * by using "(m_exp * m_lev * (m_lev)) / (p_lev * (m_lev + n_killed))"
1047 * instead of simply "(m_exp * m_lev) / (p_lev)", to make the first
1048 * monster worth more than subsequent monsters. This would also need
1049 * to induce changes in the monster recall code.
1052 bool mon_take_hit(player_type *target_ptr, MONSTER_IDX m_idx, HIT_POINT dam, bool *fear, concptr note)
1054 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
1055 monster_race *r_ptr = &r_info[m_ptr->r_idx];
1056 monster_type exp_mon;
1058 /* Innocent until proven otherwise */
1059 bool innocent = TRUE, thief = FALSE;
1063 (void)COPY(&exp_mon, m_ptr, monster_type);
1065 expdam = (m_ptr->hp > dam) ? dam : m_ptr->hp;
1067 get_exp_from_mon(target_ptr, expdam, &exp_mon);
1069 /* Genocided by chaos patron */
1070 if (!monster_is_valid(m_ptr)) m_idx = 0;
1072 /* Redraw (later) if needed */
1073 if (target_ptr->health_who == m_idx) target_ptr->redraw |= (PR_HEALTH);
1074 if (target_ptr->riding == m_idx) target_ptr->redraw |= (PR_UHEALTH);
1076 (void)set_monster_csleep(target_ptr, m_idx, 0);
1078 /* Hack - Cancel any special player stealth magics. -LM- */
1079 if (target_ptr->special_defense & NINJA_S_STEALTH)
1081 set_superstealth(target_ptr, FALSE);
1084 /* Genocided by chaos patron */
1085 if (!m_idx) return TRUE;
1088 m_ptr->dealt_damage += dam;
1090 if (m_ptr->dealt_damage > m_ptr->max_maxhp * 100) m_ptr->dealt_damage = m_ptr->max_maxhp * 100;
1092 if (current_world_ptr->wizard)
1094 msg_format(_("合計%d/%dのダメージを与えた。", "You do %d (out of %d) damage."), m_ptr->dealt_damage, m_ptr->maxhp);
1097 /* It is dead now */
1100 GAME_TEXT m_name[MAX_NLEN];
1102 if (r_info[m_ptr->r_idx].flags7 & RF7_TANUKI)
1104 /* You might have unmasked Tanuki first time */
1105 r_ptr = &r_info[m_ptr->r_idx];
1106 m_ptr->ap_r_idx = m_ptr->r_idx;
1107 if (r_ptr->r_sights < MAX_SHORT) r_ptr->r_sights++;
1110 if (m_ptr->mflag2 & MFLAG2_CHAMELEON)
1112 /* You might have unmasked Chameleon first time */
1113 r_ptr = real_r_ptr(m_ptr);
1114 if (r_ptr->r_sights < MAX_SHORT) r_ptr->r_sights++;
1117 if (!(m_ptr->smart & SM_CLONED))
1119 /* When the player kills a Unique, it stays dead */
1120 if (r_ptr->flags1 & RF1_UNIQUE)
1124 /* Mega-Hack -- Banor & Lupart */
1125 if ((m_ptr->r_idx == MON_BANOR) || (m_ptr->r_idx == MON_LUPART))
1127 r_info[MON_BANORLUPART].max_num = 0;
1128 r_info[MON_BANORLUPART].r_pkills++;
1129 r_info[MON_BANORLUPART].r_akills++;
1130 if (r_info[MON_BANORLUPART].r_tkills < MAX_SHORT) r_info[MON_BANORLUPART].r_tkills++;
1132 else if (m_ptr->r_idx == MON_BANORLUPART)
1134 r_info[MON_BANOR].max_num = 0;
1135 r_info[MON_BANOR].r_pkills++;
1136 r_info[MON_BANOR].r_akills++;
1137 if (r_info[MON_BANOR].r_tkills < MAX_SHORT) r_info[MON_BANOR].r_tkills++;
1138 r_info[MON_LUPART].max_num = 0;
1139 r_info[MON_LUPART].r_pkills++;
1140 r_info[MON_LUPART].r_akills++;
1141 if (r_info[MON_LUPART].r_tkills < MAX_SHORT) r_info[MON_LUPART].r_tkills++;
1145 /* When the player kills a Nazgul, it stays dead */
1146 else if (r_ptr->flags7 & RF7_NAZGUL) r_ptr->max_num--;
1149 /* Count all monsters killed */
1150 if (r_ptr->r_akills < MAX_SHORT) r_ptr->r_akills++;
1152 /* Recall even invisible uniques or winners */
1153 if ((m_ptr->ml && !target_ptr->image) || (r_ptr->flags1 & RF1_UNIQUE))
1155 /* Count kills this life */
1156 if ((m_ptr->mflag2 & MFLAG2_KAGE) && (r_info[MON_KAGE].r_pkills < MAX_SHORT)) r_info[MON_KAGE].r_pkills++;
1157 else if (r_ptr->r_pkills < MAX_SHORT) r_ptr->r_pkills++;
1159 /* Count kills in all lives */
1160 if ((m_ptr->mflag2 & MFLAG2_KAGE) && (r_info[MON_KAGE].r_tkills < MAX_SHORT)) r_info[MON_KAGE].r_tkills++;
1161 else if (r_ptr->r_tkills < MAX_SHORT) r_ptr->r_tkills++;
1163 /* Hack -- Auto-recall */
1164 monster_race_track(target_ptr, m_ptr->ap_r_idx);
1167 monster_desc(target_ptr, m_name, m_ptr, MD_TRUE_NAME);
1169 /* Don't kill Amberites */
1170 if ((r_ptr->flags3 & RF3_AMBERITE) && one_in_(2))
1172 int curses = 1 + randint1(3);
1173 bool stop_ty = FALSE;
1176 msg_format(_("%^sは恐ろしい血の呪いをあなたにかけた!", "%^s puts a terrible blood curse on you!"), m_name);
1177 curse_equipment(target_ptr, 100, 50);
1181 stop_ty = activate_ty_curse(target_ptr, stop_ty, &count);
1185 if (r_ptr->flags2 & RF2_CAN_SPEAK)
1187 char line_got[1024];
1188 if (!get_rnd_line(_("mondeath_j.txt", "mondeath.txt"), m_ptr->r_idx, line_got))
1190 msg_format("%^s %s", m_name, line_got);
1194 if (m_ptr->r_idx == MON_SERPENT)
1196 screen_dump = make_screen_dump(target_ptr, process_autopick_file_command);
1201 if (!(d_info[target_ptr->dungeon_idx].flags1 & DF1_BEGINNER))
1203 if (!target_ptr->current_floor_ptr->dun_level && !target_ptr->ambush_flag && !target_ptr->current_floor_ptr->inside_arena)
1205 chg_virtue(target_ptr, V_VALOUR, -1);
1207 else if (r_ptr->level > target_ptr->current_floor_ptr->dun_level)
1209 if (randint1(10) <= (r_ptr->level - target_ptr->current_floor_ptr->dun_level))
1210 chg_virtue(target_ptr, V_VALOUR, 1);
1212 if (r_ptr->level > 60)
1214 chg_virtue(target_ptr, V_VALOUR, 1);
1216 if (r_ptr->level >= 2 * (target_ptr->lev + 1))
1217 chg_virtue(target_ptr, V_VALOUR, 2);
1220 if (r_ptr->flags1 & RF1_UNIQUE)
1222 if (r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)) chg_virtue(target_ptr, V_HARMONY, 2);
1224 if (r_ptr->flags3 & RF3_GOOD)
1226 chg_virtue(target_ptr, V_UNLIFE, 2);
1227 chg_virtue(target_ptr, V_VITALITY, -2);
1230 if (one_in_(3)) chg_virtue(target_ptr, V_INDIVIDUALISM, -1);
1233 if (m_ptr->r_idx == MON_BEGGAR || m_ptr->r_idx == MON_LEPER)
1235 chg_virtue(target_ptr, V_COMPASSION, -1);
1238 if ((r_ptr->flags3 & RF3_GOOD) && ((r_ptr->level) / 10 + (3 * target_ptr->current_floor_ptr->dun_level) >= randint1(100)))
1239 chg_virtue(target_ptr, V_UNLIFE, 1);
1241 if (r_ptr->d_char == 'A')
1243 if (r_ptr->flags1 & RF1_UNIQUE)
1244 chg_virtue(target_ptr, V_FAITH, -2);
1245 else if ((r_ptr->level) / 10 + (3 * target_ptr->current_floor_ptr->dun_level) >= randint1(100))
1247 if (r_ptr->flags3 & RF3_GOOD) chg_virtue(target_ptr, V_FAITH, -1);
1248 else chg_virtue(target_ptr, V_FAITH, 1);
1251 else if (r_ptr->flags3 & RF3_DEMON)
1253 if (r_ptr->flags1 & RF1_UNIQUE)
1254 chg_virtue(target_ptr, V_FAITH, 2);
1255 else if ((r_ptr->level) / 10 + (3 * target_ptr->current_floor_ptr->dun_level) >= randint1(100))
1256 chg_virtue(target_ptr, V_FAITH, 1);
1259 if ((r_ptr->flags3 & RF3_UNDEAD) && (r_ptr->flags1 & RF1_UNIQUE))
1260 chg_virtue(target_ptr, V_VITALITY, 2);
1262 if (r_ptr->r_deaths)
1264 if (r_ptr->flags1 & RF1_UNIQUE)
1266 chg_virtue(target_ptr, V_HONOUR, 10);
1268 else if ((r_ptr->level) / 10 + (2 * target_ptr->current_floor_ptr->dun_level) >= randint1(100))
1270 chg_virtue(target_ptr, V_HONOUR, 1);
1273 if ((r_ptr->flags2 & RF2_MULTIPLY) && (r_ptr->r_akills > 1000) && one_in_(10))
1275 chg_virtue(target_ptr, V_VALOUR, -1);
1278 for (i = 0; i < 4; i++)
1280 if (r_ptr->blow[i].d_dice != 0) innocent = FALSE; /* Murderer! */
1282 if ((r_ptr->blow[i].effect == RBE_EAT_ITEM)
1283 || (r_ptr->blow[i].effect == RBE_EAT_GOLD))
1285 thief = TRUE; /* Thief! */
1288 /* The new law says it is illegal to live in the dungeon */
1289 if (r_ptr->level != 0) innocent = FALSE;
1293 if (r_ptr->flags1 & RF1_UNIQUE)
1294 chg_virtue(target_ptr, V_JUSTICE, 3);
1295 else if (1 + ((r_ptr->level) / 10 + (2 * target_ptr->current_floor_ptr->dun_level)) >= randint1(100))
1296 chg_virtue(target_ptr, V_JUSTICE, 1);
1300 chg_virtue(target_ptr, V_JUSTICE, -1);
1303 if ((r_ptr->flags3 & RF3_ANIMAL) && !(r_ptr->flags3 & RF3_EVIL) && !(r_ptr->flags4 & ~(RF4_NOMAGIC_MASK)) && !(r_ptr->a_ability_flags1 & ~(RF5_NOMAGIC_MASK)) && !(r_ptr->a_ability_flags2 & ~(RF6_NOMAGIC_MASK)))
1305 if (one_in_(4)) chg_virtue(target_ptr, V_NATURE, -1);
1308 if ((r_ptr->flags1 & RF1_UNIQUE) && record_destroy_uniq)
1311 sprintf(note_buf, "%s%s", r_name + r_ptr->name, (m_ptr->smart & SM_CLONED) ? _("(クローン)", "(Clone)") : "");
1312 exe_write_diary(target_ptr, DIARY_UNIQUE, 0, note_buf);
1318 /* Death by Missile/Spell attack */
1321 msg_format("%^s%s", m_name, note);
1324 /* Death by physical attack -- invisible monster */
1325 else if (!m_ptr->ml)
1328 if (IS_ECHIZEN(target_ptr))
1329 msg_format("せっかくだから%sを殺した。", m_name);
1331 msg_format("%sを殺した。", m_name);
1333 msg_format("You have killed %s.", m_name);
1338 /* Death by Physical attack -- non-living monster */
1339 else if (!monster_living(m_ptr->r_idx))
1341 bool explode = FALSE;
1343 for (i = 0; i < 4; i++)
1345 if (r_ptr->blow[i].method == RBM_EXPLODE) explode = TRUE;
1348 /* Special note at death */
1350 msg_format(_("%sは爆発して粉々になった。", "%^s explodes into tiny shreds."), m_name);
1354 if (IS_ECHIZEN(target_ptr))
1355 msg_format("せっかくだから%sを倒した。", m_name);
1357 msg_format("%sを倒した。", m_name);
1359 msg_format("You have destroyed %s.", m_name);
1364 /* Death by Physical attack -- living monster */
1368 if (IS_ECHIZEN(target_ptr))
1369 msg_format("せっかくだから%sを葬り去った。", m_name);
1371 msg_format("%sを葬り去った。", m_name);
1373 msg_format("You have slain %s.", m_name);
1377 if ((r_ptr->flags1 & RF1_UNIQUE) && !(m_ptr->smart & SM_CLONED) && !vanilla_town)
1379 for (i = 0; i < MAX_BOUNTY; i++)
1381 if ((current_world_ptr->bounty_r_idx[i] == m_ptr->r_idx) && !(m_ptr->mflag2 & MFLAG2_CHAMELEON))
1383 msg_format(_("%sの首には賞金がかかっている。", "There is a price on %s's head."), m_name);
1389 /* Generate treasure */
1390 monster_death(target_ptr, m_idx, TRUE);
1392 /* Mega hack : replace IKETA to BIKETAL */
1393 if ((m_ptr->r_idx == MON_IKETA) && !(target_ptr->current_floor_ptr->inside_arena || target_ptr->phase_out))
1395 POSITION dummy_y = m_ptr->fy;
1396 POSITION dummy_x = m_ptr->fx;
1397 BIT_FLAGS mode = 0L;
1398 if (is_pet(m_ptr)) mode |= PM_FORCE_PET;
1399 delete_monster_idx(target_ptr, m_idx);
1400 if (summon_named_creature(target_ptr, 0, dummy_y, dummy_x, MON_BIKETAL, mode))
1402 msg_print(_("「ハァッハッハッハ!!私がバイケタルだ!!」", "Uwa-hahaha! *I* am Biketal!"));
1407 delete_monster_idx(target_ptr, m_idx);
1410 get_exp_from_mon(target_ptr, (long)exp_mon.max_maxhp * 2, &exp_mon);
1415 /* Monster is dead */
1419 /* Mega-Hack -- Pain cancels fear */
1420 if (MON_MONFEAR(m_ptr) && (dam > 0))
1423 if (set_monster_monfear(target_ptr, m_idx, MON_MONFEAR(m_ptr) - randint1(dam)))
1430 /* Sometimes a monster gets scared by damage */
1431 if (!MON_MONFEAR(m_ptr) && !(r_ptr->flags3 & (RF3_NO_FEAR)))
1433 /* Percentage of fully healthy */
1434 int percentage = (100L * m_ptr->hp) / m_ptr->maxhp;
1437 * Run (sometimes) if at 10% or less of max hit points,
1438 * or (usually) when hit for half its current hit points
1440 if ((randint1(10) >= percentage) || ((dam >= m_ptr->hp) && (randint0(100) < 80)))
1442 /* Hack -- note fear */
1445 /* Hack -- Add some timed fear */
1446 (void)set_monster_monfear(target_ptr, m_idx, (randint1(10) +
1447 (((dam >= m_ptr->hp) && (percentage > 7)) ?
1448 20 : ((11 - percentage) * 5))));
1457 bool monster_is_valid(monster_type *m_ptr)
1459 return (m_ptr->r_idx != 0);