2 * @brief モンスター同士が乱闘する処理
7 #include "melee/monster-attack-monster.h"
8 #include "combat/attack-accuracy.h"
9 #include "combat/hallucination-attacks-table.h"
10 #include "core/disturbance.h"
11 #include "core/player-redraw-types.h"
12 #include "dungeon/dungeon-flag-types.h"
13 #include "dungeon/dungeon.h"
14 #include "effect/effect-characteristics.h"
15 #include "effect/effect-processor.h"
16 #include "main/sound-definitions-table.h"
17 #include "main/sound-of-music.h"
18 #include "melee/melee-postprocess.h"
19 #include "melee/melee-switcher.h"
20 #include "melee/melee-util.h"
21 #include "monster-attack/monster-attack-effect.h"
22 #include "monster-race/monster-race-hook.h"
23 #include "monster-race/monster-race.h"
24 #include "monster-race/race-flags-resistance.h"
25 #include "monster-race/race-flags1.h"
26 #include "monster-race/race-flags2.h"
27 #include "monster-race/race-flags3.h"
28 #include "monster/monster-describer.h"
29 #include "monster/monster-info.h"
30 #include "monster/monster-status-setter.h"
31 #include "monster/monster-status.h"
32 #include "spell-kind/spells-teleport.h"
33 #include "spell-realm/spells-hex.h"
34 #include "spell/spell-types.h"
35 #include "system/floor-type-definition.h"
36 #include "view/display-messages.h"
38 /* todo モンスター共通なので、monster-attack-player.cでも使うはず */
39 const int MAX_BLOW = 4;
41 static void heal_monster_by_melee(player_type *subject_ptr, mam_type *mam_ptr)
43 if (!monster_living(mam_ptr->m_idx) || (mam_ptr->damage <= 2))
46 bool did_heal = mam_ptr->m_ptr->hp < mam_ptr->m_ptr->maxhp;
47 mam_ptr->m_ptr->hp += damroll(4, mam_ptr->damage / 6);
48 if (mam_ptr->m_ptr->hp > mam_ptr->m_ptr->maxhp)
49 mam_ptr->m_ptr->hp = mam_ptr->m_ptr->maxhp;
51 if (subject_ptr->health_who == mam_ptr->m_idx)
52 subject_ptr->redraw |= (PR_HEALTH);
54 if (subject_ptr->riding == mam_ptr->m_idx)
55 subject_ptr->redraw |= (PR_UHEALTH);
57 if (mam_ptr->see_m && did_heal)
58 msg_format(_("%sは体力を回復したようだ。", "%^s appears healthier."), mam_ptr->m_name);
61 static void process_blow_effect(player_type *subject_ptr, mam_type *mam_ptr)
63 monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
64 switch (mam_ptr->effect_type) {
65 case BLOW_EFFECT_TYPE_FEAR:
66 project(subject_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, mam_ptr->damage, GF_TURN_ALL,
67 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1);
69 case BLOW_EFFECT_TYPE_SLEEP:
70 project(subject_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, r_ptr->level, GF_OLD_SLEEP, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED,
73 case BLOW_EFFECT_TYPE_HEAL:
74 heal_monster_by_melee(subject_ptr, mam_ptr);
79 static void aura_fire_by_melee(player_type *subject_ptr, mam_type *mam_ptr)
81 monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
82 monster_race *tr_ptr = &r_info[mam_ptr->t_ptr->r_idx];
83 if (((tr_ptr->flags2 & RF2_AURA_FIRE) == 0) || (mam_ptr->m_ptr->r_idx == 0))
86 if (((r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK) != 0) && is_original_ap_and_seen(subject_ptr, mam_ptr->m_ptr)) {
87 r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK);
91 if (mam_ptr->see_either)
92 msg_format(_("%^sは突然熱くなった!", "%^s is suddenly very hot!"), mam_ptr->m_name);
94 if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(subject_ptr, mam_ptr->t_ptr))
95 tr_ptr->r_flags2 |= RF2_AURA_FIRE;
97 project(subject_ptr, mam_ptr->t_idx, 0, mam_ptr->m_ptr->fy, mam_ptr->m_ptr->fx, damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17)), GF_FIRE,
98 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1);
101 static void aura_cold_by_melee(player_type *subject_ptr, mam_type *mam_ptr)
103 monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
104 monster_race *tr_ptr = &r_info[mam_ptr->t_ptr->r_idx];
105 if (((tr_ptr->flags3 & RF3_AURA_COLD) == 0) || (mam_ptr->m_ptr->r_idx == 0))
108 if (((r_ptr->flagsr & RFR_EFF_IM_COLD_MASK) != 0) && is_original_ap_and_seen(subject_ptr, mam_ptr->m_ptr)) {
109 r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_COLD_MASK);
113 if (mam_ptr->see_either)
114 msg_format(_("%^sは突然寒くなった!", "%^s is suddenly very cold!"), mam_ptr->m_name);
116 if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(subject_ptr, mam_ptr->t_ptr))
117 tr_ptr->r_flags3 |= RF3_AURA_COLD;
119 project(subject_ptr, mam_ptr->t_idx, 0, mam_ptr->m_ptr->fy, mam_ptr->m_ptr->fx, damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17)), GF_COLD,
120 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1);
123 static void aura_elec_by_melee(player_type *subject_ptr, mam_type *mam_ptr)
125 monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
126 monster_race *tr_ptr = &r_info[mam_ptr->t_ptr->r_idx];
127 if (((tr_ptr->flags2 & RF2_AURA_ELEC) == 0) || (mam_ptr->m_ptr->r_idx == 0))
130 if (((r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK) != 0) && is_original_ap_and_seen(subject_ptr, mam_ptr->m_ptr)) {
131 r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK);
135 if (mam_ptr->see_either)
136 msg_format(_("%^sは電撃を食らった!", "%^s gets zapped!"), mam_ptr->m_name);
138 if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(subject_ptr, mam_ptr->t_ptr))
139 tr_ptr->r_flags2 |= RF2_AURA_ELEC;
141 project(subject_ptr, mam_ptr->t_idx, 0, mam_ptr->m_ptr->fy, mam_ptr->m_ptr->fx, damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17)), GF_ELEC,
142 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1);
145 static bool check_same_monster(player_type *subject_ptr, mam_type *mam_ptr)
147 if (mam_ptr->m_idx == mam_ptr->t_idx)
150 monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
151 if (r_ptr->flags1 & RF1_NEVER_BLOW)
154 if (d_info[subject_ptr->dungeon_idx].flags1 & DF1_NO_MELEE)
160 static void redraw_health_bar(player_type *subject_ptr, mam_type *mam_ptr)
162 if (!mam_ptr->t_ptr->ml)
165 if (subject_ptr->health_who == mam_ptr->t_idx)
166 subject_ptr->redraw |= (PR_HEALTH);
168 if (subject_ptr->riding == mam_ptr->t_idx)
169 subject_ptr->redraw |= (PR_UHEALTH);
172 static void describe_silly_melee(mam_type *mam_ptr)
175 if ((mam_ptr->act == NULL) || !mam_ptr->see_either)
179 if (mam_ptr->do_silly_attack)
180 mam_ptr->act = silly_attacks2[randint0(MAX_SILLY_ATTACK)];
182 strfmt(temp, mam_ptr->act, mam_ptr->t_name);
183 msg_format("%^sは%s", mam_ptr->m_name, temp);
185 if (mam_ptr->do_silly_attack) {
186 mam_ptr->act = silly_attacks[randint0(MAX_SILLY_ATTACK)];
187 strfmt(temp, "%s %s.", mam_ptr->act, mam_ptr->t_name);
189 strfmt(temp, mam_ptr->act, mam_ptr->t_name);
191 msg_format("%^s %s", mam_ptr->m_name, temp);
195 static void process_monster_attack_effect(player_type *subject_ptr, mam_type *mam_ptr)
197 if (mam_ptr->pt == GF_NONE)
200 if (!mam_ptr->explode)
201 project(subject_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, mam_ptr->damage, mam_ptr->pt,
202 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1);
204 process_blow_effect(subject_ptr, mam_ptr);
205 if (!mam_ptr->touched)
208 aura_fire_by_melee(subject_ptr, mam_ptr);
209 aura_cold_by_melee(subject_ptr, mam_ptr);
210 aura_elec_by_melee(subject_ptr, mam_ptr);
213 static void process_melee(player_type *subject_ptr, mam_type *mam_ptr)
215 if (mam_ptr->effect && !check_hit_from_monster_to_monster(mam_ptr->power, mam_ptr->rlev, mam_ptr->ac, monster_stunned_remaining(mam_ptr->m_ptr))) {
216 describe_monster_missed_monster(subject_ptr, mam_ptr);
220 (void)set_monster_csleep(subject_ptr, mam_ptr->t_idx, 0);
221 redraw_health_bar(subject_ptr, mam_ptr);
222 describe_melee_method(subject_ptr, mam_ptr);
223 describe_silly_melee(mam_ptr);
224 mam_ptr->obvious = TRUE;
225 mam_ptr->damage = damroll(mam_ptr->d_dice, mam_ptr->d_side);
226 mam_ptr->effect_type = BLOW_EFFECT_TYPE_NONE;
227 mam_ptr->pt = GF_MISSILE;
228 decide_monster_attack_effect(subject_ptr, mam_ptr);
229 process_monster_attack_effect(subject_ptr, mam_ptr);
232 static void thief_runaway_by_melee(player_type *subject_ptr, mam_type *mam_ptr)
234 if (teleport_barrier(subject_ptr, mam_ptr->m_idx)) {
235 if (mam_ptr->see_m) {
236 msg_print(_("泥棒は笑って逃げ...ようとしたがバリアに防がれた。", "The thief flees laughing...? But a magic barrier obstructs it."));
237 } else if (mam_ptr->known) {
238 subject_ptr->current_floor_ptr->monster_noise = TRUE;
241 if (mam_ptr->see_m) {
242 msg_print(_("泥棒は笑って逃げた!", "The thief flees laughing!"));
243 } else if (mam_ptr->known) {
244 subject_ptr->current_floor_ptr->monster_noise = TRUE;
247 teleport_away(subject_ptr, mam_ptr->m_idx, MAX_SIGHT * 2 + 5, TELEPORT_SPONTANEOUS);
251 static void explode_monster_by_melee(player_type *subject_ptr, mam_type *mam_ptr)
253 if (!mam_ptr->explode)
256 sound(SOUND_EXPLODE);
257 (void)set_monster_invulner(subject_ptr, mam_ptr->m_idx, 0, FALSE);
258 mon_take_hit_mon(subject_ptr, mam_ptr->m_idx, mam_ptr->m_ptr->hp + 1, &mam_ptr->dead, &mam_ptr->fear,
259 _("は爆発して粉々になった。", " explodes into tiny shreds."), mam_ptr->m_idx);
260 mam_ptr->blinked = FALSE;
264 * @brief r_infoで定義した攻撃回数の分だけ、モンスターからモンスターへの直接攻撃処理を繰り返す
265 * @param subject_ptr プレーヤーへの参照ポインタ
266 * @param mam_ptr モンスター乱闘構造体への参照ポインタ
269 void repeat_melee(player_type *subject_ptr, mam_type *mam_ptr)
271 monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
272 for (mam_ptr->ap_cnt = 0; mam_ptr->ap_cnt < MAX_BLOW; mam_ptr->ap_cnt++) {
273 mam_ptr->effect = r_ptr->blow[mam_ptr->ap_cnt].effect;
274 mam_ptr->method = r_ptr->blow[mam_ptr->ap_cnt].method;
275 mam_ptr->d_dice = r_ptr->blow[mam_ptr->ap_cnt].d_dice;
276 mam_ptr->d_side = r_ptr->blow[mam_ptr->ap_cnt].d_side;
278 if (!monster_is_valid(mam_ptr->m_ptr) || (mam_ptr->t_ptr->fx != mam_ptr->x_saver) || (mam_ptr->t_ptr->fy != mam_ptr->y_saver) || !mam_ptr->method)
281 if (mam_ptr->method == RBM_SHOOT)
284 mam_ptr->power = mbe_info[mam_ptr->effect].power;
285 process_melee(subject_ptr, mam_ptr);
286 if (!is_original_ap_and_seen(subject_ptr, mam_ptr->m_ptr) || mam_ptr->do_silly_attack)
289 if (!mam_ptr->obvious && !mam_ptr->damage && (r_ptr->r_blows[mam_ptr->ap_cnt] <= 10))
292 if (r_ptr->r_blows[mam_ptr->ap_cnt] < MAX_UCHAR)
293 r_ptr->r_blows[mam_ptr->ap_cnt]++;
298 * @brief モンスターから敵モンスターへの打撃攻撃処理
299 * @param m_idx 攻撃側モンスターの参照ID
300 * @param t_idx 目標側モンスターの参照ID
301 * @return 実際に打撃処理が行われた場合TRUEを返す
303 bool monst_attack_monst(player_type *subject_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx)
306 mam_type *mam_ptr = initialize_mam_type(subject_ptr, &tmp_mam, m_idx, t_idx);
308 if (!check_same_monster(subject_ptr, mam_ptr))
311 monster_desc(subject_ptr, mam_ptr->m_name, mam_ptr->m_ptr, 0);
312 monster_desc(subject_ptr, mam_ptr->t_name, mam_ptr->t_ptr, 0);
313 if (!mam_ptr->see_either && mam_ptr->known)
314 subject_ptr->current_floor_ptr->monster_noise = TRUE;
316 if (subject_ptr->riding && (m_idx == subject_ptr->riding))
317 disturb(subject_ptr, TRUE, TRUE);
319 repeat_melee(subject_ptr, mam_ptr);
320 explode_monster_by_melee(subject_ptr, mam_ptr);
321 if (!mam_ptr->blinked || mam_ptr->m_ptr->r_idx == 0)
324 thief_runaway_by_melee(subject_ptr, mam_ptr);