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;
58 fprintf(fff, _("《遂行中のクエスト》\n", "< Current Quest >\n"));
60 for (const auto &[q_idx, quest] : quest_list) {
61 if (q_idx == QuestId::NONE) {
65 auto is_print = quest.status == QuestStatusType::TAKEN;
66 is_print |= (quest.status == QuestStatusType::STAGE_COMPLETED) && (quest.type == QuestKindType::TOWER);
67 is_print |= quest.status == QuestStatusType::COMPLETED;
72 const auto old_quest = player_ptr->current_floor_ptr->quest_number;
73 for (int j = 0; j < 10; j++) {
74 quest_text[j][0] = '\0';
78 player_ptr->current_floor_ptr->quest_number = q_idx;
79 init_flags = INIT_SHOW_TEXT;
80 parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
81 player_ptr->current_floor_ptr->quest_number = old_quest;
82 if (quest.flags & QUEST_FLAG_SILENT) {
87 if (quest.type != QuestKindType::RANDOM) {
89 if (quest.status == QuestStatusType::TAKEN || quest.status == QuestStatusType::STAGE_COMPLETED) {
91 case QuestKindType::KILL_LEVEL: {
92 const auto &monrace = monraces_info[quest.r_idx];
93 if (quest.max_num > 1) {
95 note = format(" - %d 体の%sを倒す。(あと %d 体)", (int)quest.max_num, monrace.name.data(), (int)(quest.max_num - quest.cur_num));
97 auto monster_name(monrace.name);
98 plural_aux(monster_name.data());
99 note = format(" - kill %d %s, have killed %d.", (int)quest.max_num, monster_name.data(), (int)quest.cur_num);
102 note = format(_(" - %sを倒す。", " - kill %s."), monrace.name.data());
107 case QuestKindType::FIND_ARTIFACT: {
108 std::string item_name("");
109 if (quest.has_reward()) {
110 const auto &artifact = quest.get_reward();
112 auto bi_id = lookup_baseitem_id(artifact.bi_key);
114 item.fixed_artifact_idx = quest.reward_artifact_idx;
115 item.ident = IDENT_STORE;
116 item_name = describe_flavor(player_ptr, &item, OD_NAME_ONLY);
119 note = format(_("\n - %sを見つけ出す。", "\n - Find %s."), item_name.data());
122 case QuestKindType::FIND_EXIT:
123 note = _(" - 出口に到達する。", " - Reach exit.");
125 case QuestKindType::KILL_NUMBER:
127 note = format(" - %d 体のモンスターを倒す。(あと %d 体)", (int)quest.max_num, (int)(quest.max_num - quest.cur_num));
129 note = format(" - Kill %d monsters, have killed %d.", (int)quest.max_num, (int)quest.cur_num);
133 case QuestKindType::KILL_ALL:
134 case QuestKindType::TOWER:
135 note = _(" - 全てのモンスターを倒す。", " - Kill all monsters.");
142 fprintf(fff, _(" %s (危険度:%d階相当)%s\n", " %s (Danger level: %d)%s\n"), quest.name.data(), (int)quest.level, note.data());
143 if (quest.status == QuestStatusType::COMPLETED) {
144 fputs(_(" クエスト達成 - まだ報酬を受けとってない。\n", " Quest Completed - Unrewarded\n"), fff);
149 while (quest_text[k][0] && k < 10) {
150 fprintf(fff, " %s\n", quest_text[k]);
157 if (quest.level >= rand_level) {
160 rand_level = quest.level;
161 if (max_dlv[DUNGEON_ANGBAND] < rand_level) {
165 const auto &monrace = monraces_info[quest.r_idx];
166 if (quest.max_num <= 1) {
167 constexpr auto mes = _(" %s (%d 階) - %sを倒す。\n", " %s (Dungeon level: %d)\n Kill %s.\n");
168 rand_tmp_str = format(mes, quest.name.data(), (int)quest.level, monrace.name.data());
173 rand_tmp_str = format(" %s (%d 階) - %d 体の%sを倒す。(あと %d 体)\n", quest.name.data(), (int)quest.level, (int)quest.max_num, monrace.name.data(),
174 (int)(quest.max_num - quest.cur_num));
176 auto monster_name(monrace.name);
177 plural_aux(monster_name.data());
178 rand_tmp_str = format(" %s (Dungeon level: %d)\n Kill %d %s, have killed %d.\n", quest.name.data(), (int)quest.level, (int)quest.max_num,
179 monster_name.data(), (int)quest.cur_num);
183 if (!rand_tmp_str.empty()) {
184 fputs(rand_tmp_str.data(), fff);
188 fprintf(fff, _(" なし\n", " Nothing.\n"));
192 static bool do_cmd_knowledge_quests_aux(PlayerType *player_ptr, FILE *fff, QuestId q_idx)
194 const auto &quest_list = QuestList::get_instance();
195 const auto &quest = quest_list[q_idx];
197 auto *floor_ptr = player_ptr->current_floor_ptr;
198 auto is_fixed_quest = QuestType::is_fixed(q_idx);
199 if (is_fixed_quest) {
200 QuestId old_quest = floor_ptr->quest_number;
201 floor_ptr->quest_number = q_idx;
202 init_flags = INIT_NAME_ONLY;
203 parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
204 floor_ptr->quest_number = old_quest;
205 if (quest.flags & QUEST_FLAG_SILENT) {
210 std::string playtime_str = format("%02d:%02d:%02d", quest.comptime / (60 * 60), (quest.comptime / 60) % 60, quest.comptime % 60);
212 auto fputs_name_remain = [fff](const auto &name) {
213 for (auto i = 1U; i < name.size(); ++i) {
214 fprintf(fff, " %s\n", name[i].data());
218 if (is_fixed_quest || !MonsterRace(quest.r_idx).is_valid()) {
219 auto name = str_separate(quest.name, 35);
220 constexpr auto mes = _(" %-35s (危険度:%3d階相当) - レベル%2d - %s\n", " %-35s (Danger level: %3d) - level %2d - %s\n");
221 fprintf(fff, mes, name.front().data(), (int)quest.level, quest.complev, playtime_str.data());
222 fputs_name_remain(name);
226 auto name = str_separate(monraces_info[quest.r_idx].name, 35);
227 if (quest.complev == 0) {
228 constexpr auto mes = _(" %-35s (%3d階) - 不戦勝 - %s\n", " %-35s (Dungeon level: %3d) - Unearned - %s\n");
229 fprintf(fff, mes, name.front().data(), (int)quest.level, playtime_str.data());
230 fputs_name_remain(name);
234 const auto mes = _(" %-35s (%3d階) - レベル%2d - %s\n", " %-35s (Dungeon level: %3d) - level %2d - %s\n");
235 fprintf(fff, mes, name.front().data(), (int)quest.level, quest.complev, playtime_str.data());
236 fputs_name_remain(name);
241 * Print all finished quests
242 * @param player_ptr プレイヤーへの参照ポインタ
243 * @param fff セーブファイル (展開済?)
244 * @param quest_numbers 受注したことのあるクエスト群
246 void do_cmd_knowledge_quests_completed(PlayerType *player_ptr, FILE *fff, const std::vector<QuestId> &quest_numbers)
248 fprintf(fff, _("《達成したクエスト》\n", "< Completed Quest >\n"));
250 for (auto &q_idx : quest_numbers) {
251 const auto &quest_list = QuestList::get_instance();
252 const auto &quest = quest_list[q_idx];
253 if (quest.status == QuestStatusType::FINISHED && do_cmd_knowledge_quests_aux(player_ptr, fff, q_idx)) {
259 fprintf(fff, _(" なし\n", " Nothing.\n"));
264 * Print all failed quests
265 * @param player_ptr プレイヤーへの参照ポインタ
266 * @param fff セーブファイル (展開済?)
267 * @param quest_numbers 受注したことのあるクエスト群
269 void do_cmd_knowledge_quests_failed(PlayerType *player_ptr, FILE *fff, const std::vector<QuestId> &quest_numbers)
271 fprintf(fff, _("《失敗したクエスト》\n", "< Failed Quest >\n"));
273 for (auto &q_idx : quest_numbers) {
274 const auto &quest_list = QuestList::get_instance();
275 const auto &quest = quest_list[q_idx];
276 if (((quest.status == QuestStatusType::FAILED_DONE) || (quest.status == QuestStatusType::FAILED)) && do_cmd_knowledge_quests_aux(player_ptr, fff, q_idx)) {
282 fprintf(fff, _(" なし\n", " Nothing.\n"));
287 * Print all random quests
289 static void do_cmd_knowledge_quests_wiz_random(FILE *fff)
291 fprintf(fff, _("《残りのランダムクエスト》\n", "< Remaining Random Quest >\n"));
292 const auto &quest_list = QuestList::get_instance();
294 for (const auto &[q_idx, quest] : quest_list) {
295 if (quest.flags & QUEST_FLAG_SILENT) {
299 if ((quest.type == QuestKindType::RANDOM) && (quest.status == QuestStatusType::TAKEN)) {
301 constexpr auto mes = _(" %s (%d階, %s)\n", " %s (%d, %s)\n");
302 fprintf(fff, mes, quest.name.data(), (int)quest.level, monraces_info[quest.r_idx].name.data());
307 fprintf(fff, _(" なし\n", " Nothing.\n"));
312 * Print quest status of all active quests
313 * @param player_ptr プレイヤーへの参照ポインタ
315 void do_cmd_knowledge_quests(PlayerType *player_ptr)
318 GAME_TEXT file_name[FILE_NAME_SIZE];
319 if (!open_temporary_file(&fff, file_name)) {
323 std::vector<QuestId> quest_numbers;
324 const auto &quest_list = QuestList::get_instance();
325 for (const auto &[q_idx, quest] : quest_list) {
326 quest_numbers.push_back(q_idx);
329 ang_sort(player_ptr, quest_numbers.data(), &dummy, quest_numbers.size(), ang_sort_comp_quest_num, ang_sort_swap_quest_num);
331 do_cmd_knowledge_quests_current(player_ptr, fff);
333 do_cmd_knowledge_quests_completed(player_ptr, fff, quest_numbers);
335 do_cmd_knowledge_quests_failed(player_ptr, fff, quest_numbers);
338 do_cmd_knowledge_quests_wiz_random(fff);
342 (void)show_file(player_ptr, true, file_name, _("クエスト達成状況", "Quest status"), 0, 0);