1 #include "player/player-skill.h"
2 #include "core/player-update-types.h"
3 #include "monster-race/monster-race.h"
4 #include "player-info/class-info.h"
5 #include "player/player-realm.h"
6 #include "system/floor-type-definition.h"
7 #include "system/monster-race-definition.h"
8 #include "system/monster-type-definition.h"
9 #include "system/object-type-definition.h"
10 #include "system/player-type-definition.h"
11 #include "util/bit-flags-calculator.h"
13 /* Proficiency of weapons and misc. skills (except riding) */
14 constexpr SUB_EXP WEAPON_EXP_UNSKILLED = 0;
15 constexpr SUB_EXP WEAPON_EXP_BEGINNER = 4000;
16 constexpr SUB_EXP WEAPON_EXP_SKILLED = 6000;
17 constexpr SUB_EXP WEAPON_EXP_EXPERT = 7000;
18 constexpr SUB_EXP WEAPON_EXP_MASTER = 8000;
20 /* Proficiency of riding */
21 constexpr SUB_EXP RIDING_EXP_UNSKILLED = 0;
22 constexpr SUB_EXP RIDING_EXP_BEGINNER = 500;
23 constexpr SUB_EXP RIDING_EXP_SKILLED = 2000;
24 constexpr SUB_EXP RIDING_EXP_EXPERT = 5000;
25 constexpr SUB_EXP RIDING_EXP_MASTER = 8000;
27 /* Proficiency of spells */
28 constexpr SUB_EXP SPELL_EXP_UNSKILLED = 0;
29 constexpr SUB_EXP SPELL_EXP_BEGINNER = 900;
30 constexpr SUB_EXP SPELL_EXP_SKILLED = 1200;
31 constexpr SUB_EXP SPELL_EXP_EXPERT = 1400;
32 constexpr SUB_EXP SPELL_EXP_MASTER = 1600;
37 std::vector<skill_table> s_info;
41 using GainAmountList = std::array<int, enum2i(PlayerSkillRank::MASTER)>;
43 void gain_attack_skill_exp(player_type *player_ptr, short &exp, const GainAmountList &gain_amount_list)
46 auto calc_gain_amount = [&gain_amount_list, exp](PlayerSkillRank rank, int next_rank_exp) {
47 return std::min(gain_amount_list[enum2i(rank)], next_rank_exp - exp);
50 if (exp < WEAPON_EXP_BEGINNER) {
51 gain_amount = calc_gain_amount(PlayerSkillRank::UNSKILLED, WEAPON_EXP_BEGINNER);
52 } else if (exp < WEAPON_EXP_SKILLED) {
53 gain_amount = calc_gain_amount(PlayerSkillRank::BEGINNER, WEAPON_EXP_SKILLED);
54 } else if ((exp < WEAPON_EXP_EXPERT) && (player_ptr->lev > 19)) {
55 gain_amount = calc_gain_amount(PlayerSkillRank::SKILLED, WEAPON_EXP_EXPERT);
56 } else if ((exp < WEAPON_EXP_MASTER) && (player_ptr->lev > 34)) {
57 gain_amount = calc_gain_amount(PlayerSkillRank::EXPERT, WEAPON_EXP_MASTER);
60 exp += static_cast<short>(gain_amount);
61 set_bits(player_ptr->update, PU_BONUS);
64 void gain_spell_skill_exp_aux(player_type *player_ptr, short &exp, const GainAmountList &gain_amount_list, int spell_level)
66 const auto dlev = player_ptr->current_floor_ptr->dun_level;
67 const auto plev = player_ptr->lev;
70 auto calc_gain_amount = [&gain_amount_list, exp](PlayerSkillRank rank, int next_rank_exp) {
71 return std::min(gain_amount_list[enum2i(rank)], next_rank_exp - exp);
74 if (exp < SPELL_EXP_BEGINNER) {
75 gain_amount = calc_gain_amount(PlayerSkillRank::UNSKILLED, SPELL_EXP_BEGINNER);
76 } else if (exp < SPELL_EXP_SKILLED) {
77 if ((dlev > 4) && ((dlev + 10) > plev)) {
78 gain_amount = calc_gain_amount(PlayerSkillRank::BEGINNER, SPELL_EXP_SKILLED);
80 } else if (exp < SPELL_EXP_EXPERT) {
81 if (((dlev + 5) > plev) && ((dlev + 5) > spell_level)) {
82 gain_amount = calc_gain_amount(PlayerSkillRank::SKILLED, SPELL_EXP_EXPERT);
84 } else if (exp < SPELL_EXP_MASTER) {
85 if (((dlev + 5) > plev) && (dlev > spell_level)) {
86 gain_amount = calc_gain_amount(PlayerSkillRank::EXPERT, SPELL_EXP_MASTER);
90 exp += static_cast<short>(gain_amount);
91 set_bits(player_ptr->update, PU_BONUS);
96 PlayerSkill::PlayerSkill(player_type *player_ptr)
97 : player_ptr(player_ptr)
101 SUB_EXP PlayerSkill::weapon_exp_at(PlayerSkillRank rank)
104 case PlayerSkillRank::UNSKILLED:
105 return WEAPON_EXP_UNSKILLED;
106 case PlayerSkillRank::BEGINNER:
107 return WEAPON_EXP_BEGINNER;
108 case PlayerSkillRank::SKILLED:
109 return WEAPON_EXP_SKILLED;
110 case PlayerSkillRank::EXPERT:
111 return WEAPON_EXP_EXPERT;
112 case PlayerSkillRank::MASTER:
113 return WEAPON_EXP_MASTER;
116 return WEAPON_EXP_UNSKILLED;
119 SUB_EXP PlayerSkill::spell_exp_at(PlayerSkillRank rank)
122 case PlayerSkillRank::UNSKILLED:
123 return SPELL_EXP_UNSKILLED;
124 case PlayerSkillRank::BEGINNER:
125 return SPELL_EXP_BEGINNER;
126 case PlayerSkillRank::SKILLED:
127 return SPELL_EXP_SKILLED;
128 case PlayerSkillRank::EXPERT:
129 return SPELL_EXP_EXPERT;
130 case PlayerSkillRank::MASTER:
131 return SPELL_EXP_MASTER;
134 return SPELL_EXP_UNSKILLED;
137 * @brief 武器や各種スキル(騎乗以外)の抽象的表現ランクを返す。 / Return proficiency level of weapons and misc. skills (except riding)
138 * @param weapon_exp 経験値
141 PlayerSkillRank PlayerSkill::weapon_skill_rank(int weapon_exp)
143 if (weapon_exp < WEAPON_EXP_BEGINNER)
144 return PlayerSkillRank::UNSKILLED;
145 else if (weapon_exp < WEAPON_EXP_SKILLED)
146 return PlayerSkillRank::BEGINNER;
147 else if (weapon_exp < WEAPON_EXP_EXPERT)
148 return PlayerSkillRank::SKILLED;
149 else if (weapon_exp < WEAPON_EXP_MASTER)
150 return PlayerSkillRank::EXPERT;
152 return PlayerSkillRank::MASTER;
155 bool PlayerSkill::valid_weapon_exp(int weapon_exp)
157 return (WEAPON_EXP_UNSKILLED <= weapon_exp) && (weapon_exp <= WEAPON_EXP_MASTER);
161 * @brief 騎乗スキルの抽象的ランクを返す。 / Return proficiency level of riding
162 * @param riding_exp 経験値
165 PlayerSkillRank PlayerSkill::riding_skill_rank(int riding_exp)
167 if (riding_exp < RIDING_EXP_BEGINNER)
168 return PlayerSkillRank::UNSKILLED;
169 else if (riding_exp < RIDING_EXP_SKILLED)
170 return PlayerSkillRank::BEGINNER;
171 else if (riding_exp < RIDING_EXP_EXPERT)
172 return PlayerSkillRank::SKILLED;
173 else if (riding_exp < RIDING_EXP_MASTER)
174 return PlayerSkillRank::EXPERT;
176 return PlayerSkillRank::MASTER;
180 * @brief プレイヤーの呪文レベルの抽象的ランクを返す。 / Return proficiency level of spells
181 * @param spell_exp 経験値
184 PlayerSkillRank PlayerSkill::spell_skill_rank(int spell_exp)
186 if (spell_exp < SPELL_EXP_BEGINNER)
187 return PlayerSkillRank::UNSKILLED;
188 else if (spell_exp < SPELL_EXP_SKILLED)
189 return PlayerSkillRank::BEGINNER;
190 else if (spell_exp < SPELL_EXP_EXPERT)
191 return PlayerSkillRank::SKILLED;
192 else if (spell_exp < SPELL_EXP_MASTER)
193 return PlayerSkillRank::EXPERT;
195 return PlayerSkillRank::MASTER;
198 concptr PlayerSkill::skill_name(PlayerSkillKindType skill)
201 case PlayerSkillKindType::MARTIAL_ARTS:
202 return _("マーシャルアーツ", "Martial Arts");
203 case PlayerSkillKindType::TWO_WEAPON:
204 return _("二刀流", "Dual Wielding");
205 case PlayerSkillKindType::RIDING:
206 return _("乗馬", "Riding");
207 case PlayerSkillKindType::SHIELD:
208 return _("盾", "Shield");
209 case PlayerSkillKindType::MAX:
213 return _("不明", "Unknown");
216 concptr PlayerSkill::skill_rank_str(PlayerSkillRank rank)
219 case PlayerSkillRank::UNSKILLED:
220 return _("[初心者]", "[Unskilled]");
221 case PlayerSkillRank::BEGINNER:
222 return _("[入門者]", "[Beginner]");
223 case PlayerSkillRank::SKILLED:
224 return _("[熟練者]", "[Skilled]");
225 case PlayerSkillRank::EXPERT:
226 return _("[エキスパート]", "[Expert]");
227 case PlayerSkillRank::MASTER:
228 return _("[達人]", "[Master]");
231 return _("[不明]", "[Unknown]");
234 void PlayerSkill::gain_melee_weapon_exp(const object_type *o_ptr)
236 const GainAmountList gain_amount_list{ 80, 10, 1, (one_in_(2) ? 1 : 0) };
237 constexpr GainAmountList others_gain_amount_list{ 8, 1, 0, 0 };
239 for (auto sval = 0U; sval < this->player_ptr->weapon_exp[o_ptr->tval].size(); ++sval) {
240 auto &now_exp = this->player_ptr->weapon_exp[o_ptr->tval][sval];
241 if (now_exp < s_info[enum2i(this->player_ptr->pclass)].w_max[o_ptr->tval][sval]) {
242 gain_attack_skill_exp(this->player_ptr, now_exp,
243 (static_cast<int>(sval) == o_ptr->sval) ? gain_amount_list : others_gain_amount_list);
248 void PlayerSkill::gain_range_weapon_exp(const object_type *o_ptr)
250 constexpr GainAmountList gain_amount_list{ 80, 25, 10, 2 };
251 constexpr GainAmountList others_gain_amount_list{ 8, 2, 0, 0 };
253 for (auto sval = 0U; sval < this->player_ptr->weapon_exp[o_ptr->tval].size(); ++sval) {
254 auto &now_exp = this->player_ptr->weapon_exp[o_ptr->tval][sval];
255 if (now_exp < s_info[enum2i(this->player_ptr->pclass)].w_max[o_ptr->tval][sval]) {
256 gain_attack_skill_exp(this->player_ptr, now_exp,
257 (static_cast<int>(sval) == o_ptr->sval) ? gain_amount_list : others_gain_amount_list);
262 void PlayerSkill::gain_martial_arts_skill_exp()
264 if (this->player_ptr->skill_exp[PlayerSkillKindType::MARTIAL_ARTS] < s_info[enum2i(this->player_ptr->pclass)].s_max[PlayerSkillKindType::MARTIAL_ARTS]) {
265 const GainAmountList gain_amount_list{ 40, 5, 1, (one_in_(3) ? 1 : 0) };
266 gain_attack_skill_exp(this->player_ptr, this->player_ptr->skill_exp[PlayerSkillKindType::MARTIAL_ARTS], gain_amount_list);
270 void PlayerSkill::gain_two_weapon_skill_exp()
272 if (this->player_ptr->skill_exp[PlayerSkillKindType::TWO_WEAPON] < s_info[enum2i(this->player_ptr->pclass)].s_max[PlayerSkillKindType::TWO_WEAPON]) {
273 const GainAmountList gain_amount_list{ 80, 4, 1, (one_in_(3) ? 1 : 0) };
274 gain_attack_skill_exp(this->player_ptr, this->player_ptr->skill_exp[PlayerSkillKindType::TWO_WEAPON], gain_amount_list);
278 void PlayerSkill::gain_riding_skill_exp_on_melee_attack(const monster_race *r_ptr)
280 auto now_exp = this->player_ptr->skill_exp[PlayerSkillKindType::RIDING];
281 auto max_exp = s_info[enum2i(this->player_ptr->pclass)].s_max[PlayerSkillKindType::RIDING];
282 if (now_exp >= max_exp)
285 auto riding_level = r_info[this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding].r_idx].level;
288 if ((now_exp / 200 - 5) < r_ptr->level)
291 if ((now_exp / 100) < riding_level) {
292 if ((now_exp / 100 + 15) < riding_level)
293 inc += 1 + (riding_level - (now_exp / 100 + 15));
298 this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] = std::min<SUB_EXP>(max_exp, now_exp + inc);
299 set_bits(this->player_ptr->update, PU_BONUS);
302 void PlayerSkill::gain_riding_skill_exp_on_range_attack()
304 auto now_exp = this->player_ptr->skill_exp[PlayerSkillKindType::RIDING];
305 auto max_exp = s_info[enum2i(this->player_ptr->pclass)].s_max[PlayerSkillKindType::RIDING];
306 if (now_exp >= max_exp)
309 if (((this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] - (RIDING_EXP_BEGINNER * 2)) / 200 < r_info[this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding].r_idx].level) && one_in_(2)) {
310 this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] += 1;
311 set_bits(this->player_ptr->update, PU_BONUS);
315 void PlayerSkill::gain_riding_skill_exp_on_fall_off_check(HIT_POINT dam)
317 auto now_exp = this->player_ptr->skill_exp[PlayerSkillKindType::RIDING];
318 auto max_exp = s_info[enum2i(this->player_ptr->pclass)].s_max[PlayerSkillKindType::RIDING];
319 if (now_exp >= max_exp || max_exp <= 1000)
322 auto riding_level = r_info[this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding].r_idx].level;
324 if ((dam / 2 + riding_level) <= (now_exp / 30 + 10))
328 if ((now_exp / 100 + 15) < riding_level)
329 inc += 1 + (riding_level - (now_exp / 100 + 15));
333 this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] = std::min<SUB_EXP>(max_exp, now_exp + inc);
334 set_bits(this->player_ptr->update, PU_BONUS);
337 void PlayerSkill::gain_spell_skill_exp(int realm, int spell_idx)
339 if (((spell_idx < 0) || (32 <= spell_idx)) ||
340 ((realm < 1) || (static_cast<int>(std::size(mp_ptr->info)) < realm)) ||
341 ((realm != this->player_ptr->realm1) && (realm != this->player_ptr->realm2))) {
345 constexpr GainAmountList gain_amount_list_first{ 60, 8, 2, 1 };
346 constexpr GainAmountList gain_amount_list_second{ 60, 8, 2, 0 };
348 const auto is_first_realm = (realm == this->player_ptr->realm1);
349 const auto *s_ptr = &mp_ptr->info[realm - 1][spell_idx];
351 gain_spell_skill_exp_aux(this->player_ptr, this->player_ptr->spell_exp[spell_idx + (is_first_realm ? 0 : 32)],
352 (is_first_realm ? gain_amount_list_first : gain_amount_list_second), s_ptr->slevel);
355 void PlayerSkill::gain_continuous_spell_skill_exp(int realm, int spell_idx)
357 if (((spell_idx < 0) || (32 <= spell_idx)) ||
358 ((realm != REALM_MUSIC) && (realm != REALM_HEX))) {
362 const auto *s_ptr = &technic_info[realm - MIN_TECHNIC][spell_idx];
364 const GainAmountList gain_amount_list{ 5, (one_in_(2) ? 1 : 0), (one_in_(5) ? 1 : 0), (one_in_(5) ? 1 : 0) };
366 gain_spell_skill_exp_aux(this->player_ptr, this->player_ptr->spell_exp[spell_idx], gain_amount_list, s_ptr->slevel);
369 PlayerSkillRank PlayerSkill::gain_spell_skill_exp_over_learning(int spell_idx)
371 if ((spell_idx < 0) || (static_cast<int>(std::size(this->player_ptr->spell_exp)) <= spell_idx)) {
372 return PlayerSkillRank::UNSKILLED;
375 auto &exp = this->player_ptr->spell_exp[spell_idx];
377 if (exp >= SPELL_EXP_EXPERT) {
378 exp = SPELL_EXP_MASTER;
379 } else if (exp >= SPELL_EXP_SKILLED) {
380 if (spell_idx >= 32) {
381 exp = SPELL_EXP_EXPERT;
383 exp += SPELL_EXP_EXPERT - SPELL_EXP_SKILLED;
385 } else if (exp >= SPELL_EXP_BEGINNER) {
386 exp = SPELL_EXP_SKILLED + (exp - SPELL_EXP_BEGINNER) * 2 / 3;
388 exp = SPELL_EXP_BEGINNER + exp / 3;
391 set_bits(this->player_ptr->update, PU_BONUS);
393 return PlayerSkill::spell_skill_rank(exp);
398 * Returns experience of a spell
399 * @param use_realm 魔法領域
400 * @param spell_idx 呪文ID
403 EXP PlayerSkill::exp_of_spell(int realm, int spell_idx) const
405 if (this->player_ptr->pclass == PlayerClassType::SORCERER)
406 return SPELL_EXP_MASTER;
407 else if (this->player_ptr->pclass == PlayerClassType::RED_MAGE)
408 return SPELL_EXP_SKILLED;
409 else if (realm == this->player_ptr->realm1)
410 return this->player_ptr->spell_exp[spell_idx];
411 else if (realm == this->player_ptr->realm2)
412 return this->player_ptr->spell_exp[spell_idx + 32];