OSDN Git Service

Since struct dirent only holds the last element in the path, build the full path...
[hengband/hengband.git] / src / knowledge / knowledge-quests.c
1 /*!
2  * @brief 既知のクエストを表示する
3  * @date 2020/04/23
4  * @author Hourier
5  */
6
7 #include "knowledge-quests.h"
8 #include "core/show-file.h"
9 #include "dungeon/dungeon.h"
10 #include "dungeon/quest.h"
11 #include "flavor/flavor-describer.h"
12 #include "flavor/object-flavor-types.h"
13 #include "info-reader/fixed-map-parser.h"
14 #include "io-dump/dump-util.h"
15 #include "locale/english.h"
16 #include "monster-race/monster-race.h"
17 #include "object-enchant/special-object-flags.h"
18 #include "object/object-generator.h"
19 #include "object/object-kind-hook.h"
20 #include "system/artifact-type-definition.h"
21 #include "system/floor-type-definition.h"
22 #include "system/system-variables.h" // 暫定、init_flagsのため。後で消すかも.
23 #include "term/screen-processor.h"
24 #include "util/angband-files.h"
25 #include "util/sort.h"
26 #include "world/world.h"
27
28 /*
29  * Check on the status of an active quest
30  * @param creature_ptr プレーヤーへの参照ポインタ
31  * @return なし
32  */
33 void do_cmd_checkquest(player_type *creature_ptr)
34 {
35     screen_save();
36     do_cmd_knowledge_quests(creature_ptr);
37     screen_load();
38 }
39
40 /*
41  * todo player_typeではなくQUEST_IDXを引数にすべきかもしれない
42  * Print all active quests
43  * @param creature_ptr プレーヤーへの参照ポインタ
44  * @return なし
45  */
46 static void do_cmd_knowledge_quests_current(player_type *creature_ptr, FILE *fff)
47 {
48     char tmp_str[120];
49     char rand_tmp_str[120] = "\0";
50     GAME_TEXT name[MAX_NLEN];
51     monster_race *r_ptr;
52     int rand_level = 100;
53     int total = 0;
54
55     fprintf(fff, _("《遂行中のクエスト》\n", "< Current Quest >\n"));
56
57     for (QUEST_IDX i = 1; i < max_q_idx; i++) {
58         bool is_print = quest[i].status == QUEST_STATUS_TAKEN;
59         is_print |= (quest[i].status == QUEST_STATUS_STAGE_COMPLETED) && (quest[i].type == QUEST_TYPE_TOWER);
60         is_print |= quest[i].status == QUEST_STATUS_COMPLETED;
61         if (!is_print)
62             continue;
63
64         QUEST_IDX old_quest = creature_ptr->current_floor_ptr->inside_quest;
65         for (int j = 0; j < 10; j++)
66             quest_text[j][0] = '\0';
67
68         quest_text_line = 0;
69         creature_ptr->current_floor_ptr->inside_quest = i;
70         init_flags = INIT_SHOW_TEXT;
71         parse_fixed_map(creature_ptr, "q_info.txt", 0, 0, 0, 0);
72         creature_ptr->current_floor_ptr->inside_quest = old_quest;
73         if (quest[i].flags & QUEST_FLAG_SILENT)
74             continue;
75
76         total++;
77         if (quest[i].type != QUEST_TYPE_RANDOM) {
78             char note[80] = "\0";
79
80             if (quest[i].status == QUEST_STATUS_TAKEN || quest[i].status == QUEST_STATUS_STAGE_COMPLETED) {
81                 switch (quest[i].type) {
82                 case QUEST_TYPE_KILL_LEVEL:
83                 case QUEST_TYPE_KILL_ANY_LEVEL:
84                     r_ptr = &r_info[quest[i].r_idx];
85                     strcpy(name, r_name + r_ptr->name);
86                     if (quest[i].max_num > 1) {
87 #ifdef JP
88                         sprintf(note, " - %d 体の%sを倒す。(あと %d 体)", (int)quest[i].max_num, name, (int)(quest[i].max_num - quest[i].cur_num));
89 #else
90                         plural_aux(name);
91                         sprintf(note, " - kill %d %s, have killed %d.", (int)quest[i].max_num, name, (int)quest[i].cur_num);
92 #endif
93                     } else
94                         sprintf(note, _(" - %sを倒す。", " - kill %s."), name);
95                     break;
96
97                 case QUEST_TYPE_FIND_ARTIFACT:
98                     if (quest[i].k_idx) {
99                         artifact_type *a_ptr = &a_info[quest[i].k_idx];
100                         object_type forge;
101                         object_type *q_ptr = &forge;
102                         KIND_OBJECT_IDX k_idx = lookup_kind(a_ptr->tval, a_ptr->sval);
103                         object_prep(creature_ptr, q_ptr, k_idx);
104                         q_ptr->name1 = quest[i].k_idx;
105                         q_ptr->ident = IDENT_STORE;
106                         describe_flavor(creature_ptr, name, q_ptr, OD_NAME_ONLY);
107                     }
108                     sprintf(note, _("\n   - %sを見つけ出す。", "\n   - Find %s."), name);
109                     break;
110                 case QUEST_TYPE_FIND_EXIT:
111                     sprintf(note, _(" - 出口に到達する。", " - Reach exit."));
112                     break;
113
114                 case QUEST_TYPE_KILL_NUMBER:
115 #ifdef JP
116                     sprintf(note, " - %d 体のモンスターを倒す。(あと %d 体)", (int)quest[i].max_num, (int)(quest[i].max_num - quest[i].cur_num));
117 #else
118                     sprintf(note, " - Kill %d monsters, have killed %d.", (int)quest[i].max_num, (int)quest[i].cur_num);
119 #endif
120                     break;
121
122                 case QUEST_TYPE_KILL_ALL:
123                 case QUEST_TYPE_TOWER:
124                     sprintf(note, _(" - 全てのモンスターを倒す。", " - Kill all monsters."));
125                     break;
126                 }
127             }
128
129             sprintf(tmp_str, _("  %s (危険度:%d階相当)%s\n", "  %s (Danger level: %d)%s\n"), quest[i].name, (int)quest[i].level, note);
130             fputs(tmp_str, fff);
131             if (quest[i].status == QUEST_STATUS_COMPLETED) {
132                 sprintf(tmp_str, _("    クエスト達成 - まだ報酬を受けとってない。\n", "    Quest Completed - Unrewarded\n"));
133                 fputs(tmp_str, fff);
134                 continue;
135             }
136
137             int k = 0;
138             while (quest_text[k][0] && k < 10) {
139                 fprintf(fff, "    %s\n", quest_text[k]);
140                 k++;
141             }
142
143             continue;
144         }
145
146         if (quest[i].level >= rand_level)
147             continue;
148
149         rand_level = quest[i].level;
150         if (max_dlv[DUNGEON_ANGBAND] < rand_level)
151             continue;
152
153         r_ptr = &r_info[quest[i].r_idx];
154         strcpy(name, r_name + r_ptr->name);
155         if (quest[i].max_num <= 1) {
156             sprintf(rand_tmp_str, _("  %s (%d 階) - %sを倒す。\n", "  %s (Dungeon level: %d)\n  Kill %s.\n"), quest[i].name, (int)quest[i].level, name);
157             continue;
158         }
159
160 #ifdef JP
161         sprintf(rand_tmp_str, "  %s (%d 階) - %d 体の%sを倒す。(あと %d 体)\n", quest[i].name, (int)quest[i].level, (int)quest[i].max_num, name,
162             (int)(quest[i].max_num - quest[i].cur_num));
163 #else
164         plural_aux(name);
165
166         sprintf(rand_tmp_str, "  %s (Dungeon level: %d)\n  Kill %d %s, have killed %d.\n", quest[i].name, (int)quest[i].level, (int)quest[i].max_num, name,
167             (int)quest[i].cur_num);
168 #endif
169     }
170
171     if (rand_tmp_str[0])
172         fputs(rand_tmp_str, fff);
173
174     if (!total)
175         fprintf(fff, _("  なし\n", "  Nothing.\n"));
176 }
177
178 static bool do_cmd_knowledge_quests_aux(player_type *player_ptr, FILE *fff, IDX q_idx)
179 {
180     char tmp_str[120];
181     char playtime_str[16];
182     quest_type *const q_ptr = &quest[q_idx];
183
184     floor_type *floor_ptr = player_ptr->current_floor_ptr;
185     if (is_fixed_quest_idx(q_idx)) {
186         IDX old_quest = floor_ptr->inside_quest;
187         floor_ptr->inside_quest = q_idx;
188         init_flags = INIT_NAME_ONLY;
189         parse_fixed_map(player_ptr, "q_info.txt", 0, 0, 0, 0);
190         floor_ptr->inside_quest = old_quest;
191         if (q_ptr->flags & QUEST_FLAG_SILENT)
192             return FALSE;
193     }
194
195     strnfmt(playtime_str, sizeof(playtime_str), "%02d:%02d:%02d", q_ptr->comptime / (60 * 60), (q_ptr->comptime / 60) % 60, q_ptr->comptime % 60);
196
197     if (is_fixed_quest_idx(q_idx) || (q_ptr->r_idx == 0)) {
198         sprintf(tmp_str, _("  %-35s (危険度:%3d階相当) - レベル%2d - %s\n", "  %-35s (Danger  level: %3d) - level %2d - %s\n"), q_ptr->name, (int)q_ptr->level,
199             q_ptr->complev, playtime_str);
200         fputs(tmp_str, fff);
201         return TRUE;
202     }
203
204     if (q_ptr->complev == 0) {
205         sprintf(tmp_str, _("  %-35s (%3d階)            -   不戦勝 - %s\n", "  %-35s (Dungeon level: %3d) - Unearned - %s\n"),
206             r_name + r_info[q_ptr->r_idx].name, (int)q_ptr->level, playtime_str);
207         fputs(tmp_str, fff);
208         return TRUE;
209     }
210
211     sprintf(tmp_str, _("  %-35s (%3d階)            - レベル%2d - %s\n", "  %-35s (Dungeon level: %3d) - level %2d - %s\n"), r_name + r_info[q_ptr->r_idx].name,
212         (int)q_ptr->level, q_ptr->complev, playtime_str);
213     fputs(tmp_str, fff);
214     return TRUE;
215 }
216
217 /*
218  * Print all finished quests
219  * @param creature_ptr プレーヤーへの参照ポインタ
220  * @param fff セーブファイル (展開済?)
221  * @param quest_num[] 受注したことのあるクエスト群
222  * @return なし
223  */
224 void do_cmd_knowledge_quests_completed(player_type *creature_ptr, FILE *fff, QUEST_IDX quest_num[])
225 {
226     fprintf(fff, _("《達成したクエスト》\n", "< Completed Quest >\n"));
227     QUEST_IDX total = 0;
228     for (QUEST_IDX i = 1; i < max_q_idx; i++) {
229         QUEST_IDX q_idx = quest_num[i];
230         quest_type *const q_ptr = &quest[q_idx];
231
232         if (q_ptr->status == QUEST_STATUS_FINISHED && do_cmd_knowledge_quests_aux(creature_ptr, fff, q_idx)) {
233             ++total;
234         }
235     }
236
237     if (!total)
238         fprintf(fff, _("  なし\n", "  Nothing.\n"));
239 }
240
241 /*
242  * Print all failed quests
243  * @param creature_ptr プレーヤーへの参照ポインタ
244  * @param fff セーブファイル (展開済?)
245  * @param quest_num[] 受注したことのあるクエスト群
246  * @return なし
247  */
248 void do_cmd_knowledge_quests_failed(player_type *creature_ptr, FILE *fff, QUEST_IDX quest_num[])
249 {
250     fprintf(fff, _("《失敗したクエスト》\n", "< Failed Quest >\n"));
251     QUEST_IDX total = 0;
252     for (QUEST_IDX i = 1; i < max_q_idx; i++) {
253         QUEST_IDX q_idx = quest_num[i];
254         quest_type *const q_ptr = &quest[q_idx];
255
256         if (((q_ptr->status == QUEST_STATUS_FAILED_DONE) || (q_ptr->status == QUEST_STATUS_FAILED)) && do_cmd_knowledge_quests_aux(creature_ptr, fff, q_idx)) {
257             ++total;
258         }
259     }
260
261     if (!total)
262         fprintf(fff, _("  なし\n", "  Nothing.\n"));
263 }
264
265 /*
266  * Print all random quests
267  */
268 static void do_cmd_knowledge_quests_wiz_random(FILE *fff)
269 {
270     fprintf(fff, _("《残りのランダムクエスト》\n", "< Remaining Random Quest >\n"));
271     GAME_TEXT tmp_str[120];
272     QUEST_IDX total = 0;
273     for (QUEST_IDX i = 1; i < max_q_idx; i++) {
274         if (quest[i].flags & QUEST_FLAG_SILENT)
275             continue;
276
277         if ((quest[i].type == QUEST_TYPE_RANDOM) && (quest[i].status == QUEST_STATUS_TAKEN)) {
278             total++;
279             sprintf(tmp_str, _("  %s (%d階, %s)\n", "  %s (%d, %s)\n"), quest[i].name, (int)quest[i].level, r_name + r_info[quest[i].r_idx].name);
280             fputs(tmp_str, fff);
281         }
282     }
283
284     if (!total)
285         fprintf(fff, _("  なし\n", "  Nothing.\n"));
286 }
287
288 /*
289  * Print quest status of all active quests
290  * @param creature_ptr プレーヤーへの参照ポインタ
291  * @return なし
292  */
293 void do_cmd_knowledge_quests(player_type *creature_ptr)
294 {
295     FILE *fff = NULL;
296     GAME_TEXT file_name[FILE_NAME_SIZE];
297     if (!open_temporary_file(&fff, file_name))
298         return;
299
300     IDX *quest_num;
301     C_MAKE(quest_num, max_q_idx, QUEST_IDX);
302
303     for (IDX i = 1; i < max_q_idx; i++)
304         quest_num[i] = i;
305
306     int dummy;
307     ang_sort(creature_ptr, quest_num, &dummy, max_q_idx, ang_sort_comp_quest_num, ang_sort_swap_quest_num);
308
309     do_cmd_knowledge_quests_current(creature_ptr, fff);
310     fputc('\n', fff);
311     do_cmd_knowledge_quests_completed(creature_ptr, fff, quest_num);
312     fputc('\n', fff);
313     do_cmd_knowledge_quests_failed(creature_ptr, fff, quest_num);
314     if (current_world_ptr->wizard) {
315         fputc('\n', fff);
316         do_cmd_knowledge_quests_wiz_random(fff);
317     }
318
319     angband_fclose(fff);
320     (void)show_file(creature_ptr, TRUE, file_name, _("クエスト達成状況", "Quest status"), 0, 0);
321     fd_kill(file_name);
322     C_KILL(quest_num, max_q_idx, QUEST_IDX);
323 }