OSDN Git Service

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