OSDN Git Service

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