OSDN Git Service

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