OSDN Git Service

1c7f314c17716abcdcf1313fac520e5cd3a4aead
[hengbandforosx/hengbandosx.git] / src / birth / birth-stat.cpp
1 #include "birth/birth-stat.h"
2 #include "birth/auto-roller.h"
3 #include "core/player-redraw-types.h"
4 #include "player-base/player-class.h"
5 #include "player-base/player-race.h"
6 #include "player-info/class-info.h"
7 #include "player-info/race-info.h"
8 #include "player-info/race-types.h"
9 #include "player/player-personality-types.h"
10 #include "player/player-personality.h"
11 #include "player/player-skill.h"
12 #include "spell/spells-status.h"
13 #include "sv-definition/sv-weapon-types.h"
14 #include "system/player-type-definition.h"
15 #include "system/redrawing-flags-updater.h"
16 #include <array>
17
18 namespace {
19
20 constexpr auto random_distribution = 60;
21
22 /*! オートロール能力値の乱数分布 (1d3, 1d4, 1d5 を3 * 4 * 5 = 60個で表現) */
23 constexpr std::array<short, random_distribution> auto_roller_distribution = {
24     {
25         8, 9, 9, 9, 10, 10, 10, 10, 10, 10, /*00-09*/
26         11, 11, 11, 11, 11, 11, 11, 11, 11, 12, /*10-19*/
27         12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /*20-29*/
28         13, 13, 13, 13, 13, 13, 13, 13, 13, 13, /*30-49*/
29         13, 14, 14, 14, 14, 14, 14, 14, 14, 14, /*40-49*/
30         15, 15, 15, 15, 15, 15, 16, 16, 16, 17 /*50-59*/
31     }
32 };
33 }
34
35 /*!
36  * @brief プレイヤーの能力値表現に基づいて加減算を行う。
37  * @param value 現在の能力値
38  * @param amount 加減算する値
39  * @return 加減算の結果
40  */
41 int adjust_stat(int value, int amount)
42 {
43     if (amount < 0) {
44         for (int i = 0; i < (0 - amount); i++) {
45             if (value >= 18 + 10) {
46                 value -= 10;
47             } else if (value > 18) {
48                 value = 18;
49             } else if (value > 3) {
50                 value--;
51             }
52         }
53     } else if (amount > 0) {
54         for (int i = 0; i < amount; i++) {
55             if (value < 18) {
56                 value++;
57             } else {
58                 value += 10;
59             }
60         }
61     }
62
63     return value;
64 }
65
66 /*!
67  * @brief プレイヤーの能力値を一通りロールする。 / Roll for a characters stats
68  * @param player_ptr プレイヤーへの参照ポインタ
69  * @details
70  * calc_bonuses()による、独立ステータスからの副次ステータス算出も行っている。
71  * For efficiency, we include a chunk of "calc_bonuses()".\n
72  */
73 void get_stats(PlayerType *player_ptr)
74 {
75     while (true) {
76         auto sum = 0;
77         for (auto i = 0; i < 2; i++) {
78             auto tmp = randint0(random_distribution * random_distribution * random_distribution);
79             for (auto j = 0; j < 3; j++) {
80                 auto stat = i * 3 + j;
81                 auto val = auto_roller_distribution[tmp % random_distribution];
82                 sum += val;
83                 player_ptr->stat_cur[stat] = player_ptr->stat_max[stat] = val;
84                 tmp /= random_distribution;
85             }
86         }
87
88         if ((sum > 42 + 5 * 6) && (sum < 57 + 5 * 6)) {
89             break;
90         }
91     }
92 }
93
94 /*!
95  * @brief 経験値修正の合計値を計算
96  */
97 uint16_t get_expfact(PlayerType *player_ptr)
98 {
99     uint16_t expfact = rp_ptr->r_exp;
100
101     PlayerRace pr(player_ptr);
102     if (!pr.equals(PlayerRaceType::ANDROID)) {
103         expfact += cp_ptr->c_exp;
104     }
105
106     auto is_race_gaining_additional_speed = pr.equals(PlayerRaceType::KLACKON) || pr.equals(PlayerRaceType::SPRITE);
107     auto is_class_gaining_additional_speed = PlayerClass(player_ptr).has_additional_speed();
108     if (is_race_gaining_additional_speed && is_class_gaining_additional_speed) {
109         expfact -= 15;
110     }
111
112     return expfact;
113 }
114
115 /*!
116  * @brief その他「オートローラ中は算出の対象にしない」副次ステータスを処理する / Roll for some info that the auto-roller ignores
117  */
118 void get_extra(PlayerType *player_ptr, bool roll_hitdie)
119 {
120     player_ptr->expfact = get_expfact(player_ptr);
121
122     /* Reset record of race/realm changes */
123     player_ptr->start_race = player_ptr->prace;
124     player_ptr->old_race1 = 0L;
125     player_ptr->old_race2 = 0L;
126     player_ptr->old_realm = 0;
127
128     PlayerClass pc(player_ptr);
129     auto is_sorcerer = pc.equals(PlayerClassType::SORCERER);
130     for (int i = 0; i < 64; i++) {
131         if (is_sorcerer) {
132             player_ptr->spell_exp[i] = PlayerSkill::spell_exp_at(PlayerSkillRank::MASTER);
133         } else if (pc.equals(PlayerClassType::RED_MAGE)) {
134             player_ptr->spell_exp[i] = PlayerSkill::spell_exp_at(PlayerSkillRank::SKILLED);
135         } else {
136             player_ptr->spell_exp[i] = PlayerSkill::spell_exp_at(PlayerSkillRank::UNSKILLED);
137         }
138     }
139
140     auto pclass = enum2i(player_ptr->pclass);
141     player_ptr->weapon_exp = class_skills_info[pclass].w_start;
142     player_ptr->weapon_exp_max = class_skills_info[pclass].w_max;
143
144     if (player_ptr->ppersonality == PERSONALITY_SEXY) {
145         auto &whip_exp = player_ptr->weapon_exp[ItemKindType::HAFTED][SV_WHIP];
146         whip_exp = std::max(whip_exp, PlayerSkill::weapon_exp_at(PlayerSkillRank::BEGINNER));
147     }
148
149     for (auto i : PLAYER_SKILL_KIND_TYPE_RANGE) {
150         player_ptr->skill_exp[i] = class_skills_info[pclass].s_start[i];
151     }
152
153     player_ptr->hitdie = cp_ptr->c_mhp + ap_ptr->a_mhp;
154     player_ptr->hitdie += is_sorcerer ? rp_ptr->r_mhp / 2 : rp_ptr->r_mhp;
155     if (roll_hitdie) {
156         roll_hitdice(player_ptr, SPOP_NO_UPDATE);
157     }
158
159     player_ptr->mhp = player_ptr->player_hp[0];
160 }
161
162 /*!
163  * @brief プレイヤーの限界ステータスを決める。
164  * @param player_ptr プレイヤーへの参照ポインタ
165  * @details 新生の薬やステータスシャッフルでもこの関数が呼ばれる
166  */
167 void get_max_stats(PlayerType *player_ptr)
168 {
169     int dice[6]{};
170     while (true) {
171         auto j = 0;
172         for (auto i = 0; i < A_MAX; i++) {
173             dice[i] = randint1(7);
174             j += dice[i];
175         }
176
177         if (j == 24) {
178             break;
179         }
180     }
181
182     for (auto i = 0; i < A_MAX; i++) {
183         short max_max = 18 + 60 + dice[i] * 10;
184         player_ptr->stat_max_max[i] = max_max;
185         if (player_ptr->stat_max[i] > max_max) {
186             player_ptr->stat_max[i] = max_max;
187         }
188         if (player_ptr->stat_cur[i] > max_max) {
189             player_ptr->stat_cur[i] = max_max;
190         }
191     }
192
193     player_ptr->knowledge &= ~(KNOW_STAT);
194     RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
195 }