OSDN Git Service

Merge pull request #1907 from sikabane-works/release/3.0.0Alpha48
[hengbandforosx/hengbandosx.git] / src / player / player-skill.cpp
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"
12
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;
19
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;
26
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;
33
34 /*
35  * The skill table
36  */
37 std::vector<skill_table> s_info;
38
39 namespace {
40
41 using GainAmountList = std::array<int, enum2i(PlayerSkillRank::MASTER)>;
42
43 void gain_attack_skill_exp(PlayerType *player_ptr, short &exp, const GainAmountList &gain_amount_list)
44 {
45     auto gain_amount = 0;
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);
48     };
49
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);
58     }
59
60     exp += static_cast<short>(gain_amount);
61     set_bits(player_ptr->update, PU_BONUS);
62 }
63
64 void gain_spell_skill_exp_aux(PlayerType *player_ptr, short &exp, const GainAmountList &gain_amount_list, int spell_level)
65 {
66     const auto dlev = player_ptr->current_floor_ptr->dun_level;
67     const auto plev = player_ptr->lev;
68
69     auto gain_amount = 0;
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);
72     };
73
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);
79         }
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);
83         }
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);
87         }
88     }
89
90     exp += static_cast<short>(gain_amount);
91     set_bits(player_ptr->update, PU_BONUS);
92 }
93
94 }
95
96 PlayerSkill::PlayerSkill(PlayerType *player_ptr)
97     : player_ptr(player_ptr)
98 {
99 }
100
101 SUB_EXP PlayerSkill::weapon_exp_at(PlayerSkillRank rank)
102 {
103     switch (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;
114     }
115
116     return WEAPON_EXP_UNSKILLED;
117 }
118
119 SUB_EXP PlayerSkill::spell_exp_at(PlayerSkillRank rank)
120 {
121     switch (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;
132     }
133
134     return SPELL_EXP_UNSKILLED;
135 }
136 /*!
137  * @brief 武器や各種スキル(騎乗以外)の抽象的表現ランクを返す。 /  Return proficiency level of weapons and misc. skills (except riding)
138  * @param weapon_exp 経験値
139  * @return ランク値
140  */
141 PlayerSkillRank PlayerSkill::weapon_skill_rank(int weapon_exp)
142 {
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;
151     else
152         return PlayerSkillRank::MASTER;
153 }
154
155 bool PlayerSkill::valid_weapon_exp(int weapon_exp)
156 {
157     return (WEAPON_EXP_UNSKILLED <= weapon_exp) && (weapon_exp <= WEAPON_EXP_MASTER);
158 }
159
160 /*!
161  * @brief 騎乗スキルの抽象的ランクを返す。 / Return proficiency level of riding
162  * @param riding_exp 経験値
163  * @return ランク値
164  */
165 PlayerSkillRank PlayerSkill::riding_skill_rank(int riding_exp)
166 {
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;
175     else
176         return PlayerSkillRank::MASTER;
177 }
178
179 /*!
180  * @brief プレイヤーの呪文レベルの抽象的ランクを返す。 / Return proficiency level of spells
181  * @param spell_exp 経験値
182  * @return ランク値
183  */
184 PlayerSkillRank PlayerSkill::spell_skill_rank(int spell_exp)
185 {
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;
194     else
195         return PlayerSkillRank::MASTER;
196 }
197
198 concptr PlayerSkill::skill_name(PlayerSkillKindType skill)
199 {
200     switch (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:
210         break;
211     }
212
213     return _("不明", "Unknown");
214 }
215
216 concptr PlayerSkill::skill_rank_str(PlayerSkillRank rank)
217 {
218     switch (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]");
229     }
230
231     return _("[不明]", "[Unknown]");
232 }
233
234 void PlayerSkill::gain_melee_weapon_exp(const object_type *o_ptr)
235 {
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 };
238
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);
244         }
245     }
246 }
247
248 void PlayerSkill::gain_range_weapon_exp(const object_type *o_ptr)
249 {
250     constexpr GainAmountList gain_amount_list{ 80, 25, 10, 2 };
251     constexpr GainAmountList others_gain_amount_list{ 8, 2, 0, 0 };
252
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);
258         }
259     }
260 }
261
262 void PlayerSkill::gain_martial_arts_skill_exp()
263 {
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);
267     }
268 }
269
270 void PlayerSkill::gain_two_weapon_skill_exp()
271 {
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);
275     }
276 }
277
278 void PlayerSkill::gain_riding_skill_exp_on_melee_attack(const monster_race *r_ptr)
279 {
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)
283         return;
284
285     auto riding_level = r_info[this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding].r_idx].level;
286     int inc = 0;
287
288     if ((now_exp / 200 - 5) < r_ptr->level)
289         inc += 1;
290
291     if ((now_exp / 100) < riding_level) {
292         if ((now_exp / 100 + 15) < riding_level)
293             inc += 1 + (riding_level - (now_exp / 100 + 15));
294         else
295             inc += 1;
296     }
297
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);
300 }
301
302 void PlayerSkill::gain_riding_skill_exp_on_range_attack()
303 {
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)
307         return;
308
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);
312     }
313 }
314
315 void PlayerSkill::gain_riding_skill_exp_on_fall_off_check(HIT_POINT dam)
316 {
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)
320         return;
321
322     auto riding_level = r_info[this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding].r_idx].level;
323
324     if ((dam / 2 + riding_level) <= (now_exp / 30 + 10))
325         return;
326
327     int inc = 0;
328     if ((now_exp / 100 + 15) < riding_level)
329         inc += 1 + (riding_level - (now_exp / 100 + 15));
330     else
331         inc += 1;
332
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);
335 }
336
337 void PlayerSkill::gain_spell_skill_exp(int realm, int spell_idx)
338 {
339     if ((realm < 1) || ((static_cast<int>(std::size(mp_ptr->info)) < realm) && (realm != REALM_MUSIC) && (realm != REALM_HEX))) {
340         return;
341     }
342
343     if (((spell_idx < 0) || (32 <= spell_idx)) ||
344         ((realm != this->player_ptr->realm1) && (realm != this->player_ptr->realm2))) {
345         return;
346     }
347
348     constexpr GainAmountList gain_amount_list_first{ 60, 8, 2, 1 };
349     constexpr GainAmountList gain_amount_list_second{ 60, 8, 2, 0 };
350
351     const auto is_first_realm = (realm == this->player_ptr->realm1);
352     const auto *s_ptr = &mp_ptr->info[realm - 1][spell_idx];
353
354     gain_spell_skill_exp_aux(this->player_ptr, this->player_ptr->spell_exp[spell_idx + (is_first_realm ? 0 : 32)],
355         (is_first_realm ? gain_amount_list_first : gain_amount_list_second), s_ptr->slevel);
356 }
357
358 void PlayerSkill::gain_continuous_spell_skill_exp(int realm, int spell_idx)
359 {
360     if (((spell_idx < 0) || (32 <= spell_idx)) ||
361         ((realm != REALM_MUSIC) && (realm != REALM_HEX))) {
362         return;
363     }
364
365     const auto *s_ptr = &technic_info[realm - MIN_TECHNIC][spell_idx];
366
367     const GainAmountList gain_amount_list{ 5, (one_in_(2) ? 1 : 0), (one_in_(5) ? 1 : 0), (one_in_(5) ? 1 : 0) };
368
369     gain_spell_skill_exp_aux(this->player_ptr, this->player_ptr->spell_exp[spell_idx], gain_amount_list, s_ptr->slevel);
370 }
371
372 PlayerSkillRank PlayerSkill::gain_spell_skill_exp_over_learning(int spell_idx)
373 {
374     if ((spell_idx < 0) || (static_cast<int>(std::size(this->player_ptr->spell_exp)) <= spell_idx)) {
375         return PlayerSkillRank::UNSKILLED;
376     }
377
378     auto &exp = this->player_ptr->spell_exp[spell_idx];
379
380     if (exp >= SPELL_EXP_EXPERT) {
381         exp = SPELL_EXP_MASTER;
382     } else if (exp >= SPELL_EXP_SKILLED) {
383         if (spell_idx >= 32) {
384             exp = SPELL_EXP_EXPERT;
385         } else {
386             exp += SPELL_EXP_EXPERT - SPELL_EXP_SKILLED;
387         }
388     } else if (exp >= SPELL_EXP_BEGINNER) {
389         exp = SPELL_EXP_SKILLED + (exp - SPELL_EXP_BEGINNER) * 2 / 3;
390     } else {
391         exp = SPELL_EXP_BEGINNER + exp / 3;
392     }
393
394     set_bits(this->player_ptr->update, PU_BONUS);
395
396     return PlayerSkill::spell_skill_rank(exp);
397 }
398
399 /*!
400  * @brief 呪文の経験値を返す /
401  * Returns experience of a spell
402  * @param use_realm 魔法領域
403  * @param spell_idx 呪文ID
404  * @return 経験値
405  */
406 EXP PlayerSkill::exp_of_spell(int realm, int spell_idx) const
407 {
408     if (this->player_ptr->pclass == PlayerClassType::SORCERER)
409         return SPELL_EXP_MASTER;
410     else if (this->player_ptr->pclass == PlayerClassType::RED_MAGE)
411         return SPELL_EXP_SKILLED;
412     else if (realm == this->player_ptr->realm1)
413         return this->player_ptr->spell_exp[spell_idx];
414     else if (realm == this->player_ptr->realm2)
415         return this->player_ptr->spell_exp[spell_idx + 32];
416     else
417         return 0;
418 }