OSDN Git Service

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