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-info/monk-data-type.h"
14 #include "player/attack-defense-types.h"
15 #include "player/player-status-flags.h"
16 #include "player/player-status.h"
17 #include "player/special-defense-types.h"
18 #include "spell-realm/spells-hex.h"
19 #include "status/base-status.h"
20 #include "status/buff-setter.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-hallucination.h"
25 #include "timed-effect/player-paralysis.h"
26 #include "timed-effect/player-stun.h"
27 #include "timed-effect/timed-effects.h"
28 #include "view/display-messages.h"
31 BadStatusSetter::BadStatusSetter(PlayerType *player_ptr)
32 : player_ptr(player_ptr)
33 , player_confusion(player_ptr->effects()->confusion())
38 * @brief 盲目の継続時間をセットする / Set "blind", notice observable changes
40 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
42 * Note the use of "PU_UN_LITE" and "PU_UN_VIEW", which is needed to\n
43 * memorize any terrain features which suddenly become "visible".\n
44 * Note that blindness is currently the only thing which can affect\n
45 * "player_can_see_bold()".\n
47 bool BadStatusSetter::blindness(const TIME_EFFECT tmp_v)
50 auto v = std::clamp<short>(tmp_v, 0, 10000);
51 if (this->player_ptr->is_dead) {
55 PlayerRace pr(player_ptr);
57 if (!this->player_ptr->blind) {
58 if (pr.equals(PlayerRaceType::ANDROID)) {
59 msg_print(_("センサーをやられた!", "The sensor broke!"));
61 msg_print(_("目が見えなくなってしまった!", "You are blind!"));
65 chg_virtue(this->player_ptr, V_ENLIGHTEN, -1);
68 if (this->player_ptr->blind) {
69 if (pr.equals(PlayerRaceType::ANDROID)) {
70 msg_print(_("センサーが復旧した。", "The sensor has been restored."));
72 msg_print(_("やっと目が見えるようになった。", "You can see again."));
79 this->player_ptr->blind = v;
80 this->player_ptr->redraw |= PR_STATUS;
86 disturb(this->player_ptr, false, false);
89 this->player_ptr->update |= PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_MONSTERS | PU_MON_LITE;
90 this->player_ptr->redraw |= PR_MAP;
91 this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
92 handle_stuff(this->player_ptr);
96 bool BadStatusSetter::mod_blindness(const TIME_EFFECT tmp_v)
98 return this->blindness(this->player_ptr->blind + tmp_v);
102 * @brief 混乱の継続時間をセットする / Set "confused", notice observable changes
104 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
106 bool BadStatusSetter::confusion(const TIME_EFFECT tmp_v)
109 auto v = std::clamp<short>(tmp_v, 0, 10000);
110 if (this->player_ptr->is_dead) {
114 auto is_confused = this->player_confusion->is_confused();
117 msg_print(_("あなたは混乱した!", "You are confused!"));
119 if (this->player_ptr->action == ACTION_LEARN) {
120 msg_print(_("学習が続けられない!", "You cannot continue learning!"));
121 auto bluemage_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
122 bluemage_data->new_magic_learned = false;
124 this->player_ptr->redraw |= PR_STATE;
125 this->player_ptr->action = ACTION_NONE;
127 if (this->player_ptr->action == ACTION_MONK_STANCE) {
128 msg_print(_("構えがとけた。", "You lose your stance."));
129 PlayerClass(player_ptr).set_monk_stance(MonkStanceType::NONE);
130 this->player_ptr->update |= PU_BONUS;
131 this->player_ptr->redraw |= PR_STATE;
132 this->player_ptr->action = ACTION_NONE;
133 } else if (this->player_ptr->action == ACTION_SAMURAI_STANCE) {
134 msg_print(_("型が崩れた。", "You lose your stance."));
135 PlayerClass(player_ptr).lose_balance();
139 reset_concentration(this->player_ptr, true);
141 SpellHex spell_hex(this->player_ptr);
142 if (spell_hex.is_spelling_any()) {
143 (void)spell_hex.stop_all_spells();
147 this->player_ptr->counter = false;
148 chg_virtue(this->player_ptr, V_HARMONY, -1);
152 msg_print(_("やっと混乱がおさまった。", "You feel less confused now."));
153 this->player_ptr->special_attack &= ~(ATTACK_SUIKEN);
158 this->player_confusion->set(v);
159 this->player_ptr->redraw |= PR_STATUS;
165 disturb(this->player_ptr, false, false);
168 handle_stuff(this->player_ptr);
172 bool BadStatusSetter::mod_confusion(const TIME_EFFECT tmp_v)
174 return this->confusion(this->player_confusion->current() + tmp_v);
178 * @brief 毒の継続時間をセットする / Set "poisoned", notice observable changes
180 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
182 bool BadStatusSetter::poison(const TIME_EFFECT tmp_v)
185 auto v = std::clamp<short>(tmp_v, 0, 10000);
186 if (this->player_ptr->is_dead) {
191 if (!this->player_ptr->poisoned) {
192 msg_print(_("毒に侵されてしまった!", "You are poisoned!"));
196 if (this->player_ptr->poisoned) {
197 msg_print(_("やっと毒の痛みがなくなった。", "You are no longer poisoned."));
202 this->player_ptr->poisoned = v;
203 this->player_ptr->redraw |= PR_STATUS;
209 disturb(this->player_ptr, false, false);
212 handle_stuff(this->player_ptr);
216 bool BadStatusSetter::mod_poison(const TIME_EFFECT tmp_v)
218 return this->poison(this->player_ptr->poisoned + tmp_v);
222 * @brief 恐怖の継続時間をセットする / Set "afraid", notice observable changes
224 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
226 bool BadStatusSetter::afraidness(const TIME_EFFECT tmp_v)
229 auto v = std::clamp<short>(tmp_v, 0, 10000);
230 if (this->player_ptr->is_dead) {
235 if (!this->player_ptr->afraid) {
236 msg_print(_("何もかも恐くなってきた!", "You are terrified!"));
237 if (PlayerClass(this->player_ptr).lose_balance()) {
238 msg_print(_("型が崩れた。", "You lose your stance."));
242 this->player_ptr->counter = false;
243 chg_virtue(this->player_ptr, V_VALOUR, -1);
246 if (this->player_ptr->afraid) {
247 msg_print(_("やっと恐怖を振り払った。", "You feel bolder now."));
252 this->player_ptr->afraid = v;
253 this->player_ptr->redraw |= PR_STATUS;
259 disturb(this->player_ptr, false, false);
262 handle_stuff(this->player_ptr);
266 bool BadStatusSetter::mod_afraidness(const TIME_EFFECT tmp_v)
268 return this->afraidness(this->player_ptr->afraid + tmp_v);
272 * @brief 麻痺の継続時間をセットする / Set "paralyzed", notice observable changes
274 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
276 bool BadStatusSetter::paralysis(const TIME_EFFECT tmp_v)
279 auto v = std::clamp<short>(tmp_v, 0, 10000);
280 if (this->player_ptr->is_dead) {
284 auto paralysis = this->player_ptr->effects()->paralysis();
286 if (!paralysis->is_paralyzed()) {
287 msg_print(_("体が麻痺してしまった!", "You are paralyzed!"));
288 reset_concentration(this->player_ptr, true);
290 SpellHex spell_hex(this->player_ptr);
291 if (spell_hex.is_spelling_any()) {
292 (void)spell_hex.stop_all_spells();
295 this->player_ptr->counter = false;
299 if (paralysis->is_paralyzed()) {
300 msg_print(_("やっと動けるようになった。", "You can move again."));
306 this->player_ptr->redraw |= PR_STATUS;
312 disturb(this->player_ptr, false, false);
315 this->player_ptr->redraw |= PR_STATE;
316 handle_stuff(this->player_ptr);
320 bool BadStatusSetter::mod_paralysis(const TIME_EFFECT tmp_v)
322 return this->paralysis(this->player_ptr->effects()->paralysis()->current() + tmp_v);
326 * @brief 幻覚の継続時間をセットする / Set "image", notice observable changes
328 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
329 * @details Note that we must redraw the map when hallucination changes.
331 bool BadStatusSetter::hallucination(const TIME_EFFECT tmp_v)
334 auto v = std::clamp<short>(tmp_v, 0, 10000);
335 if (this->player_ptr->is_dead) {
339 if (is_chargeman(this->player_ptr)) {
343 auto hallucination = this->player_ptr->effects()->hallucination();
345 set_tsuyoshi(this->player_ptr, 0, true);
346 if (!hallucination->is_hallucinated()) {
347 msg_print(_("ワーオ!何もかも虹色に見える!", "Oh, wow! Everything looks so cosmic now!"));
348 reset_concentration(this->player_ptr, true);
350 this->player_ptr->counter = false;
354 if (hallucination->is_hallucinated()) {
355 msg_print(_("やっとはっきりと物が見えるようになった。", "You can see clearly again."));
360 hallucination->set(v);
361 this->player_ptr->redraw |= PR_STATUS;
367 disturb(this->player_ptr, false, true);
370 this->player_ptr->redraw |= PR_MAP | PR_HEALTH | PR_UHEALTH;
371 this->player_ptr->update |= PU_MONSTERS;
372 this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
373 handle_stuff(this->player_ptr);
377 bool BadStatusSetter::mod_hallucination(const TIME_EFFECT tmp_v)
379 return this->hallucination(this->player_ptr->effects()->hallucination()->current() + tmp_v);
383 * @brief 減速の継続時間をセットする / Set "slow", notice observable changes
385 * @param do_dec 現在の継続時間より長い値のみ上書きする
386 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
388 bool BadStatusSetter::slowness(const TIME_EFFECT tmp_v, bool do_dec)
391 auto v = std::clamp<short>(tmp_v, 0, 10000);
392 if (this->player_ptr->is_dead) {
397 if (this->player_ptr->slow && !do_dec) {
398 if (this->player_ptr->slow > v) {
401 } else if (!this->player_ptr->slow) {
402 msg_print(_("体の動きが遅くなってしまった!", "You feel yourself moving slower!"));
406 if (this->player_ptr->slow) {
407 msg_print(_("動きの遅さがなくなったようだ。", "You feel yourself speed up."));
412 this->player_ptr->slow = v;
418 disturb(this->player_ptr, false, false);
421 this->player_ptr->update |= PU_BONUS;
422 handle_stuff(this->player_ptr);
426 bool BadStatusSetter::mod_slowness(const TIME_EFFECT tmp_v, bool do_dec)
428 return this->slowness(this->player_ptr->slow + tmp_v, do_dec);
432 * @brief 朦朧の継続時間をセットする / Set "stun", notice observable changes
434 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
436 * Note the special code to only notice "range" changes.
438 bool BadStatusSetter::stun(const TIME_EFFECT tmp_v)
440 auto v = std::clamp<short>(tmp_v, 0, 10000);
441 if (this->player_ptr->is_dead) {
445 if (PlayerRace(this->player_ptr).has_stun_immunity() || PlayerClass(this->player_ptr).has_stun_immunity()) {
449 auto notice = this->process_stun_effect(v);
450 this->player_ptr->effects()->stun()->set(v);
456 disturb(this->player_ptr, false, false);
459 this->player_ptr->update |= PU_BONUS;
460 this->player_ptr->redraw |= PR_STUN;
461 handle_stuff(this->player_ptr);
465 bool BadStatusSetter::mod_stun(const TIME_EFFECT tmp_v)
467 return this->stun(this->player_ptr->effects()->stun()->current() + tmp_v);
471 * @brief 出血の継続時間をセットする / Set "cut", notice observable changes
473 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
475 * Note the special code to only notice "range" changes.
477 bool BadStatusSetter::cut(const TIME_EFFECT tmp_v)
479 auto v = std::clamp<short>(tmp_v, 0, 10000);
480 if (this->player_ptr->is_dead) {
484 if (PlayerRace(this->player_ptr).has_cut_immunity()) {
488 auto notice = this->process_cut_effect(v);
489 this->player_ptr->effects()->cut()->set(v);
495 disturb(this->player_ptr, false, false);
498 this->player_ptr->update |= PU_BONUS;
499 this->player_ptr->redraw |= PR_CUT;
500 handle_stuff(this->player_ptr);
504 bool BadStatusSetter::mod_cut(const TIME_EFFECT tmp_v)
506 return this->cut(this->player_ptr->effects()->cut()->current() + tmp_v);
509 bool BadStatusSetter::process_stun_effect(const short v)
511 auto old_rank = this->player_ptr->effects()->stun()->get_rank();
512 auto new_rank = PlayerStun::get_rank(v);
513 if (new_rank > old_rank) {
514 this->process_stun_status(new_rank, v);
518 if (new_rank < old_rank) {
526 void BadStatusSetter::process_stun_status(const PlayerStunRank new_rank, const short v)
528 auto stun_mes = PlayerStun::get_stun_mes(new_rank);
529 msg_print(stun_mes.data());
530 this->decrease_int_wis(v);
531 if (PlayerClass(this->player_ptr).lose_balance()) {
532 msg_print(_("型が崩れた。", "You lose your stance."));
535 reset_concentration(this->player_ptr, true);
537 SpellHex spell_hex(this->player_ptr);
538 if (spell_hex.is_spelling_any()) {
539 (void)spell_hex.stop_all_spells();
543 void BadStatusSetter::clear_head()
545 if (this->player_ptr->effects()->stun()->is_stunned()) {
549 msg_print(_("やっと朦朧状態から回復した。", "You are no longer stunned."));
551 disturb(this->player_ptr, false, false);
556 * @todo 後で知能と賢さが両方減る確率を減らす.
558 void BadStatusSetter::decrease_int_wis(const short v)
560 if ((v <= randint1(1000)) && !one_in_(16)) {
564 msg_print(_("割れるような頭痛がする。", "A vicious blow hits your head."));
565 auto rand = randint0(5);
568 if (has_sustain_int(this->player_ptr) == 0) {
569 (void)do_dec_stat(this->player_ptr, A_INT);
572 if (has_sustain_wis(this->player_ptr) == 0) {
573 (void)do_dec_stat(this->player_ptr, A_WIS);
579 if (has_sustain_int(this->player_ptr) == 0) {
580 (void)do_dec_stat(this->player_ptr, A_INT);
586 if (has_sustain_wis(this->player_ptr) == 0) {
587 (void)do_dec_stat(this->player_ptr, A_WIS);
592 throw("Invalid random number is specified!");
596 bool BadStatusSetter::process_cut_effect(const short v)
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);
606 if (new_rank < old_rank) {
607 this->stop_blooding(new_rank);
614 void BadStatusSetter::decrease_charisma(const PlayerCutRank new_rank, const short v)
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)) {
623 if (has_sustain_chr(this->player_ptr)) {
627 msg_print(_("ひどい傷跡が残ってしまった。", "You have been horribly scarred."));
628 do_dec_stat(this->player_ptr, A_CHR);
631 void BadStatusSetter::stop_blooding(const PlayerCutRank new_rank)
633 if (new_rank >= PlayerCutRank::GRAZING) {
637 auto blood_stop_mes = PlayerRace(this->player_ptr).equals(PlayerRaceType::ANDROID)
638 ? _("怪我が直った", "leaking fluid")
639 : _("出血が止まった", "bleeding");
640 msg_format(_("やっと%s。", "You are no longer %s."), blood_stop_mes);
642 disturb(this->player_ptr, false, false);