2 * @brief プレイヤーの職業クラスに基づく耐性・能力の判定処理等を行うクラス
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"
32 PlayerClass::PlayerClass(PlayerType *player_ptr)
33 : player_ptr(player_ptr)
37 bool PlayerClass::equals(PlayerClassType type) const
39 return this->player_ptr->pclass == type;
43 * @brief プレイヤーの職業により得られる特性フラグを返す
45 TrFlags PlayerClass::tr_flags() const
48 const auto plev = this->player_ptr->lev;
50 switch (this->player_ptr->pclass) {
51 case PlayerClassType::WARRIOR: {
53 flags.set(TR_RES_FEAR);
59 case PlayerClassType::SAMURAI: {
61 flags.set(TR_RES_FEAR);
65 case PlayerClassType::PALADIN: {
67 flags.set(TR_RES_FEAR);
71 case PlayerClassType::CHAOS_WARRIOR: {
73 flags.set(TR_RES_CHAOS);
75 flags.set(TR_RES_FEAR);
79 case PlayerClassType::MONK:
80 case PlayerClassType::FORCETRAINER: {
81 if ((plev > 9) && !heavy_armor(this->player_ptr))
83 if ((plev > 24) && !heavy_armor(this->player_ptr))
84 flags.set(TR_FREE_ACT);
88 case PlayerClassType::NINJA: {
89 if (heavy_armor(this->player_ptr)) {
92 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)))
94 if (plev > 24 && !this->player_ptr->is_icky_wield[0] && !this->player_ptr->is_icky_wield[1])
95 flags.set(TR_FREE_ACT);
98 flags.set(TR_SLOW_DIGEST);
99 flags.set(TR_RES_FEAR);
101 flags.set(TR_RES_POIS);
103 flags.set(TR_SUST_DEX);
105 flags.set(TR_SEE_INVIS);
109 case PlayerClassType::MINDCRAFTER: {
111 flags.set(TR_RES_FEAR);
113 flags.set(TR_SUST_WIS);
115 flags.set(TR_RES_CONF);
117 flags.set(TR_TELEPATHY);
121 case PlayerClassType::BARD: {
122 flags.set(TR_RES_SOUND);
125 case PlayerClassType::BERSERKER: {
126 flags.set(TR_SUST_STR);
127 flags.set(TR_SUST_DEX);
128 flags.set(TR_SUST_CON);
130 flags.set(TR_FREE_ACT);
133 flags.set(TR_REFLECT);
137 case PlayerClassType::MIRROR_MASTER: {
139 flags.set(TR_REFLECT);
143 case PlayerClassType::ELEMENTALIST:
144 if (has_element_resist(this->player_ptr, ElementRealmType::FIRE, 1))
145 flags.set(TR_RES_FIRE);
146 if (has_element_resist(this->player_ptr, ElementRealmType::FIRE, 30))
147 flags.set(TR_IM_FIRE);
148 if (has_element_resist(this->player_ptr, ElementRealmType::ICE, 1))
149 flags.set(TR_RES_COLD);
150 if (has_element_resist(this->player_ptr, ElementRealmType::ICE, 30))
151 flags.set(TR_IM_COLD);
152 if (has_element_resist(this->player_ptr, ElementRealmType::SKY, 1))
153 flags.set(TR_RES_ELEC);
154 if (has_element_resist(this->player_ptr, ElementRealmType::SKY, 30))
155 flags.set(TR_IM_ELEC);
156 if (has_element_resist(this->player_ptr, ElementRealmType::SEA, 1))
157 flags.set(TR_RES_ACID);
158 if (has_element_resist(this->player_ptr, ElementRealmType::SEA, 30))
159 flags.set(TR_IM_ACID);
160 if (has_element_resist(this->player_ptr, ElementRealmType::DARKNESS, 1))
161 flags.set(TR_RES_DARK);
162 if (has_element_resist(this->player_ptr, ElementRealmType::DARKNESS, 30))
163 flags.set(TR_RES_NETHER);
164 if (has_element_resist(this->player_ptr, ElementRealmType::CHAOS, 1))
165 flags.set(TR_RES_CONF);
166 if (has_element_resist(this->player_ptr, ElementRealmType::CHAOS, 30))
167 flags.set(TR_RES_CHAOS);
168 if (has_element_resist(this->player_ptr, ElementRealmType::EARTH, 1))
169 flags.set(TR_RES_SHARDS);
170 if (has_element_resist(this->player_ptr, ElementRealmType::EARTH, 30))
171 flags.set(TR_REFLECT);
172 if (has_element_resist(this->player_ptr, ElementRealmType::DEATH, 1))
173 flags.set(TR_RES_POIS);
174 if (has_element_resist(this->player_ptr, ElementRealmType::DEATH, 30))
175 flags.set(TR_RES_DISEN);
184 TrFlags PlayerClass::stance_tr_flags() const
188 switch (this->get_samurai_stance()) {
189 case SamuraiStanceType::FUUJIN:
190 if (!this->player_ptr->blind) {
191 flags.set(TR_REFLECT);
194 case SamuraiStanceType::MUSOU:
195 flags.set({ TR_RES_ACID, TR_RES_ELEC, TR_RES_FIRE, TR_RES_COLD, TR_RES_POIS });
196 flags.set({ TR_REFLECT, TR_RES_FEAR, TR_RES_LITE, TR_RES_DARK, TR_RES_BLIND, TR_RES_CONF,
197 TR_RES_SOUND, TR_RES_SHARDS, TR_RES_NETHER, TR_RES_NEXUS, TR_RES_CHAOS, TR_RES_DISEN,
198 TR_RES_WATER, TR_RES_TIME, TR_RES_CURSE });
199 flags.set({ TR_HOLD_EXP, TR_FREE_ACT, TR_LEVITATION, TR_LITE_1, TR_SEE_INVIS, TR_TELEPATHY, TR_SLOW_DIGEST, TR_REGEN });
200 flags.set({ TR_SH_FIRE, TR_SH_ELEC, TR_SH_COLD });
201 flags.set({ TR_SUST_STR, TR_SUST_INT, TR_SUST_WIS, TR_SUST_DEX, TR_SUST_CON, TR_SUST_CHR });
203 case SamuraiStanceType::KOUKIJIN:
204 flags.set({ TR_VUL_ACID, TR_VUL_ELEC, TR_VUL_FIRE, TR_VUL_COLD });
210 switch (this->get_monk_stance()) {
211 case MonkStanceType::GENBU:
212 flags.set(TR_REFLECT);
214 case MonkStanceType::SUZAKU:
215 flags.set(TR_LEVITATION);
217 case MonkStanceType::SEIRYU:
218 flags.set({ TR_RES_ACID, TR_RES_ELEC, TR_RES_FIRE, TR_RES_COLD, TR_RES_POIS });
219 flags.set({ TR_SH_FIRE, TR_SH_ELEC, TR_SH_COLD });
220 flags.set(TR_LEVITATION);
229 bool PlayerClass::has_stun_immunity() const
231 return (this->player_ptr->pclass == PlayerClassType::BERSERKER) && (this->player_ptr->lev > 34);
235 * @brief 加速ボーナスのある種族かを返す
236 * @return 加速ボーナスのある種族か否か
238 * 種族と職業の両方で特性による加速が得られる場合、重複して加速することはない.
241 bool PlayerClass::has_additional_speed() const
243 auto has_additional_speed = this->equals(PlayerClassType::MONK);
244 has_additional_speed |= this->equals(PlayerClassType::FORCETRAINER);
245 has_additional_speed |= this->equals(PlayerClassType::NINJA);
246 return has_additional_speed;
249 bool PlayerClass::is_soldier() const
251 auto is_soldier = this->equals(PlayerClassType::WARRIOR);
252 is_soldier |= this->equals(PlayerClassType::ARCHER);
253 is_soldier |= this->equals(PlayerClassType::CAVALRY);
254 is_soldier |= this->equals(PlayerClassType::BERSERKER);
255 is_soldier |= this->equals(PlayerClassType::SMITH);
259 bool PlayerClass::is_wizard() const
261 auto is_wizard = this->equals(PlayerClassType::MAGE);
262 is_wizard |= this->equals(PlayerClassType::HIGH_MAGE);
263 is_wizard |= this->equals(PlayerClassType::SORCERER);
264 is_wizard |= this->equals(PlayerClassType::MAGIC_EATER);
265 is_wizard |= this->equals(PlayerClassType::BLUE_MAGE);
266 is_wizard |= this->equals(PlayerClassType::ELEMENTALIST);
270 bool PlayerClass::lose_balance()
272 if (this->player_ptr->pclass != PlayerClassType::SAMURAI) {
276 if (this->samurai_stance_is(SamuraiStanceType::NONE)) {
280 this->set_samurai_stance(SamuraiStanceType::NONE);
281 this->player_ptr->update |= PU_BONUS;
282 this->player_ptr->update |= PU_MONSTERS;
283 this->player_ptr->redraw |= PR_STATE;
284 this->player_ptr->redraw |= PR_STATUS;
285 this->player_ptr->action = ACTION_NONE;
289 SamuraiStanceType PlayerClass::get_samurai_stance() const
291 auto samurai_data = this->get_specific_data<samurai_data_type>();
293 return SamuraiStanceType::NONE;
296 return samurai_data->stance;
299 bool PlayerClass::samurai_stance_is(SamuraiStanceType stance) const
301 return this->get_samurai_stance() == stance;
307 * @param stance_list 崩す型を指定する。取っている型が指定された型に含まれない場合は崩さない。
309 void PlayerClass::break_samurai_stance(std::initializer_list<SamuraiStanceType> stance_list)
311 auto samurai_data = this->get_specific_data<samurai_data_type>();
316 for (auto stance : stance_list) {
317 if (samurai_data->stance == stance) {
318 set_action(player_ptr, ACTION_NONE);
319 samurai_data->stance = SamuraiStanceType::NONE;
325 void PlayerClass::set_samurai_stance(SamuraiStanceType stance) const
327 auto samurai_data = this->get_specific_data<samurai_data_type>();
332 samurai_data->stance = stance;
335 MonkStanceType PlayerClass::get_monk_stance() const
337 auto monk_data = this->get_specific_data<monk_data_type>();
339 return MonkStanceType::NONE;
342 return monk_data->stance;
345 bool PlayerClass::monk_stance_is(MonkStanceType stance) const
347 return this->get_monk_stance() == stance;
350 void PlayerClass::set_monk_stance(MonkStanceType stance) const
352 auto monk_data = this->get_specific_data<monk_data_type>();
357 monk_data->stance = stance;
361 * @brief プレイヤーの職業にで使用する職業固有データ領域を初期化する
362 * @details 事前条件: PlayerType の職業や領域が決定済みであること
364 void PlayerClass::init_specific_data()
366 switch (this->player_ptr->pclass) {
367 case PlayerClassType::SMITH:
368 this->player_ptr->class_specific_data = std::make_shared<smith_data_type>();
370 case PlayerClassType::FORCETRAINER:
371 this->player_ptr->class_specific_data = std::make_shared<force_trainer_data_type>();
373 case PlayerClassType::BLUE_MAGE:
374 this->player_ptr->class_specific_data = std::make_shared<bluemage_data_type>();
376 case PlayerClassType::MAGIC_EATER:
377 this->player_ptr->class_specific_data = std::make_shared<magic_eater_data_type>();
379 case PlayerClassType::BARD:
380 this->player_ptr->class_specific_data = std::make_shared<bard_data_type>();
382 case PlayerClassType::IMITATOR:
383 this->player_ptr->class_specific_data = std::make_shared<mane_data_type>();
385 case PlayerClassType::SNIPER:
386 this->player_ptr->class_specific_data = std::make_shared<sniper_data_type>();
388 case PlayerClassType::SAMURAI:
389 this->player_ptr->class_specific_data = std::make_shared<samurai_data_type>();
391 case PlayerClassType::MONK:
392 this->player_ptr->class_specific_data = std::make_shared<monk_data_type>();
394 case PlayerClassType::NINJA:
395 this->player_ptr->class_specific_data = std::make_shared<ninja_data_type>();
397 case PlayerClassType::HIGH_MAGE:
398 if (this->player_ptr->realm1 == REALM_HEX) {
399 this->player_ptr->class_specific_data = std::make_shared<spell_hex_data_type>();
401 this->player_ptr->class_specific_data = no_class_specific_data();
405 this->player_ptr->class_specific_data = no_class_specific_data();