OSDN Git Service

[Refactor] #3264 BASE_STATUS 型エイリアスを削除した
[hengbandforosx/hengbandosx.git] / src / action / racial-execution.cpp
1 /*!
2  * @file racial-execution.cpp
3  * @brief レイシャルパワー実行処理実装
4  */
5
6 #include "action/racial-execution.h"
7 #include "action/action-limited.h"
8 #include "artifact/fixed-art-types.h"
9 #include "core/asking-player.h"
10 #include "game-option/disturbance-options.h"
11 #include "inventory/inventory-slot-types.h"
12 #include "player-base/player-class.h"
13 #include "player-info/race-info.h"
14 #include "player-status/player-energy.h"
15 #include "racial/racial-switcher.h"
16 #include "racial/racial-util.h"
17 #include "system/item-entity.h"
18 #include "system/player-type-definition.h"
19 #include "term/screen-processor.h"
20 #include "timed-effect/player-confusion.h"
21 #include "timed-effect/player-stun.h"
22 #include "timed-effect/timed-effects.h"
23 #include "view/display-messages.h"
24
25 /*!
26  * @brief レイシャル・パワー発動処理
27  * @param player_ptr プレイヤーへの参照ポインタ
28  * @param command 発動するレイシャルのID
29  * @return 処理を実際に実行した場合はTRUE、キャンセルした場合FALSEを返す。
30  */
31 bool exe_racial_power(PlayerType *player_ptr, const int32_t command)
32 {
33     if (command <= -3) {
34         return switch_class_racial_execution(player_ptr, command);
35     }
36
37     if (player_ptr->mimic_form != MimicKindType::NONE) {
38         return switch_mimic_racial_execution(player_ptr);
39     }
40
41     return switch_race_racial_execution(player_ptr, command);
42 }
43
44 /*!
45  * @brief レイシャル・パワーの発動成功率を計算する / Returns the chance to activate a racial power/mutation
46  * @param rpi_ptr 発動したいレイシャル・パワー情報の構造体参照ポインタ
47  * @return 成功率(%)を返す
48  */
49 PERCENTAGE racial_chance(PlayerType *player_ptr, rpi_type *rpi_ptr)
50 {
51     if ((player_ptr->lev < rpi_ptr->min_level) || player_ptr->effects()->confusion()->is_confused()) {
52         return 0;
53     }
54
55     PERCENTAGE difficulty = rpi_ptr->fail;
56     if (difficulty == 0) {
57         return 100;
58     }
59
60     auto player_stun = player_ptr->effects()->stun();
61     if (player_stun->is_stunned()) {
62         difficulty += player_stun->current();
63     } else if (player_ptr->lev > rpi_ptr->min_level) {
64         PERCENTAGE lev_adj = (PERCENTAGE)((player_ptr->lev - rpi_ptr->min_level) / 3);
65         if (lev_adj > 10) {
66             lev_adj = 10;
67         }
68
69         difficulty -= lev_adj;
70     }
71
72     auto special_easy = PlayerClass(player_ptr).equals(PlayerClassType::IMITATOR);
73     special_easy &= player_ptr->inventory_list[INVEN_NECK].is_specific_artifact(FixedArtifactId::GOGO_PENDANT);
74     special_easy &= rpi_ptr->racial_name.compare("倍返し") == 0;
75     if (special_easy) {
76         difficulty -= 12;
77     }
78
79     if (difficulty < 5) {
80         difficulty = 5;
81     }
82
83     difficulty = difficulty / 2;
84     const auto stat = player_ptr->stat_cur[rpi_ptr->stat];
85     auto sum = 0;
86     for (auto i = 1; i <= stat; i++) {
87         int val = i - difficulty;
88         if (val > 0) {
89             sum += (val <= difficulty) ? val : difficulty;
90         }
91     }
92
93     if (difficulty == 0) {
94         return 100;
95     } else {
96         return ((sum * 100) / difficulty) / stat;
97     }
98 }
99
100 static void adjust_racial_power_difficulty(PlayerType *player_ptr, rpi_type *rpi_ptr, int *difficulty)
101 {
102     if (*difficulty == 0) {
103         return;
104     }
105
106     auto player_stun = player_ptr->effects()->stun();
107     if (player_stun->is_stunned()) {
108         *difficulty += player_stun->current();
109     } else if (player_ptr->lev > rpi_ptr->min_level) {
110         int lev_adj = ((player_ptr->lev - rpi_ptr->min_level) / 3);
111         if (lev_adj > 10) {
112             lev_adj = 10;
113         }
114         *difficulty -= lev_adj;
115     }
116
117     if (*difficulty < 5) {
118         *difficulty = 5;
119     }
120 }
121
122 /*!
123  * @brief レイシャル・パワーの発動の判定処理
124  * @param rpi_ptr 発動したいレイシャル・パワー情報の構造体参照ポインタ
125  * @return racial_level_check_result
126  */
127 racial_level_check_result check_racial_level(PlayerType *player_ptr, rpi_type *rpi_ptr)
128 {
129     PLAYER_LEVEL min_level = rpi_ptr->min_level;
130     int use_stat = rpi_ptr->stat;
131     int difficulty = rpi_ptr->fail;
132     int use_hp = 0;
133     rpi_ptr->racial_cost = rpi_ptr->cost;
134     if (player_ptr->csp < rpi_ptr->racial_cost) {
135         use_hp = rpi_ptr->racial_cost - player_ptr->csp;
136     }
137
138     PlayerEnergy energy(player_ptr);
139     if (player_ptr->lev < min_level) {
140         msg_format(_("この能力を使用するにはレベル %d に達していなければなりません。", "You need to attain level %d to use this power."), min_level);
141         energy.reset_player_turn();
142         return RACIAL_CANCEL;
143     }
144
145     if (cmd_limit_confused(player_ptr)) {
146         energy.reset_player_turn();
147         return RACIAL_CANCEL;
148     } else if (player_ptr->chp < use_hp) {
149         if (!get_check(_("本当に今の衰弱した状態でこの能力を使いますか?", "Really use the power in your weakened state? "))) {
150             energy.reset_player_turn();
151             return RACIAL_CANCEL;
152         }
153     }
154
155     adjust_racial_power_difficulty(player_ptr, rpi_ptr, &difficulty);
156     energy.set_player_turn_energy(100);
157     if (randint1(player_ptr->stat_cur[use_stat]) >= ((difficulty / 2) + randint1(difficulty / 2))) {
158         return RACIAL_SUCCESS;
159     }
160
161     if (flush_failure) {
162         flush();
163     }
164
165     msg_print(_("充分に集中できなかった。", "You've failed to concentrate hard enough."));
166     return RACIAL_FAILURE;
167 }