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 "effect/attribute-types.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 "system/dungeon-info.h"
35 #include "system/floor-type-definition.h"
36 #include "system/monster-race-definition.h"
37 #include "system/monster-type-definition.h"
38 #include "system/player-type-definition.h"
39 #include "view/display-messages.h"
41 static void heal_monster_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
43 if (!monster_living(mam_ptr->t_ptr->r_idx) || (mam_ptr->damage <= 2)) {
47 bool did_heal = mam_ptr->m_ptr->hp < mam_ptr->m_ptr->maxhp;
48 mam_ptr->m_ptr->hp += damroll(4, mam_ptr->damage / 6);
49 if (mam_ptr->m_ptr->hp > mam_ptr->m_ptr->maxhp) {
50 mam_ptr->m_ptr->hp = mam_ptr->m_ptr->maxhp;
53 if (player_ptr->health_who == mam_ptr->m_idx) {
54 player_ptr->redraw |= (PR_HEALTH);
57 if (player_ptr->riding == mam_ptr->m_idx) {
58 player_ptr->redraw |= (PR_UHEALTH);
61 if (mam_ptr->see_m && did_heal) {
62 msg_format(_("%sは体力を回復したようだ。", "%^s appears healthier."), mam_ptr->m_name);
66 static void process_blow_effect(PlayerType *player_ptr, mam_type *mam_ptr)
68 auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
69 switch (mam_ptr->attribute) {
70 case BlowEffectType::FEAR:
71 project(player_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, mam_ptr->damage,
72 AttributeType::TURN_ALL, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
74 case BlowEffectType::SLEEP:
75 project(player_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, r_ptr->level,
76 AttributeType::OLD_SLEEP, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
78 case BlowEffectType::HEAL:
79 heal_monster_by_melee(player_ptr, mam_ptr);
86 static void aura_fire_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
88 auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
89 MonsterRaceInfo *tr_ptr = &monraces_info[mam_ptr->t_ptr->r_idx];
90 if (tr_ptr->aura_flags.has_not(MonsterAuraType::FIRE) || !MonsterRace(mam_ptr->m_ptr->r_idx).is_valid()) {
94 if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_FIRE_MASK) && is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr)) {
95 r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_FIRE_MASK);
99 if (mam_ptr->see_either) {
100 msg_format(_("%^sは突然熱くなった!", "%^s is suddenly very hot!"), mam_ptr->m_name);
103 if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr)) {
104 tr_ptr->aura_flags.set(MonsterAuraType::FIRE);
107 project(player_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)), AttributeType::FIRE,
108 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
111 static void aura_cold_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
113 auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
114 MonsterRaceInfo *tr_ptr = &monraces_info[mam_ptr->t_ptr->r_idx];
115 if (tr_ptr->aura_flags.has_not(MonsterAuraType::COLD) || !MonsterRace(mam_ptr->m_ptr->r_idx).is_valid()) {
119 if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_COLD_MASK) && is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr)) {
120 r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_COLD_MASK);
124 if (mam_ptr->see_either) {
125 msg_format(_("%^sは突然寒くなった!", "%^s is suddenly very cold!"), mam_ptr->m_name);
128 if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr)) {
129 tr_ptr->aura_flags.set(MonsterAuraType::COLD);
132 project(player_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)), AttributeType::COLD,
133 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
136 static void aura_elec_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
138 auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
139 MonsterRaceInfo *tr_ptr = &monraces_info[mam_ptr->t_ptr->r_idx];
140 if (tr_ptr->aura_flags.has_not(MonsterAuraType::ELEC) || !MonsterRace(mam_ptr->m_ptr->r_idx).is_valid()) {
144 if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_ELEC_MASK) && is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr)) {
145 r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_ELEC_MASK);
149 if (mam_ptr->see_either) {
150 msg_format(_("%^sは電撃を食らった!", "%^s gets zapped!"), mam_ptr->m_name);
153 if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr)) {
154 tr_ptr->aura_flags.set(MonsterAuraType::ELEC);
157 project(player_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)), AttributeType::ELEC,
158 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
161 static bool check_same_monster(PlayerType *player_ptr, mam_type *mam_ptr)
163 if (mam_ptr->m_idx == mam_ptr->t_idx) {
167 auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
168 if (r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_BLOW)) {
172 if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
179 static void redraw_health_bar(PlayerType *player_ptr, mam_type *mam_ptr)
181 if (!mam_ptr->t_ptr->ml) {
185 if (player_ptr->health_who == mam_ptr->t_idx) {
186 player_ptr->redraw |= (PR_HEALTH);
189 if (player_ptr->riding == mam_ptr->t_idx) {
190 player_ptr->redraw |= (PR_UHEALTH);
194 static void describe_silly_melee(mam_type *mam_ptr)
197 if ((mam_ptr->act == nullptr) || !mam_ptr->see_either) {
202 if (mam_ptr->do_silly_attack) {
203 mam_ptr->act = silly_attacks2[randint0(MAX_SILLY_ATTACK)];
206 strfmt(temp, mam_ptr->act, mam_ptr->t_name);
207 msg_format("%^sは%s", mam_ptr->m_name, temp);
209 if (mam_ptr->do_silly_attack) {
210 mam_ptr->act = silly_attacks[randint0(MAX_SILLY_ATTACK)];
211 strfmt(temp, "%s %s.", mam_ptr->act, mam_ptr->t_name);
213 strfmt(temp, mam_ptr->act, mam_ptr->t_name);
216 msg_format("%^s %s", mam_ptr->m_name, temp);
220 static void process_monster_attack_effect(PlayerType *player_ptr, mam_type *mam_ptr)
222 if (mam_ptr->pt == AttributeType::NONE) {
226 if (!mam_ptr->explode) {
227 project(player_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, mam_ptr->damage, mam_ptr->pt,
228 PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
231 process_blow_effect(player_ptr, mam_ptr);
232 if (!mam_ptr->touched) {
236 aura_fire_by_melee(player_ptr, mam_ptr);
237 aura_cold_by_melee(player_ptr, mam_ptr);
238 aura_elec_by_melee(player_ptr, mam_ptr);
241 static void process_melee(PlayerType *player_ptr, mam_type *mam_ptr)
243 if (mam_ptr->effect != RaceBlowEffectType::NONE && !check_hit_from_monster_to_monster(mam_ptr->power, mam_ptr->rlev, mam_ptr->ac, mam_ptr->m_ptr->get_remaining_stun())) {
244 describe_monster_missed_monster(player_ptr, mam_ptr);
248 (void)set_monster_csleep(player_ptr, mam_ptr->t_idx, 0);
249 redraw_health_bar(player_ptr, mam_ptr);
250 describe_melee_method(player_ptr, mam_ptr);
251 describe_silly_melee(mam_ptr);
252 mam_ptr->obvious = true;
253 mam_ptr->damage = damroll(mam_ptr->d_dice, mam_ptr->d_side);
254 mam_ptr->attribute = BlowEffectType::NONE;
255 mam_ptr->pt = AttributeType::MONSTER_MELEE;
256 decide_monster_attack_effect(player_ptr, mam_ptr);
257 process_monster_attack_effect(player_ptr, mam_ptr);
260 static void thief_runaway_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
262 if (SpellHex(player_ptr).check_hex_barrier(mam_ptr->m_idx, HEX_ANTI_TELE)) {
263 if (mam_ptr->see_m) {
264 msg_print(_("泥棒は笑って逃げ...ようとしたがバリアに防がれた。", "The thief flees laughing...? But a magic barrier obstructs it."));
265 } else if (mam_ptr->known) {
266 player_ptr->current_floor_ptr->monster_noise = true;
269 if (mam_ptr->see_m) {
270 msg_print(_("泥棒は笑って逃げた!", "The thief flees laughing!"));
271 } else if (mam_ptr->known) {
272 player_ptr->current_floor_ptr->monster_noise = true;
275 teleport_away(player_ptr, mam_ptr->m_idx, MAX_PLAYER_SIGHT * 2 + 5, TELEPORT_SPONTANEOUS);
279 static void explode_monster_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
281 if (!mam_ptr->explode) {
285 sound(SOUND_EXPLODE);
286 (void)set_monster_invulner(player_ptr, mam_ptr->m_idx, 0, false);
287 mon_take_hit_mon(player_ptr, mam_ptr->m_idx, mam_ptr->m_ptr->hp + 1, &mam_ptr->dead, &mam_ptr->fear,
288 _("は爆発して粉々になった。", " explodes into tiny shreds."), mam_ptr->m_idx);
289 mam_ptr->blinked = false;
293 * @brief MonsterRaceDefinitionで定義した攻撃回数の分だけ、モンスターからモンスターへの直接攻撃処理を繰り返す
294 * @param player_ptr プレイヤーへの参照ポインタ
295 * @param mam_ptr モンスター乱闘構造体への参照ポインタ
297 void repeat_melee(PlayerType *player_ptr, mam_type *mam_ptr)
299 const auto *m_ptr = mam_ptr->m_ptr;
300 auto *r_ptr = &monraces_info[m_ptr->r_idx];
301 for (int ap_cnt = 0; ap_cnt < MAX_NUM_BLOWS; ap_cnt++) {
302 mam_ptr->effect = r_ptr->blow[ap_cnt].effect;
303 mam_ptr->method = r_ptr->blow[ap_cnt].method;
304 mam_ptr->d_dice = r_ptr->blow[ap_cnt].d_dice;
305 mam_ptr->d_side = r_ptr->blow[ap_cnt].d_side;
307 if (!m_ptr->is_valid() || (mam_ptr->t_ptr->fx != mam_ptr->x_saver) || (mam_ptr->t_ptr->fy != mam_ptr->y_saver) || mam_ptr->method == RaceBlowMethodType::NONE) {
311 if (mam_ptr->method == RaceBlowMethodType::SHOOT) {
315 mam_ptr->power = mbe_info[enum2i(mam_ptr->effect)].power;
316 process_melee(player_ptr, mam_ptr);
317 if (!is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr) || mam_ptr->do_silly_attack) {
321 if (!mam_ptr->obvious && !mam_ptr->damage && (r_ptr->r_blows[ap_cnt] <= 10)) {
325 if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR) {
326 r_ptr->r_blows[ap_cnt]++;
332 * @brief モンスターから敵モンスターへの打撃攻撃処理
333 * @param m_idx 攻撃側モンスターの参照ID
334 * @param t_idx 目標側モンスターの参照ID
335 * @return 実際に打撃処理が行われた場合TRUEを返す
337 bool monst_attack_monst(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx)
340 mam_type *mam_ptr = initialize_mam_type(player_ptr, &tmp_mam, m_idx, t_idx);
342 if (!check_same_monster(player_ptr, mam_ptr)) {
346 monster_desc(player_ptr, mam_ptr->m_name, mam_ptr->m_ptr, 0);
347 monster_desc(player_ptr, mam_ptr->t_name, mam_ptr->t_ptr, 0);
348 if (!mam_ptr->see_either && mam_ptr->known) {
349 player_ptr->current_floor_ptr->monster_noise = true;
352 if (player_ptr->riding && (m_idx == player_ptr->riding)) {
353 disturb(player_ptr, true, true);
356 repeat_melee(player_ptr, mam_ptr);
357 explode_monster_by_melee(player_ptr, mam_ptr);
358 if (!mam_ptr->blinked || !MonsterRace(mam_ptr->m_ptr->r_idx).is_valid()) {
362 thief_runaway_by_melee(player_ptr, mam_ptr);