OSDN Git Service

[Refactor] #2122 PlayerType::confused を削除し、TimedEffects::Confusion 側に処理を全て移した
[hengbandforosx/hengbandosx.git] / src / status / buff-setter.cpp
1 #include "status/buff-setter.h"
2 #include "avatar/avatar.h"
3 #include "core/disturbance.h"
4 #include "core/player-redraw-types.h"
5 #include "core/player-update-types.h"
6 #include "core/speed-table.h"
7 #include "core/stuff-handler.h"
8 #include "core/window-redrawer.h"
9 #include "game-option/disturbance-options.h"
10 #include "monster/monster-status-setter.h"
11 #include "player-base/player-class.h"
12 #include "player-info/class-info.h"
13 #include "player-info/race-info.h"
14 #include "player/attack-defense-types.h"
15 #include "player/player-status.h"
16 #include "realm/realm-song-numbers.h"
17 #include "spell-realm/spells-song.h"
18 #include "status/base-status.h"
19 #include "status/buff-setter.h"
20 #include "status/element-resistance.h"
21 #include "system/player-type-definition.h"
22 #include "timed-effect/player-confusion.h"
23 #include "timed-effect/player-cut.h"
24 #include "timed-effect/player-stun.h"
25 #include "timed-effect/timed-effects.h"
26 #include "view/display-messages.h"
27
28 /*!
29  * @brief プレイヤーの全ての時限効果をリセットする。 / reset timed flags
30  */
31 void reset_tim_flags(PlayerType *player_ptr)
32 {
33     auto effects = player_ptr->effects();
34     player_ptr->fast = 0; /* Timed -- Fast */
35     player_ptr->lightspeed = 0;
36     player_ptr->slow = 0; /* Timed -- Slow */
37     player_ptr->blind = 0; /* Timed -- Blindness */
38     player_ptr->paralyzed = 0; /* Timed -- Paralysis */
39     effects->confusion()->reset();
40     player_ptr->afraid = 0; /* Timed -- Fear */
41     player_ptr->hallucinated = 0; /* Timed -- Hallucination */
42     player_ptr->poisoned = 0; /* Timed -- Poisoned */
43     effects->cut()->reset();
44     effects->stun()->reset();
45
46     player_ptr->protevil = 0; /* Timed -- Protection */
47     player_ptr->invuln = 0; /* Timed -- Invulnerable */
48     player_ptr->ult_res = 0;
49     player_ptr->hero = 0; /* Timed -- Heroism */
50     player_ptr->shero = 0; /* Timed -- Super Heroism */
51     player_ptr->shield = 0; /* Timed -- Shield Spell */
52     player_ptr->blessed = 0; /* Timed -- Blessed */
53     player_ptr->tim_invis = 0; /* Timed -- Invisibility */
54     player_ptr->tim_infra = 0; /* Timed -- Infra Vision */
55     player_ptr->tim_regen = 0; /* Timed -- Regeneration */
56     player_ptr->tim_stealth = 0; /* Timed -- Stealth */
57     player_ptr->tim_esp = 0;
58     player_ptr->wraith_form = 0; /* Timed -- Wraith Form */
59     player_ptr->tim_levitation = 0;
60     player_ptr->tim_sh_touki = 0;
61     player_ptr->tim_sh_fire = 0;
62     player_ptr->tim_sh_holy = 0;
63     player_ptr->tim_eyeeye = 0;
64     player_ptr->magicdef = 0;
65     player_ptr->resist_magic = 0;
66     player_ptr->tsuyoshi = 0;
67     player_ptr->tim_pass_wall = 0;
68     player_ptr->tim_res_nether = 0;
69     player_ptr->tim_res_time = 0;
70     player_ptr->tim_mimic = 0;
71     player_ptr->mimic_form = MimicKindType::NONE;
72     player_ptr->tim_reflect = 0;
73     player_ptr->multishadow = 0;
74     player_ptr->dustrobe = 0;
75     player_ptr->action = ACTION_NONE;
76
77     player_ptr->oppose_acid = 0; /* Timed -- oppose acid */
78     player_ptr->oppose_elec = 0; /* Timed -- oppose lightning */
79     player_ptr->oppose_fire = 0; /* Timed -- oppose heat */
80     player_ptr->oppose_cold = 0; /* Timed -- oppose cold */
81     player_ptr->oppose_pois = 0; /* Timed -- oppose poison */
82
83     player_ptr->word_recall = 0;
84     player_ptr->alter_reality = 0;
85     player_ptr->sutemi = false;
86     player_ptr->counter = false;
87     player_ptr->ele_attack = 0;
88     player_ptr->ele_immune = 0;
89     player_ptr->special_attack = 0L;
90     player_ptr->special_defense = 0L;
91
92     while (player_ptr->energy_need < 0) {
93         player_ptr->energy_need += ENERGY_NEED();
94     }
95
96     player_ptr->timewalk = false;
97
98     if (player_ptr->riding) {
99         (void)set_monster_fast(player_ptr, player_ptr->riding, 0);
100         (void)set_monster_slow(player_ptr, player_ptr->riding, 0);
101         (void)set_monster_invulner(player_ptr, player_ptr->riding, 0, false);
102     }
103
104     if (PlayerClass(player_ptr).equals(PlayerClassType::BARD)) {
105         set_singing_song_effect(player_ptr, MUSIC_NONE);
106         set_singing_song_id(player_ptr, 0);
107     }
108 }
109
110 /*!
111  * @brief 加速の継続時間をセットする / Set "fast", notice observable changes
112  * @param v 継続時間
113  * @param do_dec 現在の継続時間より長い値のみ上書きする
114  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
115  */
116 bool set_fast(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
117 {
118     bool notice = false;
119     v = (v > 10000) ? 10000 : (v < 0) ? 0
120                                       : v;
121
122     if (player_ptr->is_dead) {
123         return false;
124     }
125
126     if (v) {
127         if (player_ptr->fast && !do_dec) {
128             if (player_ptr->fast > v) {
129                 return false;
130             }
131         } else if (!is_fast(player_ptr) && !player_ptr->lightspeed) {
132             msg_print(_("素早く動けるようになった!", "You feel yourself moving much faster!"));
133             notice = true;
134             chg_virtue(player_ptr, V_PATIENCE, -1);
135             chg_virtue(player_ptr, V_DILIGENCE, 1);
136         }
137     } else {
138         if (player_ptr->fast && !player_ptr->lightspeed && !music_singing(player_ptr, MUSIC_SPEED) && !music_singing(player_ptr, MUSIC_SHERO)) {
139             msg_print(_("動きの素早さがなくなったようだ。", "You feel yourself slow down."));
140             notice = true;
141         }
142     }
143
144     player_ptr->fast = v;
145     if (!notice) {
146         return false;
147     }
148
149     if (disturb_state) {
150         disturb(player_ptr, false, false);
151     }
152     player_ptr->update |= (PU_BONUS);
153     handle_stuff(player_ptr);
154     return true;
155 }
156
157 /*!
158  * @brief 肌石化の継続時間をセットする / Set "shield", notice observable changes
159  * @param v 継続時間
160  * @param do_dec 現在の継続時間より長い値のみ上書きする
161  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
162  */
163 bool set_shield(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
164 {
165     bool notice = false;
166     v = (v > 10000) ? 10000 : (v < 0) ? 0
167                                       : v;
168
169     if (player_ptr->is_dead) {
170         return false;
171     }
172
173     if (v) {
174         if (player_ptr->shield && !do_dec) {
175             if (player_ptr->shield > v) {
176                 return false;
177             }
178         } else if (!player_ptr->shield) {
179             msg_print(_("肌が石になった。", "Your skin turns to stone."));
180             notice = true;
181         }
182     } else {
183         if (player_ptr->shield) {
184             msg_print(_("肌が元に戻った。", "Your skin returns to normal."));
185             notice = true;
186         }
187     }
188
189     player_ptr->shield = v;
190     player_ptr->redraw |= (PR_STATUS);
191
192     if (!notice) {
193         return false;
194     }
195
196     if (disturb_state) {
197         disturb(player_ptr, false, false);
198     }
199     player_ptr->update |= (PU_BONUS);
200     handle_stuff(player_ptr);
201     return true;
202 }
203
204 /*!
205  * @brief 魔法の鎧の継続時間をセットする / Set "magicdef", notice observable changes
206  * @param v 継続時間
207  * @param do_dec 現在の継続時間より長い値のみ上書きする
208  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
209  */
210 bool set_magicdef(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
211 {
212     bool notice = false;
213     v = (v > 10000) ? 10000 : (v < 0) ? 0
214                                       : v;
215
216     if (player_ptr->is_dead) {
217         return false;
218     }
219
220     if (v) {
221         if (player_ptr->magicdef && !do_dec) {
222             if (player_ptr->magicdef > v) {
223                 return false;
224             }
225         } else if (!player_ptr->magicdef) {
226             msg_print(_("魔法の防御力が増したような気がする。", "You feel more resistant to magic."));
227             notice = true;
228         }
229     } else {
230         if (player_ptr->magicdef) {
231             msg_print(_("魔法の防御力が元に戻った。", "You feel less resistant to magic."));
232             notice = true;
233         }
234     }
235
236     player_ptr->magicdef = v;
237     player_ptr->redraw |= (PR_STATUS);
238
239     if (!notice) {
240         return false;
241     }
242
243     if (disturb_state) {
244         disturb(player_ptr, false, false);
245     }
246     player_ptr->update |= (PU_BONUS);
247     handle_stuff(player_ptr);
248     return true;
249 }
250
251 /*!
252  * @brief 祝福の継続時間をセットする / Set "blessed", notice observable changes
253  * @param v 継続時間
254  * @param do_dec 現在の継続時間より長い値のみ上書きする
255  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
256  */
257 bool set_blessed(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
258 {
259     bool notice = false;
260     v = (v > 10000) ? 10000 : (v < 0) ? 0
261                                       : v;
262
263     if (player_ptr->is_dead) {
264         return false;
265     }
266
267     if (v) {
268         if (player_ptr->blessed && !do_dec) {
269             if (player_ptr->blessed > v) {
270                 return false;
271             }
272         } else if (!is_blessed(player_ptr)) {
273             msg_print(_("高潔な気分になった!", "You feel righteous!"));
274             notice = true;
275         }
276     } else {
277         if (player_ptr->blessed && !music_singing(player_ptr, MUSIC_BLESS)) {
278             msg_print(_("高潔な気分が消え失せた。", "The prayer has expired."));
279             notice = true;
280         }
281     }
282
283     player_ptr->blessed = v;
284     player_ptr->redraw |= (PR_STATUS);
285
286     if (!notice) {
287         return false;
288     }
289
290     if (disturb_state) {
291         disturb(player_ptr, false, false);
292     }
293     player_ptr->update |= (PU_BONUS);
294     handle_stuff(player_ptr);
295     return true;
296 }
297
298 /*!
299  * @brief 士気高揚の継続時間をセットする / Set "hero", notice observable changes
300  * @param v 継続時間
301  * @param do_dec 現在の継続時間より長い値のみ上書きする
302  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
303  */
304 bool set_hero(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
305 {
306     bool notice = false;
307     v = (v > 10000) ? 10000 : (v < 0) ? 0
308                                       : v;
309
310     if (player_ptr->is_dead) {
311         return false;
312     }
313
314     if (v) {
315         if (player_ptr->hero && !do_dec) {
316             if (player_ptr->hero > v) {
317                 return false;
318             }
319         } else if (!is_hero(player_ptr)) {
320             msg_print(_("ヒーローになった気がする!", "You feel like a hero!"));
321             notice = true;
322         }
323     } else {
324         if (player_ptr->hero && !music_singing(player_ptr, MUSIC_HERO) && !music_singing(player_ptr, MUSIC_SHERO)) {
325             msg_print(_("ヒーローの気分が消え失せた。", "The heroism wears off."));
326             notice = true;
327         }
328     }
329
330     player_ptr->hero = v;
331     player_ptr->redraw |= (PR_STATUS);
332
333     if (!notice) {
334         return false;
335     }
336
337     if (disturb_state) {
338         disturb(player_ptr, false, false);
339     }
340     player_ptr->update |= (PU_BONUS);
341     player_ptr->update |= (PU_HP);
342     handle_stuff(player_ptr);
343     return true;
344 }
345
346 /*!
347  * @brief 変身効果の継続時間と変身先をセットする / Set "tim_mimic", and "mimic_form", notice observable changes
348  * @param v 継続時間
349  * @param mimic_race_idx 変身内容
350  * @param do_dec 現在の継続時間より長い値のみ上書きする
351  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
352  */
353 bool set_mimic(PlayerType *player_ptr, TIME_EFFECT v, MimicKindType mimic_race_idx, bool do_dec)
354 {
355     bool notice = false;
356     v = (v > 10000) ? 10000 : (v < 0) ? 0
357                                       : v;
358
359     if (player_ptr->is_dead) {
360         return false;
361     }
362
363     if (v) {
364         if (player_ptr->tim_mimic && (player_ptr->mimic_form == mimic_race_idx) && !do_dec) {
365             if (player_ptr->tim_mimic > v) {
366                 return false;
367             }
368         } else if ((!player_ptr->tim_mimic) || (player_ptr->mimic_form != mimic_race_idx)) {
369             msg_print(_("自分の体が変わってゆくのを感じた。", "You feel that your body changes."));
370             player_ptr->mimic_form = mimic_race_idx;
371             notice = true;
372         }
373     }
374
375     else {
376         if (player_ptr->tim_mimic) {
377             msg_print(_("変身が解けた。", "You are no longer transformed."));
378             if (player_ptr->mimic_form == MimicKindType::DEMON) {
379                 set_oppose_fire(player_ptr, 0, true);
380             }
381             player_ptr->mimic_form = MimicKindType::NONE;
382             notice = true;
383             mimic_race_idx = MimicKindType::NONE;
384         }
385     }
386
387     player_ptr->tim_mimic = v;
388     if (!notice) {
389         return false;
390     }
391
392     if (disturb_state) {
393         disturb(player_ptr, false, true);
394     }
395
396     player_ptr->redraw |= (PR_BASIC | PR_STATUS);
397     player_ptr->update |= (PU_BONUS | PU_HP);
398
399     handle_stuff(player_ptr);
400     return true;
401 }
402
403 /*!
404  * @brief 狂戦士化の継続時間をセットする / Set "shero", notice observable changes
405  * @param v 継続時間/ 0ならば無条件にリセット
406  * @param do_dec FALSEの場合現在の継続時間より長い値のみ上書きする
407  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
408  */
409 bool set_shero(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
410 {
411     bool notice = false;
412     v = (v > 10000) ? 10000 : (v < 0) ? 0
413                                       : v;
414
415     if (player_ptr->is_dead) {
416         return false;
417     }
418
419     if (PlayerClass(player_ptr).equals(PlayerClassType::BERSERKER)) {
420         v = 1;
421         return false;
422     }
423
424     if (v) {
425         if (player_ptr->shero && !do_dec) {
426             if (player_ptr->shero > v) {
427                 return false;
428             }
429         } else if (!player_ptr->shero) {
430             msg_print(_("殺戮マシーンになった気がする!", "You feel like a killing machine!"));
431             notice = true;
432         }
433     } else {
434         if (player_ptr->shero) {
435             msg_print(_("野蛮な気持ちが消え失せた。", "You feel less berserk."));
436             notice = true;
437         }
438     }
439
440     player_ptr->shero = v;
441     player_ptr->redraw |= (PR_STATUS);
442
443     if (!notice) {
444         return false;
445     }
446
447     if (disturb_state) {
448         disturb(player_ptr, false, false);
449     }
450     player_ptr->update |= (PU_BONUS);
451     player_ptr->update |= (PU_HP);
452     handle_stuff(player_ptr);
453     return true;
454 }
455
456 /*!
457  * @brief 幽体化の継続時間をセットする / Set "wraith_form", notice observable changes
458  * @param v 継続時間
459  * @param do_dec 現在の継続時間より長い値のみ上書きする
460  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
461  */
462 bool set_wraith_form(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
463 {
464     bool notice = false;
465     v = (v > 10000) ? 10000 : (v < 0) ? 0
466                                       : v;
467
468     if (player_ptr->is_dead) {
469         return false;
470     }
471
472     if (v) {
473         if (player_ptr->wraith_form && !do_dec) {
474             if (player_ptr->wraith_form > v) {
475                 return false;
476             }
477         } else if (!player_ptr->wraith_form) {
478             msg_print(_("物質界を離れて幽鬼のような存在になった!", "You leave the physical world and turn into a wraith-being!"));
479             notice = true;
480             chg_virtue(player_ptr, V_UNLIFE, 3);
481             chg_virtue(player_ptr, V_HONOUR, -2);
482             chg_virtue(player_ptr, V_SACRIFICE, -2);
483             chg_virtue(player_ptr, V_VALOUR, -5);
484
485             player_ptr->redraw |= (PR_MAP);
486             player_ptr->update |= (PU_MONSTERS);
487
488             player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
489         }
490     } else {
491         if (player_ptr->wraith_form) {
492             msg_print(_("不透明になった感じがする。", "You feel opaque."));
493             notice = true;
494
495             player_ptr->redraw |= (PR_MAP);
496             player_ptr->update |= (PU_MONSTERS);
497
498             player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
499         }
500     }
501
502     player_ptr->wraith_form = v;
503     player_ptr->redraw |= (PR_STATUS);
504
505     if (!notice) {
506         return false;
507     }
508
509     if (disturb_state) {
510         disturb(player_ptr, false, false);
511     }
512     player_ptr->update |= (PU_BONUS);
513     handle_stuff(player_ptr);
514     return true;
515 }
516
517 /*!
518  * @brief オクレ兄さんの継続時間をセットする / Set "tsuyoshi", notice observable changes
519  * @param v 継続時間
520  * @param do_dec 現在の継続時間より長い値のみ上書きする
521  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
522  */
523 bool set_tsuyoshi(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
524 {
525     bool notice = false;
526     v = (v > 10000) ? 10000 : (v < 0) ? 0
527                                       : v;
528
529     if (player_ptr->is_dead) {
530         return false;
531     }
532
533     if (v) {
534         if (player_ptr->tsuyoshi && !do_dec) {
535             if (player_ptr->tsuyoshi > v) {
536                 return false;
537             }
538         } else if (!player_ptr->tsuyoshi) {
539             msg_print(_("「オクレ兄さん!」", "Brother OKURE!"));
540             notice = true;
541             chg_virtue(player_ptr, V_VITALITY, 2);
542         }
543     } else {
544         if (player_ptr->tsuyoshi) {
545             msg_print(_("肉体が急速にしぼんでいった。", "Your body has quickly shriveled."));
546
547             (void)dec_stat(player_ptr, A_CON, 20, true);
548             (void)dec_stat(player_ptr, A_STR, 20, true);
549
550             notice = true;
551             chg_virtue(player_ptr, V_VITALITY, -3);
552         }
553     }
554
555     player_ptr->tsuyoshi = v;
556     player_ptr->redraw |= (PR_STATUS);
557
558     if (!notice) {
559         return false;
560     }
561
562     if (disturb_state) {
563         disturb(player_ptr, false, false);
564     }
565     player_ptr->update |= (PU_BONUS);
566     player_ptr->update |= (PU_HP);
567     handle_stuff(player_ptr);
568     return true;
569 }