OSDN Git Service

[Refactor] #553 PlayerStunRankを外から隠蔽するように設計を少し変えた / Changed the design about PlayerSt...
[hengbandforosx/hengbandosx.git] / src / status / bad-status-setter.cpp
1 #include "status/bad-status-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/stuff-handler.h"
7 #include "core/window-redrawer.h"
8 #include "game-option/disturbance-options.h"
9 #include "mind/mind-sniper.h"
10 #include "player-base/player-class.h"
11 #include "player-base/player-race.h"
12 #include "player-info/bluemage-data-type.h"
13 #include "player/attack-defense-types.h"
14 #include "player/player-status-flags.h"
15 #include "player/player-status.h"
16 #include "player/special-defense-types.h"
17 #include "spell-realm/spells-hex.h"
18 #include "status/base-status.h"
19 #include "status/buff-setter.h"
20 #include "system/player-type-definition.h"
21 #include "timed-effect/player-cut.h"
22 #include "timed-effect/player-stun.h"
23 #include "timed-effect/timed-effects.h"
24 #include "view/display-messages.h"
25 #include <algorithm>
26
27 BadStatusSetter::BadStatusSetter(player_type *player_ptr)
28     : player_ptr(player_ptr)
29 {
30 }
31
32 /*!
33  * @brief 盲目の継続時間をセットする / Set "blind", notice observable changes
34  * @param v 継続時間
35  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
36  * @details
37  * Note the use of "PU_UN_LITE" and "PU_UN_VIEW", which is needed to\n
38  * memorize any terrain features which suddenly become "visible".\n
39  * Note that blindness is currently the only thing which can affect\n
40  * "player_can_see_bold()".\n
41  */
42 bool BadStatusSetter::blindness(const TIME_EFFECT tmp_v)
43 {
44     auto notice = false;
45     auto v = std::clamp<short>(tmp_v, 0, 10000);
46     if (this->player_ptr->is_dead) {
47         return false;
48     }
49
50     if (v > 0) {
51         if (!this->player_ptr->blind) {
52             if (this->player_ptr->prace == player_race_type::ANDROID) {
53                 msg_print(_("センサーをやられた!", "The sensor broke!"));
54             } else {
55                 msg_print(_("目が見えなくなってしまった!", "You are blind!"));
56             }
57
58             notice = true;
59             chg_virtue(this->player_ptr, V_ENLIGHTEN, -1);
60         }
61     } else {
62         if (this->player_ptr->blind) {
63             if (this->player_ptr->prace == player_race_type::ANDROID) {
64                 msg_print(_("センサーが復旧した。", "The sensor has been restored."));
65             } else {
66                 msg_print(_("やっと目が見えるようになった。", "You can see again."));
67             }
68
69             notice = true;
70         }
71     }
72
73     this->player_ptr->blind = v;
74     this->player_ptr->redraw |= PR_STATUS;
75     if (!notice) {
76         return false;
77     }
78
79     if (disturb_state) {
80         disturb(this->player_ptr, false, false);
81     }
82
83     this->player_ptr->update |= PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_MONSTERS | PU_MON_LITE;
84     this->player_ptr->redraw |= PR_MAP;
85     this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
86     handle_stuff(this->player_ptr);
87     return true;
88 }
89
90 bool BadStatusSetter::mod_blindness(const TIME_EFFECT tmp_v)
91 {
92     return this->blindness(this->player_ptr->blind + tmp_v);
93 }
94
95 /*!
96  * @brief 混乱の継続時間をセットする / Set "confused", notice observable changes
97  * @param v 継続時間
98  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
99  */
100 bool BadStatusSetter::confusion(const TIME_EFFECT tmp_v)
101 {
102     auto notice = false;
103     auto v = std::clamp<short>(tmp_v, 0, 10000);
104     if (this->player_ptr->is_dead) {
105         return false;
106     }
107
108     if (v > 0) {
109         if (!this->player_ptr->confused) {
110             msg_print(_("あなたは混乱した!", "You are confused!"));
111
112             if (this->player_ptr->action == ACTION_LEARN) {
113                 msg_print(_("学習が続けられない!", "You cannot continue learning!"));
114                 auto bluemage_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
115                 bluemage_data->new_magic_learned = false;
116
117                 this->player_ptr->redraw |= PR_STATE;
118                 this->player_ptr->action = ACTION_NONE;
119             }
120             if (this->player_ptr->action == ACTION_KAMAE) {
121                 msg_print(_("構えがとけた。", "You lose your stance."));
122                 this->player_ptr->special_defense &= ~(KAMAE_MASK);
123                 this->player_ptr->update |= PU_BONUS;
124                 this->player_ptr->redraw |= PR_STATE;
125                 this->player_ptr->action = ACTION_NONE;
126             } else if (this->player_ptr->action == ACTION_KATA) {
127                 msg_print(_("型が崩れた。", "You lose your stance."));
128                 this->player_ptr->special_defense &= ~(KATA_MASK);
129                 this->player_ptr->update |= PU_BONUS;
130                 this->player_ptr->update |= PU_MONSTERS;
131                 this->player_ptr->redraw |= PR_STATE;
132                 this->player_ptr->redraw |= PR_STATUS;
133                 this->player_ptr->action = ACTION_NONE;
134             }
135
136             /* Sniper */
137             reset_concentration(this->player_ptr, true);
138
139             SpellHex spell_hex(this->player_ptr);
140             if (spell_hex.is_spelling_any()) {
141                 (void)spell_hex.stop_all_spells();
142             }
143
144             notice = true;
145             this->player_ptr->counter = false;
146             chg_virtue(this->player_ptr, V_HARMONY, -1);
147         }
148     } else {
149         if (this->player_ptr->confused) {
150             msg_print(_("やっと混乱がおさまった。", "You feel less confused now."));
151             this->player_ptr->special_attack &= ~(ATTACK_SUIKEN);
152             notice = true;
153         }
154     }
155
156     this->player_ptr->confused = v;
157     this->player_ptr->redraw |= PR_STATUS;
158     if (!notice) {
159         return false;
160     }
161
162     if (disturb_state) {
163         disturb(this->player_ptr, false, false);
164     }
165
166     handle_stuff(this->player_ptr);
167     return true;
168 }
169
170 bool BadStatusSetter::mod_confusion(const TIME_EFFECT tmp_v)
171 {
172     return this->confusion(this->player_ptr->confused + tmp_v);
173 }
174
175 /*!
176  * @brief 毒の継続時間をセットする / Set "poisoned", notice observable changes
177  * @param v 継続時間
178  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
179  */
180 bool BadStatusSetter::poison(const TIME_EFFECT tmp_v)
181 {
182     auto notice = false;
183     auto v = std::clamp<short>(tmp_v, 0, 10000);
184     if (this->player_ptr->is_dead) {
185         return false;
186     }
187
188     if (v > 0) {
189         if (!this->player_ptr->poisoned) {
190             msg_print(_("毒に侵されてしまった!", "You are poisoned!"));
191             notice = true;
192         }
193     } else {
194         if (this->player_ptr->poisoned) {
195             msg_print(_("やっと毒の痛みがなくなった。", "You are no longer poisoned."));
196             notice = true;
197         }
198     }
199
200     this->player_ptr->poisoned = v;
201     this->player_ptr->redraw |= PR_STATUS;
202     if (!notice) {
203         return false;
204     }
205
206     if (disturb_state) {
207         disturb(this->player_ptr, false, false);
208     }
209
210     handle_stuff(this->player_ptr);
211     return true;
212 }
213
214 bool BadStatusSetter::mod_poison(const TIME_EFFECT tmp_v)
215 {
216     return this->poison(this->player_ptr->poisoned + tmp_v);
217 }
218
219 /*!
220  * @brief 恐怖の継続時間をセットする / Set "afraid", notice observable changes
221  * @param v 継続時間
222  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
223  */
224 bool BadStatusSetter::afraidness(const TIME_EFFECT tmp_v)
225 {
226     auto notice = false;
227     auto v = std::clamp<short>(tmp_v, 0, 10000);
228     if (this->player_ptr->is_dead) {
229         return false;
230     }
231
232     if (v > 0) {
233         if (!this->player_ptr->afraid) {
234             msg_print(_("何もかも恐くなってきた!", "You are terrified!"));
235             if (this->player_ptr->special_defense & KATA_MASK) {
236                 msg_print(_("型が崩れた。", "You lose your stance."));
237                 this->player_ptr->special_defense &= ~(KATA_MASK);
238                 this->player_ptr->update |= PU_BONUS;
239                 this->player_ptr->update |= PU_MONSTERS;
240                 this->player_ptr->redraw |= PR_STATE;
241                 this->player_ptr->redraw |= PR_STATUS;
242                 this->player_ptr->action = ACTION_NONE;
243             }
244
245             notice = true;
246             this->player_ptr->counter = false;
247             chg_virtue(this->player_ptr, V_VALOUR, -1);
248         }
249     } else {
250         if (this->player_ptr->afraid) {
251             msg_print(_("やっと恐怖を振り払った。", "You feel bolder now."));
252             notice = true;
253         }
254     }
255
256     this->player_ptr->afraid = v;
257     this->player_ptr->redraw |= PR_STATUS;
258     if (!notice) {
259         return false;
260     }
261
262     if (disturb_state) {
263         disturb(this->player_ptr, false, false);
264     }
265
266     handle_stuff(this->player_ptr);
267     return true;
268 }
269
270 bool BadStatusSetter::mod_afraidness(const TIME_EFFECT tmp_v)
271 {
272     return this->afraidness(this->player_ptr->afraid + tmp_v);
273 }
274
275 /*!
276  * @brief 麻痺の継続時間をセットする / Set "paralyzed", notice observable changes
277  * @param v 継続時間
278  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
279  */
280 bool BadStatusSetter::paralysis(const TIME_EFFECT tmp_v)
281 {
282     auto notice = false;
283     auto v = std::clamp<short>(tmp_v, 0, 10000);
284     if (this->player_ptr->is_dead) {
285         return false;
286     }
287
288     if (v > 0) {
289         if (!this->player_ptr->paralyzed) {
290             msg_print(_("体が麻痺してしまった!", "You are paralyzed!"));
291             reset_concentration(this->player_ptr, true);
292
293             SpellHex spell_hex(this->player_ptr);
294             if (spell_hex.is_spelling_any()) {
295                 (void)spell_hex.stop_all_spells();
296             }
297
298             this->player_ptr->counter = false;
299             notice = true;
300         }
301     } else {
302         if (this->player_ptr->paralyzed) {
303             msg_print(_("やっと動けるようになった。", "You can move again."));
304             notice = true;
305         }
306     }
307
308     this->player_ptr->paralyzed = v;
309     this->player_ptr->redraw |= PR_STATUS;
310     if (!notice) {
311         return false;
312     }
313
314     if (disturb_state) {
315         disturb(this->player_ptr, false, false);
316     }
317
318     this->player_ptr->redraw |= PR_STATE;
319     handle_stuff(this->player_ptr);
320     return true;
321 }
322
323 bool BadStatusSetter::mod_paralysis(const TIME_EFFECT tmp_v)
324 {
325     return this->paralysis(this->player_ptr->paralyzed + tmp_v);
326 }
327
328 /*!
329  * @brief 幻覚の継続時間をセットする / Set "image", notice observable changes
330  * @param v 継続時間
331  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
332  * @details Note that we must redraw the map when hallucination changes.
333  */
334 bool BadStatusSetter::hallucination(const TIME_EFFECT tmp_v)
335 {
336     auto notice = false;
337     auto v = std::clamp<short>(tmp_v, 0, 10000);
338     if (this->player_ptr->is_dead) {
339         return false;
340     }
341
342     if (is_chargeman(this->player_ptr)) {
343         v = 0;
344     }
345
346     if (v > 0) {
347         set_tsuyoshi(this->player_ptr, 0, true);
348         if (!this->player_ptr->hallucinated) {
349             msg_print(_("ワーオ!何もかも虹色に見える!", "Oh, wow! Everything looks so cosmic now!"));
350             reset_concentration(this->player_ptr, true);
351
352             this->player_ptr->counter = false;
353             notice = true;
354         }
355     } else {
356         if (this->player_ptr->hallucinated) {
357             msg_print(_("やっとはっきりと物が見えるようになった。", "You can see clearly again."));
358             notice = true;
359         }
360     }
361
362     this->player_ptr->hallucinated = v;
363     this->player_ptr->redraw |= PR_STATUS;
364     if (!notice) {
365         return false;
366     }
367
368     if (disturb_state) {
369         disturb(this->player_ptr, false, true);
370     }
371
372     this->player_ptr->redraw |= PR_MAP | PR_HEALTH | PR_UHEALTH;
373     this->player_ptr->update |= PU_MONSTERS;
374     this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
375     handle_stuff(this->player_ptr);
376     return true;
377 }
378
379 bool BadStatusSetter::mod_hallucination(const TIME_EFFECT tmp_v)
380 {
381     return this->hallucination(this->player_ptr->hallucinated + tmp_v);
382 }
383
384 /*!
385  * @brief 減速の継続時間をセットする / Set "slow", notice observable changes
386  * @param v 継続時間
387  * @param do_dec 現在の継続時間より長い値のみ上書きする
388  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
389  */
390 bool BadStatusSetter::slowness(const TIME_EFFECT tmp_v, bool do_dec)
391 {
392     auto notice = false;
393     auto v = std::clamp<short>(tmp_v, 0, 10000);
394     if (this->player_ptr->is_dead) {
395         return false;
396     }
397
398     if (v > 0) {
399         if (this->player_ptr->slow && !do_dec) {
400             if (this->player_ptr->slow > v) {
401                 return false;
402             }
403         } else if (!this->player_ptr->slow) {
404             msg_print(_("体の動きが遅くなってしまった!", "You feel yourself moving slower!"));
405             notice = true;
406         }
407     } else {
408         if (this->player_ptr->slow) {
409             msg_print(_("動きの遅さがなくなったようだ。", "You feel yourself speed up."));
410             notice = true;
411         }
412     }
413
414     this->player_ptr->slow = v;
415     if (!notice) {
416         return false;
417     }
418
419     if (disturb_state) {
420         disturb(this->player_ptr, false, false);
421     }
422
423     this->player_ptr->update |= PU_BONUS;
424     handle_stuff(this->player_ptr);
425     return true;
426 }
427
428 bool BadStatusSetter::mod_slowness(const TIME_EFFECT tmp_v, bool do_dec)
429 {
430     return this->slowness(this->player_ptr->slow + tmp_v, do_dec);
431 }
432
433 /*!
434  * @brief 朦朧の継続時間をセットする / Set "stun", notice observable changes
435  * @param v 継続時間
436  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
437  * @details
438  * Note the special code to only notice "range" changes.
439  */
440 bool BadStatusSetter::stun(const TIME_EFFECT tmp_v)
441 {
442     auto v = std::clamp<short>(tmp_v, 0, 10000);
443     if (this->player_ptr->is_dead) {
444         return false;
445     }
446
447     if (PlayerRace(this->player_ptr).equals(player_race_type::GOLEM) || PlayerClass(this->player_ptr).can_resist_stun()) {
448         v = 0;
449     }
450
451     auto notice = this->process_stun_effect(v);
452     this->player_ptr->effects()->stun()->set(v);
453     if (!notice) {
454         return false;
455     }
456
457     if (disturb_state) {
458         disturb(this->player_ptr, false, false);
459     }
460
461     this->player_ptr->update |= PU_BONUS;
462     this->player_ptr->redraw |= PR_STUN;
463     handle_stuff(this->player_ptr);
464     return true;
465 }
466
467 bool BadStatusSetter::mod_stun(const TIME_EFFECT tmp_v)
468 {
469     return this->stun(this->player_ptr->effects()->stun()->current() + tmp_v);
470 }
471
472 /*!
473  * @brief 出血の継続時間をセットする / Set "cut", notice observable changes
474  * @param v 継続時間
475  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
476  * @details
477  * Note the special code to only notice "range" changes.
478  */
479 bool BadStatusSetter::cut(const TIME_EFFECT tmp_v)
480 {
481     auto v = std::clamp<short>(tmp_v, 0, 10000);
482     if (this->player_ptr->is_dead) {
483         return false;
484     }
485
486     if (PlayerRace(this->player_ptr).can_resist_cut() && !this->player_ptr->mimic_form) {
487         v = 0;
488     }
489
490     auto notice = this->process_cut_effect(v);
491     this->player_ptr->effects()->cut()->set(v);
492     if (!notice) {
493         return false;
494     }
495
496     if (disturb_state) {
497         disturb(this->player_ptr, false, false);
498     }
499
500     this->player_ptr->update |= PU_BONUS;
501     this->player_ptr->redraw |= PR_CUT;
502     handle_stuff(this->player_ptr);
503     return true;
504 }
505
506 bool BadStatusSetter::mod_cut(const TIME_EFFECT tmp_v)
507 {
508     return this->cut(this->player_ptr->effects()->cut()->current() + tmp_v);
509 }
510
511 bool BadStatusSetter::process_stun_effect(const short v)
512 {
513     auto old_rank = this->player_ptr->effects()->stun()->get_rank();
514     auto new_rank = PlayerStun::get_rank(v);
515     if (new_rank > old_rank) {
516         this->process_stun_status(new_rank, v);
517         return true;
518     }
519     
520     if (new_rank < old_rank) {
521         this->clear_head();
522         return true;
523     }
524
525     return false;
526 }
527
528 void BadStatusSetter::process_stun_status(const PlayerStunRank new_rank, const short v)
529 {
530     auto stun_mes = PlayerStun::get_stun_mes(new_rank);
531     msg_print(stun_mes.data());
532     this->decrease_int_wis(v);
533     if (PlayerClass(this->player_ptr).lose_balance()) {
534         msg_print(_("型が崩れた。", "You lose your stance."));
535     }
536
537     reset_concentration(this->player_ptr, true);
538
539     SpellHex spell_hex(this->player_ptr);
540     if (spell_hex.is_spelling_any()) {
541         (void)spell_hex.stop_all_spells();
542     }
543 }
544
545 void BadStatusSetter::clear_head()
546 {
547     if (this->player_ptr->effects()->stun()->is_stunned()) {
548         return;
549     }
550
551     msg_print(_("やっと朦朧状態から回復した。", "You are no longer stunned."));
552     if (disturb_state) {
553         disturb(this->player_ptr, false, false);
554     }
555 }
556
557 /*!
558  * @todo 後で知能と賢さが両方減る確率を減らす.
559  */
560 void BadStatusSetter::decrease_int_wis(const short v)
561 {
562     if ((v <= randint1(1000)) && !one_in_(16)) {
563         return;
564     }
565
566     msg_print(_("割れるような頭痛がする。", "A vicious blow hits your head."));
567     auto rand = randint0(3);
568     switch (rand) {
569     case 0:
570         if (has_sustain_int(this->player_ptr) == 0) {
571             (void)do_dec_stat(this->player_ptr, A_INT);
572         }
573
574         if (has_sustain_wis(this->player_ptr) == 0) {
575             (void)do_dec_stat(this->player_ptr, A_WIS);
576         }
577
578         return;
579     case 1:
580         if (has_sustain_int(this->player_ptr) == 0) {
581             (void)do_dec_stat(this->player_ptr, A_INT);
582         }
583         
584         return;
585     case 2:
586         if (has_sustain_wis(this->player_ptr) == 0) {
587             (void)do_dec_stat(this->player_ptr, A_WIS);
588         }
589
590         return;
591     default:
592         return;
593     }
594 }
595
596 bool BadStatusSetter::process_cut_effect(const short v)
597 {
598     auto player_cut = this->player_ptr->effects()->cut();
599     auto old_rank = player_cut->get_rank();
600     auto new_rank = player_cut->get_rank(v);
601     if (new_rank > old_rank) {
602         this->decrease_charisma(new_rank, v);
603         return true;
604     }
605
606     if (new_rank < old_rank) {
607         this->stop_blooding(new_rank);
608         return true;
609     }
610
611     return false;
612 }
613
614 void BadStatusSetter::decrease_charisma(const PlayerCutRank new_rank, const short v)
615 {
616     auto player_cut = this->player_ptr->effects()->cut();
617     auto cut_mes = player_cut->get_cut_mes(new_rank);
618     msg_print(cut_mes.data());
619     if (v <= randint1(1000) && !one_in_(16)) {
620         return;
621     }
622
623     if (has_sustain_chr(this->player_ptr)) {
624         return;
625     }
626
627     msg_print(_("ひどい傷跡が残ってしまった。", "You have been horribly scarred."));
628     do_dec_stat(this->player_ptr, A_CHR);
629 }
630
631 void BadStatusSetter::stop_blooding(const PlayerCutRank new_rank)
632 {
633     if (new_rank >= PlayerCutRank::GRAZING) {
634         return;
635     }
636
637     auto blood_stop_mes = PlayerRace(this->player_ptr).equals(player_race_type::ANDROID)
638         ? _("怪我が直った", "leaking fluid")
639         : _("出血が止まった", "bleeding");
640     msg_format(_("やっと%s。", "You are no longer %s."), blood_stop_mes);
641     if (disturb_state) {
642         disturb(this->player_ptr, false, false);
643     }
644 }