1 #include "status/bad-status-setter.h"
2 #include "avatar/avatar.h"
3 #include "core/disturbance.h"
4 #include "core/stuff-handler.h"
5 #include "core/window-redrawer.h"
6 #include "game-option/disturbance-options.h"
7 #include "mind/mind-sniper.h"
8 #include "player-base/player-class.h"
9 #include "player-base/player-race.h"
10 #include "player-info/bluemage-data-type.h"
11 #include "player-info/monk-data-type.h"
12 #include "player/attack-defense-types.h"
13 #include "player/player-status-flags.h"
14 #include "player/player-status.h"
15 #include "player/special-defense-types.h"
16 #include "spell-realm/spells-hex.h"
17 #include "status/base-status.h"
18 #include "status/buff-setter.h"
19 #include "system/player-type-definition.h"
20 #include "system/redrawing-flags-updater.h"
21 #include "timed-effect/player-blindness.h"
22 #include "timed-effect/player-confusion.h"
23 #include "timed-effect/player-cut.h"
24 #include "timed-effect/player-deceleration.h"
25 #include "timed-effect/player-fear.h"
26 #include "timed-effect/player-hallucination.h"
27 #include "timed-effect/player-paralysis.h"
28 #include "timed-effect/player-poison.h"
29 #include "timed-effect/player-stun.h"
30 #include "timed-effect/timed-effects.h"
31 #include "view/display-messages.h"
34 BadStatusSetter::BadStatusSetter(PlayerType *player_ptr)
35 : player_ptr(player_ptr)
36 , player_confusion(player_ptr->effects()->confusion())
41 * @brief 盲目の継続時間をセットする / Set "blind", notice observable changes
43 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
45 * Note the use of "PU_UN_LITE" and "PU_UN_VIEW", which is needed to\n
46 * memorize any terrain features which suddenly become "visible".\n
47 * Note that blindness is currently the only thing which can affect\n
48 * "player_can_see_bold()".\n
50 bool BadStatusSetter::set_blindness(const TIME_EFFECT tmp_v)
53 auto v = std::clamp<short>(tmp_v, 0, 10000);
54 if (this->player_ptr->is_dead) {
58 PlayerRace pr(this->player_ptr);
59 const auto blindness = this->player_ptr->effects()->blindness();
60 const auto is_blind = blindness->is_blind();
63 if (pr.equals(PlayerRaceType::ANDROID)) {
64 msg_print(_("センサーをやられた!", "The sensor broke!"));
66 msg_print(_("目が見えなくなってしまった!", "You are blind!"));
70 chg_virtue(this->player_ptr, Virtue::ENLIGHTEN, -1);
74 if (pr.equals(PlayerRaceType::ANDROID)) {
75 msg_print(_("センサーが復旧した。", "The sensor has been restored."));
77 msg_print(_("やっと目が見えるようになった。", "You can see again."));
85 auto &rfu = RedrawingFlagsUpdater::get_instance();
86 rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
92 disturb(this->player_ptr, false, false);
95 const auto flags_srf = {
96 StatusRedrawingFlag::UN_VIEW,
97 StatusRedrawingFlag::UN_LITE,
98 StatusRedrawingFlag::VIEW,
99 StatusRedrawingFlag::LITE,
100 StatusRedrawingFlag::MONSTER_STATUSES,
101 StatusRedrawingFlag::MONSTER_LITE,
103 rfu.set_flags(flags_srf);
104 rfu.set_flag(MainWindowRedrawingFlag::MAP);
105 this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
106 handle_stuff(this->player_ptr);
110 bool BadStatusSetter::mod_blindness(const TIME_EFFECT tmp_v)
112 return this->set_blindness(this->player_ptr->effects()->blindness()->current() + tmp_v);
116 * @brief 混乱の継続時間をセットする / Set "confused", notice observable changes
118 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
120 bool BadStatusSetter::set_confusion(const TIME_EFFECT tmp_v)
123 auto v = std::clamp<short>(tmp_v, 0, 10000);
124 if (this->player_ptr->is_dead) {
128 auto &rfu = RedrawingFlagsUpdater::get_instance();
129 auto is_confused = this->player_confusion->is_confused();
132 msg_print(_("あなたは混乱した!", "You are confused!"));
133 if (this->player_ptr->action == ACTION_LEARN) {
134 msg_print(_("学習が続けられない!", "You cannot continue learning!"));
135 auto bluemage_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
136 bluemage_data->new_magic_learned = false;
137 rfu.set_flag(MainWindowRedrawingFlag::ACTION);
138 this->player_ptr->action = ACTION_NONE;
140 if (this->player_ptr->action == ACTION_MONK_STANCE) {
141 msg_print(_("構えがとけた。", "You lose your stance."));
142 PlayerClass(player_ptr).set_monk_stance(MonkStanceType::NONE);
143 rfu.set_flag(StatusRedrawingFlag::BONUS);
144 rfu.set_flag(MainWindowRedrawingFlag::ACTION);
145 this->player_ptr->action = ACTION_NONE;
146 } else if (this->player_ptr->action == ACTION_SAMURAI_STANCE) {
147 msg_print(_("型が崩れた。", "You lose your stance."));
148 PlayerClass(player_ptr).lose_balance();
152 reset_concentration(this->player_ptr, true);
154 SpellHex spell_hex(this->player_ptr);
155 if (spell_hex.is_spelling_any()) {
156 (void)spell_hex.stop_all_spells();
160 this->player_ptr->counter = false;
161 chg_virtue(this->player_ptr, Virtue::HARMONY, -1);
165 msg_print(_("やっと混乱がおさまった。", "You feel less confused now."));
166 this->player_ptr->special_attack &= ~(ATTACK_SUIKEN);
171 this->player_confusion->set(v);
172 rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
178 disturb(this->player_ptr, false, false);
181 handle_stuff(this->player_ptr);
185 bool BadStatusSetter::mod_confusion(const TIME_EFFECT tmp_v)
187 return this->set_confusion(this->player_confusion->current() + tmp_v);
191 * @brief 毒の継続時間をセットする / Set "poisoned", notice observable changes
193 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
195 bool BadStatusSetter::set_poison(const TIME_EFFECT tmp_v)
198 auto v = std::clamp<short>(tmp_v, 0, 10000);
199 if (this->player_ptr->is_dead) {
203 const auto player_poison = this->player_ptr->effects()->poison();
204 const auto is_poisoned = player_poison->is_poisoned();
207 msg_print(_("毒に侵されてしまった!", "You are poisoned!"));
212 msg_print(_("やっと毒の痛みがなくなった。", "You are no longer poisoned."));
217 player_poison->set(v);
218 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
224 disturb(this->player_ptr, false, false);
227 handle_stuff(this->player_ptr);
231 bool BadStatusSetter::mod_poison(const TIME_EFFECT tmp_v)
233 return this->set_poison(this->player_ptr->effects()->poison()->current() + tmp_v);
237 * @brief 恐怖の継続時間をセットする / Set "fearful", notice observable changes
239 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
241 bool BadStatusSetter::set_fear(const TIME_EFFECT tmp_v)
244 auto v = std::clamp<short>(tmp_v, 0, 10000);
245 if (this->player_ptr->is_dead) {
249 auto fear = this->player_ptr->effects()->fear();
251 if (!fear->is_fearful()) {
252 msg_print(_("何もかも恐くなってきた!", "You are terrified!"));
253 if (PlayerClass(this->player_ptr).lose_balance()) {
254 msg_print(_("型が崩れた。", "You lose your stance."));
258 this->player_ptr->counter = false;
259 chg_virtue(this->player_ptr, Virtue::VALOUR, -1);
262 if (fear->is_fearful()) {
263 msg_print(_("やっと恐怖を振り払った。", "You feel bolder now."));
269 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
275 disturb(this->player_ptr, false, false);
278 handle_stuff(this->player_ptr);
282 bool BadStatusSetter::mod_fear(const TIME_EFFECT tmp_v)
284 return this->set_fear(this->player_ptr->effects()->fear()->current() + tmp_v);
288 * @brief 麻痺の継続時間をセットする / Set "paralyzed", notice observable changes
290 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
292 bool BadStatusSetter::set_paralysis(const TIME_EFFECT tmp_v)
295 auto v = std::clamp<short>(tmp_v, 0, 10000);
296 if (this->player_ptr->is_dead) {
300 auto paralysis = this->player_ptr->effects()->paralysis();
302 if (!paralysis->is_paralyzed()) {
303 msg_print(_("体が麻痺してしまった!", "You are paralyzed!"));
304 reset_concentration(this->player_ptr, true);
306 SpellHex spell_hex(this->player_ptr);
307 if (spell_hex.is_spelling_any()) {
308 (void)spell_hex.stop_all_spells();
311 this->player_ptr->counter = false;
315 if (paralysis->is_paralyzed()) {
316 msg_print(_("やっと動けるようになった。", "You can move again."));
322 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
328 disturb(this->player_ptr, false, false);
331 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
332 handle_stuff(this->player_ptr);
336 bool BadStatusSetter::mod_paralysis(const TIME_EFFECT tmp_v)
338 return this->set_paralysis(this->player_ptr->effects()->paralysis()->current() + tmp_v);
342 * @brief 幻覚の継続時間をセットする / Set "image", notice observable changes
344 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
345 * @details Note that we must redraw the map when hallucination changes.
347 bool BadStatusSetter::hallucination(const TIME_EFFECT tmp_v)
350 auto v = std::clamp<short>(tmp_v, 0, 10000);
351 if (this->player_ptr->is_dead) {
355 if (is_chargeman(this->player_ptr)) {
359 auto hallucination = this->player_ptr->effects()->hallucination();
361 set_tsuyoshi(this->player_ptr, 0, true);
362 if (!hallucination->is_hallucinated()) {
363 msg_print(_("ワーオ!何もかも虹色に見える!", "Oh, wow! Everything looks so cosmic now!"));
364 reset_concentration(this->player_ptr, true);
366 this->player_ptr->counter = false;
370 if (hallucination->is_hallucinated()) {
371 msg_print(_("やっとはっきりと物が見えるようになった。", "You can see clearly again."));
376 hallucination->set(v);
377 auto &rfu = RedrawingFlagsUpdater::get_instance();
378 rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
384 disturb(this->player_ptr, false, true);
387 const auto flags_mwrf = {
388 MainWindowRedrawingFlag::MAP,
389 MainWindowRedrawingFlag::HEALTH,
390 MainWindowRedrawingFlag::UHEALTH,
392 rfu.set_flags(flags_mwrf);
393 rfu.set_flag(StatusRedrawingFlag::MONSTER_STATUSES);
394 this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
395 handle_stuff(this->player_ptr);
399 bool BadStatusSetter::mod_hallucination(const TIME_EFFECT tmp_v)
401 return this->hallucination(this->player_ptr->effects()->hallucination()->current() + tmp_v);
405 * @brief 減速の継続時間をセットする / Set "slow", notice observable changes
407 * @param do_dec 現在の継続時間より長い値のみ上書きする
408 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
410 bool BadStatusSetter::set_deceleration(const TIME_EFFECT tmp_v, bool do_dec)
413 auto v = std::clamp<short>(tmp_v, 0, 10000);
414 if (this->player_ptr->is_dead) {
418 auto deceleration = this->player_ptr->effects()->deceleration();
419 auto is_slow = deceleration->is_slow();
421 if (is_slow && !do_dec) {
422 if (deceleration->current() > v) {
425 } else if (!is_slow) {
426 msg_print(_("体の動きが遅くなってしまった!", "You feel yourself moving slower!"));
431 msg_print(_("動きの遅さがなくなったようだ。", "You feel yourself speed up."));
436 deceleration->set(v);
442 disturb(this->player_ptr, false, false);
445 RedrawingFlagsUpdater::get_instance().set_flag(StatusRedrawingFlag::BONUS);
446 handle_stuff(this->player_ptr);
450 bool BadStatusSetter::mod_deceleration(const TIME_EFFECT tmp_v, bool do_dec)
452 return this->set_deceleration(this->player_ptr->effects()->deceleration()->current() + tmp_v, do_dec);
456 * @brief 朦朧の継続時間をセットする / Set "stun", notice observable changes
458 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
460 * Note the special code to only notice "range" changes.
462 bool BadStatusSetter::set_stun(const TIME_EFFECT tmp_v)
464 auto v = std::clamp<short>(tmp_v, 0, 10000);
465 if (this->player_ptr->is_dead) {
469 if (PlayerRace(this->player_ptr).has_stun_immunity() || PlayerClass(this->player_ptr).has_stun_immunity()) {
473 auto notice = this->process_stun_effect(v);
474 this->player_ptr->effects()->stun()->set(v);
480 disturb(this->player_ptr, false, false);
483 auto &rfu = RedrawingFlagsUpdater::get_instance();
484 rfu.set_flag(StatusRedrawingFlag::BONUS);
485 rfu.set_flag(MainWindowRedrawingFlag::STUN);
486 handle_stuff(this->player_ptr);
490 bool BadStatusSetter::mod_stun(const TIME_EFFECT tmp_v)
492 return this->set_stun(this->player_ptr->effects()->stun()->current() + tmp_v);
496 * @brief 出血の継続時間をセットする / Set "cut", notice observable changes
498 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
500 * Note the special code to only notice "range" changes.
502 bool BadStatusSetter::set_cut(const TIME_EFFECT tmp_v)
504 auto v = std::clamp<short>(tmp_v, 0, 10000);
505 if (this->player_ptr->is_dead) {
509 if (PlayerRace(this->player_ptr).has_cut_immunity()) {
513 auto notice = this->process_cut_effect(v);
514 this->player_ptr->effects()->cut()->set(v);
520 disturb(this->player_ptr, false, false);
523 auto &rfu = RedrawingFlagsUpdater::get_instance();
524 rfu.set_flag(StatusRedrawingFlag::BONUS);
525 rfu.set_flag(MainWindowRedrawingFlag::CUT);
526 handle_stuff(this->player_ptr);
530 bool BadStatusSetter::mod_cut(const TIME_EFFECT tmp_v)
532 return this->set_cut(this->player_ptr->effects()->cut()->current() + tmp_v);
535 bool BadStatusSetter::process_stun_effect(const short v)
537 auto old_rank = this->player_ptr->effects()->stun()->get_rank();
538 auto new_rank = PlayerStun::get_rank(v);
539 if (new_rank > old_rank) {
540 this->process_stun_status(new_rank, v);
544 if (new_rank < old_rank) {
552 void BadStatusSetter::process_stun_status(const PlayerStunRank new_rank, const short v)
554 auto stun_mes = PlayerStun::get_stun_mes(new_rank);
556 this->decrease_int_wis(v);
557 if (PlayerClass(this->player_ptr).lose_balance()) {
558 msg_print(_("型が崩れた。", "You lose your stance."));
561 reset_concentration(this->player_ptr, true);
563 SpellHex spell_hex(this->player_ptr);
564 if (spell_hex.is_spelling_any()) {
565 (void)spell_hex.stop_all_spells();
569 void BadStatusSetter::clear_head()
571 if (this->player_ptr->effects()->stun()->is_stunned()) {
575 msg_print(_("やっと朦朧状態から回復した。", "You are no longer stunned."));
577 disturb(this->player_ptr, false, false);
582 * @todo 後で知能と賢さが両方減る確率を減らす.
584 void BadStatusSetter::decrease_int_wis(const short v)
586 if ((v <= randint1(1000)) && !one_in_(16)) {
590 msg_print(_("割れるような頭痛がする。", "A vicious blow hits your head."));
591 auto rand = randint0(5);
594 if (has_sustain_int(this->player_ptr) == 0) {
595 (void)do_dec_stat(this->player_ptr, A_INT);
598 if (has_sustain_wis(this->player_ptr) == 0) {
599 (void)do_dec_stat(this->player_ptr, A_WIS);
605 if (has_sustain_int(this->player_ptr) == 0) {
606 (void)do_dec_stat(this->player_ptr, A_INT);
612 if (has_sustain_wis(this->player_ptr) == 0) {
613 (void)do_dec_stat(this->player_ptr, A_WIS);
618 throw("Invalid random number is specified!");
622 bool BadStatusSetter::process_cut_effect(const short v)
624 auto player_cut = this->player_ptr->effects()->cut();
625 auto old_rank = player_cut->get_rank();
626 auto new_rank = player_cut->get_rank(v);
627 if (new_rank > old_rank) {
628 this->decrease_charisma(new_rank, v);
632 if (new_rank < old_rank) {
633 this->stop_blooding(new_rank);
640 void BadStatusSetter::decrease_charisma(const PlayerCutRank new_rank, const short v)
642 auto player_cut = this->player_ptr->effects()->cut();
643 auto cut_mes = player_cut->get_cut_mes(new_rank);
645 if (v <= randint1(1000) && !one_in_(16)) {
649 if (has_sustain_chr(this->player_ptr)) {
653 msg_print(_("ひどい傷跡が残ってしまった。", "You have been horribly scarred."));
654 do_dec_stat(this->player_ptr, A_CHR);
657 void BadStatusSetter::stop_blooding(const PlayerCutRank new_rank)
659 if (new_rank >= PlayerCutRank::GRAZING) {
663 auto blood_stop_mes = PlayerRace(this->player_ptr).equals(PlayerRaceType::ANDROID)
664 ? _("怪我が直った", "leaking fluid")
665 : _("出血が止まった", "bleeding");
666 msg_format(_("やっと%s。", "You are no longer %s."), blood_stop_mes);
668 disturb(this->player_ptr, false, false);