OSDN Git Service

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