OSDN Git Service

[Refactor] ソースコード内BattleForm表記をStance表記に統一
[hengbandforosx/hengbandosx.git] / src / player-base / player-class.cpp
1 /*!
2  * @brief プレイヤーの職業クラスに基づく耐性・能力の判定処理等を行うクラス
3  * @date 2021/09/08
4  * @author Hourier
5  */
6 #include "player-base/player-class.h"
7 #include "core/player-redraw-types.h"
8 #include "core/player-update-types.h"
9 #include "inventory/inventory-slot-types.h"
10 #include "mind/mind-elementalist.h"
11 #include "player-info/bard-data-type.h"
12 #include "player-info/bluemage-data-type.h"
13 #include "player-info/equipment-info.h"
14 #include "player-info/force-trainer-data-type.h"
15 #include "player-info/magic-eater-data-type.h"
16 #include "player-info/mane-data-type.h"
17 #include "player-info/monk-data-type.h"
18 #include "player-info/ninja-data-type.h"
19 #include "player-info/samurai-data-type.h"
20 #include "player-info/smith-data-type.h"
21 #include "player-info/sniper-data-type.h"
22 #include "player-info/spell-hex-data-type.h"
23 #include "player/attack-defense-types.h"
24 #include "player/player-status-flags.h"
25 #include "player/special-defense-types.h"
26 #include "realm/realm-types.h"
27 #include "status/action-setter.h"
28 #include "system/object-type-definition.h"
29 #include "system/player-type-definition.h"
30 #include "util/bit-flags-calculator.h"
31
32 PlayerClass::PlayerClass(player_type *player_ptr)
33     : player_ptr(player_ptr)
34 {
35 }
36
37 /*!
38  * @brief プレイヤーの職業により得られる特性フラグを返す
39  */
40 TrFlags PlayerClass::tr_flags() const
41 {
42     TrFlags flags;
43     const auto plev = this->player_ptr->lev;
44
45     switch (this->player_ptr->pclass) {
46     case PlayerClassType::WARRIOR: {
47         if (plev > 29)
48             flags.set(TR_RES_FEAR);
49         if (plev > 44)
50             flags.set(TR_REGEN);
51
52         break;
53     }
54     case PlayerClassType::SAMURAI: {
55         if (plev > 29)
56             flags.set(TR_RES_FEAR);
57
58         break;
59     }
60     case PlayerClassType::PALADIN: {
61         if (plev > 39)
62             flags.set(TR_RES_FEAR);
63
64         break;
65     }
66     case PlayerClassType::CHAOS_WARRIOR: {
67         if (plev > 29)
68             flags.set(TR_RES_CHAOS);
69         if (plev > 39)
70             flags.set(TR_RES_FEAR);
71
72         break;
73     }
74     case PlayerClassType::MONK:
75     case PlayerClassType::FORCETRAINER: {
76         if ((plev > 9) && !heavy_armor(this->player_ptr))
77             flags.set(TR_SPEED);
78         if ((plev > 24) && !heavy_armor(this->player_ptr))
79             flags.set(TR_FREE_ACT);
80
81         break;
82     }
83     case PlayerClassType::NINJA: {
84         if (heavy_armor(this->player_ptr)) {
85             flags.set(TR_SPEED);
86         } else {
87             if ((!this->player_ptr->inventory_list[INVEN_MAIN_HAND].k_idx || can_attack_with_main_hand(this->player_ptr)) && (!this->player_ptr->inventory_list[INVEN_SUB_HAND].k_idx || can_attack_with_sub_hand(this->player_ptr)))
88                 flags.set(TR_SPEED);
89             if (plev > 24 && !this->player_ptr->is_icky_wield[0] && !this->player_ptr->is_icky_wield[1])
90                 flags.set(TR_FREE_ACT);
91         }
92
93         flags.set(TR_SLOW_DIGEST);
94         flags.set(TR_RES_FEAR);
95         if (plev > 19)
96             flags.set(TR_RES_POIS);
97         if (plev > 24)
98             flags.set(TR_SUST_DEX);
99         if (plev > 29)
100             flags.set(TR_SEE_INVIS);
101
102         break;
103     }
104     case PlayerClassType::MINDCRAFTER: {
105         if (plev > 9)
106             flags.set(TR_RES_FEAR);
107         if (plev > 19)
108             flags.set(TR_SUST_WIS);
109         if (plev > 29)
110             flags.set(TR_RES_CONF);
111         if (plev > 39)
112             flags.set(TR_TELEPATHY);
113
114         break;
115     }
116     case PlayerClassType::BARD: {
117         flags.set(TR_RES_SOUND);
118         break;
119     }
120     case PlayerClassType::BERSERKER: {
121         flags.set(TR_SUST_STR);
122         flags.set(TR_SUST_DEX);
123         flags.set(TR_SUST_CON);
124         flags.set(TR_REGEN);
125         flags.set(TR_FREE_ACT);
126         flags.set(TR_SPEED);
127         if (plev > 39)
128             flags.set(TR_REFLECT);
129
130         break;
131     }
132     case PlayerClassType::MIRROR_MASTER: {
133         if (plev > 39)
134             flags.set(TR_REFLECT);
135
136         break;
137     }
138     case PlayerClassType::ELEMENTALIST:
139         if (has_element_resist(this->player_ptr, ElementRealm::FIRE, 1))
140             flags.set(TR_RES_FIRE);
141         if (has_element_resist(this->player_ptr, ElementRealm::FIRE, 30))
142             flags.set(TR_IM_FIRE);
143         if (has_element_resist(this->player_ptr, ElementRealm::ICE, 1))
144             flags.set(TR_RES_COLD);
145         if (has_element_resist(this->player_ptr, ElementRealm::ICE, 30))
146             flags.set(TR_IM_COLD);
147         if (has_element_resist(this->player_ptr, ElementRealm::SKY, 1))
148             flags.set(TR_RES_ELEC);
149         if (has_element_resist(this->player_ptr, ElementRealm::SKY, 30))
150             flags.set(TR_IM_ELEC);
151         if (has_element_resist(this->player_ptr, ElementRealm::SEA, 1))
152             flags.set(TR_RES_ACID);
153         if (has_element_resist(this->player_ptr, ElementRealm::SEA, 30))
154             flags.set(TR_IM_ACID);
155         if (has_element_resist(this->player_ptr, ElementRealm::DARKNESS, 1))
156             flags.set(TR_RES_DARK);
157         if (has_element_resist(this->player_ptr, ElementRealm::DARKNESS, 30))
158             flags.set(TR_RES_NETHER);
159         if (has_element_resist(this->player_ptr, ElementRealm::CHAOS, 1))
160             flags.set(TR_RES_CONF);
161         if (has_element_resist(this->player_ptr, ElementRealm::CHAOS, 30))
162             flags.set(TR_RES_CHAOS);
163         if (has_element_resist(this->player_ptr, ElementRealm::EARTH, 1))
164             flags.set(TR_RES_SHARDS);
165         if (has_element_resist(this->player_ptr, ElementRealm::EARTH, 30))
166             flags.set(TR_REFLECT);
167         if (has_element_resist(this->player_ptr, ElementRealm::DEATH, 1))
168             flags.set(TR_RES_POIS);
169         if (has_element_resist(this->player_ptr, ElementRealm::DEATH, 30))
170             flags.set(TR_RES_DISEN);
171         break;
172     default:
173         break;
174     }
175
176     return flags;
177 }
178
179 TrFlags PlayerClass::stance_tr_flags() const
180 {
181     TrFlags flags;
182
183     switch (this->get_samurai_stance()) {
184     case SamuraiStance::FUUJIN:
185         if (!this->player_ptr->blind) {
186             flags.set(TR_REFLECT);
187         }
188         break;
189     case SamuraiStance::MUSOU:
190         flags.set({ TR_RES_ACID, TR_RES_ELEC, TR_RES_FIRE, TR_RES_COLD, TR_RES_POIS });
191         flags.set({ TR_REFLECT, TR_RES_FEAR, TR_RES_LITE, TR_RES_DARK, TR_RES_BLIND, TR_RES_CONF,
192             TR_RES_SOUND, TR_RES_SHARDS, TR_RES_NETHER, TR_RES_NEXUS, TR_RES_CHAOS, TR_RES_DISEN,
193             TR_RES_WATER, TR_RES_TIME, TR_RES_CURSE });
194         flags.set({ TR_HOLD_EXP, TR_FREE_ACT, TR_LEVITATION, TR_LITE_1, TR_SEE_INVIS, TR_TELEPATHY, TR_SLOW_DIGEST, TR_REGEN });
195         flags.set({ TR_SH_FIRE, TR_SH_ELEC, TR_SH_COLD });
196         flags.set({ TR_SUST_STR, TR_SUST_INT, TR_SUST_WIS, TR_SUST_DEX, TR_SUST_CON, TR_SUST_CHR });
197         break;
198     case SamuraiStance::KOUKIJIN:
199         flags.set({ TR_VUL_ACID, TR_VUL_ELEC, TR_VUL_FIRE, TR_VUL_COLD });
200         break;
201     default:
202         break;
203     }
204
205     switch (this->get_monk_stance()) {
206     case MonkStance::GENBU:
207         flags.set(TR_REFLECT);
208         break;
209     case MonkStance::SUZAKU:
210         flags.set(TR_LEVITATION);
211         break;
212     case MonkStance::SEIRYU:
213         flags.set({ TR_RES_ACID, TR_RES_ELEC, TR_RES_FIRE, TR_RES_COLD, TR_RES_POIS });
214         flags.set({ TR_SH_FIRE, TR_SH_ELEC, TR_SH_COLD });
215         flags.set(TR_LEVITATION);
216         break;
217     default:
218         break;
219     }
220
221     return flags;
222 }
223
224 bool PlayerClass::has_stun_immunity() const
225 {
226     return (this->player_ptr->pclass == PlayerClassType::BERSERKER) && (this->player_ptr->lev > 34);
227 }
228
229 bool PlayerClass::is_wizard() const
230 {
231     auto is_wizard = this->player_ptr->pclass == PlayerClassType::MAGE;
232     is_wizard |= this->player_ptr->pclass == PlayerClassType::HIGH_MAGE;
233     is_wizard |= this->player_ptr->pclass == PlayerClassType::SORCERER;
234     is_wizard |= this->player_ptr->pclass == PlayerClassType::MAGIC_EATER;
235     is_wizard |= this->player_ptr->pclass == PlayerClassType::BLUE_MAGE;
236     is_wizard |= this->player_ptr->pclass == PlayerClassType::ELEMENTALIST;
237     return is_wizard;
238 }
239
240 bool PlayerClass::lose_balance()
241 {
242     if (this->player_ptr->pclass != PlayerClassType::SAMURAI) {
243         return false;
244     }
245
246     if (this->samurai_stance_is(SamuraiStance::NONE)) {
247         return false;
248     }
249
250     this->set_samurai_stance(SamuraiStance::NONE);
251     this->player_ptr->update |= PU_BONUS;
252     this->player_ptr->update |= PU_MONSTERS;
253     this->player_ptr->redraw |= PR_STATE;
254     this->player_ptr->redraw |= PR_STATUS;
255     this->player_ptr->action = ACTION_NONE;
256     return true;
257 }
258
259 SamuraiStance PlayerClass::get_samurai_stance() const
260 {
261     auto samurai_data = this->get_specific_data<samurai_data_type>();
262     if (!samurai_data) {
263         return SamuraiStance::NONE;
264     }
265
266     return samurai_data->stance;
267 }
268
269 bool PlayerClass::samurai_stance_is(SamuraiStance stance) const
270 {
271     return this->get_samurai_stance() == stance;
272 }
273
274 /**
275  * @brief 剣術家の型を崩す
276  *
277  * @param stance_list 崩す型を指定する。取っている型が指定された型に含まれない場合は崩さない。
278  */
279 void PlayerClass::break_samurai_stance(std::initializer_list<SamuraiStance> stance_list)
280 {
281     auto samurai_data = this->get_specific_data<samurai_data_type>();
282     if (!samurai_data) {
283         return;
284     }
285
286     for (auto stance : stance_list) {
287         if (samurai_data->stance == stance) {
288             set_action(player_ptr, ACTION_NONE);
289             samurai_data->stance = SamuraiStance::NONE;
290             break;
291         }
292     }
293 }
294
295 void PlayerClass::set_samurai_stance(SamuraiStance stance) const
296 {
297     auto samurai_data = this->get_specific_data<samurai_data_type>();
298     if (!samurai_data) {
299         return;
300     }
301
302     samurai_data->stance = stance;
303 }
304
305 MonkStance PlayerClass::get_monk_stance() const
306 {
307     auto monk_data = this->get_specific_data<monk_data_type>();
308     if (!monk_data) {
309         return MonkStance::NONE;
310     }
311
312     return monk_data->stance;
313 }
314
315 bool PlayerClass::monk_stance_is(MonkStance stance) const
316 {
317     return this->get_monk_stance() == stance;
318 }
319
320 void PlayerClass::set_monk_stance(MonkStance stance) const
321 {
322     auto monk_data = this->get_specific_data<monk_data_type>();
323     if (!monk_data) {
324         return;
325     }
326
327     monk_data->stance = stance;
328 }
329
330 /**
331  * @brief プレイヤーの職業にで使用する職業固有データ領域を初期化する
332  * @details 事前条件: player_type の職業や領域が決定済みであること
333  */
334 void PlayerClass::init_specific_data()
335 {
336     switch (this->player_ptr->pclass) {
337     case PlayerClassType::SMITH:
338         this->player_ptr->class_specific_data = std::make_shared<smith_data_type>();
339         break;
340     case PlayerClassType::FORCETRAINER:
341         this->player_ptr->class_specific_data = std::make_shared<force_trainer_data_type>();
342         break;
343     case PlayerClassType::BLUE_MAGE:
344         this->player_ptr->class_specific_data = std::make_shared<bluemage_data_type>();
345         break;
346     case PlayerClassType::MAGIC_EATER:
347         this->player_ptr->class_specific_data = std::make_shared<magic_eater_data_type>();
348         break;
349     case PlayerClassType::BARD:
350         this->player_ptr->class_specific_data = std::make_shared<bard_data_type>();
351         break;
352     case PlayerClassType::IMITATOR:
353         this->player_ptr->class_specific_data = std::make_shared<mane_data_type>();
354         break;
355     case PlayerClassType::SNIPER:
356         this->player_ptr->class_specific_data = std::make_shared<sniper_data_type>();
357         break;
358     case PlayerClassType::SAMURAI:
359         this->player_ptr->class_specific_data = std::make_shared<samurai_data_type>();
360         break;
361     case PlayerClassType::MONK:
362         this->player_ptr->class_specific_data = std::make_shared<monk_data_type>();
363         break;
364     case PlayerClassType::NINJA:
365         this->player_ptr->class_specific_data = std::make_shared<ninja_data_type>();
366         break;
367     case PlayerClassType::HIGH_MAGE:
368         if (this->player_ptr->realm1 == REALM_HEX) {
369             this->player_ptr->class_specific_data = std::make_shared<spell_hex_data_type>();
370         } else {
371             this->player_ptr->class_specific_data = no_class_specific_data();
372         }
373         break;
374     default:
375         this->player_ptr->class_specific_data = no_class_specific_data();
376         break;
377     }
378 }