OSDN Git Service

64546a1cf91f1f867d8c0b9eed1e5400ba098a64
[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 /*!
40  * @brief 技能値到達表記テーブル
41  */
42 const concptr exp_level_str[5] =
43 #ifdef JP
44     { "[初心者]", "[入門者]", "[熟練者]", "[エキスパート]", "[達人]" };
45 #else
46     { "[Unskilled]", "[Beginner]", "[Skilled]", "[Expert]", "[Master]" };
47 #endif
48
49 namespace {
50
51 using GainAmountList = std::array<int, EXP_LEVEL_MASTER>;
52
53 void gain_attack_skill_exp(player_type *player_ptr, short &exp, const GainAmountList &gain_amount_list)
54 {
55     auto gain_amount = 0;
56
57     if (exp < WEAPON_EXP_BEGINNER) {
58         gain_amount = std::min(gain_amount_list[EXP_LEVEL_UNSKILLED], WEAPON_EXP_BEGINNER - exp);
59     } else if (exp < WEAPON_EXP_SKILLED) {
60         gain_amount = std::min(gain_amount_list[EXP_LEVEL_BEGINNER], WEAPON_EXP_SKILLED - exp);
61     } else if ((exp < WEAPON_EXP_EXPERT) && (player_ptr->lev > 19)) {
62         gain_amount = std::min(gain_amount_list[EXP_LEVEL_SKILLED], WEAPON_EXP_EXPERT - exp);
63     } else if ((exp < WEAPON_EXP_MASTER) && (player_ptr->lev > 34)) {
64         gain_amount = std::min(gain_amount_list[EXP_LEVEL_EXPERT], WEAPON_EXP_MASTER - exp);
65     }
66
67     exp += static_cast<short>(gain_amount);
68     set_bits(player_ptr->update, PU_BONUS);
69 }
70
71 void gain_spell_skill_exp_aux(player_type *player_ptr, short &exp, const GainAmountList &gain_amount_list, int spell_level)
72 {
73     const auto dlev = player_ptr->current_floor_ptr->dun_level;
74     const auto plev = player_ptr->lev;
75
76     auto gain_amount = 0;
77     if (exp < SPELL_EXP_BEGINNER) {
78         gain_amount = std::min(gain_amount_list[EXP_LEVEL_UNSKILLED], SPELL_EXP_BEGINNER - exp);
79     } else if (exp < SPELL_EXP_SKILLED) {
80         if ((dlev > 4) && ((dlev + 10) > plev)) {
81             gain_amount = std::min(gain_amount_list[EXP_LEVEL_BEGINNER], SPELL_EXP_SKILLED - exp);
82         }
83     } else if (exp < SPELL_EXP_EXPERT) {
84         if (((dlev + 5) > plev) && ((dlev + 5) > spell_level)) {
85             gain_amount = std::min(gain_amount_list[EXP_LEVEL_SKILLED], SPELL_EXP_EXPERT - exp);
86         }
87     } else if (exp < SPELL_EXP_MASTER) {
88         if (((dlev + 5) > plev) && (dlev > spell_level)) {
89             gain_amount = std::min(gain_amount_list[EXP_LEVEL_EXPERT], SPELL_EXP_MASTER - exp);
90         }
91     }
92
93     exp += static_cast<short>(gain_amount);
94     set_bits(player_ptr->update, PU_BONUS);
95 }
96
97 }
98
99 PlayerSkill::PlayerSkill(player_type *player_ptr)
100     : player_ptr(player_ptr)
101 {
102 }
103
104 SUB_EXP PlayerSkill::weapon_exp_at(int level)
105 {
106     switch (level) {
107     case EXP_LEVEL_UNSKILLED:
108         return WEAPON_EXP_UNSKILLED;
109     case EXP_LEVEL_BEGINNER:
110         return WEAPON_EXP_BEGINNER;
111     case EXP_LEVEL_SKILLED:
112         return WEAPON_EXP_SKILLED;
113     case EXP_LEVEL_EXPERT:
114         return WEAPON_EXP_EXPERT;
115     case EXP_LEVEL_MASTER:
116         return WEAPON_EXP_MASTER;
117     }
118
119     return WEAPON_EXP_UNSKILLED;
120 }
121
122 SUB_EXP PlayerSkill::spell_exp_at(int level)
123 {
124     switch (level) {
125     case EXP_LEVEL_UNSKILLED:
126         return SPELL_EXP_UNSKILLED;
127     case EXP_LEVEL_BEGINNER:
128         return SPELL_EXP_BEGINNER;
129     case EXP_LEVEL_SKILLED:
130         return SPELL_EXP_SKILLED;
131     case EXP_LEVEL_EXPERT:
132         return SPELL_EXP_EXPERT;
133     case EXP_LEVEL_MASTER:
134         return SPELL_EXP_MASTER;
135     }
136
137     return SPELL_EXP_UNSKILLED;
138 }
139 /*!
140  * @brief 武器や各種スキル(騎乗以外)の抽象的表現ランクを返す。 /  Return proficiency level of weapons and misc. skills (except riding)
141  * @param weapon_exp 経験値
142  * @return ランク値
143  */
144 int PlayerSkill::weapon_exp_level(int weapon_exp)
145 {
146     if (weapon_exp < WEAPON_EXP_BEGINNER)
147         return EXP_LEVEL_UNSKILLED;
148     else if (weapon_exp < WEAPON_EXP_SKILLED)
149         return EXP_LEVEL_BEGINNER;
150     else if (weapon_exp < WEAPON_EXP_EXPERT)
151         return EXP_LEVEL_SKILLED;
152     else if (weapon_exp < WEAPON_EXP_MASTER)
153         return EXP_LEVEL_EXPERT;
154     else
155         return EXP_LEVEL_MASTER;
156 }
157
158 bool PlayerSkill::valid_weapon_exp(int weapon_exp)
159 {
160     return (WEAPON_EXP_UNSKILLED <= weapon_exp) && (weapon_exp <= WEAPON_EXP_MASTER);
161 }
162
163 /*!
164  * @brief 騎乗スキルの抽象的ランクを返す。 / Return proficiency level of riding
165  * @param riding_exp 経験値
166  * @return ランク値
167  */
168 int PlayerSkill::riding_exp_level(int riding_exp)
169 {
170     if (riding_exp < RIDING_EXP_BEGINNER)
171         return EXP_LEVEL_UNSKILLED;
172     else if (riding_exp < RIDING_EXP_SKILLED)
173         return EXP_LEVEL_BEGINNER;
174     else if (riding_exp < RIDING_EXP_EXPERT)
175         return EXP_LEVEL_SKILLED;
176     else if (riding_exp < RIDING_EXP_MASTER)
177         return EXP_LEVEL_EXPERT;
178     else
179         return EXP_LEVEL_MASTER;
180 }
181
182 /*!
183  * @brief プレイヤーの呪文レベルの抽象的ランクを返す。 / Return proficiency level of spells
184  * @param spell_exp 経験値
185  * @return ランク値
186  */
187 int PlayerSkill::spell_exp_level(int spell_exp)
188 {
189     if (spell_exp < SPELL_EXP_BEGINNER)
190         return EXP_LEVEL_UNSKILLED;
191     else if (spell_exp < SPELL_EXP_SKILLED)
192         return EXP_LEVEL_BEGINNER;
193     else if (spell_exp < SPELL_EXP_EXPERT)
194         return EXP_LEVEL_SKILLED;
195     else if (spell_exp < SPELL_EXP_MASTER)
196         return EXP_LEVEL_EXPERT;
197     else
198         return EXP_LEVEL_MASTER;
199 }
200
201 void PlayerSkill::gain_melee_weapon_exp(const object_type *o_ptr)
202 {
203     const GainAmountList gain_amount_list{ 80, 10, 1, (one_in_(2) ? 1 : 0) };
204     constexpr GainAmountList others_gain_amount_list{ 8, 1, 0, 0 };
205
206     for (auto sval = 0U; sval < this->player_ptr->weapon_exp[o_ptr->tval].size(); ++sval) {
207         auto &now_exp = this->player_ptr->weapon_exp[o_ptr->tval][sval];
208         if (now_exp < s_info[enum2i(this->player_ptr->pclass)].w_max[o_ptr->tval][sval]) {
209             gain_attack_skill_exp(this->player_ptr, now_exp,
210                 (static_cast<int>(sval) == o_ptr->sval) ? gain_amount_list : others_gain_amount_list);
211         }
212     }
213 }
214
215 void PlayerSkill::gain_range_weapon_exp(const object_type *o_ptr)
216 {
217     constexpr GainAmountList gain_amount_list{ 80, 25, 10, 2 };
218     constexpr GainAmountList others_gain_amount_list{ 8, 2, 0, 0 };
219
220     for (auto sval = 0U; sval < this->player_ptr->weapon_exp[o_ptr->tval].size(); ++sval) {
221         auto &now_exp = this->player_ptr->weapon_exp[o_ptr->tval][sval];
222         if (now_exp < s_info[enum2i(this->player_ptr->pclass)].w_max[o_ptr->tval][sval]) {
223             gain_attack_skill_exp(this->player_ptr, now_exp,
224                 (static_cast<int>(sval) == o_ptr->sval) ? gain_amount_list : others_gain_amount_list);
225         }
226     }
227 }
228
229 void PlayerSkill::gain_martial_arts_skill_exp()
230 {
231     if (this->player_ptr->skill_exp[SKILL_MARTIAL_ARTS] < s_info[enum2i(this->player_ptr->pclass)].s_max[SKILL_MARTIAL_ARTS]) {
232         const GainAmountList gain_amount_list{ 40, 5, 1, (one_in_(3) ? 1 : 0) };
233         gain_attack_skill_exp(this->player_ptr, this->player_ptr->skill_exp[SKILL_MARTIAL_ARTS], gain_amount_list);
234     }
235 }
236
237 void PlayerSkill::gain_two_weapon_skill_exp()
238 {
239     if (this->player_ptr->skill_exp[SKILL_TWO_WEAPON] < s_info[enum2i(this->player_ptr->pclass)].s_max[SKILL_TWO_WEAPON]) {
240         const GainAmountList gain_amount_list{ 80, 4, 1, (one_in_(3) ? 1 : 0) };
241         gain_attack_skill_exp(this->player_ptr, this->player_ptr->skill_exp[SKILL_TWO_WEAPON], gain_amount_list);
242     }
243 }
244
245 void PlayerSkill::gain_riding_skill_exp_on_melee_attack(const monster_race *r_ptr)
246 {
247     auto now_exp = this->player_ptr->skill_exp[SKILL_RIDING];
248     auto max_exp = s_info[enum2i(this->player_ptr->pclass)].s_max[SKILL_RIDING];
249     if (now_exp >= max_exp)
250         return;
251
252     auto riding_level = r_info[this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding].r_idx].level;
253     int inc = 0;
254
255     if ((now_exp / 200 - 5) < r_ptr->level)
256         inc += 1;
257
258     if ((now_exp / 100) < riding_level) {
259         if ((now_exp / 100 + 15) < riding_level)
260             inc += 1 + (riding_level - (now_exp / 100 + 15));
261         else
262             inc += 1;
263     }
264
265     this->player_ptr->skill_exp[SKILL_RIDING] = std::min<SUB_EXP>(max_exp, now_exp + inc);
266     set_bits(this->player_ptr->update, PU_BONUS);
267 }
268
269 void PlayerSkill::gain_riding_skill_exp_on_range_attack()
270 {
271     auto now_exp = this->player_ptr->skill_exp[SKILL_RIDING];
272     auto max_exp = s_info[enum2i(this->player_ptr->pclass)].s_max[SKILL_RIDING];
273     if (now_exp >= max_exp)
274         return;
275
276     if (((this->player_ptr->skill_exp[SKILL_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)) {
277         this->player_ptr->skill_exp[SKILL_RIDING] += 1;
278         set_bits(this->player_ptr->update, PU_BONUS);
279     }
280 }
281
282 void PlayerSkill::gain_riding_skill_exp_on_fall_off_check(HIT_POINT dam)
283 {
284     auto now_exp = this->player_ptr->skill_exp[SKILL_RIDING];
285     auto max_exp = s_info[enum2i(this->player_ptr->pclass)].s_max[SKILL_RIDING];
286     if (now_exp >= max_exp || max_exp <= 1000)
287         return;
288
289     auto riding_level = r_info[this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding].r_idx].level;
290
291     if ((dam / 2 + riding_level) <= (now_exp / 30 + 10))
292         return;
293
294     int inc = 0;
295     if ((now_exp / 100 + 15) < riding_level)
296         inc += 1 + (riding_level - (now_exp / 100 + 15));
297     else
298         inc += 1;
299
300     this->player_ptr->skill_exp[SKILL_RIDING] = std::min<SUB_EXP>(max_exp, now_exp + inc);
301     set_bits(this->player_ptr->update, PU_BONUS);
302 }
303
304 void PlayerSkill::gain_spell_skill_exp(int realm, int spell_idx)
305 {
306     if (((spell_idx < 0) || (32 <= spell_idx)) ||
307         ((realm < 1) || (static_cast<int>(std::size(mp_ptr->info)) < realm)) ||
308         ((realm != this->player_ptr->realm1) && (realm != this->player_ptr->realm2))) {
309         return;
310     }
311
312     constexpr GainAmountList gain_amount_list_first{ 60, 8, 2, 1 };
313     constexpr GainAmountList gain_amount_list_second{ 60, 8, 2, 0 };
314
315     const auto is_first_realm = (realm == this->player_ptr->realm1);
316     const auto *s_ptr = &mp_ptr->info[realm - 1][spell_idx];
317
318     gain_spell_skill_exp_aux(this->player_ptr, this->player_ptr->spell_exp[spell_idx + (is_first_realm ? 0 : 32)],
319         (is_first_realm ? gain_amount_list_first : gain_amount_list_second), s_ptr->slevel);
320 }
321
322 void PlayerSkill::gain_continuous_spell_skill_exp(int realm, int spell_idx)
323 {
324     if (((spell_idx < 0) || (32 <= spell_idx)) ||
325         ((realm != REALM_MUSIC) && (realm != REALM_HEX))) {
326         return;
327     }
328
329     const auto *s_ptr = &technic_info[realm - MIN_TECHNIC][spell_idx];
330
331     const GainAmountList gain_amount_list{ 5, (one_in_(2) ? 1 : 0), (one_in_(5) ? 1 : 0), (one_in_(5) ? 1 : 0) };
332
333     gain_spell_skill_exp_aux(this->player_ptr, this->player_ptr->spell_exp[spell_idx], gain_amount_list, s_ptr->slevel);
334 }
335
336 int PlayerSkill::gain_spell_skill_exp_over_learning(int spell_idx)
337 {
338     if ((spell_idx < 0) || (static_cast<int>(std::size(this->player_ptr->spell_exp)) <= spell_idx)) {
339         return EXP_LEVEL_UNSKILLED;
340     }
341
342     auto &exp = this->player_ptr->spell_exp[spell_idx];
343
344     if (exp >= SPELL_EXP_EXPERT) {
345         exp = SPELL_EXP_MASTER;
346     } else if (exp >= SPELL_EXP_SKILLED) {
347         if (spell_idx >= 32) {
348             exp = SPELL_EXP_EXPERT;
349         } else {
350             exp += SPELL_EXP_EXPERT - SPELL_EXP_SKILLED;
351         }
352     } else if (exp >= SPELL_EXP_BEGINNER) {
353         exp = SPELL_EXP_SKILLED + (exp - SPELL_EXP_BEGINNER) * 2 / 3;
354     } else {
355         exp = SPELL_EXP_BEGINNER + exp / 3;
356     }
357
358     set_bits(this->player_ptr->update, PU_BONUS);
359
360     return PlayerSkill::spell_exp_level(exp);
361 }
362
363 /*!
364  * @brief 呪文の経験値を返す /
365  * Returns experience of a spell
366  * @param use_realm 魔法領域
367  * @param spell_idx 呪文ID
368  * @return 経験値
369  */
370 EXP PlayerSkill::exp_of_spell(int realm, int spell_idx) const
371 {
372     if (this->player_ptr->pclass == PlayerClassType::SORCERER)
373         return SPELL_EXP_MASTER;
374     else if (this->player_ptr->pclass == PlayerClassType::RED_MAGE)
375         return SPELL_EXP_SKILLED;
376     else if (realm == this->player_ptr->realm1)
377         return this->player_ptr->spell_exp[spell_idx];
378     else if (realm == this->player_ptr->realm2)
379         return this->player_ptr->spell_exp[spell_idx + 32];
380     else
381         return 0;
382 }