OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / combat / aura-counterattack.cpp
1 /*!
2  * @brief モンスターから直接攻撃を受けた時に、プレイヤーのオーラダメージで反撃する処理
3  * @date 2020/05/31
4  * @author Hourier
5  */
6
7 #include "combat/aura-counterattack.h"
8 #include "effect/attribute-types.h"
9 #include "effect/effect-characteristics.h"
10 #include "effect/effect-processor.h"
11 #include "grid/grid.h"
12 #include "inventory/inventory-slot-types.h"
13 #include "monster-attack/monster-attack-player.h"
14 #include "monster-race/monster-race.h"
15 #include "monster-race/race-flags-resistance.h"
16 #include "monster-race/race-flags3.h"
17 #include "monster-race/race-resistance-mask.h"
18 #include "monster/monster-damage.h"
19 #include "monster/monster-info.h"
20 #include "monster/monster-status.h"
21 #include "object-hook/hook-armor.h"
22 #include "player/player-status-flags.h"
23 #include "realm/realm-hex-numbers.h"
24 #include "spell-kind/spells-teleport.h"
25 #include "spell-realm/spells-hex.h"
26 #include "system/floor-type-definition.h"
27 #include "system/grid-type-definition.h"
28 #include "system/item-entity.h"
29 #include "system/monster-entity.h"
30 #include "system/monster-race-info.h"
31 #include "system/player-type-definition.h"
32 #include "view/display-messages.h"
33
34 static void aura_fire_by_monster_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
35 {
36     if (!has_sh_fire(player_ptr) || !monap_ptr->alive || player_ptr->is_dead) {
37         return;
38     }
39
40     auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
41     if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_FIRE_MASK)) {
42         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
43             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_FIRE_MASK);
44         }
45
46         return;
47     }
48
49     int dam = damroll(2, 6);
50     dam = mon_damage_mod(player_ptr, monap_ptr->m_ptr, dam, false);
51     msg_format(_("%s^は突然熱くなった!", "%s^ is suddenly very hot!"), monap_ptr->m_name);
52     MonsterDamageProcessor mdp(player_ptr, monap_ptr->m_idx, dam, &monap_ptr->fear, AttributeType::FIRE);
53     if (mdp.mon_take_hit(_("は灰の山になった。", " turns into a pile of ash."))) {
54         monap_ptr->blinked = false;
55         monap_ptr->alive = false;
56     }
57 }
58
59 static void aura_elec_by_monster_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
60 {
61     if (!has_sh_elec(player_ptr) || !monap_ptr->alive || player_ptr->is_dead) {
62         return;
63     }
64
65     auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
66     if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_ELEC_MASK)) {
67         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
68             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_ELEC_MASK);
69         }
70
71         return;
72     }
73
74     int dam = damroll(2, 6);
75     dam = mon_damage_mod(player_ptr, monap_ptr->m_ptr, dam, false);
76     msg_format(_("%s^は電撃をくらった!", "%s^ gets zapped!"), monap_ptr->m_name);
77     MonsterDamageProcessor mdp(player_ptr, monap_ptr->m_idx, dam, &monap_ptr->fear, AttributeType::ELEC);
78     if (mdp.mon_take_hit(_("は燃え殻の山になった。", " turns into a pile of cinders."))) {
79         monap_ptr->blinked = false;
80         monap_ptr->alive = false;
81     }
82 }
83
84 static void aura_cold_by_monster_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
85 {
86     if (!has_sh_cold(player_ptr) || !monap_ptr->alive || player_ptr->is_dead) {
87         return;
88     }
89
90     auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
91     if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_COLD_MASK)) {
92         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
93             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_COLD_MASK);
94         }
95
96         return;
97     }
98
99     int dam = damroll(2, 6);
100     dam = mon_damage_mod(player_ptr, monap_ptr->m_ptr, dam, false);
101     msg_format(_("%s^は冷気をくらった!", "%s^ is very cold!"), monap_ptr->m_name);
102     MonsterDamageProcessor mdp(player_ptr, monap_ptr->m_idx, dam, &monap_ptr->fear, AttributeType::COLD);
103     if (mdp.mon_take_hit(_("は凍りついた。", " was frozen."))) {
104         monap_ptr->blinked = false;
105         monap_ptr->alive = false;
106     }
107 }
108
109 static void aura_shards_by_monster_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
110 {
111     if (!player_ptr->dustrobe || !monap_ptr->alive || player_ptr->is_dead) {
112         return;
113     }
114
115     auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
116     if (r_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_SHARDS_MASK)) {
117         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
118             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_RESIST_SHARDS_MASK);
119         }
120     } else {
121         int dam = damroll(2, 6);
122         dam = mon_damage_mod(player_ptr, monap_ptr->m_ptr, dam, false);
123         msg_format(_("%s^は鏡の破片をくらった!", "%s^ gets sliced!"), monap_ptr->m_name);
124         MonsterDamageProcessor mdp(player_ptr, monap_ptr->m_idx, dam, &monap_ptr->fear, AttributeType::SHARDS);
125         if (mdp.mon_take_hit(_("はズタズタになった。", " is torn to pieces."))) {
126             monap_ptr->blinked = false;
127             monap_ptr->alive = false;
128         }
129     }
130
131     if (player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].is_mirror()) {
132         teleport_player(player_ptr, 10, TELEPORT_SPONTANEOUS);
133     }
134 }
135
136 static void aura_holy_by_monster_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
137 {
138     if (!player_ptr->tim_sh_holy || !monap_ptr->alive || player_ptr->is_dead) {
139         return;
140     }
141
142     auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
143     if (r_ptr->kind_flags.has_not(MonsterKindType::EVIL)) {
144         return;
145     }
146
147     if (r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
148         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
149             r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_ALL);
150         }
151
152         return;
153     }
154
155     int dam = damroll(2, 6);
156     dam = mon_damage_mod(player_ptr, monap_ptr->m_ptr, dam, false);
157     msg_format(_("%s^は聖なるオーラで傷ついた!", "%s^ is injured by holy power!"), monap_ptr->m_name);
158     MonsterDamageProcessor mdp(player_ptr, monap_ptr->m_idx, dam, &monap_ptr->fear, AttributeType::HOLY_FIRE);
159     if (mdp.mon_take_hit(_("は倒れた。", " is destroyed."))) {
160         monap_ptr->blinked = false;
161         monap_ptr->alive = false;
162     }
163
164     if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
165         r_ptr->r_kind_flags.set(MonsterKindType::EVIL);
166     }
167 }
168
169 static void aura_force_by_monster_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
170 {
171     if (!player_ptr->tim_sh_touki || !monap_ptr->alive || player_ptr->is_dead) {
172         return;
173     }
174
175     auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
176     if (r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
177         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
178             r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_ALL);
179         }
180
181         return;
182     }
183
184     int dam = damroll(2, 6);
185     dam = mon_damage_mod(player_ptr, monap_ptr->m_ptr, dam, false);
186     msg_format(_("%s^が鋭い闘気のオーラで傷ついた!", "%s^ is injured by the Force"), monap_ptr->m_name);
187     MonsterDamageProcessor mdp(player_ptr, monap_ptr->m_idx, dam, &monap_ptr->fear, AttributeType::MANA);
188     if (mdp.mon_take_hit(_("は倒れた。", " is destroyed."))) {
189         monap_ptr->blinked = false;
190         monap_ptr->alive = false;
191     }
192 }
193
194 static void aura_shadow_by_monster_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
195 {
196     if (!SpellHex(player_ptr).is_spelling_specific(HEX_SHADOW_CLOAK) || !monap_ptr->alive || player_ptr->is_dead) {
197         return;
198     }
199
200     int dam = 1;
201     ItemEntity *o_armed_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND];
202     auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
203     const EnumClassFlagGroup<MonsterResistanceType> resist_flags = { MonsterResistanceType::RESIST_ALL, MonsterResistanceType::RESIST_DARK };
204
205     if (r_ptr->resistance_flags.has_any_of(resist_flags)) {
206         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
207             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & resist_flags);
208         }
209
210         return;
211     }
212
213     if (o_armed_ptr->is_valid()) {
214         int basedam = ((o_armed_ptr->dd + player_ptr->to_dd[0]) * (o_armed_ptr->ds + player_ptr->to_ds[0] + 1));
215         dam = basedam / 2 + o_armed_ptr->to_d + player_ptr->to_d[0];
216     }
217
218     o_armed_ptr = &player_ptr->inventory_list[INVEN_BODY];
219     if (o_armed_ptr->is_valid() && o_armed_ptr->is_cursed()) {
220         dam *= 2;
221     }
222
223     dam = mon_damage_mod(player_ptr, monap_ptr->m_ptr, dam, false);
224     msg_format(_("影のオーラが%s^に反撃した!", "Enveloping shadows attack %s^."), monap_ptr->m_name);
225     MonsterDamageProcessor mdp(player_ptr, monap_ptr->m_idx, dam, &monap_ptr->fear, AttributeType::DARK);
226     if (mdp.mon_take_hit(_("は倒れた。", " is destroyed."))) {
227         monap_ptr->blinked = false;
228         monap_ptr->alive = false;
229         return;
230     }
231
232     struct attribute_table {
233         inventory_slot_type slot;
234         AttributeType type;
235     };
236
237     const int TABLE_SIZE = 4;
238     attribute_table table[TABLE_SIZE] = { { INVEN_HEAD, AttributeType::OLD_CONF }, { INVEN_SUB_HAND, AttributeType::OLD_SLEEP },
239         { INVEN_ARMS, AttributeType::TURN_ALL }, { INVEN_FEET, AttributeType::OLD_SLOW } };
240
241     BIT_FLAGS flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
242
243     /* Some cursed armours gives an extra effect */
244     for (int j = 0; j < TABLE_SIZE; j++) {
245         o_armed_ptr = &player_ptr->inventory_list[table[j].slot];
246         if (o_armed_ptr->is_valid() && o_armed_ptr->is_cursed() && o_armed_ptr->is_protector()) {
247             project(player_ptr, 0, 0, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, (player_ptr->lev * 2), table[j].type, flg);
248         }
249     }
250 }
251
252 void process_aura_counterattack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
253 {
254     if (!monap_ptr->touched) {
255         return;
256     }
257
258     aura_fire_by_monster_attack(player_ptr, monap_ptr);
259     aura_elec_by_monster_attack(player_ptr, monap_ptr);
260     aura_cold_by_monster_attack(player_ptr, monap_ptr);
261     aura_shards_by_monster_attack(player_ptr, monap_ptr);
262     aura_holy_by_monster_attack(player_ptr, monap_ptr);
263     aura_force_by_monster_attack(player_ptr, monap_ptr);
264     aura_shadow_by_monster_attack(player_ptr, monap_ptr);
265 }