OSDN Git Service

[Refactor] enum spells-typeをenum class AttributeTypeに置換
[hengbandforosx/hengbandosx.git] / src / melee / monster-attack-monster.cpp
1 /*!
2  * @brief モンスター同士が乱闘する処理
3  * @date 2020/05/23
4  * @author Hourier
5  */
6
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 "effect/attribute-types.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"
40
41 static void heal_monster_by_melee(player_type *player_ptr, mam_type *mam_ptr)
42 {
43     if (!monster_living(mam_ptr->m_idx) || (mam_ptr->damage <= 2))
44         return;
45
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;
50
51     if (player_ptr->health_who == mam_ptr->m_idx)
52         player_ptr->redraw |= (PR_HEALTH);
53
54     if (player_ptr->riding == mam_ptr->m_idx)
55         player_ptr->redraw |= (PR_UHEALTH);
56
57     if (mam_ptr->see_m && did_heal)
58         msg_format(_("%sは体力を回復したようだ。", "%^s appears healthier."), mam_ptr->m_name);
59 }
60
61 static void process_blow_effect(player_type *player_ptr, mam_type *mam_ptr)
62 {
63     monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
64     switch (mam_ptr->attribute) {
65     case BLOW_EFFECT_TYPE_FEAR:
66         project(player_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, mam_ptr->damage,
67             AttributeType::TURN_ALL, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
68         break;
69     case BLOW_EFFECT_TYPE_SLEEP:
70         project(player_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, r_ptr->level, 
71             AttributeType::OLD_SLEEP, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
72         break;
73     case BLOW_EFFECT_TYPE_HEAL:
74         heal_monster_by_melee(player_ptr, mam_ptr);
75         break;
76     }
77 }
78
79 static void aura_fire_by_melee(player_type *player_ptr, mam_type *mam_ptr)
80 {
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->aura_flags.has_not(MonsterAuraType::FIRE) || (mam_ptr->m_ptr->r_idx == 0))
84         return;
85
86     if (((r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK) != 0) && is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr)) {
87         r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK);
88         return;
89     }
90
91     if (mam_ptr->see_either)
92         msg_format(_("%^sは突然熱くなった!", "%^s is suddenly very hot!"), mam_ptr->m_name);
93
94     if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr))
95         tr_ptr->aura_flags.set(MonsterAuraType::FIRE);
96
97     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,
98         PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
99 }
100
101 static void aura_cold_by_melee(player_type *player_ptr, mam_type *mam_ptr)
102 {
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->aura_flags.has_not(MonsterAuraType::COLD) || (mam_ptr->m_ptr->r_idx == 0))
106         return;
107
108     if (((r_ptr->flagsr & RFR_EFF_IM_COLD_MASK) != 0) && is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr)) {
109         r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_COLD_MASK);
110         return;
111     }
112
113     if (mam_ptr->see_either)
114         msg_format(_("%^sは突然寒くなった!", "%^s is suddenly very cold!"), mam_ptr->m_name);
115
116     if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr))
117         tr_ptr->aura_flags.set(MonsterAuraType::COLD);
118
119     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,
120         PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
121 }
122
123 static void aura_elec_by_melee(player_type *player_ptr, mam_type *mam_ptr)
124 {
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->aura_flags.has_not(MonsterAuraType::ELEC) || (mam_ptr->m_ptr->r_idx == 0))
128         return;
129
130     if (((r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK) != 0) && is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr)) {
131         r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK);
132         return;
133     }
134
135     if (mam_ptr->see_either)
136         msg_format(_("%^sは電撃を食らった!", "%^s gets zapped!"), mam_ptr->m_name);
137
138     if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr))
139         tr_ptr->aura_flags.set(MonsterAuraType::ELEC);
140
141     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,
142         PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
143 }
144
145 static bool check_same_monster(player_type *player_ptr, mam_type *mam_ptr)
146 {
147     if (mam_ptr->m_idx == mam_ptr->t_idx)
148         return false;
149
150     monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
151     if (r_ptr->flags1 & RF1_NEVER_BLOW)
152         return false;
153
154     if (d_info[player_ptr->dungeon_idx].flags.has(DF::NO_MELEE))
155         return false;
156
157     return true;
158 }
159
160 static void redraw_health_bar(player_type *player_ptr, mam_type *mam_ptr)
161 {
162     if (!mam_ptr->t_ptr->ml)
163         return;
164
165     if (player_ptr->health_who == mam_ptr->t_idx)
166         player_ptr->redraw |= (PR_HEALTH);
167
168     if (player_ptr->riding == mam_ptr->t_idx)
169         player_ptr->redraw |= (PR_UHEALTH);
170 }
171
172 static void describe_silly_melee(mam_type *mam_ptr)
173 {
174     char temp[MAX_NLEN];
175     if ((mam_ptr->act == nullptr) || !mam_ptr->see_either)
176         return;
177
178 #ifdef JP
179     if (mam_ptr->do_silly_attack)
180         mam_ptr->act = silly_attacks2[randint0(MAX_SILLY_ATTACK)];
181
182     strfmt(temp, mam_ptr->act, mam_ptr->t_name);
183     msg_format("%^sは%s", mam_ptr->m_name, temp);
184 #else
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);
188     } else
189         strfmt(temp, mam_ptr->act, mam_ptr->t_name);
190
191     msg_format("%^s %s", mam_ptr->m_name, temp);
192 #endif
193 }
194
195 static void process_monster_attack_effect(player_type *player_ptr, mam_type *mam_ptr)
196 {
197     if (mam_ptr->pt == AttributeType::NONE)
198         return;
199
200     if (!mam_ptr->explode)
201         project(player_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);
203
204     process_blow_effect(player_ptr, mam_ptr);
205     if (!mam_ptr->touched)
206         return;
207
208     aura_fire_by_melee(player_ptr, mam_ptr);
209     aura_cold_by_melee(player_ptr, mam_ptr);
210     aura_elec_by_melee(player_ptr, mam_ptr);
211 }
212
213 static void process_melee(player_type *player_ptr, mam_type *mam_ptr)
214 {
215     if (mam_ptr->effect != RaceBlowEffectType::NONE && !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(player_ptr, mam_ptr);
217         return;
218     }
219
220     (void)set_monster_csleep(player_ptr, mam_ptr->t_idx, 0);
221     redraw_health_bar(player_ptr, mam_ptr);
222     describe_melee_method(player_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->attribute = BLOW_EFFECT_TYPE_NONE;
227     mam_ptr->pt = AttributeType::MISSILE;
228     decide_monster_attack_effect(player_ptr, mam_ptr);
229     process_monster_attack_effect(player_ptr, mam_ptr);
230 }
231
232 static void thief_runaway_by_melee(player_type *player_ptr, mam_type *mam_ptr)
233 {
234     if (SpellHex(player_ptr).check_hex_barrier(mam_ptr->m_idx, HEX_ANTI_TELE)) {
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             player_ptr->current_floor_ptr->monster_noise = true;
239         }
240     } else {
241         if (mam_ptr->see_m) {
242             msg_print(_("泥棒は笑って逃げた!", "The thief flees laughing!"));
243         } else if (mam_ptr->known) {
244             player_ptr->current_floor_ptr->monster_noise = true;
245         }
246
247         teleport_away(player_ptr, mam_ptr->m_idx, MAX_SIGHT * 2 + 5, TELEPORT_SPONTANEOUS);
248     }
249 }
250
251 static void explode_monster_by_melee(player_type *player_ptr, mam_type *mam_ptr)
252 {
253     if (!mam_ptr->explode)
254         return;
255
256     sound(SOUND_EXPLODE);
257     (void)set_monster_invulner(player_ptr, mam_ptr->m_idx, 0, false);
258     mon_take_hit_mon(player_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;
261 }
262
263 /*!
264  * @brief r_infoで定義した攻撃回数の分だけ、モンスターからモンスターへの直接攻撃処理を繰り返す
265  * @param player_ptr プレイヤーへの参照ポインタ
266  * @param mam_ptr モンスター乱闘構造体への参照ポインタ
267  */
268 void repeat_melee(player_type *player_ptr, mam_type *mam_ptr)
269 {
270     monster_race *r_ptr = &r_info[mam_ptr->m_ptr->r_idx];
271     for (int ap_cnt = 0; ap_cnt < MAX_NUM_BLOWS; ap_cnt++) {
272         mam_ptr->effect = r_ptr->blow[ap_cnt].effect;
273         mam_ptr->method = r_ptr->blow[ap_cnt].method;
274         mam_ptr->d_dice = r_ptr->blow[ap_cnt].d_dice;
275         mam_ptr->d_side = r_ptr->blow[ap_cnt].d_side;
276
277         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)
278             break;
279
280         if (mam_ptr->method == RBM_SHOOT)
281             continue;
282
283         mam_ptr->power = mbe_info[enum2i(mam_ptr->effect)].power;
284         process_melee(player_ptr, mam_ptr);
285         if (!is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr) || mam_ptr->do_silly_attack)
286             continue;
287
288         if (!mam_ptr->obvious && !mam_ptr->damage && (r_ptr->r_blows[ap_cnt] <= 10))
289             continue;
290
291         if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR)
292             r_ptr->r_blows[ap_cnt]++;
293     }
294 }
295
296 /*!
297  * @brief モンスターから敵モンスターへの打撃攻撃処理
298  * @param m_idx 攻撃側モンスターの参照ID
299  * @param t_idx 目標側モンスターの参照ID
300  * @return 実際に打撃処理が行われた場合TRUEを返す
301  */
302 bool monst_attack_monst(player_type *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx)
303 {
304     mam_type tmp_mam;
305     mam_type *mam_ptr = initialize_mam_type(player_ptr, &tmp_mam, m_idx, t_idx);
306
307     if (!check_same_monster(player_ptr, mam_ptr))
308         return false;
309
310     monster_desc(player_ptr, mam_ptr->m_name, mam_ptr->m_ptr, 0);
311     monster_desc(player_ptr, mam_ptr->t_name, mam_ptr->t_ptr, 0);
312     if (!mam_ptr->see_either && mam_ptr->known)
313         player_ptr->current_floor_ptr->monster_noise = true;
314
315     if (player_ptr->riding && (m_idx == player_ptr->riding))
316         disturb(player_ptr, true, true);
317
318     repeat_melee(player_ptr, mam_ptr);
319     explode_monster_by_melee(player_ptr, mam_ptr);
320     if (!mam_ptr->blinked || mam_ptr->m_ptr->r_idx == 0)
321         return true;
322
323     thief_runaway_by_melee(player_ptr, mam_ptr);
324     return true;
325 }