OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / cmd-io / cmd-macro.cpp
1 #include "cmd-io/cmd-macro.h"
2 #include "cmd-io/cmd-gameoption.h"
3 #include "cmd-io/macro-util.h"
4 #include "core/asking-player.h"
5 #include "game-option/input-options.h"
6 #include "io/files-util.h"
7 #include "io/input-key-acceptor.h"
8 #include "io/input-key-requester.h"
9 #include "io/read-pref-file.h"
10 #include "main/sound-of-music.h"
11 #include "system/player-type-definition.h"
12 #include "term/screen-processor.h"
13 #include "term/term-color-types.h"
14 #include "term/z-form.h"
15 #include "util/angband-files.h"
16 #include "util/int-char-converter.h"
17 #include "util/string-processor.h"
18 #include "view/display-messages.h"
19
20 /*!
21  * @brief マクロ情報をprefファイルに保存する
22  * @param filename ファイル名
23  */
24 static void macro_dump(FILE **fpp, std::string_view filename)
25 {
26     constexpr auto mark = "Macro Dump";
27     const auto &path = path_build(ANGBAND_DIR_USER, filename);
28     if (!open_auto_dump(fpp, path, mark)) {
29         return;
30     }
31
32     auto_dump_printf(*fpp, _("\n# 自動マクロセーブ\n\n", "\n# Automatic macro dump\n\n"));
33
34     for (auto i = 0; i < active_macros; i++) {
35         char buf[1024]{};
36         ascii_to_text(buf, macro_actions[i], sizeof(buf));
37         auto_dump_printf(*fpp, "A:%s\n", buf);
38         ascii_to_text(buf, macro_patterns[i], sizeof(buf));
39         auto_dump_printf(*fpp, "P:%s\n", buf);
40         auto_dump_printf(*fpp, "\n");
41     }
42
43     close_auto_dump(fpp, mark);
44 }
45
46 /*!
47  * @brief マクロのトリガーキーを取得する /
48  * Hack -- ask for a "trigger" (see below)
49  * @param buf キー表記を保管するバッファ
50  * @details
51  * <pre>
52  * Note the complex use of the "inkey()" function from "util.c".
53  *
54  * Note that both "flush()" calls are extremely important.
55  * </pre>
56  */
57 static void do_cmd_macro_aux(char *buf)
58 {
59     flush();
60     inkey_base = true;
61     char i = inkey();
62     int n = 0;
63     while (i) {
64         buf[n++] = i;
65         inkey_base = true;
66         inkey_scan = true;
67         i = inkey();
68     }
69
70     buf[n] = '\0';
71     flush();
72     char tmp[1024];
73     ascii_to_text(tmp, buf, sizeof(tmp));
74     term_addstr(-1, TERM_WHITE, tmp);
75 }
76
77 /*!
78  * @brief マクロのキー表記からアスキーコードを得てターミナルに表示する /
79  * Hack -- ask for a keymap "trigger" (see below)
80  * @param buf キー表記を取得するバッファ
81  * @details
82  * <pre>
83  * Note that both "flush()" calls are extremely important.  This may
84  * no longer be true, since "util.c" is much simpler now.
85  * </pre>
86  */
87 static void do_cmd_macro_aux_keymap(char *buf)
88 {
89     char tmp[1024];
90     flush();
91     buf[0] = inkey();
92     buf[1] = '\0';
93     ascii_to_text(tmp, buf, sizeof(tmp));
94     term_addstr(-1, TERM_WHITE, tmp);
95     flush();
96 }
97
98 /*!
99  * @brief キーマップをprefファイルにダンプする
100  * @param filename ファイルネーム
101  * @return エラーコード
102  */
103 static errr keymap_dump(std::string_view filename)
104 {
105     FILE *auto_dump_stream;
106     char key[1024];
107     BIT_FLAGS mode;
108     if (rogue_like_commands) {
109         mode = KEYMAP_MODE_ROGUE;
110     } else {
111         mode = KEYMAP_MODE_ORIG;
112     }
113
114     const auto &path = path_build(ANGBAND_DIR_USER, filename);
115     constexpr auto mark = "Keymap Dump";
116     if (!open_auto_dump(&auto_dump_stream, path, mark)) {
117         return -1;
118     }
119
120     auto_dump_printf(auto_dump_stream, _("\n# 自動キー配置セーブ\n\n", "\n# Automatic keymap dump\n\n"));
121     for (int i = 0; i < 256; i++) {
122         concptr act;
123         act = keymap_act[mode][i];
124         if (!act) {
125             continue;
126         }
127
128         char buf[1024]{};
129         buf[0] = (char)i;
130         ascii_to_text(key, buf, sizeof(key));
131         ascii_to_text(buf, act, sizeof(buf));
132         auto_dump_printf(auto_dump_stream, "A:%s\n", buf);
133         auto_dump_printf(auto_dump_stream, "C:%d:%s\n", mode, key);
134     }
135
136     close_auto_dump(&auto_dump_stream, mark);
137     return 0;
138 }
139
140 /*!
141  * @brief マクロを設定するコマンドのメインルーチン /
142  * Interact with "macros"
143  * @details
144  * <pre>
145  * Note that the macro "action" must be defined before the trigger.
146  *
147  * Could use some helpful instructions on this page.
148  * </pre>
149  */
150 void do_cmd_macros(PlayerType *player_ptr)
151 {
152     char buf[1024];
153     static char macro_buf[1024];
154     FILE *auto_dump_stream;
155     BIT_FLAGS mode = rogue_like_commands ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG;
156     screen_save();
157     term_clear();
158
159     auto print_macro_menu = [] {
160         prt(_("[ マクロの設定 ]", "Interact with Macros"), 2, 0);
161         prt(_("(1) ユーザー設定ファイルのロード", "(1) Load a user pref file"), 4, 5);
162         prt(_("(2) ファイルにマクロを追加", "(2) Append macros to a file"), 5, 5);
163         prt(_("(3) マクロの確認", "(3) Query a macro"), 6, 5);
164         prt(_("(4) マクロの作成", "(4) Create a macro"), 7, 5);
165         prt(_("(5) マクロの削除", "(5) Remove a macro"), 8, 5);
166         prt(_("(6) ファイルにキー配置を追加", "(6) Append keymaps to a file"), 9, 5);
167         prt(_("(7) キー配置の確認", "(7) Query a keymap"), 10, 5);
168         prt(_("(8) キー配置の作成", "(8) Create a keymap"), 11, 5);
169         prt(_("(9) キー配置の削除", "(9) Remove a keymap"), 12, 5);
170         prt(_("(0) マクロ行動の入力", "(0) Enter a new action"), 13, 5);
171     };
172     print_macro_menu();
173
174     const auto initial_filename = format("%s.prf", player_ptr->base_name);
175     while (true) {
176         msg_print(_("コマンド: ", "Command: "));
177         const auto key = inkey();
178         if (key == ESCAPE) {
179             break;
180         }
181         clear_from(1);
182         print_macro_menu();
183
184         switch (key) {
185         case '1': {
186             prt(_("コマンド: ユーザー設定ファイルのロード", "Command: Load a user pref file"), 16, 0);
187             prt(_("ファイル: ", "File: "), 18, 0);
188             const auto ask_result = askfor(70, initial_filename);
189             if (!ask_result) {
190                 continue;
191             }
192
193             const auto err = process_pref_file(player_ptr, *ask_result, true);
194             const auto *mes = ask_result->data();
195             if (-2 == err) {
196                 msg_format(_("標準の設定ファイル'%s'を読み込みました。", "Loaded default '%s'."), mes);
197             } else if (err) {
198                 msg_format(_("'%s'の読み込みに失敗しました!", "Failed to load '%s'!"), mes);
199             } else {
200                 msg_format(_("'%s'を読み込みました。", "Loaded '%s'."), mes);
201             }
202
203             break;
204         }
205         case '2': {
206             prt(_("コマンド: マクロをファイルに追加する", "Command: Append macros to a file"), 16, 0);
207             prt(_("ファイル: ", "File: "), 18, 0);
208             const auto ask_result = askfor(70, initial_filename);
209             if (!ask_result) {
210                 continue;
211             }
212
213             macro_dump(&auto_dump_stream, *ask_result);
214             msg_print(_("マクロを追加しました。", "Appended macros."));
215             break;
216         }
217         case '3': {
218             prt(_("コマンド: マクロの確認", "Command: Query a macro"), 16, 0);
219             prt(_("マクロ行動が(もしあれば)下に表示されます:", "Current action (if any) shown below:"), 20, 0);
220             prt(_("トリガーキー: ", "Trigger: "), 18, 0);
221             do_cmd_macro_aux(buf);
222             const auto k = macro_find_exact(buf);
223             if (k < 0) {
224                 msg_print(_("そのキーにはマクロは定義されていません。", "Found no macro."));
225                 break;
226             }
227
228             // マクロの作成時に参照するためmacro_bufにコピーする
229             angband_strcpy(macro_buf, macro_actions[k].data(), sizeof(macro_buf));
230             char tmp[81]{};
231             angband_strcpy(tmp, macro_buf, sizeof(tmp));
232             ascii_to_text(buf, tmp, sizeof(buf));
233             prt(buf, 22, 0);
234             msg_print(_("マクロを確認しました。", "Found a macro."));
235             break;
236         }
237         case '4': {
238             prt(_("コマンド: マクロの作成", "Command: Create a macro"), 16, 0);
239             prt(_("トリガーキー: ", "Trigger: "), 18, 0);
240             do_cmd_macro_aux(buf);
241             c_prt(TERM_L_RED,
242                 _("カーソルキーの左右でカーソル位置を移動。BackspaceかDeleteで一文字削除。",
243                     "Press Left/Right arrow keys to move cursor. Backspace/Delete to delete a char."),
244                 22, 0);
245             prt(_("マクロ行動: ", "Action: "), 20, 0);
246             // 最後に参照したマクロデータを元に作成する(コピーを行えるように)
247             macro_buf[80] = '\0';
248             char tmp[81]{};
249             ascii_to_text(tmp, macro_buf, sizeof(tmp));
250             const auto ask_result = askfor(80, tmp);
251             if (!ask_result) {
252                 break;
253             }
254
255             text_to_ascii(macro_buf, *ask_result, sizeof(macro_buf));
256             macro_add(buf, macro_buf);
257             msg_print(_("マクロを追加しました。", "Added a macro."));
258             break;
259         }
260         case '5':
261             prt(_("コマンド: マクロの削除", "Command: Remove a macro"), 16, 0);
262             prt(_("トリガーキー: ", "Trigger: "), 18, 0);
263             do_cmd_macro_aux(buf);
264             macro_add(buf, buf);
265             msg_print(_("マクロを削除しました。", "Removed a macro."));
266             break;
267         case '6': {
268             prt(_("コマンド: キー配置をファイルに追加する", "Command: Append keymaps to a file"), 16, 0);
269             prt(_("ファイル: ", "File: "), 18, 0);
270             const auto ask_result = askfor(80, initial_filename);
271             if (!ask_result) {
272                 continue;
273             }
274
275             (void)keymap_dump(*ask_result);
276             msg_print(_("キー配置を追加しました。", "Appended keymaps."));
277             break;
278         }
279         case '7': {
280             prt(_("コマンド: キー配置の確認", "Command: Query a keymap"), 16, 0);
281             prt(_("マクロ行動が(もしあれば)下に表示されます:", "Current action (if any) shown below:"), 20, 0);
282             prt(_("押すキー: ", "Keypress: "), 18, 0);
283             do_cmd_macro_aux_keymap(buf);
284             concptr act = keymap_act[mode][(byte)(buf[0])];
285             if (!act) {
286                 msg_print(_("キー配置は定義されていません。", "Found no keymap."));
287                 break;
288             }
289
290             // マクロの作成時に参照するためmacro_bufにコピーする
291             angband_strcpy(macro_buf, act, sizeof(macro_buf));
292             // too long macro must die
293             char tmp[81]{};
294             angband_strcpy(tmp, macro_buf, sizeof(tmp));
295             ascii_to_text(buf, tmp, sizeof(buf));
296             prt(buf, 22, 0);
297             msg_print(_("キー配置を確認しました。", "Found a keymap."));
298             break;
299         }
300         case '8': {
301             prt(_("コマンド: キー配置の作成", "Command: Create a keymap"), 16, 0);
302             prt(_("押すキー: ", "Keypress: "), 18, 0);
303             do_cmd_macro_aux_keymap(buf);
304             c_prt(TERM_L_RED,
305                 _("カーソルキーの左右でカーソル位置を移動。BackspaceかDeleteで一文字削除。",
306                     "Press Left/Right arrow keys to move cursor. Backspace/Delete to delete a char."),
307                 22, 0);
308             prt(_("行動: ", "Action: "), 20, 0);
309             // 最後に参照したマクロデータを元に作成する(コピーを行えるように)
310             macro_buf[80] = '\0';
311             char tmp[81]{};
312             ascii_to_text(tmp, macro_buf, sizeof(tmp));
313             const auto ask_result = askfor(80, tmp);
314             if (!ask_result) {
315                 break;
316             }
317
318             text_to_ascii(macro_buf, *ask_result, sizeof(macro_buf));
319             string_free(keymap_act[mode][(byte)(buf[0])]);
320             keymap_act[mode][(byte)(buf[0])] = string_make(macro_buf);
321             msg_print(_("キー配置を追加しました。", "Added a keymap."));
322             break;
323         }
324         case '9':
325             prt(_("コマンド: キー配置の削除", "Command: Remove a keymap"), 16, 0);
326             prt(_("押すキー: ", "Keypress: "), 18, 0);
327             do_cmd_macro_aux_keymap(buf);
328             string_free(keymap_act[mode][(byte)(buf[0])]);
329             keymap_act[mode][(byte)(buf[0])] = nullptr;
330             msg_print(_("キー配置を削除しました。", "Removed a keymap."));
331             break;
332         case '0': {
333             prt(_("コマンド: マクロ行動の入力", "Command: Enter a new action"), 16, 0);
334             c_prt(TERM_L_RED,
335                 _("カーソルキーの左右でカーソル位置を移動。BackspaceかDeleteで一文字削除。",
336                     "Press Left/Right arrow keys to move cursor. Backspace/Delete to delete a char."),
337                 22, 0);
338             prt(_("マクロ行動: ", "Action: "), 20, 0);
339             const auto ask_result = askfor(80);
340             if (!ask_result) {
341                 continue;
342             }
343
344             text_to_ascii(macro_buf, *ask_result, sizeof(macro_buf));
345             break;
346         }
347         default:
348             bell();
349             break;
350         }
351
352         msg_erase();
353     }
354
355     screen_load();
356 }