OSDN Git Service

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