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-cut.h"
23 #include "timed-effect/player-stun.h"
24 #include "timed-effect/timed-effects.h"
25 #include "view/display-messages.h"
28 BadStatusSetter::BadStatusSetter(PlayerType *player_ptr)
29 : player_ptr(player_ptr)
34 * @brief 盲目の継続時間をセットする / Set "blind", notice observable changes
36 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
38 * Note the use of "PU_UN_LITE" and "PU_UN_VIEW", which is needed to\n
39 * memorize any terrain features which suddenly become "visible".\n
40 * Note that blindness is currently the only thing which can affect\n
41 * "player_can_see_bold()".\n
43 bool BadStatusSetter::blindness(const TIME_EFFECT tmp_v)
46 auto v = std::clamp<short>(tmp_v, 0, 10000);
47 if (this->player_ptr->is_dead) {
51 PlayerRace pr(player_ptr);
53 if (!this->player_ptr->blind) {
54 if (pr.equals(PlayerRaceType::ANDROID)) {
55 msg_print(_("センサーをやられた!", "The sensor broke!"));
57 msg_print(_("目が見えなくなってしまった!", "You are blind!"));
61 chg_virtue(this->player_ptr, V_ENLIGHTEN, -1);
64 if (this->player_ptr->blind) {
65 if (pr.equals(PlayerRaceType::ANDROID)) {
66 msg_print(_("センサーが復旧した。", "The sensor has been restored."));
68 msg_print(_("やっと目が見えるようになった。", "You can see again."));
75 this->player_ptr->blind = v;
76 this->player_ptr->redraw |= PR_STATUS;
82 disturb(this->player_ptr, false, false);
85 this->player_ptr->update |= PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_MONSTERS | PU_MON_LITE;
86 this->player_ptr->redraw |= PR_MAP;
87 this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
88 handle_stuff(this->player_ptr);
92 bool BadStatusSetter::mod_blindness(const TIME_EFFECT tmp_v)
94 return this->blindness(this->player_ptr->blind + tmp_v);
98 * @brief 混乱の継続時間をセットする / Set "confused", notice observable changes
100 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
102 bool BadStatusSetter::confusion(const TIME_EFFECT tmp_v)
105 auto v = std::clamp<short>(tmp_v, 0, 10000);
106 if (this->player_ptr->is_dead) {
111 if (!this->player_ptr->confused) {
112 msg_print(_("あなたは混乱した!", "You are confused!"));
114 if (this->player_ptr->action == ACTION_LEARN) {
115 msg_print(_("学習が続けられない!", "You cannot continue learning!"));
116 auto bluemage_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
117 bluemage_data->new_magic_learned = false;
119 this->player_ptr->redraw |= PR_STATE;
120 this->player_ptr->action = ACTION_NONE;
122 if (this->player_ptr->action == ACTION_MONK_STANCE) {
123 msg_print(_("構えがとけた。", "You lose your stance."));
124 PlayerClass(player_ptr).set_monk_stance(MonkStanceType::NONE);
125 this->player_ptr->update |= PU_BONUS;
126 this->player_ptr->redraw |= PR_STATE;
127 this->player_ptr->action = ACTION_NONE;
128 } else if (this->player_ptr->action == ACTION_SAMURAI_STANCE) {
129 msg_print(_("型が崩れた。", "You lose your stance."));
130 PlayerClass(player_ptr).lose_balance();
134 reset_concentration(this->player_ptr, true);
136 SpellHex spell_hex(this->player_ptr);
137 if (spell_hex.is_spelling_any()) {
138 (void)spell_hex.stop_all_spells();
142 this->player_ptr->counter = false;
143 chg_virtue(this->player_ptr, V_HARMONY, -1);
146 if (this->player_ptr->confused) {
147 msg_print(_("やっと混乱がおさまった。", "You feel less confused now."));
148 this->player_ptr->special_attack &= ~(ATTACK_SUIKEN);
153 this->player_ptr->confused = v;
154 this->player_ptr->redraw |= PR_STATUS;
160 disturb(this->player_ptr, false, false);
163 handle_stuff(this->player_ptr);
167 bool BadStatusSetter::mod_confusion(const TIME_EFFECT tmp_v)
169 return this->confusion(this->player_ptr->confused + tmp_v);
173 * @brief 毒の継続時間をセットする / Set "poisoned", notice observable changes
175 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
177 bool BadStatusSetter::poison(const TIME_EFFECT tmp_v)
180 auto v = std::clamp<short>(tmp_v, 0, 10000);
181 if (this->player_ptr->is_dead) {
186 if (!this->player_ptr->poisoned) {
187 msg_print(_("毒に侵されてしまった!", "You are poisoned!"));
191 if (this->player_ptr->poisoned) {
192 msg_print(_("やっと毒の痛みがなくなった。", "You are no longer poisoned."));
197 this->player_ptr->poisoned = v;
198 this->player_ptr->redraw |= PR_STATUS;
204 disturb(this->player_ptr, false, false);
207 handle_stuff(this->player_ptr);
211 bool BadStatusSetter::mod_poison(const TIME_EFFECT tmp_v)
213 return this->poison(this->player_ptr->poisoned + tmp_v);
217 * @brief 恐怖の継続時間をセットする / Set "afraid", notice observable changes
219 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
221 bool BadStatusSetter::afraidness(const TIME_EFFECT tmp_v)
224 auto v = std::clamp<short>(tmp_v, 0, 10000);
225 if (this->player_ptr->is_dead) {
230 if (!this->player_ptr->afraid) {
231 msg_print(_("何もかも恐くなってきた!", "You are terrified!"));
232 if (PlayerClass(this->player_ptr).lose_balance()) {
233 msg_print(_("型が崩れた。", "You lose your stance."));
237 this->player_ptr->counter = false;
238 chg_virtue(this->player_ptr, V_VALOUR, -1);
241 if (this->player_ptr->afraid) {
242 msg_print(_("やっと恐怖を振り払った。", "You feel bolder now."));
247 this->player_ptr->afraid = v;
248 this->player_ptr->redraw |= PR_STATUS;
254 disturb(this->player_ptr, false, false);
257 handle_stuff(this->player_ptr);
261 bool BadStatusSetter::mod_afraidness(const TIME_EFFECT tmp_v)
263 return this->afraidness(this->player_ptr->afraid + tmp_v);
267 * @brief 麻痺の継続時間をセットする / Set "paralyzed", notice observable changes
269 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
271 bool BadStatusSetter::paralysis(const TIME_EFFECT tmp_v)
274 auto v = std::clamp<short>(tmp_v, 0, 10000);
275 if (this->player_ptr->is_dead) {
280 if (!this->player_ptr->paralyzed) {
281 msg_print(_("体が麻痺してしまった!", "You are paralyzed!"));
282 reset_concentration(this->player_ptr, true);
284 SpellHex spell_hex(this->player_ptr);
285 if (spell_hex.is_spelling_any()) {
286 (void)spell_hex.stop_all_spells();
289 this->player_ptr->counter = false;
293 if (this->player_ptr->paralyzed) {
294 msg_print(_("やっと動けるようになった。", "You can move again."));
299 this->player_ptr->paralyzed = v;
300 this->player_ptr->redraw |= PR_STATUS;
306 disturb(this->player_ptr, false, false);
309 this->player_ptr->redraw |= PR_STATE;
310 handle_stuff(this->player_ptr);
314 bool BadStatusSetter::mod_paralysis(const TIME_EFFECT tmp_v)
316 return this->paralysis(this->player_ptr->paralyzed + tmp_v);
320 * @brief 幻覚の継続時間をセットする / Set "image", notice observable changes
322 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
323 * @details Note that we must redraw the map when hallucination changes.
325 bool BadStatusSetter::hallucination(const TIME_EFFECT tmp_v)
328 auto v = std::clamp<short>(tmp_v, 0, 10000);
329 if (this->player_ptr->is_dead) {
333 if (is_chargeman(this->player_ptr)) {
338 set_tsuyoshi(this->player_ptr, 0, true);
339 if (!this->player_ptr->hallucinated) {
340 msg_print(_("ワーオ!何もかも虹色に見える!", "Oh, wow! Everything looks so cosmic now!"));
341 reset_concentration(this->player_ptr, true);
343 this->player_ptr->counter = false;
347 if (this->player_ptr->hallucinated) {
348 msg_print(_("やっとはっきりと物が見えるようになった。", "You can see clearly again."));
353 this->player_ptr->hallucinated = v;
354 this->player_ptr->redraw |= PR_STATUS;
360 disturb(this->player_ptr, false, true);
363 this->player_ptr->redraw |= PR_MAP | PR_HEALTH | PR_UHEALTH;
364 this->player_ptr->update |= PU_MONSTERS;
365 this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
366 handle_stuff(this->player_ptr);
370 bool BadStatusSetter::mod_hallucination(const TIME_EFFECT tmp_v)
372 return this->hallucination(this->player_ptr->hallucinated + tmp_v);
376 * @brief 減速の継続時間をセットする / Set "slow", notice observable changes
378 * @param do_dec 現在の継続時間より長い値のみ上書きする
379 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
381 bool BadStatusSetter::slowness(const TIME_EFFECT tmp_v, bool do_dec)
384 auto v = std::clamp<short>(tmp_v, 0, 10000);
385 if (this->player_ptr->is_dead) {
390 if (this->player_ptr->slow && !do_dec) {
391 if (this->player_ptr->slow > v) {
394 } else if (!this->player_ptr->slow) {
395 msg_print(_("体の動きが遅くなってしまった!", "You feel yourself moving slower!"));
399 if (this->player_ptr->slow) {
400 msg_print(_("動きの遅さがなくなったようだ。", "You feel yourself speed up."));
405 this->player_ptr->slow = v;
411 disturb(this->player_ptr, false, false);
414 this->player_ptr->update |= PU_BONUS;
415 handle_stuff(this->player_ptr);
419 bool BadStatusSetter::mod_slowness(const TIME_EFFECT tmp_v, bool do_dec)
421 return this->slowness(this->player_ptr->slow + tmp_v, do_dec);
425 * @brief 朦朧の継続時間をセットする / Set "stun", notice observable changes
427 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
429 * Note the special code to only notice "range" changes.
431 bool BadStatusSetter::stun(const TIME_EFFECT tmp_v)
433 auto v = std::clamp<short>(tmp_v, 0, 10000);
434 if (this->player_ptr->is_dead) {
438 if (PlayerRace(this->player_ptr).has_stun_immunity() || PlayerClass(this->player_ptr).has_stun_immunity()) {
442 auto notice = this->process_stun_effect(v);
443 this->player_ptr->effects()->stun()->set(v);
449 disturb(this->player_ptr, false, false);
452 this->player_ptr->update |= PU_BONUS;
453 this->player_ptr->redraw |= PR_STUN;
454 handle_stuff(this->player_ptr);
458 bool BadStatusSetter::mod_stun(const TIME_EFFECT tmp_v)
460 return this->stun(this->player_ptr->effects()->stun()->current() + tmp_v);
464 * @brief 出血の継続時間をセットする / Set "cut", notice observable changes
466 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
468 * Note the special code to only notice "range" changes.
470 bool BadStatusSetter::cut(const TIME_EFFECT tmp_v)
472 auto v = std::clamp<short>(tmp_v, 0, 10000);
473 if (this->player_ptr->is_dead) {
477 if (PlayerRace(this->player_ptr).has_cut_immunity()) {
481 auto notice = this->process_cut_effect(v);
482 this->player_ptr->effects()->cut()->set(v);
488 disturb(this->player_ptr, false, false);
491 this->player_ptr->update |= PU_BONUS;
492 this->player_ptr->redraw |= PR_CUT;
493 handle_stuff(this->player_ptr);
497 bool BadStatusSetter::mod_cut(const TIME_EFFECT tmp_v)
499 return this->cut(this->player_ptr->effects()->cut()->current() + tmp_v);
502 bool BadStatusSetter::process_stun_effect(const short v)
504 auto old_rank = this->player_ptr->effects()->stun()->get_rank();
505 auto new_rank = PlayerStun::get_rank(v);
506 if (new_rank > old_rank) {
507 this->process_stun_status(new_rank, v);
511 if (new_rank < old_rank) {
519 void BadStatusSetter::process_stun_status(const PlayerStunRank new_rank, const short v)
521 auto stun_mes = PlayerStun::get_stun_mes(new_rank);
522 msg_print(stun_mes.data());
523 this->decrease_int_wis(v);
524 if (PlayerClass(this->player_ptr).lose_balance()) {
525 msg_print(_("型が崩れた。", "You lose your stance."));
528 reset_concentration(this->player_ptr, true);
530 SpellHex spell_hex(this->player_ptr);
531 if (spell_hex.is_spelling_any()) {
532 (void)spell_hex.stop_all_spells();
536 void BadStatusSetter::clear_head()
538 if (this->player_ptr->effects()->stun()->is_stunned()) {
542 msg_print(_("やっと朦朧状態から回復した。", "You are no longer stunned."));
544 disturb(this->player_ptr, false, false);
549 * @todo 後で知能と賢さが両方減る確率を減らす.
551 void BadStatusSetter::decrease_int_wis(const short v)
553 if ((v <= randint1(1000)) && !one_in_(16)) {
557 msg_print(_("割れるような頭痛がする。", "A vicious blow hits your head."));
558 auto rand = randint0(5);
561 if (has_sustain_int(this->player_ptr) == 0) {
562 (void)do_dec_stat(this->player_ptr, A_INT);
565 if (has_sustain_wis(this->player_ptr) == 0) {
566 (void)do_dec_stat(this->player_ptr, A_WIS);
572 if (has_sustain_int(this->player_ptr) == 0) {
573 (void)do_dec_stat(this->player_ptr, A_INT);
579 if (has_sustain_wis(this->player_ptr) == 0) {
580 (void)do_dec_stat(this->player_ptr, A_WIS);
585 throw("Invalid random number is specified!");
589 bool BadStatusSetter::process_cut_effect(const short v)
591 auto player_cut = this->player_ptr->effects()->cut();
592 auto old_rank = player_cut->get_rank();
593 auto new_rank = player_cut->get_rank(v);
594 if (new_rank > old_rank) {
595 this->decrease_charisma(new_rank, v);
599 if (new_rank < old_rank) {
600 this->stop_blooding(new_rank);
607 void BadStatusSetter::decrease_charisma(const PlayerCutRank new_rank, const short v)
609 auto player_cut = this->player_ptr->effects()->cut();
610 auto cut_mes = player_cut->get_cut_mes(new_rank);
611 msg_print(cut_mes.data());
612 if (v <= randint1(1000) && !one_in_(16)) {
616 if (has_sustain_chr(this->player_ptr)) {
620 msg_print(_("ひどい傷跡が残ってしまった。", "You have been horribly scarred."));
621 do_dec_stat(this->player_ptr, A_CHR);
624 void BadStatusSetter::stop_blooding(const PlayerCutRank new_rank)
626 if (new_rank >= PlayerCutRank::GRAZING) {
630 auto blood_stop_mes = PlayerRace(this->player_ptr).equals(PlayerRaceType::ANDROID)
631 ? _("怪我が直った", "leaking fluid")
632 : _("出血が止まった", "bleeding");
633 msg_format(_("やっと%s。", "You are no longer %s."), blood_stop_mes);
635 disturb(this->player_ptr, false, false);