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-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::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(player_ptr);
60 if (!this->player_ptr->blind) {
61 if (pr.equals(PlayerRaceType::ANDROID)) {
62 msg_print(_("センサーをやられた!", "The sensor broke!"));
64 msg_print(_("目が見えなくなってしまった!", "You are blind!"));
68 chg_virtue(this->player_ptr, V_ENLIGHTEN, -1);
71 if (this->player_ptr->blind) {
72 if (pr.equals(PlayerRaceType::ANDROID)) {
73 msg_print(_("センサーが復旧した。", "The sensor has been restored."));
75 msg_print(_("やっと目が見えるようになった。", "You can see again."));
82 this->player_ptr->blind = v;
83 this->player_ptr->redraw |= PR_STATUS;
89 disturb(this->player_ptr, false, false);
92 this->player_ptr->update |= PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_MONSTERS | PU_MON_LITE;
93 this->player_ptr->redraw |= PR_MAP;
94 this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
95 handle_stuff(this->player_ptr);
99 bool BadStatusSetter::mod_blindness(const TIME_EFFECT tmp_v)
101 return this->blindness(this->player_ptr->blind + tmp_v);
105 * @brief 混乱の継続時間をセットする / Set "confused", notice observable changes
107 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
109 bool BadStatusSetter::confusion(const TIME_EFFECT tmp_v)
112 auto v = std::clamp<short>(tmp_v, 0, 10000);
113 if (this->player_ptr->is_dead) {
117 auto is_confused = this->player_confusion->is_confused();
120 msg_print(_("あなたは混乱した!", "You are confused!"));
122 if (this->player_ptr->action == ACTION_LEARN) {
123 msg_print(_("学習が続けられない!", "You cannot continue learning!"));
124 auto bluemage_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
125 bluemage_data->new_magic_learned = false;
127 this->player_ptr->redraw |= PR_STATE;
128 this->player_ptr->action = ACTION_NONE;
130 if (this->player_ptr->action == ACTION_MONK_STANCE) {
131 msg_print(_("構えがとけた。", "You lose your stance."));
132 PlayerClass(player_ptr).set_monk_stance(MonkStanceType::NONE);
133 this->player_ptr->update |= PU_BONUS;
134 this->player_ptr->redraw |= PR_STATE;
135 this->player_ptr->action = ACTION_NONE;
136 } else if (this->player_ptr->action == ACTION_SAMURAI_STANCE) {
137 msg_print(_("型が崩れた。", "You lose your stance."));
138 PlayerClass(player_ptr).lose_balance();
142 reset_concentration(this->player_ptr, true);
144 SpellHex spell_hex(this->player_ptr);
145 if (spell_hex.is_spelling_any()) {
146 (void)spell_hex.stop_all_spells();
150 this->player_ptr->counter = false;
151 chg_virtue(this->player_ptr, V_HARMONY, -1);
155 msg_print(_("やっと混乱がおさまった。", "You feel less confused now."));
156 this->player_ptr->special_attack &= ~(ATTACK_SUIKEN);
161 this->player_confusion->set(v);
162 this->player_ptr->redraw |= PR_STATUS;
168 disturb(this->player_ptr, false, false);
171 handle_stuff(this->player_ptr);
175 bool BadStatusSetter::mod_confusion(const TIME_EFFECT tmp_v)
177 return this->confusion(this->player_confusion->current() + tmp_v);
181 * @brief 毒の継続時間をセットする / Set "poisoned", notice observable changes
183 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
185 bool BadStatusSetter::poison(const TIME_EFFECT tmp_v)
188 auto v = std::clamp<short>(tmp_v, 0, 10000);
189 if (this->player_ptr->is_dead) {
193 const auto player_poison = this->player_ptr->effects()->poison();
194 const auto is_poisoned = player_poison->is_poisoned();
197 msg_print(_("毒に侵されてしまった!", "You are poisoned!"));
202 msg_print(_("やっと毒の痛みがなくなった。", "You are no longer poisoned."));
207 player_poison->set(v);
208 this->player_ptr->redraw |= PR_STATUS;
214 disturb(this->player_ptr, false, false);
217 handle_stuff(this->player_ptr);
221 bool BadStatusSetter::mod_poison(const TIME_EFFECT tmp_v)
223 return this->poison(this->player_ptr->effects()->poison()->current() + tmp_v);
227 * @brief 恐怖の継続時間をセットする / Set "fearful", notice observable changes
229 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
231 bool BadStatusSetter::fear(const TIME_EFFECT tmp_v)
234 auto v = std::clamp<short>(tmp_v, 0, 10000);
235 if (this->player_ptr->is_dead) {
239 auto fear = this->player_ptr->effects()->fear();
241 if (!fear->is_fearful()) {
242 msg_print(_("何もかも恐くなってきた!", "You are terrified!"));
243 if (PlayerClass(this->player_ptr).lose_balance()) {
244 msg_print(_("型が崩れた。", "You lose your stance."));
248 this->player_ptr->counter = false;
249 chg_virtue(this->player_ptr, V_VALOUR, -1);
252 if (fear->is_fearful()) {
253 msg_print(_("やっと恐怖を振り払った。", "You feel bolder now."));
259 this->player_ptr->redraw |= PR_STATUS;
265 disturb(this->player_ptr, false, false);
268 handle_stuff(this->player_ptr);
272 bool BadStatusSetter::mod_fear(const TIME_EFFECT tmp_v)
274 return this->fear(this->player_ptr->effects()->fear()->current() + tmp_v);
278 * @brief 麻痺の継続時間をセットする / Set "paralyzed", notice observable changes
280 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
282 bool BadStatusSetter::paralysis(const TIME_EFFECT tmp_v)
285 auto v = std::clamp<short>(tmp_v, 0, 10000);
286 if (this->player_ptr->is_dead) {
290 auto paralysis = this->player_ptr->effects()->paralysis();
292 if (!paralysis->is_paralyzed()) {
293 msg_print(_("体が麻痺してしまった!", "You are paralyzed!"));
294 reset_concentration(this->player_ptr, true);
296 SpellHex spell_hex(this->player_ptr);
297 if (spell_hex.is_spelling_any()) {
298 (void)spell_hex.stop_all_spells();
301 this->player_ptr->counter = false;
305 if (paralysis->is_paralyzed()) {
306 msg_print(_("やっと動けるようになった。", "You can move again."));
312 this->player_ptr->redraw |= PR_STATUS;
318 disturb(this->player_ptr, false, false);
321 this->player_ptr->redraw |= PR_STATE;
322 handle_stuff(this->player_ptr);
326 bool BadStatusSetter::mod_paralysis(const TIME_EFFECT tmp_v)
328 return this->paralysis(this->player_ptr->effects()->paralysis()->current() + tmp_v);
332 * @brief 幻覚の継続時間をセットする / Set "image", notice observable changes
334 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
335 * @details Note that we must redraw the map when hallucination changes.
337 bool BadStatusSetter::hallucination(const TIME_EFFECT tmp_v)
340 auto v = std::clamp<short>(tmp_v, 0, 10000);
341 if (this->player_ptr->is_dead) {
345 if (is_chargeman(this->player_ptr)) {
349 auto hallucination = this->player_ptr->effects()->hallucination();
351 set_tsuyoshi(this->player_ptr, 0, true);
352 if (!hallucination->is_hallucinated()) {
353 msg_print(_("ワーオ!何もかも虹色に見える!", "Oh, wow! Everything looks so cosmic now!"));
354 reset_concentration(this->player_ptr, true);
356 this->player_ptr->counter = false;
360 if (hallucination->is_hallucinated()) {
361 msg_print(_("やっとはっきりと物が見えるようになった。", "You can see clearly again."));
366 hallucination->set(v);
367 this->player_ptr->redraw |= PR_STATUS;
373 disturb(this->player_ptr, false, true);
376 this->player_ptr->redraw |= PR_MAP | PR_HEALTH | PR_UHEALTH;
377 this->player_ptr->update |= PU_MONSTERS;
378 this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
379 handle_stuff(this->player_ptr);
383 bool BadStatusSetter::mod_hallucination(const TIME_EFFECT tmp_v)
385 return this->hallucination(this->player_ptr->effects()->hallucination()->current() + tmp_v);
389 * @brief 減速の継続時間をセットする / Set "slow", notice observable changes
391 * @param do_dec 現在の継続時間より長い値のみ上書きする
392 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
394 bool BadStatusSetter::set_deceleration(const TIME_EFFECT tmp_v, bool do_dec)
397 auto v = std::clamp<short>(tmp_v, 0, 10000);
398 if (this->player_ptr->is_dead) {
402 auto deceleration = this->player_ptr->effects()->deceleration();
403 auto is_slow = deceleration->is_slow();
405 if (is_slow && !do_dec) {
406 if (deceleration->current() > v) {
409 } else if (!is_slow) {
410 msg_print(_("体の動きが遅くなってしまった!", "You feel yourself moving slower!"));
415 msg_print(_("動きの遅さがなくなったようだ。", "You feel yourself speed up."));
420 deceleration->set(v);
426 disturb(this->player_ptr, false, false);
429 this->player_ptr->update |= PU_BONUS;
430 handle_stuff(this->player_ptr);
434 bool BadStatusSetter::mod_deceleration(const TIME_EFFECT tmp_v, bool do_dec)
436 return this->set_deceleration(this->player_ptr->effects()->deceleration()->current() + tmp_v, do_dec);
440 * @brief 朦朧の継続時間をセットする / Set "stun", notice observable changes
442 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
444 * Note the special code to only notice "range" changes.
446 bool BadStatusSetter::stun(const TIME_EFFECT tmp_v)
448 auto v = std::clamp<short>(tmp_v, 0, 10000);
449 if (this->player_ptr->is_dead) {
453 if (PlayerRace(this->player_ptr).has_stun_immunity() || PlayerClass(this->player_ptr).has_stun_immunity()) {
457 auto notice = this->process_stun_effect(v);
458 this->player_ptr->effects()->stun()->set(v);
464 disturb(this->player_ptr, false, false);
467 this->player_ptr->update |= PU_BONUS;
468 this->player_ptr->redraw |= PR_STUN;
469 handle_stuff(this->player_ptr);
473 bool BadStatusSetter::mod_stun(const TIME_EFFECT tmp_v)
475 return this->stun(this->player_ptr->effects()->stun()->current() + tmp_v);
479 * @brief 出血の継続時間をセットする / Set "cut", notice observable changes
481 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
483 * Note the special code to only notice "range" changes.
485 bool BadStatusSetter::cut(const TIME_EFFECT tmp_v)
487 auto v = std::clamp<short>(tmp_v, 0, 10000);
488 if (this->player_ptr->is_dead) {
492 if (PlayerRace(this->player_ptr).has_cut_immunity()) {
496 auto notice = this->process_cut_effect(v);
497 this->player_ptr->effects()->cut()->set(v);
503 disturb(this->player_ptr, false, false);
506 this->player_ptr->update |= PU_BONUS;
507 this->player_ptr->redraw |= PR_CUT;
508 handle_stuff(this->player_ptr);
512 bool BadStatusSetter::mod_cut(const TIME_EFFECT tmp_v)
514 return this->cut(this->player_ptr->effects()->cut()->current() + tmp_v);
517 bool BadStatusSetter::process_stun_effect(const short v)
519 auto old_rank = this->player_ptr->effects()->stun()->get_rank();
520 auto new_rank = PlayerStun::get_rank(v);
521 if (new_rank > old_rank) {
522 this->process_stun_status(new_rank, v);
526 if (new_rank < old_rank) {
534 void BadStatusSetter::process_stun_status(const PlayerStunRank new_rank, const short v)
536 auto stun_mes = PlayerStun::get_stun_mes(new_rank);
538 this->decrease_int_wis(v);
539 if (PlayerClass(this->player_ptr).lose_balance()) {
540 msg_print(_("型が崩れた。", "You lose your stance."));
543 reset_concentration(this->player_ptr, true);
545 SpellHex spell_hex(this->player_ptr);
546 if (spell_hex.is_spelling_any()) {
547 (void)spell_hex.stop_all_spells();
551 void BadStatusSetter::clear_head()
553 if (this->player_ptr->effects()->stun()->is_stunned()) {
557 msg_print(_("やっと朦朧状態から回復した。", "You are no longer stunned."));
559 disturb(this->player_ptr, false, false);
564 * @todo 後で知能と賢さが両方減る確率を減らす.
566 void BadStatusSetter::decrease_int_wis(const short v)
568 if ((v <= randint1(1000)) && !one_in_(16)) {
572 msg_print(_("割れるような頭痛がする。", "A vicious blow hits your head."));
573 auto rand = randint0(5);
576 if (has_sustain_int(this->player_ptr) == 0) {
577 (void)do_dec_stat(this->player_ptr, A_INT);
580 if (has_sustain_wis(this->player_ptr) == 0) {
581 (void)do_dec_stat(this->player_ptr, A_WIS);
587 if (has_sustain_int(this->player_ptr) == 0) {
588 (void)do_dec_stat(this->player_ptr, A_INT);
594 if (has_sustain_wis(this->player_ptr) == 0) {
595 (void)do_dec_stat(this->player_ptr, A_WIS);
600 throw("Invalid random number is specified!");
604 bool BadStatusSetter::process_cut_effect(const short v)
606 auto player_cut = this->player_ptr->effects()->cut();
607 auto old_rank = player_cut->get_rank();
608 auto new_rank = player_cut->get_rank(v);
609 if (new_rank > old_rank) {
610 this->decrease_charisma(new_rank, v);
614 if (new_rank < old_rank) {
615 this->stop_blooding(new_rank);
622 void BadStatusSetter::decrease_charisma(const PlayerCutRank new_rank, const short v)
624 auto player_cut = this->player_ptr->effects()->cut();
625 auto cut_mes = player_cut->get_cut_mes(new_rank);
627 if (v <= randint1(1000) && !one_in_(16)) {
631 if (has_sustain_chr(this->player_ptr)) {
635 msg_print(_("ひどい傷跡が残ってしまった。", "You have been horribly scarred."));
636 do_dec_stat(this->player_ptr, A_CHR);
639 void BadStatusSetter::stop_blooding(const PlayerCutRank new_rank)
641 if (new_rank >= PlayerCutRank::GRAZING) {
645 auto blood_stop_mes = PlayerRace(this->player_ptr).equals(PlayerRaceType::ANDROID)
646 ? _("怪我が直った", "leaking fluid")
647 : _("出血が止まった", "bleeding");
648 msg_format(_("やっと%s。", "You are no longer %s."), blood_stop_mes);
650 disturb(this->player_ptr, false, false);