OSDN Git Service

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