OSDN Git Service

Merge remote-tracking branch 'remotes/origin/feature/Fix-saved-floor-exceed' into...
[hengband/hengband.git] / src / cmd-action / cmd-racial.c
1 #include "cmd-action/cmd-racial.h"
2 #include "action/action-limited.h"
3 #include "action/mutation-execution.h"
4 #include "core/asking-player.h"
5 #include "core/player-redraw-types.h"
6 #include "core/player-update-types.h"
7 #include "core/window-redrawer.h"
8 #include "game-option/text-display-options.h"
9 #include "io/command-repeater.h"
10 #include "io/input-key-requester.h"
11 #include "main/sound-of-music.h"
12 #include "mutation/mutation-flag-types.h"
13 #include "player/attack-defense-types.h"
14 #include "player/player-damage.h"
15 #include "player/special-defense-types.h"
16 #include "racial/class-racial-switcher.h"
17 #include "racial/mutation-racial-selector.h"
18 #include "action/racial-execution.h"
19 #include "racial/race-racial-command-setter.h"
20 #include "racial/racial-util.h"
21 #include "status/action-setter.h"
22 #include "term/screen-processor.h"
23 #include "util/int-char-converter.h"
24
25 static bool input_racial_power_selection(player_type *creature_ptr, rc_type *rc_ptr)
26 {
27     switch (rc_ptr->choice) {
28     case '0':
29         screen_load();
30         free_turn(creature_ptr);
31         return TRUE;
32     case '8':
33     case 'k':
34     case 'K':
35         rc_ptr->menu_line += (rc_ptr->num - 1);
36         return FALSE;
37     case '2':
38     case 'j':
39     case 'J':
40         rc_ptr->menu_line++;
41         return FALSE;
42     case '6':
43     case 'l':
44     case 'L':
45     case '4':
46     case 'h':
47     case 'H':
48         if (rc_ptr->menu_line > 18)
49             rc_ptr->menu_line -= 18;
50         else if (rc_ptr->menu_line + 18 <= rc_ptr->num)
51             rc_ptr->menu_line += 18;
52
53         return FALSE;
54     case 'x':
55     case 'X':
56     case '\r':
57         rc_ptr->command_code = rc_ptr->menu_line - 1;
58         rc_ptr->ask = FALSE;
59         return FALSE;
60     default:
61         return FALSE;
62     }
63 }
64
65 static bool check_input_racial_power(player_type *creature_ptr, rc_type *rc_ptr)
66 {
67     if (!use_menu || rc_ptr->choice == ' ')
68         return FALSE;
69
70     if (input_racial_power_selection(creature_ptr, rc_ptr))
71         return TRUE;
72
73     if (rc_ptr->menu_line > rc_ptr->num)
74         rc_ptr->menu_line -= rc_ptr->num;
75
76     return FALSE;
77 }
78
79 static void display_racial_list(rc_type *rc_ptr, char *dummy)
80 {
81     strcpy(dummy, "");
82     rc_ptr->redraw = TRUE;
83     if (!use_menu)
84         screen_save();
85
86     if (rc_ptr->num < 18) {
87         prt(_("                            Lv   MP 失率", "                            Lv Cost Fail"), 1, 0);
88         return;
89     }
90
91     prt(_("                            Lv   MP 失率                            Lv   MP 失率",
92             "                            Lv Cost Fail                            Lv Cost Fail"),
93         1, 0);
94 }
95
96 static void select_racial_power(player_type *creature_ptr, rc_type *rc_ptr)
97 {
98     char dummy[80];
99     display_racial_list(rc_ptr, dummy);
100     byte y = 2;
101     byte x = 0;
102     int ctr = 0;
103     while (ctr < rc_ptr->num) {
104         TERM_LEN x1 = ((ctr < 18) ? x : x + 40);
105         TERM_LEN y1 = ((ctr < 18) ? y + ctr : y + ctr - 18);
106         if (use_menu) {
107             if (ctr == (rc_ptr->menu_line - 1))
108                 strcpy(dummy, _(" 》 ", " >  "));
109             else
110                 strcpy(dummy, "    ");
111         } else {
112             char letter;
113             if (ctr < 26)
114                 letter = I2A(ctr);
115             else
116                 letter = '0' + ctr - 26;
117
118             sprintf(dummy, " %c) ", letter);
119         }
120
121         strcat(dummy,
122             format("%-23.23s %2d %4d %3d%%", rc_ptr->power_desc[ctr].racial_name, rc_ptr->power_desc[ctr].min_level, rc_ptr->power_desc[ctr].cost,
123                 100 - racial_chance(creature_ptr, &rc_ptr->power_desc[ctr])));
124         prt(dummy, y1, x1);
125         ctr++;
126     }
127 }
128
129 static bool check_racial_power_choice(player_type *creature_ptr, rc_type *rc_ptr)
130 {
131     if ((rc_ptr->choice != ' ') && (rc_ptr->choice != '*') && (rc_ptr->choice != '?') && (!use_menu || !rc_ptr->ask))
132         return FALSE;
133
134     if (!rc_ptr->redraw || use_menu) {
135         select_racial_power(creature_ptr, rc_ptr);
136         return TRUE;
137     }
138
139     rc_ptr->redraw = FALSE;
140     screen_load();
141     return TRUE;
142 }
143
144 static void decide_racial_command(rc_type *rc_ptr)
145 {
146     if (use_menu)
147         return;
148
149     if (rc_ptr->choice == '\r' && rc_ptr->num == 1)
150         rc_ptr->choice = 'a';
151
152     if (!isalpha(rc_ptr->choice)) {
153         rc_ptr->ask = FALSE;
154         rc_ptr->command_code = rc_ptr->choice - '0' + 26;
155         return;
156     }
157
158     rc_ptr->ask = (isupper(rc_ptr->choice));
159     if (rc_ptr->ask)
160         rc_ptr->choice = (char)tolower(rc_ptr->choice);
161
162     rc_ptr->command_code = (islower(rc_ptr->choice) ? A2I(rc_ptr->choice) : -1);
163 }
164
165 static bool ask_invoke_racial_power(rc_type *rc_ptr)
166 {
167     if ((rc_ptr->command_code < 0) || (rc_ptr->command_code >= rc_ptr->num)) {
168         bell();
169         return FALSE;
170     }
171
172     if (!rc_ptr->ask)
173         return TRUE;
174
175     char tmp_val[160];
176     (void)strnfmt(tmp_val, 78, _("%sを使いますか? ", "Use %s? "), rc_ptr->power_desc[rc_ptr->command_code].racial_name);
177     return get_check(tmp_val);
178 }
179
180 static bool process_racial_power_choice(player_type *creature_ptr, rc_type *rc_ptr)
181 {
182     rc_ptr->choice = (always_show_list || use_menu) ? ESCAPE : 1;
183     while (!rc_ptr->flag) {
184         if (rc_ptr->choice == ESCAPE)
185             rc_ptr->choice = ' ';
186         else if (!get_com(rc_ptr->out_val, &rc_ptr->choice, FALSE))
187             break;
188
189         if (check_input_racial_power(creature_ptr, rc_ptr))
190             return TRUE;
191
192         if (check_racial_power_choice(creature_ptr, rc_ptr))
193             continue;
194
195         decide_racial_command(rc_ptr);
196         if (!ask_invoke_racial_power(rc_ptr))
197             continue;
198
199         rc_ptr->flag = TRUE;
200     }
201
202     return FALSE;
203 }
204
205 static bool repeat_racial_power(player_type *creature_ptr, rc_type *rc_ptr)
206 {
207     if (repeat_pull(&rc_ptr->command_code) && (rc_ptr->command_code >= 0) && (rc_ptr->command_code < rc_ptr->num))
208         return FALSE;
209
210     if (use_menu)
211         screen_save();
212
213     if (process_racial_power_choice(creature_ptr, rc_ptr))
214         return TRUE;
215
216     if (rc_ptr->redraw)
217         screen_load();
218
219     if (!rc_ptr->flag) {
220         free_turn(creature_ptr);
221         return TRUE;
222     }
223
224     repeat_push(rc_ptr->command_code);
225     return FALSE;
226 }
227
228 static void check_cast_racial_power(player_type *creature_ptr, rc_type *rc_ptr)
229 {
230     switch (check_racial_level(creature_ptr, &rc_ptr->power_desc[rc_ptr->command_code])) {
231     case RACIAL_SUCCESS:
232         if (rc_ptr->power_desc[rc_ptr->command_code].number < 0)
233             rc_ptr->cast = exe_racial_power(creature_ptr, rc_ptr->power_desc[rc_ptr->command_code].number);
234         else
235             rc_ptr->cast = exe_mutation_power(creature_ptr, rc_ptr->power_desc[rc_ptr->command_code].number);
236
237         break;
238     case RACIAL_FAILURE:
239         rc_ptr->cast = TRUE;
240         break;
241     case RACIAL_CANCEL:
242         rc_ptr->cast = FALSE;
243         break;
244     }
245 }
246
247 static bool reduce_mana_by_racial(player_type *creature_ptr, rc_type *rc_ptr)
248 {
249     int racial_cost = rc_ptr->power_desc[rc_ptr->command_code].racial_cost;
250     if (racial_cost == 0)
251         return FALSE;
252
253     int actual_racial_cost = racial_cost / 2 + randint1(racial_cost / 2);
254     if (creature_ptr->csp >= actual_racial_cost) {
255         creature_ptr->csp -= actual_racial_cost;
256         return TRUE;
257     }
258
259     actual_racial_cost -= creature_ptr->csp;
260     creature_ptr->csp = 0;
261     take_hit(creature_ptr, DAMAGE_USELIFE, actual_racial_cost, _("過度の集中", "concentrating too hard"), -1);
262     return TRUE;
263 }
264
265 /*!
266  * @brief レイシャル・パワーコマンドのメインルーチン / Allow user to choose a power (racial / mutation) to activate
267  * @param creature_ptr プレーヤーへの参照ポインタ
268  * @return なし
269  */
270 void do_cmd_racial_power(player_type *creature_ptr)
271 {
272     if (creature_ptr->wild_mode)
273         return;
274
275     if (cmd_limit_confused(creature_ptr)) {
276         free_turn(creature_ptr);
277         return;
278     }
279
280     if (creature_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN))
281         set_action(creature_ptr, ACTION_NONE);
282
283     rc_type tmp_rc;
284     rc_type *rc_ptr = initialize_rc_type(creature_ptr, &tmp_rc);
285     switch_class_racial(creature_ptr, rc_ptr);
286     if (creature_ptr->mimic_form)
287         set_mimic_racial_command(creature_ptr, rc_ptr);
288     else
289         set_race_racial_command(creature_ptr, rc_ptr);
290
291     select_mutation_racial(creature_ptr, rc_ptr);
292     rc_ptr->flag = FALSE;
293     rc_ptr->redraw = FALSE;
294
295     (void)strnfmt(rc_ptr->out_val, 78,
296         _("(特殊能力 %c-%c, *'で一覧, ESCで中断) どの特殊能力を使いますか?", "(Powers %c-%c, *=List, ESC=exit) Use which power? "), I2A(0),
297         (rc_ptr->num <= 26) ? I2A(rc_ptr->num - 1) : '0' + rc_ptr->num - 27);
298
299     if (repeat_racial_power(creature_ptr, rc_ptr))
300         return;
301
302     check_cast_racial_power(creature_ptr, rc_ptr);
303     if (!rc_ptr->cast) {
304         free_turn(creature_ptr);
305         return;
306     }
307
308     if (!reduce_mana_by_racial(creature_ptr, rc_ptr))
309         return;
310
311     creature_ptr->redraw |= PR_HP | PR_MANA;
312     creature_ptr->window |= PW_PLAYER | PW_SPELL;
313 }