OSDN Git Service

Merge branch 'master' of https://github.com/hengband/hengband
[hengbandforosx/hengbandosx.git] / src / system / player-type-definition.cpp
1 #include "system/player-type-definition.h"
2 #include "floor/geometry.h"
3 #include "market/arena-info-table.h"
4 #include "system/angband-exceptions.h"
5 #include "system/redrawing-flags-updater.h"
6 #include "timed-effect/player-blindness.h"
7 #include "timed-effect/player-confusion.h"
8 #include "timed-effect/player-cut.h"
9 #include "timed-effect/player-deceleration.h"
10 #include "timed-effect/player-fear.h"
11 #include "timed-effect/player-hallucination.h"
12 #include "timed-effect/player-paralysis.h"
13 #include "timed-effect/player-poison.h"
14 #include "timed-effect/player-stun.h"
15 #include "timed-effect/timed-effects.h"
16 #include "world/world.h"
17
18 /*!
19  * @brief プレイヤー構造体実体 / Static player info record
20  */
21 PlayerType p_body;
22
23 /*!
24  * @brief プレイヤー構造体へのグローバル参照ポインタ / Pointer to the player info
25  */
26 PlayerType *p_ptr = &p_body;
27
28 PlayerType::PlayerType()
29     : timed_effects(std::make_shared<TimedEffects>())
30 {
31 }
32
33 bool PlayerType::is_true_winner() const
34 {
35     return (w_ptr->total_winner > 0) && (this->arena_number > MAX_ARENA_MONS + 2);
36 }
37
38 std::shared_ptr<TimedEffects> PlayerType::effects() const
39 {
40     return this->timed_effects;
41 }
42
43 /*!
44  * @brief 自身の状態が全快で、かつフロアに影響を与えないかを検証する
45  * @return 上記の通りか
46  * @todo 時限効果系に分類されるものはいずれTimedEffectsクラスのメソッドとして繰り込みたい
47  */
48 bool PlayerType::is_fully_healthy() const
49 {
50     auto effects = this->effects();
51     auto is_fully_healthy = this->chp == this->mhp;
52     is_fully_healthy &= this->csp >= this->msp;
53     is_fully_healthy &= !effects->blindness()->is_blind();
54     is_fully_healthy &= !effects->confusion()->is_confused();
55     is_fully_healthy &= !effects->poison()->is_poisoned();
56     is_fully_healthy &= !effects->fear()->is_fearful();
57     is_fully_healthy &= !effects->stun()->is_stunned();
58     is_fully_healthy &= !effects->cut()->is_cut();
59     is_fully_healthy &= !effects->deceleration()->is_slow();
60     is_fully_healthy &= !effects->paralysis()->is_paralyzed();
61     is_fully_healthy &= !effects->hallucination()->is_hallucinated();
62     is_fully_healthy &= !this->word_recall;
63     is_fully_healthy &= !this->alter_reality;
64     return is_fully_healthy;
65 }
66
67 /*
68  * @brief ランダムに1つアビリティスコアを減少させる
69  * @return アビリティスコア減少メッセージ
70  * @todo stat_curにのみ依存するのでアビリティスコアを表すクラスへ移設する
71  */
72 std::string PlayerType::decrease_ability_random()
73 {
74     constexpr std::array<std::pair<int, std::string_view>, 6> candidates = { {
75         { A_STR, _("強く", "strong") },
76         { A_INT, _("聡明で", "bright") },
77         { A_WIS, _("賢明で", "wise") },
78         { A_DEX, _("器用で", "agile") },
79         { A_CON, _("健康で", "hale") },
80         { A_CHR, _("美しく", "beautiful") },
81     } };
82
83     const auto &[k, act] = rand_choice(candidates);
84     this->stat_cur[k] = (this->stat_cur[k] * 3) / 4;
85     if (this->stat_cur[k] < 3) {
86         this->stat_cur[k] = 3;
87     }
88
89     RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
90     return format(_("あなたは以前ほど%sなくなってしまった...。", "You're not as %s as you used to be..."), act.data());
91 }
92
93 /*
94  * @brief 全てのアビリティスコアを減少させる
95  * @return アビリティスコア減少メッセージ
96  * @todo stat_curにのみ依存するのでアビリティスコアを表すクラスへ移設する
97  */
98 std::string PlayerType::decrease_ability_all()
99 {
100     for (auto i = 0; i < A_MAX; i++) {
101         this->stat_cur[i] = (this->stat_cur[i] * 7) / 8;
102         if (this->stat_cur[i] < 3) {
103             this->stat_cur[i] = 3;
104         }
105     }
106
107     RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
108     return _("あなたは以前ほど力強くなくなってしまった...。", "You're not as powerful as you used to be...");
109 }
110
111 /*!
112  * @brief 現在地の瞬時値を返す
113  * @details プレイヤーが移動する前後の文脈で使用すると不整合を起こすので注意
114  */
115 Pos2D PlayerType::get_position() const
116 {
117     return Pos2D(this->y, this->x);
118 }
119
120 /*!
121  * @brief 現在地の隣 (瞬時値)または現在地を返す
122  * @param dir 隣を表す方向番号
123  * @details プレイヤーが移動する前後の文脈で使用すると不整合を起こすので注意
124  * 方向番号による位置取りは以下の通り. 0と5は現在地.
125  * 123 ...
126  * 456 .@.
127  * 789 ...
128  */
129 Pos2D PlayerType::get_neighbor(int dir) const
130 {
131     if ((dir < 0) || (dir >= static_cast<int>(std::size(ddx)))) {
132         THROW_EXCEPTION(std::logic_error, "Invalid direction is specified!");
133     }
134
135     return Pos2D(this->y + ddy[dir], this->x + ddx[dir]);
136 }
137
138 bool PlayerType::is_located_at_running_destination() const
139 {
140     return (this->y == this->run_py) && (this->x == this->run_px);
141 }
142
143 bool PlayerType::is_located_at(const Pos2D &pos) const
144 {
145     return (this->y == pos.y) && (this->x == pos.x);
146 }
147
148 bool PlayerType::in_saved_floor() const
149 {
150     return this->floor_id != 0;
151 }