7 #include "knowledge/knowledge-quests.h"
8 #include "artifact/fixed-art-types.h"
9 #include "core/show-file.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-kind-hook.h"
19 #include "system/artifact-type-definition.h"
20 #include "system/baseitem-info.h"
21 #include "system/dungeon-info.h"
22 #include "system/floor-type-definition.h"
23 #include "system/item-entity.h"
24 #include "system/monster-race-info.h"
25 #include "system/player-type-definition.h"
26 #include "term/screen-processor.h"
27 #include "term/z-form.h"
28 #include "util/angband-files.h"
29 #include "util/enum-converter.h"
30 #include "util/sort.h"
31 #include "util/string-processor.h"
32 #include "world/world.h"
36 * @brief Check on the status of an active quest
37 * @param player_ptr プレイヤーへの参照ポインタ
39 void do_cmd_checkquest(PlayerType *player_ptr)
42 do_cmd_knowledge_quests(player_ptr);
47 * @brief Print all active quests
48 * @param player_ptr プレイヤーへの参照ポインタ
49 * @todo PlayerTypeではなくQUEST_IDXを引数にすべきかもしれない
51 static void do_cmd_knowledge_quests_current(PlayerType *player_ptr, FILE *fff)
53 const auto &quest_list = QuestList::get_instance();
54 std::string rand_tmp_str;
55 GAME_TEXT name[MAX_NLEN];
56 MonsterRaceInfo *r_ptr;
60 fprintf(fff, _("《遂行中のクエスト》\n", "< Current Quest >\n"));
62 for (const auto &[q_idx, q_ref] : quest_list) {
63 bool is_print = q_ref.status == QuestStatusType::TAKEN;
64 is_print |= (q_ref.status == QuestStatusType::STAGE_COMPLETED) && (q_ref.type == QuestKindType::TOWER);
65 is_print |= q_ref.status == QuestStatusType::COMPLETED;
70 QuestId old_quest = player_ptr->current_floor_ptr->quest_number;
71 for (int j = 0; j < 10; j++) {
72 quest_text[j][0] = '\0';
76 player_ptr->current_floor_ptr->quest_number = q_idx;
77 init_flags = INIT_SHOW_TEXT;
78 parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
79 player_ptr->current_floor_ptr->quest_number = old_quest;
80 if (q_ref.flags & QUEST_FLAG_SILENT) {
84 if (q_ref.type != QuestKindType::RANDOM) {
86 if (q_ref.status == QuestStatusType::TAKEN || q_ref.status == QuestStatusType::STAGE_COMPLETED) {
88 case QuestKindType::KILL_LEVEL:
89 r_ptr = &monraces_info[q_ref.r_idx];
90 if (q_ref.max_num > 1) {
92 note = format(" - %d 体の%sを倒す。(あと %d 体)", (int)q_ref.max_num, r_ptr->name.data(), (int)(q_ref.max_num - q_ref.cur_num));
94 angband_strcpy(name, r_ptr->name.data(), sizeof(name));
96 note = format(" - kill %d %s, have killed %d.", (int)q_ref.max_num, name, (int)q_ref.cur_num);
99 note = format(_(" - %sを倒す。", " - kill %s."), r_ptr->name.data());
103 case QuestKindType::FIND_ARTIFACT:
104 if (q_ref.reward_artifact_idx != FixedArtifactId::NONE) {
105 const auto &a_ref = artifacts_info.at(q_ref.reward_artifact_idx);
107 auto bi_id = lookup_baseitem_id(a_ref.bi_key);
109 item.fixed_artifact_idx = q_ref.reward_artifact_idx;
110 item.ident = IDENT_STORE;
111 describe_flavor(player_ptr, name, &item, OD_NAME_ONLY);
114 note = format(_("\n - %sを見つけ出す。", "\n - Find %s."), name);
116 case QuestKindType::FIND_EXIT:
117 note = _(" - 出口に到達する。", " - Reach exit.");
119 case QuestKindType::KILL_NUMBER:
121 note = format(" - %d 体のモンスターを倒す。(あと %d 体)", (int)q_ref.max_num, (int)(q_ref.max_num - q_ref.cur_num));
123 note = format(" - Kill %d monsters, have killed %d.", (int)q_ref.max_num, (int)q_ref.cur_num);
127 case QuestKindType::KILL_ALL:
128 case QuestKindType::TOWER:
129 note = _(" - 全てのモンスターを倒す。", " - Kill all monsters.");
136 fprintf(fff, _(" %s (危険度:%d階相当)%s\n", " %s (Danger level: %d)%s\n"), q_ref.name, (int)q_ref.level, note.data());
137 if (q_ref.status == QuestStatusType::COMPLETED) {
138 fputs(_(" クエスト達成 - まだ報酬を受けとってない。\n", " Quest Completed - Unrewarded\n"), fff);
143 while (quest_text[k][0] && k < 10) {
144 fprintf(fff, " %s\n", quest_text[k]);
151 if (q_ref.level >= rand_level) {
154 rand_level = q_ref.level;
155 if (max_dlv[DUNGEON_ANGBAND] < rand_level) {
159 r_ptr = &monraces_info[q_ref.r_idx];
160 if (q_ref.max_num <= 1) {
161 rand_tmp_str = format(_(" %s (%d 階) - %sを倒す。\n", " %s (Dungeon level: %d)\n Kill %s.\n"), q_ref.name, (int)q_ref.level, r_ptr->name.data());
166 rand_tmp_str = format(" %s (%d 階) - %d 体の%sを倒す。(あと %d 体)\n", q_ref.name, (int)q_ref.level, (int)q_ref.max_num, r_ptr->name.data(),
167 (int)(q_ref.max_num - q_ref.cur_num));
169 angband_strcpy(name, r_ptr->name.data(), sizeof(name));
172 rand_tmp_str = format(" %s (Dungeon level: %d)\n Kill %d %s, have killed %d.\n", q_ref.name, (int)q_ref.level, (int)q_ref.max_num, name,
177 if (!rand_tmp_str.empty()) {
178 fputs(rand_tmp_str.data(), fff);
182 fprintf(fff, _(" なし\n", " Nothing.\n"));
186 static bool do_cmd_knowledge_quests_aux(PlayerType *player_ptr, FILE *fff, QuestId q_idx)
188 const auto &quest_list = QuestList::get_instance();
189 const auto &q_ref = quest_list[q_idx];
191 auto *floor_ptr = player_ptr->current_floor_ptr;
192 auto is_fixed_quest = quest_type::is_fixed(q_idx);
193 if (is_fixed_quest) {
194 QuestId old_quest = floor_ptr->quest_number;
195 floor_ptr->quest_number = q_idx;
196 init_flags = INIT_NAME_ONLY;
197 parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
198 floor_ptr->quest_number = old_quest;
199 if (q_ref.flags & QUEST_FLAG_SILENT) {
204 std::string playtime_str = format("%02d:%02d:%02d", q_ref.comptime / (60 * 60), (q_ref.comptime / 60) % 60, q_ref.comptime % 60);
206 auto fputs_name_remain = [fff](const auto &name) {
207 for (auto i = 1U; i < name.size(); ++i) {
208 fprintf(fff, " %s\n", name[i].data());
212 if (is_fixed_quest || !MonsterRace(q_ref.r_idx).is_valid()) {
213 auto name = str_separate(q_ref.name, 35);
214 fprintf(fff, _(" %-35s (危険度:%3d階相当) - レベル%2d - %s\n", " %-35s (Danger level: %3d) - level %2d - %s\n"), name.front().data(), (int)q_ref.level,
215 q_ref.complev, playtime_str.data());
216 fputs_name_remain(name);
220 auto name = str_separate(monraces_info[q_ref.r_idx].name, 35);
221 if (q_ref.complev == 0) {
222 fprintf(fff, _(" %-35s (%3d階) - 不戦勝 - %s\n", " %-35s (Dungeon level: %3d) - Unearned - %s\n"),
223 name.front().data(), (int)q_ref.level, playtime_str.data());
224 fputs_name_remain(name);
228 fprintf(fff, _(" %-35s (%3d階) - レベル%2d - %s\n", " %-35s (Dungeon level: %3d) - level %2d - %s\n"), name.front().data(),
229 (int)q_ref.level, q_ref.complev, playtime_str.data());
230 fputs_name_remain(name);
235 * Print all finished quests
236 * @param player_ptr プレイヤーへの参照ポインタ
237 * @param fff セーブファイル (展開済?)
238 * @param quest_numbers 受注したことのあるクエスト群
240 void do_cmd_knowledge_quests_completed(PlayerType *player_ptr, FILE *fff, const std::vector<QuestId> &quest_numbers)
242 fprintf(fff, _("《達成したクエスト》\n", "< Completed Quest >\n"));
244 for (auto &q_idx : quest_numbers) {
245 const auto &quest_list = QuestList::get_instance();
246 const auto &q_ref = quest_list[q_idx];
248 if (q_ref.status == QuestStatusType::FINISHED && do_cmd_knowledge_quests_aux(player_ptr, fff, q_idx)) {
254 fprintf(fff, _(" なし\n", " Nothing.\n"));
259 * Print all failed quests
260 * @param player_ptr プレイヤーへの参照ポインタ
261 * @param fff セーブファイル (展開済?)
262 * @param quest_numbers 受注したことのあるクエスト群
264 void do_cmd_knowledge_quests_failed(PlayerType *player_ptr, FILE *fff, const std::vector<QuestId> &quest_numbers)
266 fprintf(fff, _("《失敗したクエスト》\n", "< Failed Quest >\n"));
268 for (auto &q_idx : quest_numbers) {
269 const auto &quest_list = QuestList::get_instance();
270 const auto &q_ref = quest_list[q_idx];
272 if (((q_ref.status == QuestStatusType::FAILED_DONE) || (q_ref.status == QuestStatusType::FAILED)) && do_cmd_knowledge_quests_aux(player_ptr, fff, q_idx)) {
278 fprintf(fff, _(" なし\n", " Nothing.\n"));
283 * Print all random quests
285 static void do_cmd_knowledge_quests_wiz_random(FILE *fff)
287 fprintf(fff, _("《残りのランダムクエスト》\n", "< Remaining Random Quest >\n"));
288 const auto &quest_list = QuestList::get_instance();
290 for (const auto &[q_idx, q_ref] : quest_list) {
291 if (q_ref.flags & QUEST_FLAG_SILENT) {
295 if ((q_ref.type == QuestKindType::RANDOM) && (q_ref.status == QuestStatusType::TAKEN)) {
297 fprintf(fff, _(" %s (%d階, %s)\n", " %s (%d, %s)\n"), q_ref.name, (int)q_ref.level, monraces_info[q_ref.r_idx].name.data());
302 fprintf(fff, _(" なし\n", " Nothing.\n"));
307 * Print quest status of all active quests
308 * @param player_ptr プレイヤーへの参照ポインタ
310 void do_cmd_knowledge_quests(PlayerType *player_ptr)
313 GAME_TEXT file_name[FILE_NAME_SIZE];
314 if (!open_temporary_file(&fff, file_name)) {
318 std::vector<QuestId> quest_numbers;
319 const auto &quest_list = QuestList::get_instance();
320 for (const auto &[q_idx, q_ref] : quest_list) {
321 quest_numbers.push_back(q_idx);
324 ang_sort(player_ptr, quest_numbers.data(), &dummy, quest_numbers.size(), ang_sort_comp_quest_num, ang_sort_swap_quest_num);
326 do_cmd_knowledge_quests_current(player_ptr, fff);
328 do_cmd_knowledge_quests_completed(player_ptr, fff, quest_numbers);
330 do_cmd_knowledge_quests_failed(player_ptr, fff, quest_numbers);
333 do_cmd_knowledge_quests_wiz_random(fff);
337 (void)show_file(player_ptr, true, file_name, _("クエスト達成状況", "Quest status"), 0, 0);