OSDN Git Service

536d6a1192737f43a865107f3a3976e19f24d8e1
[hengbandforosx/hengbandosx.git] / src / io / interpret-pref-file.cpp
1 /*!
2  * @brief prefファイルの内容を解釈しメモリに展開する
3  * @date 2020/03/01
4  * @author Hourier
5  */
6
7 #include "io/interpret-pref-file.h"
8 #include "birth/character-builder.h"
9 #include "cmd-io/macro-util.h"
10 #include "game-option/game-play-options.h"
11 #include "game-option/option-flags.h"
12 #include "game-option/option-types-table.h"
13 #include "grid/feature.h"
14 #include "io/gf-descriptions.h"
15 #include "io/input-key-requester.h"
16 #include "io/tokenizer.h"
17 #include "monster-race/monster-race.h"
18 #include "object/object-kind.h"
19 #include "system/game-option-types.h"
20 #include "system/monster-race-definition.h"
21 #include "system/player-type-definition.h"
22 #include "term/gameterm.h"
23 #include "util/quarks.h"
24 #include "util/string-processor.h"
25 #include "view/display-messages.h"
26 #include "world/world.h"
27
28 #define MAX_MACRO_CHARS 16128 // 1つのマクロキー押下で実行可能なコマンド最大数 (エスケープシーケンス含む).
29
30 char *histpref_buf = nullptr;
31
32 /*!
33  * @brief Rトークンの解釈 / Process "R:<num>:<a>/<c>" -- attr/char for monster races
34  * @param buf バッファ
35  * @return エラーコード
36  */
37 static errr interpret_r_token(char *buf)
38 {
39     char *zz[16];
40     if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3)
41         return 1;
42
43     monster_race *r_ptr;
44     int i = (int)strtol(zz[0], nullptr, 0);
45     TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], nullptr, 0);
46     SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], nullptr, 0);
47     if (i >= static_cast<int>(r_info.size()))
48         return 1;
49
50     r_ptr = &r_info[i];
51     if (n1 || (!(n2 & 0x80) && n2))
52         r_ptr->x_attr = n1; /* Allow TERM_DARK text */
53     if (n2)
54         r_ptr->x_char = n2;
55
56     return 0;
57 }
58
59 /*!
60  * @brief Kトークンの解釈 / Process "K:<num>:<a>/<c>"  -- attr/char for object kinds
61  * @param buf バッファ
62  * @return エラーコード
63  */
64 static errr interpret_k_token(char *buf)
65 {
66     char *zz[16];
67     if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3)
68         return 1;
69
70     object_kind *k_ptr;
71     int i = (int)strtol(zz[0], nullptr, 0);
72     TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], nullptr, 0);
73     SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], nullptr, 0);
74     if (i >= static_cast<int>(k_info.size()))
75         return 1;
76
77     k_ptr = &k_info[i];
78     if (n1 || (!(n2 & 0x80) && n2))
79         k_ptr->x_attr = n1; /* Allow TERM_DARK text */
80     if (n2)
81         k_ptr->x_char = n2;
82
83     return 0;
84 }
85
86 /*!
87  * @brief トークン数によって地形の文字形と色を決定する
88  * @param i 地形種別
89  * @param num トークン数
90  * @return エラーコード
91  */
92 static errr decide_feature_type(int i, int num, char **zz)
93 {
94     feature_type *f_ptr;
95     f_ptr = &f_info[i];
96
97     TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], nullptr, 0);
98     SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], nullptr, 0);
99     if (n1 || (!(n2 & 0x80) && n2))
100         f_ptr->x_attr[F_LIT_STANDARD] = n1; /* Allow TERM_DARK text */
101     if (n2)
102         f_ptr->x_char[F_LIT_STANDARD] = n2;
103
104     switch (num) {
105     case 3: {
106         /* No lighting support */
107         n1 = f_ptr->x_attr[F_LIT_STANDARD];
108         n2 = f_ptr->x_char[F_LIT_STANDARD];
109         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
110             f_ptr->x_attr[j] = n1;
111             f_ptr->x_char[j] = n2;
112         }
113
114         return 0;
115     }
116     case 4: {
117         /* Use default lighting */
118         apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
119         return 0;
120     }
121     case F_LIT_MAX * 2 + 1: {
122         /* Use desired lighting */
123         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
124             n1 = (TERM_COLOR)strtol(zz[j * 2 + 1], nullptr, 0);
125             n2 = (SYMBOL_CODE)strtol(zz[j * 2 + 2], nullptr, 0);
126             if (n1 || (!(n2 & 0x80) && n2))
127                 f_ptr->x_attr[j] = n1; /* Allow TERM_DARK text */
128             if (n2)
129                 f_ptr->x_char[j] = n2;
130         }
131
132         return 0;
133     }
134     default:
135         return 0;
136     }
137 }
138
139 /*!
140  * @brief Fトークンの解釈 / Process "F:<num>:<a>/<c>" -- attr/char for terrain features
141  * @param buf バッファ
142  * @return エラーコード
143  * @details
144  * "F:<num>:<a>/<c>"
145  * "F:<num>:<a>/<c>:LIT"
146  * "F:<num>:<a>/<c>:<la>/<lc>:<da>/<dc>"
147  */
148 static errr interpret_f_token(char *buf)
149 {
150     char *zz[16];
151     int num = tokenize(buf + 2, F_LIT_MAX * 2 + 1, zz, TOKENIZE_CHECKQUOTE);
152
153     if ((num != 3) && (num != 4) && (num != F_LIT_MAX * 2 + 1))
154         return 1;
155     else if ((num == 4) && !streq(zz[3], "LIT"))
156         return 1;
157
158     int i = (int)strtol(zz[0], nullptr, 0);
159     if (i >= static_cast<int>(f_info.size()))
160         return 1;
161
162     return decide_feature_type(i, num, zz);
163 }
164
165 /*!
166  * @brief Fトークンの解釈 / Process "S:<num>:<a>/<c>" -- attr/char for special things
167  * @param buf バッファ
168  * @return エラーコード
169  */
170 static errr interpret_s_token(char *buf)
171 {
172     char *zz[16];
173     if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3)
174         return 1;
175
176     int j = (byte)strtol(zz[0], nullptr, 0);
177     TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], nullptr, 0);
178     SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], nullptr, 0);
179     misc_to_attr[j] = n1;
180     misc_to_char[j] = n2;
181     return 0;
182 }
183
184 /*!
185  * @brief Uトークンの解釈 / Process "U:<tv>:<a>/<c>" -- attr/char for unaware items
186  * @param buf バッファ
187  * @return エラーコード
188  */
189 static errr interpret_u_token(char *buf)
190 {
191     char *zz[16];
192     if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3)
193         return 1;
194
195     int j = (int)strtol(zz[0], nullptr, 0);
196     TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], nullptr, 0);
197     SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], nullptr, 0);
198     for (auto &k_ref : k_info) {
199         if ((k_ref.idx > 0) && (enum2i(k_ref.tval) == j)) {
200             if (n1)
201                 k_ref.d_attr = n1;
202             if (n2)
203                 k_ref.d_char = n2;
204         }
205     }
206
207     return 0;
208 }
209
210 /*!
211  * @brief Eトークンの解釈 / Process "E:<tv>:<a>" -- attribute for inventory objects
212  * @param buf バッファ
213  * @return エラーコード
214  */
215 static errr interpret_e_token(char *buf)
216 {
217     char *zz[16];
218     if (tokenize(buf + 2, 2, zz, TOKENIZE_CHECKQUOTE) != 2)
219         return 1;
220
221     int j = (byte)strtol(zz[0], nullptr, 0) % 128;
222     TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], nullptr, 0);
223     if (n1)
224         tval_to_attr[j] = n1;
225     return 0;
226 }
227
228 /*!
229  * @brief Pトークンの解釈 / Process "P:<str>" -- normal macro
230  * @param buf バッファ
231  * @return エラーコード
232  */
233 static errr interpret_p_token(char *buf)
234 {
235     char tmp[1024];
236     text_to_ascii(tmp, buf + 2);
237     return macro_add(tmp, macro__buf.data());
238 }
239
240 /*!
241  * @brief Cトークンの解釈 / Process "C:<str>" -- create keymap
242  * @param buf バッファ
243  * @return エラーコード
244  */
245 static errr interpret_c_token(char *buf)
246 {
247     char *zz[16];
248     if (tokenize(buf + 2, 2, zz, TOKENIZE_CHECKQUOTE) != 2)
249         return 1;
250
251     int mode = strtol(zz[0], nullptr, 0);
252     if ((mode < 0) || (mode >= KEYMAP_MODES))
253         return 1;
254
255     char tmp[1024];
256     text_to_ascii(tmp, zz[1]);
257     if (!tmp[0] || tmp[1])
258         return 1;
259
260     int i = (byte)(tmp[0]);
261     string_free(keymap_act[mode][i]);
262     keymap_act[mode][i] = string_make(macro__buf.data());
263     return 0;
264 }
265
266 /*!
267  * @brief Vトークンの解釈 / Process "V:<num>:<kv>:<rv>:<gv>:<bv>" -- visual info
268  * @param buf バッファ
269  * @return エラーコード
270  */
271 static errr interpret_v_token(char *buf)
272 {
273     char *zz[16];
274     if (tokenize(buf + 2, 5, zz, TOKENIZE_CHECKQUOTE) != 5)
275         return 1;
276
277     int i = (byte)strtol(zz[0], nullptr, 0);
278     angband_color_table[i][0] = (byte)strtol(zz[1], nullptr, 0);
279     angband_color_table[i][1] = (byte)strtol(zz[2], nullptr, 0);
280     angband_color_table[i][2] = (byte)strtol(zz[3], nullptr, 0);
281     angband_color_table[i][3] = (byte)strtol(zz[4], nullptr, 0);
282     return 0;
283 }
284
285 /*!
286  * @brief X/Yトークンの解釈
287  * @param player_ptr プレイヤーへの参照ポインタ
288  * @param buf バッファ
289  * @return エラーコード
290  * @details
291  * Process "X:<str>" -- turn option off
292  * Process "Y:<str>" -- turn option on
293  */
294 static errr interpret_xy_token(player_type *player_ptr, char *buf)
295 {
296     for (int i = 0; option_info[i].o_desc; i++) {
297         bool is_option = option_info[i].o_var != nullptr;
298         is_option &= option_info[i].o_text != nullptr;
299         is_option &= streq(option_info[i].o_text, buf + 2);
300         if (!is_option)
301             continue;
302
303         int os = option_info[i].o_set;
304         int ob = option_info[i].o_bit;
305
306         if ((player_ptr->playing || w_ptr->character_xtra) && (OPT_PAGE_BIRTH == option_info[i].o_page) && !allow_debug_options) {
307             msg_format(_("初期オプションは変更できません! '%s'", "Birth options can not changed! '%s'"), buf);
308             msg_print(nullptr);
309             return 0;
310         }
311
312         if (buf[0] == 'X') {
313             option_flag[os] &= ~(1UL << ob);
314             (*option_info[i].o_var) = false;
315             return 0;
316         }
317
318         option_flag[os] |= (1UL << ob);
319         (*option_info[i].o_var) = true;
320         return 0;
321     }
322
323     msg_format(_("オプションの名前が正しくありません: %s", "Ignored invalid option: %s"), buf);
324     msg_print(nullptr);
325     return 0;
326 }
327
328 /*!
329  * @brief Zトークンの解釈 / Process "Z:<type>:<str>" -- set spell color
330  * @param buf バッファ
331  * @param zz トークン保管文字列
332  * @return エラーコード
333  */
334 static errr interpret_z_token(char *buf)
335 {
336     char *t = angband_strchr(buf + 2, ':');
337     if (!t)
338         return 1;
339
340     *(t++) = '\0';
341     for (int i = 0; i < MAX_NAMED_NUM; i++) {
342         if (!streq(gf_desc[i].name, buf + 2))
343             continue;
344
345         gf_color[gf_desc[i].num] = (TERM_COLOR)quark_add(t);
346         return 0;
347     }
348
349     return 1;
350 }
351
352 /*!
353  * @brief Tトークンの解釈 / Process "T:<template>:<modifier chr>:<modifier name>:..." for 4 tokens
354  * @param buf バッファ
355  * @param zz トークン保管文字列
356  * @return エラーコード
357  */
358 static errr decide_template_modifier(int tok, char **zz)
359 {
360     if (macro_template != nullptr) {
361         int macro_modifier_length = strlen(macro_modifier_chr);
362         string_free(macro_template);
363         macro_template = nullptr;
364         string_free(macro_modifier_chr);
365         for (int i = 0; i < macro_modifier_length; i++) {
366             string_free(macro_modifier_name[i]);
367         }
368
369         for (int i = 0; i < max_macrotrigger; i++) {
370             string_free(macro_trigger_name[i]);
371             string_free(macro_trigger_keycode[0][i]);
372             string_free(macro_trigger_keycode[1][i]);
373         }
374
375         max_macrotrigger = 0;
376     }
377
378     if (*zz[0] == '\0')
379         return 0;
380
381     int zz_length = strlen(zz[1]);
382     zz_length = std::min(MAX_MACRO_MOD, zz_length);
383     if (2 + zz_length != tok)
384         return 1;
385
386     macro_template = string_make(zz[0]);
387     macro_modifier_chr = string_make(zz[1]);
388     for (int i = 0; i < zz_length; i++) {
389         macro_modifier_name[i] = string_make(zz[2 + i]);
390     }
391
392     return 0;
393 }
394
395 /*!
396  * @brief Tトークンの解釈 / Process "T:<trigger>:<keycode>:<shift-keycode>" for 2 or 3 tokens
397  * @param tok トークン数
398  * @param zz トークン保管文字列
399  * @return エラーコード
400  */
401 static errr interpret_macro_keycodes(int tok, char **zz)
402 {
403     char buf_aux[MAX_MACRO_CHARS];
404     char *t, *s;
405     if (max_macrotrigger >= MAX_MACRO_TRIG) {
406         msg_print(_("マクロトリガーの設定が多すぎます!", "Too many macro triggers!"));
407         return 1;
408     }
409
410     int m = max_macrotrigger;
411     max_macrotrigger++;
412     t = buf_aux;
413     s = zz[0];
414     while (*s) {
415         if ('\\' == *s)
416             s++;
417         *t++ = *s++;
418     }
419
420     *t = '\0';
421     macro_trigger_name[m] = string_make(buf_aux);
422     macro_trigger_keycode[0][m] = string_make(zz[1]);
423     if (tok == 3) {
424         macro_trigger_keycode[1][m] = string_make(zz[2]);
425         return 0;
426     }
427
428     macro_trigger_keycode[1][m] = string_make(zz[1]);
429     return 0;
430 }
431
432 /*!
433  * @brief Tトークンの個数調査 (解釈はサブルーチンで) / Initialize macro trigger names and a template
434  * @param buf バッファ
435  * @return エラーコード
436  * @todo 2.2.1r時点のコードからトークン数0~1の場合もエラーコード0だが、1であるべきでは?
437  */
438 static errr interpret_t_token(char *buf)
439 {
440     char *zz[16];
441     int tok = tokenize(buf + 2, 2 + MAX_MACRO_MOD, zz, 0);
442     if (tok >= 4)
443         return decide_template_modifier(tok, zz);
444     if (tok < 2)
445         return 0;
446
447     return interpret_macro_keycodes(tok, zz);
448 }
449
450 /*!
451  * @brief 設定ファイルの各行から各種テキスト情報を取得する /
452  * Parse a sub-file of the "extra info" (format shown below)
453  * @param player_ptr プレイヤーへの参照ポインタ
454  * @param buf データテキストの参照ポインタ
455  * @return エラーコード
456  * @details
457  * <pre>
458  * Each "action" line has an "action symbol" in the first column,
459  * followed by a colon, followed by some command specific info,
460  * usually in the form of "tokens" separated by colons or slashes.
461  * Blank lines, lines starting with white space, and lines starting
462  * with pound signs ("#") are ignored (as comments).
463  * Note the use of "tokenize()" to allow the use of both colons and
464  * slashes as delimeters, while still allowing final tokens which
465  * may contain any characters including "delimiters".
466  * Note the use of "strtol()" to allow all "integers" to be encoded
467  * in decimal, hexidecimal, or octal form.
468  * Note that "monster zero" is used for the "player" attr/char, "object
469  * zero" will be used for the "stack" attr/char, and "feature zero" is
470  * used for the "nothing" attr/char.
471  * </pre>
472  */
473 errr interpret_pref_file(player_type *player_ptr, char *buf)
474 {
475     if (buf[1] != ':')
476         return 1;
477
478     switch (buf[0]) {
479     case 'H': {
480         /* Process "H:<history>" */
481         add_history_from_pref_line(buf + 2);
482         return 0;
483     }
484     case 'R':
485         return interpret_r_token(buf);
486     case 'K':
487         return interpret_k_token(buf);
488     case 'F':
489         return interpret_f_token(buf);
490     case 'S':
491         return interpret_s_token(buf);
492     case 'U':
493         return interpret_u_token(buf);
494     case 'E':
495         return interpret_e_token(buf);
496     case 'A': {
497         /* Process "A:<str>" -- save an "action" for later */
498         text_to_ascii(macro__buf.data(), buf + 2);
499         return 0;
500     }
501     case 'P':
502         return interpret_p_token(buf);
503     case 'C':
504         return interpret_c_token(buf);
505     case 'V':
506         return interpret_v_token(buf);
507     case 'X':
508     case 'Y':
509         return interpret_xy_token(player_ptr, buf);
510     case 'Z':
511         return interpret_z_token(buf);
512     case 'T':
513         return interpret_t_token(buf);
514     default:
515         return 1;
516     }
517 }
518
519 /*!
520  * @brief 生い立ちメッセージの内容をバッファに加える。 / Hook function for reading the histpref.prf file.
521  */
522 void add_history_from_pref_line(concptr t)
523 {
524     if (!histpref_buf)
525         return;
526
527     angband_strcat(histpref_buf, t, HISTPREF_LIMIT);
528 }