OSDN Git Service

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