4 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
11 /* Purpose: Angband utilities -BEN- */
13 #include "system/angband.h"
14 #include "util/util.h"
15 #include "cmd-io/cmd-dump.h"
16 #include "cmd-io/cmd-menu-content-table.h"
17 #include "cmd-io/macro-util.h"
18 #include "core/asking-player.h"
19 #include "core/output-updater.h"
20 #include "core/stuff-handler.h"
21 #include "dungeon/quest.h"
22 #include "floor/floor.h"
23 #include "game-option/cheat-options.h"
24 #include "game-option/disturbance-options.h"
25 #include "game-option/input-options.h"
26 #include "game-option/map-screen-options.h"
27 #include "game-option/option-flags.h"
28 #include "game-option/special-options.h"
29 #include "io/files-util.h"
30 #include "io/input-key-acceptor.h"
31 #include "io/input-key-processor.h"
32 #include "io/signal-handlers.h"
33 #include "io/write-diary.h"
34 #include "locale/japanese.h"
35 #include "main/music-definitions-table.h"
36 #include "main/sound-of-music.h"
37 #include "monster-race/monster-race-hook.h"
38 #include "player/player-class.h"
39 #include "system/system-variables.h"
40 #include "term/gameterm.h"
41 #include "term/term-color-types.h"
42 #include "util/quarks.h"
43 #include "util/string-processor.h"
44 #include "view/display-main-window.h"
45 #include "view/display-messages.h"
46 #include "world/world.h"
49 * 10進数から16進数への変換テーブル /
50 * Global array for converting numbers to uppercase hecidecimal digit
51 * This array can also be used to convert a number to an octal digit
53 const char hexsym[16] =
55 '0', '1', '2', '3', '4', '5', '6', '7',
56 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
60 * Keymaps for each "mode" associated with each keypress.
62 concptr keymap_act[KEYMAP_MODES][256];
65 * Array of macro types [MACRO_MAX]
70 * Current macro action [1024]
74 bool get_com_no_macros = FALSE; /* Expand macros in "get_com" or not */
80 int max_macrotrigger = 0; /*!< 現在登録中のマクロ(トリガー)の数 */
81 concptr macro_template = NULL; /*!< Angband設定ファイルのT: タグ情報から読み込んだ長いTコードを処理するために利用する文字列ポインタ */
82 concptr macro_modifier_chr; /*!< &x# で指定されるマクロトリガーに関する情報を記録する文字列ポインタ */
83 concptr macro_modifier_name[MAX_MACRO_MOD]; /*!< マクロ上で取り扱う特殊キーを文字列上で表現するためのフォーマットを記録した文字列ポインタ配列 */
84 concptr macro_trigger_name[MAX_MACRO_TRIG]; /*!< マクロのトリガーコード */
85 concptr macro_trigger_keycode[2][MAX_MACRO_TRIG]; /*!< マクロの内容 */
87 s16b command_cmd; /* Current "Angband Command" */
88 COMMAND_ARG command_arg; /*!< 各種コマンドの汎用的な引数として扱う / Gives argument of current command */
89 COMMAND_NUM command_rep; /*!< 各種コマンドの汎用的なリピート数として扱う / Gives repetition of current command */
90 DIRECTION command_dir; /*!< 各種コマンドの汎用的な方向値処理として扱う/ Gives direction of current command */
91 s16b command_see; /* アイテム使用時等にリストを表示させるかどうか (ゲームオプションの他、様々なタイミングでONになったりOFFになったりする模様……) */
92 s16b command_wrk; /* アイテムの使用許可状況 (ex. 装備品のみ、床上もOK等) */
93 TERM_LEN command_gap = 999; /* アイテムの表示に使う (詳細未調査) */
94 s16b command_new; /* Command chaining from inven/equip view */
99 void move_cursor(int row, int col)
101 Term_gotoxy(col, row);
105 * Flush all input chars. Actually, remember the flush,
106 * and do a "special flush" before the next "inkey()".
108 * This is not only more efficient, but also necessary to make sure
109 * that various "inkey()" codes are not "lost" along the way.
118 * Hack -- prevent "accidents" in "screen_save()" or "screen_load()"
120 static int screen_depth = 0;
124 * Save the screen, and increase the "icky" depth.
126 * This function must match exactly one call to "screen_load()".
131 if (screen_depth++ == 0) Term_save();
133 current_world_ptr->character_icky++;
138 * Load the screen, and decrease the "icky" depth.
140 * This function must match exactly one call to "screen_save()".
145 if (--screen_depth == 0) Term_load();
147 current_world_ptr->character_icky--;
152 * Display a string on the screen using an attribute.
154 * At the given location, using the given attribute, if allowed,
155 * add the given string. Do not clear the line.
157 void c_put_str(TERM_COLOR attr, concptr str, TERM_LEN row, TERM_LEN col)
159 Term_putstr(col, row, -1, attr, str);
164 * As above, but in "white"
166 void put_str(concptr str, TERM_LEN row, TERM_LEN col)
168 Term_putstr(col, row, -1, TERM_WHITE, str);
173 * Display a string on the screen using an attribute, and clear
174 * to the end of the line.
176 void c_prt(TERM_COLOR attr, concptr str, TERM_LEN row, TERM_LEN col)
178 Term_erase(col, row, 255);
179 Term_addstr(-1, attr, str);
184 * As above, but in "white"
186 void prt(concptr str, TERM_LEN row, TERM_LEN col)
189 c_prt(TERM_WHITE, str, row, col);
194 * Print some (colored) text to the screen at the current cursor position,
195 * automatically "wrapping" existing text (at spaces) when necessary to
196 * avoid placing any text into the last column, and clearing every line
197 * before placing any text in that line. Also, allow "newline" to force
198 * a "wrap" to the next line. Advance the cursor as needed so sequential
199 * calls to this function will work correctly.
201 * Once this function has been called, the cursor should not be moved
202 * until all the related "c_roff()" calls to the window are complete.
204 * This function will correctly handle any width up to the maximum legal
205 * value of 256, though it works best for a standard 80 character width.
207 void c_roff(TERM_COLOR a, concptr str)
210 (void)Term_get_size(&w, &h);
213 (void)Term_locate(&x, &y);
215 if (y == h - 1 && x > w - 3) return;
217 for (concptr s = str; *s; s++)
221 int k_flag = iskanji(*s);
229 Term_erase(x, y, 255);
234 ch = ((k_flag || isprint(*s)) ? *s : ' ');
236 ch = (isprint(*s) ? *s : ' ');
240 if ((x >= ((k_flag) ? w - 2 : w - 1)) && (ch != ' '))
242 if ((x >= w - 1) && (ch != ' '))
256 for (i = w - 2; i >= 0; i--)
258 Term_what(i, y, &av[i], &cv[i]);
259 if (cv[i] == ' ') break;
263 if (cv[i] == '(') break;
271 /* 文頭が「。」「、」等になるときは、その1つ前の語で改行 */
272 if (strncmp(s, "。", 2) == 0 || strncmp(s, "、", 2) == 0)
274 Term_what(x, y, &av[x], &cv[x]);
275 Term_what(x - 1, y, &av[x - 1], &cv[x - 1]);
276 Term_what(x - 2, y, &av[x - 2], &cv[x - 2]);
285 Term_erase(n, y, 255);
290 Term_erase(x, y, 255);
291 for (i = n; i < w - 1; i++)
294 if (cv[i] == '\0') break;
296 Term_addch(av[i], cv[i]);
302 Term_addch((byte)(a | 0x10), ch);
313 Term_addch((byte)(a | 0x20), ch);
323 * As above, but in "white"
325 void roff(concptr str)
328 c_roff(TERM_WHITE, str);
333 * Clear part of the screen
335 void clear_from(int row)
337 for (int y = row; y < Term->hgt; y++)
339 Term_erase(0, y, 255);
345 * Hack -- special buffer to hold the action of the current keymap
347 static char request_command_buffer[256];
349 static char inkey_from_menu(player_type *player_ptr)
353 int num = 0, max_num, old_num = 0;
357 if (player_ptr->y - panel_row_min > 10) basey = 2;
364 floor_type* floor_ptr = player_ptr->current_floor_ptr;
370 if (!menu) old_num = num;
371 put_str("+----------------------------------------------------+", basey, basex);
372 put_str("| |", basey + 1, basex);
373 put_str("| |", basey + 2, basex);
374 put_str("| |", basey + 3, basex);
375 put_str("| |", basey + 4, basex);
376 put_str("| |", basey + 5, basex);
377 put_str("+----------------------------------------------------+", basey + 6, basex);
379 for (i = 0; i < 10; i++)
382 if (!menu_info[menu][i].cmd) break;
383 menu_name = menu_info[menu][i].name;
384 for (hoge = 0; ; hoge++)
386 if (!special_menu_info[hoge].name[0]) break;
387 if ((menu != special_menu_info[hoge].window) || (i != special_menu_info[hoge].number)) continue;
388 switch (special_menu_info[hoge].jouken)
391 if (player_ptr->pclass == special_menu_info[hoge].jouken_naiyou) menu_name = special_menu_info[hoge].name;
394 if (!floor_ptr->dun_level && !floor_ptr->inside_arena && !floor_ptr->inside_quest)
396 if ((byte)player_ptr->wild_mode == special_menu_info[hoge].jouken_naiyou) menu_name = special_menu_info[hoge].name;
404 put_str(menu_name, basey + 1 + i / 2, basex + 4 + (i % 2) * 24);
409 put_str(_("》", "> "), basey + 1 + num / 2, basex + 2 + (num % 2) * 24);
411 move_cursor_relative(player_ptr->y, player_ptr->x);
413 if ((sub_cmd == ' ') || (sub_cmd == 'x') || (sub_cmd == 'X') || (sub_cmd == '\r') || (sub_cmd == '\n'))
415 if (menu_info[menu][num].fin)
417 cmd = menu_info[menu][num].cmd;
423 menu = menu_info[menu][num].cmd;
429 else if ((sub_cmd == ESCAPE) || (sub_cmd == 'z') || (sub_cmd == 'Z') || (sub_cmd == '0'))
446 else if ((sub_cmd == '2') || (sub_cmd == 'j') || (sub_cmd == 'J'))
451 num = (num + 2) % (max_num - 1);
453 num = (num + 2) % (max_num + 1);
455 else num = (num + 2) % max_num;
457 else if ((sub_cmd == '8') || (sub_cmd == 'k') || (sub_cmd == 'K'))
462 num = (num + max_num - 3) % (max_num - 1);
464 num = (num + max_num - 1) % (max_num + 1);
466 else num = (num + max_num - 2) % max_num;
468 else if ((sub_cmd == '4') || (sub_cmd == '6') || (sub_cmd == 'h') || (sub_cmd == 'H') || (sub_cmd == 'l') || (sub_cmd == 'L'))
470 if ((num % 2) || (num == max_num - 1))
474 else if (num < max_num - 1)
482 if (!inkey_next) inkey_next = "";
489 * Request a command from the user.
491 * Sets player_ptr->command_cmd, player_ptr->command_dir, player_ptr->command_rep,
492 * player_ptr->command_arg. May modify player_ptr->command_new.
494 * Note that "caret" ("^") is treated specially, and is used to
495 * allow manual input of control characters. This can be used
496 * on many machines to request repeated tunneling (Ctrl-H) and
497 * on the Macintosh to request "Control-Caret".
499 * Note that "backslash" is treated specially, and is used to bypass any
500 * keymap entry for the following character. This is useful for macros.
502 * Note that this command is used both in the dungeon and in
503 * stores, and must be careful to work in both situations.
505 * Note that "player_ptr->command_new" may not work any more.
507 void request_command(player_type *player_ptr, int shopping)
517 if (rogue_like_commands)
519 mode = KEYMAP_MODE_ROGUE;
523 mode = KEYMAP_MODE_ORIG;
545 if (!shopping && command_menu && ((cmd == '\r') || (cmd == '\n') || (cmd == 'x') || (cmd == 'X'))
546 && !keymap_act[mode][(byte)(cmd)])
547 cmd = inkey_from_menu(player_ptr);
553 COMMAND_ARG old_arg = command_arg;
555 prt(_("回数: ", "Count: "), 0, 0);
559 if ((cmd == 0x7F) || (cmd == KTRL('H')))
561 command_arg = command_arg / 10;
562 prt(format(_("回数: %d", "Count: %d"), command_arg), 0, 0);
564 else if (cmd >= '0' && cmd <= '9')
566 if (command_arg >= 1000)
573 command_arg = command_arg * 10 + D2I(cmd);
576 prt(format(_("回数: %d", "Count: %d"), command_arg), 0, 0);
584 if (command_arg == 0)
587 prt(format(_("回数: %d", "Count: %d"), command_arg), 0, 0);
592 command_arg = old_arg;
593 prt(format(_("回数: %d", "Count: %d"), command_arg), 0, 0);
596 if ((cmd == ' ') || (cmd == '\n') || (cmd == '\r'))
598 if (!get_com(_("コマンド: ", "Command: "), (char *)&cmd, FALSE))
608 (void)get_com(_("コマンド: ", "Command: "), (char *)&cmd, FALSE);
609 if (!inkey_next) inkey_next = "";
614 if (get_com(_("CTRL: ", "Control: "), (char *)&cmd, FALSE)) cmd = KTRL(cmd);
617 act = keymap_act[mode][(byte)(cmd)];
618 if (act && !inkey_next)
620 (void)strnfmt(request_command_buffer, 256, "%s", act);
621 inkey_next = request_command_buffer;
627 command_cmd = (byte)cmd;
631 if (always_repeat && (command_arg <= 0))
633 if (angband_strchr("TBDoc+", (char)command_cmd))
643 case 'p': command_cmd = 'g'; break;
645 case 'm': command_cmd = 'g'; break;
647 case 's': command_cmd = 'd'; break;
652 for (int i = 0; i < 256; i++)
655 if ((s = keymap_act[mode][i]) != NULL)
657 if (*s == command_cmd && *(s + 1) == 0)
666 caretcmd = command_cmd;
669 for (int i = INVEN_RARM; i < INVEN_TOTAL; i++)
671 object_type *o_ptr = &player_ptr->inventory_list[i];
672 if (!o_ptr->k_idx) continue;
674 if (!o_ptr->inscription) continue;
676 concptr s = quark_str(o_ptr->inscription);
677 s = angband_strchr(s, '^');
681 if ((s[1] == caretcmd) || (s[1] == '*'))
683 if ((s[1] == command_cmd) || (s[1] == '*'))
686 if (!get_check(_("本当ですか? ", "Are you sure? ")))
692 s = angband_strchr(s + 1, '^');
701 * Check a char for "vowel-hood"
703 bool is_a_vowel(int ch)
726 * Called from cmd4.c and a few other places. Just extracts
727 * a direction from the keymap for ch (the last direction,
728 * in fact) byte or char here? I'm thinking that keymaps should
729 * generally only apply to single keys, which makes it no more
730 * than 128, so a char should suffice... but keymap_act is 256...
732 int get_keymap_dir(char ch)
743 if (rogue_like_commands)
745 mode = KEYMAP_MODE_ROGUE;
749 mode = KEYMAP_MODE_ORIG;
752 concptr act = keymap_act[mode][(byte)(ch)];
755 for (concptr s = act; *s; ++s)
757 if (isdigit(*s)) d = D2I(*s);
768 #define REPEAT_MAX 20
770 /* Number of chars saved */
771 static int repeat__cnt = 0;
774 static int repeat__idx = 0;
777 static COMMAND_CODE repeat__key[REPEAT_MAX];
779 void repeat_push(COMMAND_CODE what)
781 if (repeat__cnt == REPEAT_MAX) return;
783 repeat__key[repeat__cnt++] = what;
788 bool repeat_pull(COMMAND_CODE *what)
790 if (repeat__idx == repeat__cnt) return FALSE;
792 *what = repeat__key[repeat__idx++];
796 void repeat_check(void)
798 if (command_cmd == ESCAPE) return;
799 if (command_cmd == ' ') return;
800 if (command_cmd == '\r') return;
801 if (command_cmd == '\n') return;
804 if (command_cmd == 'n')
807 if (repeat_pull(&what))
823 * Array size for which InsertionSort
824 * is used instead of QuickSort
830 * Exchange two sort-entries
831 * (should probably be coded inline
832 * for speed increase)
834 static void swap(tag_type *a, tag_type *b)
845 * Insertion-Sort algorithm
846 * (used by the Quicksort algorithm)
848 static void InsertionSort(tag_type elements[], int number)
851 for (int i = 1; i < number; i++)
855 for (j = i; (j > 0) && (elements[j - 1].tag > tmp.tag); j--)
856 elements[j] = elements[j - 1];
863 * Helper function for Quicksort
865 static tag_type median3(tag_type elements[], int left, int right)
867 int center = (left + right) / 2;
869 if (elements[left].tag > elements[center].tag)
870 swap(&elements[left], &elements[center]);
871 if (elements[left].tag > elements[right].tag)
872 swap(&elements[left], &elements[right]);
873 if (elements[center].tag > elements[right].tag)
874 swap(&elements[center], &elements[right]);
876 swap(&elements[center], &elements[right - 1]);
877 return (elements[right - 1]);
882 * Quicksort algorithm
884 * The "median of three" pivot selection eliminates
885 * the bad case of already sorted input.
887 * We use InsertionSort for smaller sub-arrays,
888 * because it is faster in this case.
890 * For details see: "Data Structures and Algorithm
891 * Analysis in C" by Mark Allen Weiss.
893 static void quicksort(tag_type elements[], int left, int right)
896 if (left + CUTOFF <= right)
898 pivot = median3(elements, left, right);
905 while (elements[++i].tag < pivot.tag);
906 while (elements[--j].tag > pivot.tag);
909 swap(&elements[i], &elements[j]);
914 swap(&elements[i], &elements[right - 1]);
916 quicksort(elements, left, i - 1);
917 quicksort(elements, i + 1, right);
921 InsertionSort(elements + left, right - left + 1);
927 * Frontend for the sorting algorithm
929 * Sorts an array of tagged pointers
930 * with <number> elements.
932 void tag_sort(tag_type elements[], int number)
934 quicksort(elements, 0, number - 1);
938 * Add a series of keypresses to the "queue".
940 * Return any errors generated by Term_keypress() in doing so, or SUCCESS
943 * Catch the "out of space" error before anything is printed.
945 * NB: The keys added here will be interpreted by any macros or keymaps.
947 errr type_string(concptr str, uint len)
952 if (!len) len = strlen(str);
954 Term_activate(term_screen);
955 for (concptr s = str; s < str + len; s++)
957 if (*s == '\0') break;
959 err = Term_keypress(*s);
968 void roff_to_buf(concptr str, int maxlen, char *tbuf, size_t bufsize)
980 bool kinsoku = FALSE;
984 ch[0] = str[read_pt];
987 kanji = iskanji(ch[0]);
991 ch[1] = str[read_pt + 1];
994 if (strcmp(ch, "。") == 0 ||
995 strcmp(ch, "、") == 0 ||
996 strcmp(ch, "ィ") == 0 ||
997 strcmp(ch, "ー") == 0)
1000 else if (!isprint(ch[0]))
1003 if (!isprint(ch[0]))
1007 if (line_len + ch_len > maxlen - 1 || str[read_pt] == '\n')
1009 int word_len = read_pt - word_punct;
1011 if (kanji && !kinsoku)
1015 if (ch[0] == ' ' || word_len >= line_len / 2)
1019 read_pt = word_punct;
1020 if (str[word_punct] == ' ')
1022 write_pt -= word_len;
1025 tbuf[write_pt++] = '\0';
1027 word_punct = read_pt;
1032 word_punct = read_pt;
1035 if (!kinsoku) word_punct = read_pt;
1038 if ((size_t)(write_pt + 3) >= bufsize) break;
1040 tbuf[write_pt++] = ch[0];
1046 tbuf[write_pt++] = ch[1];
1053 tbuf[write_pt] = '\0';
1054 tbuf[write_pt + 1] = '\0';
1060 * The angband_strcpy() function copies up to 'bufsize'-1 characters from 'src'
1061 * to 'buf' and NUL-terminates the result. The 'buf' and 'src' strings may
1064 * angband_strcpy() returns strlen(src). This makes checking for truncation
1065 * easy. Example: if (angband_strcpy(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
1067 * This function should be equivalent to the strlcpy() function in BSD.
1069 size_t angband_strcpy(char *buf, concptr src, size_t bufsize)
1077 /* reserve for NUL termination */
1080 /* Copy as many bytes as will fit */
1081 while (*s && (len < bufsize))
1085 if (len + 1 >= bufsize || !*(s + 1)) break;
1103 size_t len = strlen(src);
1105 if (bufsize == 0) return ret;
1107 if (len >= bufsize) len = bufsize - 1;
1109 (void)memcpy(buf, src, len);
1117 * The angband_strcat() tries to append a string to an existing NUL-terminated string.
1118 * It never writes more characters into the buffer than indicated by 'bufsize' and
1119 * NUL-terminates the buffer. The 'buf' and 'src' strings may not overlap.
1121 * angband_strcat() returns strlen(buf) + strlen(src). This makes checking for
1122 * truncation easy. Example:
1123 * if (angband_strcat(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
1125 * This function should be equivalent to the strlcat() function in BSD.
1127 size_t angband_strcat(char *buf, concptr src, size_t bufsize)
1129 size_t dlen = strlen(buf);
1130 if (dlen < bufsize - 1)
1132 return (dlen + angband_strcpy(buf + dlen, src, bufsize - dlen));
1136 return (dlen + strlen(src));
1142 * A copy of ANSI strstr()
1144 * angband_strstr() can handle Kanji strings correctly.
1146 char *angband_strstr(concptr haystack, concptr needle)
1148 int l1 = strlen(haystack);
1149 int l2 = strlen(needle);
1153 for (int i = 0; i <= l1 - l2; i++)
1155 if (!strncmp(haystack + i, needle, l2))
1156 return (char *)haystack + i;
1159 if (iskanji(*(haystack + i))) i++;
1169 * A copy of ANSI strchr()
1171 * angband_strchr() can handle Kanji strings correctly.
1173 char *angband_strchr(concptr ptr, char ch)
1175 for (; *ptr != '\0'; ptr++)
1177 if (*ptr == ch) return (char *)ptr;
1180 if (iskanji(*ptr)) ptr++;
1189 * Convert string to lower case
1191 void str_tolower(char *str)
1202 *str = (char)tolower(*str);