OSDN Git Service

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