OSDN Git Service

[Refactor] Spoiler File作成時のメッセージを分離
[hengbandforosx/hengbandosx.git] / src / wizard / wizard-spoiler.c
1 /*!
2  * @brief スポイラー出力処理 (行数の都合でモンスター進化ツリーもここに入っている)
3  * @date 2014/02/17
4  * @author
5  * Copyright (c) 1997 Ben Harrison, and others
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.
9  * 2013 Deskull rearranged comment for Doxygen.
10  * 2020 Hourier rearranged for decreasing lines.
11  */
12
13 #include "wizard/wizard-spoiler.h"
14 #include "io/files-util.h"
15 #include "io/input-key-acceptor.h"
16 #include "main/sound-of-music.h"
17 #include "monster-race/monster-race.h"
18 #include "system/angband-version.h"
19 #include "term/screen-processor.h"
20 #include "util/angband-files.h"
21 #include "util/int-char-converter.h"
22 #include "util/sort.h"
23 #include "view/display-messages.h"
24 #include "wizard/fixed-artifacts-spoiler.h"
25 #include "wizard/items-spoiler.h"
26 #include "wizard/monster-info-spoiler.h"
27 #include "wizard/spoiler-util.h"
28
29 /*!
30  * @brief int配列でstrncmp()と似た比較処理を行う /
31  * Compare two int-type array like strncmp() and return TRUE if equals
32  * @param a 比較するint配列1
33  * @param b 比較するint配列2
34  * @param length
35  * @return 両者の値が等しければTRUEを返す
36  */
37 static bool int_n_cmp(int *a, int *b, int length)
38 {
39     if (!length)
40         return TRUE;
41
42     do {
43         if (*a != *(b++))
44             return FALSE;
45         if (!(*(a++)))
46             break;
47     } while (--length);
48
49     return TRUE;
50 }
51
52 /*!
53  * @brief ある木が指定された木の部分木かどうかを返す /
54  * Returns TRUE if an evolution tree is "partial tree"
55  * @param tree 元となる木構造リスト
56  * @param partial_tree 部分木かどうか判定したい木構造リスト
57  * @return 部分木ならばTRUEを返す
58  */
59 static bool is_partial_tree(int *tree, int *partial_tree)
60 {
61     int pt_head = *(partial_tree++);
62     int pt_len = 0;
63     while (partial_tree[pt_len])
64         pt_len++;
65
66     while (*tree) {
67         if (*(tree++) == pt_head) {
68             if (int_n_cmp(tree, partial_tree, pt_len))
69                 return TRUE;
70         }
71     }
72
73     return FALSE;
74 }
75
76 /*!
77  * @brief 進化ツリーをスポイラー出力するメインルーチン /
78  * Print monsters' evolution information to file
79  * @param fname 出力ファイル名
80  * @return なし
81  */
82 static spoiler_output_status spoil_mon_evol(concptr fname)
83 {
84     char buf[1024];
85     monster_race *r_ptr;
86     player_type dummy;
87     int **evol_tree, i, j, n, r_idx;
88     int *evol_tree_zero; /* For C_KILL() */
89     path_build(buf, sizeof buf, ANGBAND_DIR_USER, fname);
90     spoiler_file = angband_fopen(buf, "w");
91     if (!spoiler_file) {
92         return SPOILER_OUTPUT_FAIL_FOPEN;
93     }
94
95     char title[200];
96     put_version(title);
97     sprintf(buf, "Monster Spoilers for %s\n", title);
98     spoil_out(buf);
99
100     spoil_out("------------------------------------------\n\n");
101     C_MAKE(evol_tree, max_r_idx, int *);
102     C_MAKE(*evol_tree, max_r_idx * (max_evolution_depth + 1), int);
103     for (i = 1; i < max_r_idx; i++)
104         evol_tree[i] = *evol_tree + i * (max_evolution_depth + 1);
105
106     evol_tree_zero = *evol_tree;
107     for (i = 1; i < max_r_idx; i++) {
108         r_ptr = &r_info[i];
109         if (!r_ptr->next_exp)
110             continue;
111
112         n = 0;
113         evol_tree[i][n++] = i;
114         do {
115             evol_tree[i][n++] = r_ptr->next_r_idx;
116             r_ptr = &r_info[r_ptr->next_r_idx];
117         } while (r_ptr->next_exp && (n < max_evolution_depth));
118     }
119
120     for (i = 1; i < max_r_idx; i++) {
121         if (!evol_tree[i][0])
122             continue;
123
124         for (j = 1; j < max_r_idx; j++) {
125             if (i == j)
126                 continue;
127
128             if (!evol_tree[j][0])
129                 continue;
130
131             if (is_partial_tree(evol_tree[j], evol_tree[i])) {
132                 evol_tree[i][0] = 0;
133                 break;
134             }
135         }
136     }
137
138     ang_sort(&dummy, evol_tree, NULL, max_r_idx, ang_sort_comp_evol_tree, ang_sort_swap_evol_tree);
139     for (i = 0; i < max_r_idx; i++) {
140         r_idx = evol_tree[i][0];
141         if (!r_idx)
142             continue;
143
144         r_ptr = &r_info[r_idx];
145         fprintf(spoiler_file, _("[%d]: %s (レベル%d, '%c')\n", "[%d]: %s (Level %d, '%c')\n"), r_idx, r_name + r_ptr->name, (int)r_ptr->level, r_ptr->d_char);
146         for (n = 1; r_ptr->next_exp; n++) {
147             fprintf(spoiler_file, "%*s-(%ld)-> ", n * 2, "", (long int)r_ptr->next_exp);
148             fprintf(spoiler_file, "[%d]: ", r_ptr->next_r_idx);
149             r_ptr = &r_info[r_ptr->next_r_idx];
150             fprintf(spoiler_file, _("%s (レベル%d, '%c')\n", "%s (Level %d, '%c')\n"), r_name + r_ptr->name, (int)r_ptr->level, r_ptr->d_char);
151         }
152
153         fputc('\n', spoiler_file);
154     }
155
156     C_KILL(evol_tree_zero, max_r_idx * (max_evolution_depth + 1), int);
157     C_KILL(evol_tree, max_r_idx, int *);
158     if (ferror(spoiler_file) || angband_fclose(spoiler_file)) {
159         return SPOILER_OUTPUT_FAIL_FCLOSE;
160     }
161     return SPOILER_OUTPUT_SUCCESS;
162 }
163
164 /*!
165  * @brief スポイラー出力を行うコマンドのメインルーチン /
166  * Create Spoiler files -BEN-
167  * @return なし
168  */
169 void exe_output_spoilers(void)
170 {
171     screen_save();
172     while (TRUE) {
173         spoiler_output_status status = SPOILER_OUTPUT_CANCEL;
174         term_clear();
175         prt("Create a spoiler file.", 2, 0);
176         prt("(1) Brief Object Info (obj-desc.txt)", 5, 5);
177         prt("(2) Brief Artifact Info (artifact.txt)", 6, 5);
178         prt("(3) Brief Monster Info (mon-desc.txt)", 7, 5);
179         prt("(4) Full Monster Info (mon-info.txt)", 8, 5);
180         prt("(5) Monster Evolution Info (mon-evol.txt)", 9, 5);
181         prt(_("コマンド:", "Command: "), _(18, 12), 0);
182         switch (inkey()) {
183         case ESCAPE:
184             screen_load();
185             return;
186         case '1':
187             status = spoil_obj_desc("obj-desc.txt");
188             break;
189         case '2':
190             status = spoil_fixed_artifact("artifact.txt");
191             break;
192         case '3':
193             status = spoil_mon_desc("mon-desc.txt");
194             break;
195         case '4':
196             status = spoil_mon_info("mon-info.txt");
197             break;
198         case '5':
199             status = spoil_mon_evol("mon-evol.txt");
200             break;
201         default:
202             bell();
203             break;
204         }
205
206         switch (status) {
207         case SPOILER_OUTPUT_FAIL_FOPEN:
208             msg_print("Cannot create spoiler file.");
209             break;
210         case SPOILER_OUTPUT_FAIL_FCLOSE:
211             msg_print("Cannot close spoiler file.");
212             break;
213         case SPOILER_OUTPUT_SUCCESS:
214             msg_print("Successfully created a spoiler file.");
215             break;
216         }
217         msg_erase();
218     }
219 }