OSDN Git Service

Merge pull request #1186 from dis-/feature/Fix-calc_num_fire
[hengbandforosx/hengbandosx.git] / src / core / asking-player.cpp
1 #include "core/asking-player.h"
2 #include "cmd-io/macro-util.h"
3 #include "core/stuff-handler.h"
4 #include "core/window-redrawer.h"
5 #include "game-option/input-options.h"
6 #include "io/command-repeater.h"
7 #include "io/input-key-acceptor.h"
8 #include "io/input-key-requester.h" //!< @todo 相互依存している、後で何とかする.
9 #include "main/sound-of-music.h"
10 #include "system/player-type-definition.h"
11 #include "term/screen-processor.h"
12 #include "term/term-color-types.h"
13 #include "util/int-char-converter.h"
14 #include "util/string-processor.h"
15 #include "view/display-messages.h"
16
17 /*
18  * Get some string input at the cursor location.
19  * Assume the buffer is initialized to a default string.
20  *
21  * The default buffer is in Overwrite mode and displayed in yellow at
22  * first.  Normal chars clear the yellow text and append the char in
23  * white text.
24  *
25  * LEFT (^B) and RIGHT (^F) movement keys move the cursor position.
26  * If the text is still displayed in yellow (Overwite mode), it will
27  * turns into white (Insert mode) when cursor moves.
28  *
29  * DELETE (^D) deletes a char at the cursor position.
30  * BACKSPACE (^H) deletes a char at the left of cursor position.
31  * ESCAPE clears the buffer and the window and returns FALSE.
32  * RETURN accepts the current buffer contents and returns TRUE.
33  */
34 bool askfor_aux(char *buf, int len, bool numpad_cursor)
35 {
36     /*
37      * Text color
38      * TERM_YELLOW : Overwrite mode
39      * TERM_WHITE : Insert mode
40      */
41     byte color = TERM_YELLOW;
42
43     int y, x;
44     term_locate(&x, &y);
45     if (len < 1)
46         len = 1;
47     if ((x < 0) || (x >= 80))
48         x = 0;
49     if (x + len > 80)
50         len = 80 - x;
51
52     buf[len] = '\0';
53
54     int pos = 0;
55     while (true) {
56         term_erase(x, y, len);
57         term_putstr(x, y, -1, color, buf);
58
59         term_gotoxy(x + pos, y);
60         int skey = inkey_special(numpad_cursor);
61
62         switch (skey) {
63         case SKEY_LEFT:
64         case KTRL('b'): {
65             int i = 0;
66             color = TERM_WHITE;
67
68             if (0 == pos)
69                 break;
70             while (true) {
71                 int next_pos = i + 1;
72 #ifdef JP
73                 if (iskanji(buf[i]))
74                     next_pos++;
75 #endif
76                 if (next_pos >= pos)
77                     break;
78
79                 i = next_pos;
80             }
81
82             pos = i;
83             break;
84         }
85
86         case SKEY_RIGHT:
87         case KTRL('f'):
88             color = TERM_WHITE;
89             if ('\0' == buf[pos])
90                 break;
91
92 #ifdef JP
93             if (iskanji(buf[pos]))
94                 pos += 2;
95             else
96                 pos++;
97 #else
98             pos++;
99 #endif
100             break;
101
102         case ESCAPE:
103             buf[0] = '\0';
104             return false;
105
106         case '\n':
107         case '\r':
108             return true;
109
110         case '\010': {
111             int i = 0;
112             color = TERM_WHITE;
113             if (0 == pos)
114                 break;
115             while (true) {
116                 int next_pos = i + 1;
117 #ifdef JP
118                 if (iskanji(buf[i]))
119                     next_pos++;
120 #endif
121                 if (next_pos >= pos)
122                     break;
123
124                 i = next_pos;
125             }
126
127             pos = i;
128         }
129             /* Fall through */
130
131         case 0x7F:
132         case KTRL('d'): {
133             color = TERM_WHITE;
134             if ('\0' == buf[pos])
135                 break;
136             int src = pos + 1;
137 #ifdef JP
138             if (iskanji(buf[pos]))
139                 src++;
140 #endif
141
142             int dst = pos;
143             while ('\0' != (buf[dst++] = buf[src++]))
144                 ;
145             break;
146         }
147
148         default: {
149             char tmp[100];
150             if (skey & SKEY_MASK)
151                 break;
152             char c = (char)skey;
153
154             if (color == TERM_YELLOW) {
155                 buf[0] = '\0';
156                 color = TERM_WHITE;
157             }
158
159             strcpy(tmp, buf + pos);
160 #ifdef JP
161             if (iskanji(c)) {
162                 inkey_base = true;
163                 char next = inkey();
164                 if (pos + 1 < len) {
165                     buf[pos++] = c;
166                     buf[pos++] = next;
167                 } else {
168                     bell();
169                 }
170             } else
171 #endif
172             {
173 #ifdef JP
174                 if (pos < len && (isprint(c) || iskana(c)))
175 #else
176                 if (pos < len && isprint(c))
177 #endif
178                 {
179                     buf[pos++] = c;
180                 } else {
181                     bell();
182                 }
183             }
184
185             buf[pos] = '\0';
186             angband_strcat(buf, tmp, len + 1);
187
188             break;
189         }
190         }
191     }
192 }
193
194 /*
195  * Get some string input at the cursor location.
196  *
197  * Allow to use numpad keys as cursor keys.
198  */
199 bool askfor(char *buf, int len) { return askfor_aux(buf, len, true); }
200
201 /*
202  * Get a string from the user
203  *
204  * The "prompt" should take the form "Prompt: "
205  *
206  * Note that the initial contents of the string is used as
207  * the default response, so be sure to "clear" it if needed.
208  *
209  * We clear the input, and return FALSE, on "ESCAPE".
210  */
211 bool get_string(concptr prompt, char *buf, int len)
212 {
213     bool res;
214     msg_print(NULL);
215     prt(prompt, 0, 0);
216     res = askfor(buf, len);
217     prt("", 0, 0);
218     return (res);
219 }
220
221 /*
222  * Verify something with the user
223  *
224  * The "prompt" should take the form "Query? "
225  *
226  * Note that "[y/n]" is appended to the prompt.
227  */
228 bool get_check(concptr prompt) { return get_check_strict(p_ptr, prompt, 0); }
229
230 /*
231  * Verify something with the user strictly
232  *
233  * mode & CHECK_OKAY_CANCEL : force user to answer 'O'kay or 'C'ancel
234  * mode & CHECK_NO_ESCAPE   : don't allow ESCAPE key
235  * mode & CHECK_NO_HISTORY  : no message_add
236  * mode & CHECK_DEFAULT_Y   : accept any key as y, except n and Esc.
237  */
238 bool get_check_strict(player_type *player_ptr, concptr prompt, BIT_FLAGS mode)
239 {
240     char buf[80];
241     if (!rogue_like_commands)
242         mode &= ~CHECK_OKAY_CANCEL;
243
244     if (mode & CHECK_OKAY_CANCEL) {
245         angband_strcpy(buf, prompt, sizeof(buf) - 15);
246         strcat(buf, "[(O)k/(C)ancel]");
247     } else if (mode & CHECK_DEFAULT_Y) {
248         angband_strcpy(buf, prompt, sizeof(buf) - 5);
249         strcat(buf, "[Y/n]");
250     } else {
251         angband_strcpy(buf, prompt, sizeof(buf) - 5);
252         strcat(buf, "[y/n]");
253     }
254
255     if (auto_more) {
256         player_ptr->window_flags |= PW_MESSAGE;
257         handle_stuff(player_ptr);
258         num_more = 0;
259     }
260
261     msg_print(NULL);
262
263     prt(buf, 0, 0);
264     if (!(mode & CHECK_NO_HISTORY) && player_ptr->playing) {
265         message_add(buf);
266         player_ptr->window_flags |= (PW_MESSAGE);
267         handle_stuff(player_ptr);
268     }
269
270     bool flag = false;
271     while (true) {
272         int i = inkey();
273
274         if (!(mode & CHECK_NO_ESCAPE)) {
275             if (i == ESCAPE) {
276                 flag = false;
277                 break;
278             }
279         }
280
281         if (mode & CHECK_OKAY_CANCEL) {
282             if (i == 'o' || i == 'O') {
283                 flag = true;
284                 break;
285             } else if (i == 'c' || i == 'C') {
286                 flag = false;
287                 break;
288             }
289         } else {
290             if (i == 'y' || i == 'Y') {
291                 flag = true;
292                 break;
293             } else if (i == 'n' || i == 'N') {
294                 flag = false;
295                 break;
296             }
297         }
298
299         if (mode & CHECK_DEFAULT_Y) {
300             flag = true;
301             break;
302         }
303
304         bell();
305     }
306
307     prt("", 0, 0);
308     return flag;
309 }
310
311 /*
312  * Prompts for a keypress
313  *
314  * The "prompt" should take the form "Command: "
315  *
316  * Returns TRUE unless the character is "Escape"
317  */
318 bool get_com(concptr prompt, char *command, bool z_escape)
319 {
320     msg_print(NULL);
321     prt(prompt, 0, 0);
322     if (get_com_no_macros)
323         *command = (char)inkey_special(false);
324     else
325         *command = inkey();
326
327     prt("", 0, 0);
328     if (*command == ESCAPE)
329         return false;
330     if (z_escape && ((*command == 'z') || (*command == 'Z')))
331         return false;
332
333     return true;
334 }
335
336 /*
337  * Request a "quantity" from the user
338  *
339  * Hack -- allow "command_arg" to specify a quantity
340  */
341 QUANTITY get_quantity(concptr prompt, QUANTITY max)
342 {
343     bool res;
344     char tmp[80];
345     char buf[80];
346
347     QUANTITY amt;
348     if (command_arg) {
349         amt = command_arg;
350         command_arg = 0;
351         if (amt > max)
352             amt = max;
353
354         return (amt);
355     }
356
357     COMMAND_CODE code;
358     bool result = repeat_pull(&code);
359     amt = (QUANTITY)code;
360     if ((max != 1) && result) {
361         if (amt > max)
362             amt = max;
363         if (amt < 0)
364             amt = 0;
365
366         return (amt);
367     }
368
369     if (!prompt) {
370         sprintf(tmp, _("いくつですか (1-%d): ", "Quantity (1-%d): "), max);
371         prompt = tmp;
372     }
373
374     msg_print(NULL);
375     prt(prompt, 0, 0);
376     amt = 1;
377     sprintf(buf, "%d", amt);
378
379     /*
380      * Ask for a quantity
381      * Don't allow to use numpad as cursor key.
382      */
383     res = askfor_aux(buf, 6, false);
384
385     prt("", 0, 0);
386     if (!res)
387         return 0;
388
389     amt = (COMMAND_CODE)atoi(buf);
390     if (isalpha(buf[0]))
391         amt = max;
392     if (amt > max)
393         amt = max;
394     if (amt < 0)
395         amt = 0;
396     if (amt)
397         repeat_push((COMMAND_CODE)amt);
398
399     return (amt);
400 }
401
402 /*
403  * Pause for user response
404  */
405 void pause_line(int row)
406 {
407     prt("", row, 0);
408     put_str(_("[ 何かキーを押して下さい ]", "[Press any key to continue]"), row, _(26, 23));
409
410     (void)inkey();
411     prt("", row, 0);
412 }