OSDN Git Service

6c487585d7a19fc1871838f0dc7cf0f2a459561c
[hengbandforosx/hengbandosx.git] / src / player-base / player-race.cpp
1 /*!
2  * @brief プレイヤーの種族に基づく耐性・能力の判定処理等を行うクラス
3  * @date 2021/09/08
4  * @author Hourier
5  * @details 本クラス作成時点で責務に対する余裕はかなりあるので、適宜ここへ移してくること.
6  */
7 #include "player-base/player-race.h"
8 #include "grid/feature-flag-types.h"
9 #include "grid/feature.h"
10 #include "player-info/mimic-info-table.h"
11 #include "player/race-info-table.h"
12 #include "system/floor-type-definition.h"
13 #include "system/grid-type-definition.h"
14 #include "system/player-type-definition.h"
15 #include "util/bit-flags-calculator.h"
16
17 /*!
18  * @brief Construct a new Player Race:: Player Race object
19  *
20  * @param base_race true の場合、仮に変身している場合でも元の種族について扱う。 false の場合変身している種族について扱う。
21  * 引数を省略した場合は false
22  */
23 PlayerRace::PlayerRace(player_type *player_ptr, bool base_race)
24     : player_ptr(player_ptr)
25     , base_race(base_race)
26 {
27 }
28
29 /*!
30  * @brief 種族固有の特性フラグを取得する
31  * @return
32  */
33 TrFlags PlayerRace::tr_flags() const
34 {
35     TrFlags flags;
36
37     auto race_ptr = this->get_info();
38     if (race_ptr->infra > 0)
39         flags.set(TR_INFRA);
40
41     for (auto &cond : race_ptr->extra_flags) {
42         if (player_ptr->lev < cond.level)
43             continue;
44         if (cond.pclass != std::nullopt) {
45             if (cond.not_class && player_ptr->pclass == cond.pclass)
46                 continue;
47             if (!cond.not_class && player_ptr->pclass != cond.pclass)
48                 continue;
49         }
50
51         flags.set(cond.type);
52     }
53
54     return flags;
55 }
56
57 /*!
58  * @brief プレイヤーの種族情報テーブルへのポインタを取得する
59  *
60  * @return プレイヤーの種族情報テーブルへのポインタ
61  */
62 const player_race_info *PlayerRace::get_info() const
63 {
64     if (this->base_race) {
65         return &race_info[enum2i(this->player_ptr->prace)];
66     }
67
68     switch (this->player_ptr->mimic_form) {
69     case MIMIC_DEMON:
70     case MIMIC_DEMON_LORD:
71     case MIMIC_VAMPIRE:
72         return &mimic_info[this->player_ptr->mimic_form];
73     default: // MIMIC_NONE or undefined
74         return &race_info[enum2i(this->player_ptr->prace)];
75     }
76 }
77
78 /*!
79  * @brief 種族の生命形態を返す
80  * @param player_ptr プレイヤー情報への参照ポインタ
81  * @return 生命形態
82  */
83 PlayerRaceLife PlayerRace::life() const
84 {
85     return this->get_info()->life;
86 }
87
88 /*!
89  * @brief 種族の食料形態を返す
90  * @param player_ptr プレイヤー情報への参照ポインタ
91  * @param base_race ミミック中も元種族の情報を返すならtrue
92  * @return 食料形態
93  */
94 PlayerRaceFood PlayerRace::food() const
95 {
96     return this->get_info()->food;
97 }
98
99 bool PlayerRace::is_mimic_nonliving() const
100 {
101     constexpr int nonliving_flag = 1;
102     return any_bits(mimic_info[this->player_ptr->mimic_form].choice, nonliving_flag);
103 }
104
105 bool PlayerRace::can_resist_cut() const
106 {
107     auto can_resist_cut = this->player_ptr->prace == PlayerRaceType::GOLEM;
108     can_resist_cut |= this->player_ptr->prace == PlayerRaceType::SKELETON;
109     can_resist_cut |= this->player_ptr->prace == PlayerRaceType::SPECTRE;
110     can_resist_cut |= (this->player_ptr->prace == PlayerRaceType::ZOMBIE) && (this->player_ptr->lev > 11);
111     return can_resist_cut;
112 }
113
114 bool PlayerRace::equals(PlayerRaceType prace) const
115 {
116     return (this->player_ptr->mimic_form == MIMIC_NONE) && (this->player_ptr->prace == prace);
117 }
118
119 /*!
120  * @brief 速度計算 - 種族
121  * @return 速度値の増減分
122  * @details
123  * ** クラッコンと妖精に加算(+レベル/10)
124  * ** 悪魔変化/吸血鬼変化で加算(+3)
125  * ** 魔王変化で加算(+5)
126  * ** マーフォークがFF_WATER地形にいれば加算(+2+レベル/10)
127  * ** そうでなく浮遊を持っていないなら減算(-2)
128  */
129 int16_t PlayerRace::speed() const
130 {
131     int16_t result = 0;
132
133     if (PlayerRace(this->player_ptr).equals(PlayerRaceType::KLACKON) || PlayerRace(this->player_ptr).equals(PlayerRaceType::SPRITE))
134         result += (this->player_ptr->lev) / 10;
135
136     if (PlayerRace(this->player_ptr).equals(PlayerRaceType::MERFOLK)) {
137         floor_type *floor_ptr = this->player_ptr->current_floor_ptr;
138         feature_type *f_ptr = &f_info[floor_ptr->grid_array[this->player_ptr->y][this->player_ptr->x].feat];
139         if (f_ptr->flags.has(FF::WATER)) {
140             result += (2 + this->player_ptr->lev / 10);
141         } else if (!this->player_ptr->levitation) {
142             result -= 2;
143         }
144     }
145
146     if (this->player_ptr->mimic_form) {
147         switch (this->player_ptr->mimic_form) {
148         case MIMIC_DEMON:
149             result += 3;
150             break;
151         case MIMIC_DEMON_LORD:
152             result += 5;
153             break;
154         case MIMIC_VAMPIRE:
155             result += 3;
156             break;
157         }
158     }
159     return result;
160 }
161
162 /*!
163  * @brief 腕力補正計算 - 種族
164  * @return 腕力補正値
165  * @details
166  * * 種族による腕力修正値。
167  * * エントはレベル26,41,46到達ごとに加算(+1)
168  */
169 int16_t PlayerRace::additional_strength() const
170 {
171     int16_t result = 0;
172
173     if (PlayerRace(this->player_ptr).equals(PlayerRaceType::ENT)) {
174         if (this->player_ptr->lev > 25)
175             result++;
176         if (this->player_ptr->lev > 40)
177             result++;
178         if (this->player_ptr->lev > 45)
179             result++;
180     }
181
182     return result;
183 }
184
185 /*!
186  * @brief 器用さ補正計算 - 種族
187  * @return 器用さ補正値
188  * @details
189  * * 種族による器用さ修正値。
190  * * エントはレベル26,41,46到達ごとに減算(-1)
191  */
192 int16_t PlayerRace::additional_dexterity() const
193 {
194     int16_t result = 0;
195
196     if (PlayerRace(this->player_ptr).equals(PlayerRaceType::ENT)) {
197         if (this->player_ptr->lev > 25)
198             result--;
199         if (this->player_ptr->lev > 40)
200             result--;
201         if (this->player_ptr->lev > 45)
202             result--;
203     }
204
205     return result;
206 }
207
208 /*!
209  * @brief 耐久力補正計算 - 種族
210  * @return 耐久力補正値
211  * @details
212  * * 種族による耐久力修正値。
213  * * エントはレベル26,41,46到達ごとに加算(+1)
214  */
215 int16_t PlayerRace::additional_constitution() const
216 {
217     int16_t result = 0;
218
219     if (PlayerRace(this->player_ptr).equals(PlayerRaceType::ENT)) {
220         if (this->player_ptr->lev > 25)
221             result++;
222         if (this->player_ptr->lev > 40)
223             result++;
224         if (this->player_ptr->lev > 45)
225             result++;
226     }
227
228     return result;
229 }