OSDN Git Service

[Refactor] #2628 Renamed object-type-definition.cpp/h to item-entity.cpp/h
[hengbandforosx/hengbandosx.git] / src / player-attack / attack-chaos-effect.cpp
1 /*!
2  * @brief 特殊属性武器で攻撃した際の追加効果処理
3  * @date 2020/05/23
4  * @author Hourier
5  * @details
6  * カオス属性、魔術属性、ゴールデンハンマー
7  */
8
9 #include "player-attack/attack-chaos-effect.h"
10 #include "artifact/fixed-art-types.h"
11 #include "core/player-redraw-types.h"
12 #include "flavor/flavor-describer.h"
13 #include "flavor/object-flavor-types.h"
14 #include "inventory/inventory-object.h"
15 #include "inventory/inventory-slot-types.h"
16 #include "lore/lore-store.h"
17 #include "monster-race//race-ability-mask.h"
18 #include "monster-race/monster-race.h"
19 #include "monster-race/race-flags-resistance.h"
20 #include "monster-race/race-flags1.h"
21 #include "monster-race/race-flags3.h"
22 #include "monster-race/race-resistance-mask.h"
23 #include "monster/monster-describer.h"
24 #include "monster/monster-info.h"
25 #include "monster/monster-status-setter.h"
26 #include "monster/monster-status.h"
27 #include "object/object-mark-types.h"
28 #include "player-attack/player-attack-util.h"
29 #include "player/attack-defense-types.h"
30 #include "realm/realm-hex-numbers.h"
31 #include "spell-kind/spells-polymorph.h"
32 #include "spell-kind/spells-sight.h"
33 #include "spell-kind/spells-teleport.h"
34 #include "spell-realm/spells-hex.h"
35 #include "system/floor-type-definition.h"
36 #include "system/item-entity.h"
37 #include "system/monster-race-definition.h"
38 #include "system/monster-type-definition.h"
39 #include "system/player-type-definition.h"
40 #include "util/bit-flags-calculator.h"
41 #include "view/display-messages.h"
42
43 /*!
44  * @brief 打撃でモンスターを混乱させる処理
45  * @param player_ptr プレイヤーへの参照ポインタ
46  * @param pa_ptr 直接攻撃構造体への参照ポインタ
47  * @param can_resist レベルで抵抗可能ならTRUE、できないならFALSE
48  * @details
49  * カオス属性や混乱の手
50  */
51 static void attack_confuse(PlayerType *player_ptr, player_attack_type *pa_ptr, bool can_resist = true)
52 {
53     if (player_ptr->special_attack & ATTACK_CONFUSE) {
54         player_ptr->special_attack &= ~(ATTACK_CONFUSE);
55         msg_print(_("手の輝きがなくなった。", "Your hands stop glowing."));
56         player_ptr->redraw |= (PR_STATUS);
57     }
58
59     auto *r_ptr = pa_ptr->r_ptr;
60     if (r_ptr->flags3 & RF3_NO_CONF) {
61         if (is_original_ap_and_seen(player_ptr, pa_ptr->m_ptr)) {
62             r_ptr->r_flags3 |= RF3_NO_CONF;
63         }
64         msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), pa_ptr->m_name);
65
66     } else if (can_resist && randint0(100) < r_ptr->level) {
67         msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), pa_ptr->m_name);
68     } else {
69         msg_format(_("%^sは混乱したようだ。", "%^s appears confused."), pa_ptr->m_name);
70         (void)set_monster_confused(player_ptr, pa_ptr->m_idx, pa_ptr->m_ptr->get_remaining_confusion() + 10 + randint0(player_ptr->lev) / 5);
71     }
72 }
73
74 /*!
75  * @brief 打撃でモンスターを朦朧とさせる処理
76  * @param player_ptr プレイヤーへの参照ポインタ
77  * @param pa_ptr 直接攻撃構造体への参照ポインタ
78  * @param can_resist レベルで抵抗可能ならTRUE、できないならFALSE
79  * @details
80  * 魔術属性
81  */
82 static void attack_stun(PlayerType *player_ptr, player_attack_type *pa_ptr, bool can_resist = true)
83 {
84     auto *r_ptr = pa_ptr->r_ptr;
85     if (any_bits(r_ptr->flags3, RF3_NO_STUN)) {
86         if (is_original_ap_and_seen(player_ptr, pa_ptr->m_ptr)) {
87             set_bits(r_ptr->flags3, RF3_NO_STUN);
88         }
89         msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), pa_ptr->m_name);
90     } else if (can_resist && randint0(100) < r_ptr->level) {
91         msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), pa_ptr->m_name);
92     } else {
93         msg_format(_("%^sは朦朧としたようだ。", "%^s appears stunned."), pa_ptr->m_name);
94         (void)set_monster_stunned(player_ptr, pa_ptr->m_idx, pa_ptr->m_ptr->get_remaining_stun() + 10 + randint0(player_ptr->lev) / 5);
95     }
96 }
97
98 /*!
99  * @brief 打撃でモンスターを恐怖させる処理
100  * @param player_ptr プレイヤーへの参照ポインタ
101  * @param pa_ptr 直接攻撃構造体への参照ポインタ
102  * @param can_resist レベルで抵抗可能ならTRUE、できないならFALSE
103  * @details
104  * 魔術属性
105  */
106 static void attack_scare(PlayerType *player_ptr, player_attack_type *pa_ptr, bool can_resist = true)
107 {
108     auto *r_ptr = pa_ptr->r_ptr;
109     if (any_bits(r_ptr->flags3, RF3_NO_FEAR)) {
110         if (is_original_ap_and_seen(player_ptr, pa_ptr->m_ptr)) {
111             set_bits(r_ptr->flags3, RF3_NO_FEAR);
112         }
113         msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), pa_ptr->m_name);
114     } else if (can_resist && randint0(100) < r_ptr->level) {
115         msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), pa_ptr->m_name);
116     } else {
117         msg_format(_("%^sは恐怖して逃げ出した!", "%^s flees in terror!"), pa_ptr->m_name);
118         (void)set_monster_monfear(player_ptr, pa_ptr->m_idx, pa_ptr->m_ptr->get_remaining_fear() + 10 + randint0(player_ptr->lev) / 5);
119     }
120 }
121
122 /*!
123  * @brief 打撃でモンスターを無力化する処理
124  * @param player_ptr プレイヤーへの参照ポインタ
125  * @param pa_ptr 直接攻撃構造体への参照ポインタ
126  * @details
127  * 魔術属性
128  */
129 static void attack_dispel(PlayerType *player_ptr, player_attack_type *pa_ptr)
130 {
131     if (pa_ptr->r_ptr->ability_flags.has_none_of(RF_ABILITY_ATTACK_MASK) && pa_ptr->r_ptr->ability_flags.has_none_of(RF_ABILITY_INDIRECT_MASK)) {
132         return;
133     }
134
135     auto dd = 2;
136     if (pa_ptr->m_ptr->mtimed[MTIMED_SLOW]) {
137         dd += 1;
138     }
139     if (pa_ptr->m_ptr->mtimed[MTIMED_FAST]) {
140         dd += 2;
141     }
142     if (pa_ptr->m_ptr->mtimed[MTIMED_INVULNER]) {
143         dd += 3;
144     }
145
146     msg_print(_("武器が敵の魔力を吸い取った!", "The weapon drains mana from your enemy!"));
147     dispel_monster_status(player_ptr, pa_ptr->m_idx);
148
149     auto sp = damroll(dd, 8);
150     player_ptr->csp = std::min(player_ptr->msp, player_ptr->csp + sp);
151     set_bits(player_ptr->redraw, PR_MANA);
152 }
153
154 /*!
155  * @brief 打撃でモンスターを調査する処理
156  * @param player_ptr プレイヤーへの参照ポインタ
157  * @param pa_ptr 直接攻撃構造体への参照ポインタ
158  * @details
159  * 魔術属性
160  */
161 static void attack_probe(PlayerType *player_ptr, player_attack_type *pa_ptr)
162 {
163     msg_print(_("刃が敵を調査した...", "The blade probed your enemy..."));
164     msg_print(nullptr);
165     char buf[256];
166     probed_monster_info(buf, player_ptr, pa_ptr->m_ptr, pa_ptr->r_ptr);
167     msg_print(buf);
168     msg_print(nullptr);
169     (void)lore_do_probe(player_ptr, pa_ptr->r_idx);
170 }
171
172 /*!
173  * @breif カオス武器でのテレポート・アウェイを行うか判定する (抵抗されたら無効)
174  * @param player_ptr プレイヤーへの参照ポインタ
175  * @param pa_ptr 直接攻撃構造体への参照ポインタ
176  * @return 抵抗されたらTRUE、アウェイされるならFALSE
177  */
178 static bool judge_tereprt_resistance(PlayerType *player_ptr, player_attack_type *pa_ptr)
179 {
180     auto *r_ptr = pa_ptr->r_ptr;
181     if (r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_TELEPORT)) {
182         return false;
183     }
184
185     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
186         if (is_original_ap_and_seen(player_ptr, pa_ptr->m_ptr)) {
187             r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
188         }
189
190         msg_format(_("%^sには効果がなかった。", "%^s is unaffected!"), pa_ptr->m_name);
191         return true;
192     }
193
194     if (r_ptr->level > randint1(100)) {
195         if (is_original_ap_and_seen(player_ptr, pa_ptr->m_ptr)) {
196             r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
197         }
198
199         msg_format(_("%^sは抵抗力を持っている!", "%^s resists!"), pa_ptr->m_name);
200         return true;
201     }
202
203     return false;
204 }
205
206 /*!
207  * @brief カオス武器でのテレポート・アウェイを実行する
208  * @param player_ptr プレイヤーへの参照ポインタ
209  * @param pa_ptr 直接攻撃構造体への参照ポインタ
210  * @param num 現在の攻撃回数 (テレポートしてしまったら追加攻撃できないのでその補正)
211  */
212 static void attack_teleport_away(PlayerType *player_ptr, player_attack_type *pa_ptr, int *num)
213 {
214     if (judge_tereprt_resistance(player_ptr, pa_ptr)) {
215         return;
216     }
217
218     msg_format(_("%^sは消えた!", "%^s disappears!"), pa_ptr->m_name);
219     teleport_away(player_ptr, pa_ptr->m_idx, 50, TELEPORT_PASSIVE);
220     *num = pa_ptr->num_blow + 1;
221     *(pa_ptr->mdeath) = true;
222 }
223
224 /*!
225  * @brief カオス武器でのテレポート・アウェイを実行する
226  * @param player_ptr プレイヤーへの参照ポインタ
227  * @param pa_ptr 直接攻撃構造体への参照ポインタ
228  * @param y モンスターのY座標
229  * @param x モンスターのX座標
230  */
231 static void attack_polymorph(PlayerType *player_ptr, player_attack_type *pa_ptr, POSITION y, POSITION x)
232 {
233     auto *r_ptr = pa_ptr->r_ptr;
234     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(r_ptr->flags1, RF1_QUESTOR) || r_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_CHAOS_MASK)) {
235         return;
236     }
237
238     if (polymorph_monster(player_ptr, y, x)) {
239         msg_format(_("%^sは変化した!", "%^s changes!"), pa_ptr->m_name);
240         *(pa_ptr->fear) = false;
241         pa_ptr->weak = false;
242     } else {
243         msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), pa_ptr->m_name);
244     }
245
246     pa_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[pa_ptr->m_idx];
247     monster_desc(player_ptr, pa_ptr->m_name, pa_ptr->m_ptr, 0);
248 }
249
250 /*!
251  * @brief ゴールデンハンマーによるアイテム奪取処理
252  * @param player_ptr プレイヤーへの参照ポインタ
253  * @param pa_ptr 直接攻撃構造体への参照ポインタ
254  */
255 static void attack_golden_hammer(PlayerType *player_ptr, player_attack_type *pa_ptr)
256 {
257     auto *floor_ptr = player_ptr->current_floor_ptr;
258     auto *m_ptr = &floor_ptr->m_list[pa_ptr->m_idx];
259     if (m_ptr->hold_o_idx_list.empty()) {
260         return;
261     }
262
263     auto *q_ptr = &floor_ptr->o_list[m_ptr->hold_o_idx_list.front()];
264     GAME_TEXT o_name[MAX_NLEN];
265     describe_flavor(player_ptr, o_name, q_ptr, OD_NAME_ONLY);
266     q_ptr->held_m_idx = 0;
267     q_ptr->marked = OM_TOUCHED;
268     m_ptr->hold_o_idx_list.pop_front();
269     msg_format(_("%sを奪った。", "You snatched %s."), o_name);
270     store_item_to_inventory(player_ptr, q_ptr);
271 }
272
273 /*!
274  * @brief カオス武器その他でモンスターのステータスを変化させる
275  * @param player_ptr プレイヤーへの参照ポインタ
276  * @param pa_ptr 直接攻撃構造体への参照ポインタ
277  * @param y モンスターのY座標
278  * @param x モンスターのX座標
279  * @param num 現在の攻撃回数
280  */
281 void change_monster_stat(PlayerType *player_ptr, player_attack_type *pa_ptr, const POSITION y, const POSITION x, int *num)
282 {
283     auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
284     auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + pa_ptr->hand];
285
286     if (any_bits(player_ptr->special_attack, ATTACK_CONFUSE) || pa_ptr->chaos_effect == CE_CONFUSION || pa_ptr->mode == HISSATSU_CONF || SpellHex(player_ptr).is_spelling_specific(HEX_CONFUSION)) {
287         attack_confuse(player_ptr, pa_ptr);
288     }
289
290     if (pa_ptr->magical_effect == MagicalBrandEffectType::STUN) {
291         attack_stun(player_ptr, pa_ptr, false);
292     }
293
294     if (pa_ptr->magical_effect == MagicalBrandEffectType::SCARE) {
295         attack_scare(player_ptr, pa_ptr, false);
296     }
297
298     if (pa_ptr->magical_effect == MagicalBrandEffectType::DISPELL) {
299         attack_dispel(player_ptr, pa_ptr);
300     }
301
302     if (pa_ptr->magical_effect == MagicalBrandEffectType::PROBE) {
303         attack_probe(player_ptr, pa_ptr);
304     }
305
306     if (pa_ptr->chaos_effect == CE_TELE_AWAY) {
307         attack_teleport_away(player_ptr, pa_ptr, num);
308     }
309
310     if (pa_ptr->chaos_effect == CE_POLYMORPH && randint1(90) > r_ptr->level) {
311         attack_polymorph(player_ptr, pa_ptr, y, x);
312     }
313
314     if (o_ptr->is_specific_artifact(FixedArtifactId::G_HAMMER)) {
315         attack_golden_hammer(player_ptr, pa_ptr);
316     }
317 }