1 #include "dungeon/quest-completion-checker.h"
2 #include "core/player-update-types.h"
3 #include "dungeon/quest.h"
4 #include "effect/effect-characteristics.h"
5 #include "floor/cave.h"
6 #include "floor/floor-object.h"
7 #include "floor/floor-util.h"
8 #include "grid/feature-flag-types.h"
9 #include "grid/feature.h"
10 #include "grid/grid.h"
11 #include "monster/monster-info.h"
12 #include "object-enchant/item-apply-magic.h"
13 #include "system/floor-type-definition.h"
14 #include "system/grid-type-definition.h"
15 #include "system/monster-type-definition.h"
16 #include "system/object-type-definition.h"
17 #include "system/player-type-definition.h"
18 #include "view/display-messages.h"
20 QuestCompletionChecker::QuestCompletionChecker(player_type *player_ptr, monster_type *m_ptr)
21 : player_ptr(player_ptr)
27 * @brief 特定の敵を倒した際にクエスト達成処理 /
28 * Check for "Quest" completion when a quest monster is killed or charmed.
29 * @param player_ptr プレイヤーへの参照ポインタ
30 * @param m_ptr 撃破したモンスターの構造体参照ポインタ
32 void QuestCompletionChecker::complete()
34 auto *floor_ptr = this->player_ptr->current_floor_ptr;
35 auto quest_num = floor_ptr->inside_quest;
38 for (i = max_q_idx - 1; i > 0; i--) {
39 auto *const q_ptr = &quest[i];
40 if (q_ptr->status != QUEST_STATUS_TAKEN) {
44 if (q_ptr->flags & QUEST_FLAG_PRESET) {
48 if ((q_ptr->level != floor_ptr->dun_level) && (q_ptr->type != QUEST_TYPE_KILL_ANY_LEVEL)) {
52 if ((q_ptr->type == QUEST_TYPE_FIND_ARTIFACT) || (q_ptr->type == QUEST_TYPE_FIND_EXIT)) {
56 if ((q_ptr->type == QUEST_TYPE_KILL_NUMBER) || (q_ptr->type == QUEST_TYPE_TOWER) || (q_ptr->type == QUEST_TYPE_KILL_ALL)) {
60 if (((q_ptr->type == QUEST_TYPE_KILL_LEVEL) || (q_ptr->type == QUEST_TYPE_KILL_ANY_LEVEL) || (q_ptr->type == QUEST_TYPE_RANDOM)) && (q_ptr->r_idx == this->m_ptr->r_idx)) {
68 auto create_stairs = false;
70 if ((quest_num > 0) && (quest[quest_num].status == QUEST_STATUS_TAKEN)) {
71 auto *const q_ptr = &quest[quest_num];
72 switch (q_ptr->type) {
73 case QUEST_TYPE_KILL_NUMBER:
75 if (q_ptr->cur_num >= q_ptr->num_mon) {
76 complete_quest(this->player_ptr, quest_num);
81 case QUEST_TYPE_KILL_ALL:
82 if (!is_hostile(this->m_ptr) || (this->count_all_hostile_monsters() != 1)) {
86 if (q_ptr->flags & QUEST_FLAG_SILENT) {
87 q_ptr->status = QUEST_STATUS_FINISHED;
89 complete_quest(this->player_ptr, quest_num);
93 case QUEST_TYPE_KILL_LEVEL:
94 case QUEST_TYPE_RANDOM:
95 if (q_ptr->r_idx != this->m_ptr->r_idx) {
100 if (q_ptr->cur_num < q_ptr->max_num) {
104 complete_quest(this->player_ptr, quest_num);
105 if (!(q_ptr->flags & QUEST_FLAG_PRESET)) {
106 create_stairs = true;
107 floor_ptr->inside_quest = 0;
110 if ((quest_num == QUEST_OBERON) || (quest_num == QUEST_SERPENT)) {
111 q_ptr->status = QUEST_STATUS_FINISHED;
114 if (q_ptr->type == QUEST_TYPE_RANDOM) {
116 q_ptr->status = QUEST_STATUS_FINISHED;
120 case QUEST_TYPE_KILL_ANY_LEVEL:
122 if (q_ptr->cur_num >= q_ptr->max_num) {
123 complete_quest(this->player_ptr, quest_num);
128 case QUEST_TYPE_TOWER:
129 if (!is_hostile(this->m_ptr)) {
133 if (this->count_all_hostile_monsters() == 1) {
134 q_ptr->status = QUEST_STATUS_STAGE_COMPLETED;
135 if ((quest[QUEST_TOWER1].status == QUEST_STATUS_STAGE_COMPLETED) && (quest[QUEST_TOWER2].status == QUEST_STATUS_STAGE_COMPLETED)
136 && (quest[QUEST_TOWER3].status == QUEST_STATUS_STAGE_COMPLETED)) {
137 complete_quest(this->player_ptr, QUEST_TOWER1);
147 auto y = this->m_ptr->fy;
148 auto x = this->m_ptr->fx;
150 auto *g_ptr = &floor_ptr->grid_array[y][x];
151 while (cave_has_flag_bold(floor_ptr, y, x, FF::PERMANENT) || !g_ptr->o_idx_list.empty() || g_ptr->is_object()) {
154 scatter(this->player_ptr, &ny, &nx, y, x, 1, PROJECT_NONE);
157 g_ptr = &floor_ptr->grid_array[y][x];
160 msg_print(_("魔法の階段が現れた...", "A magical staircase appears..."));
161 cave_set_feat(this->player_ptr, y, x, feat_down_stair);
162 this->player_ptr->update |= PU_FLOW;
170 auto *o_ptr = &forge;
171 for (auto i = 0; i < (floor_ptr->dun_level / 15) + 1; i++) {
173 make_object(this->player_ptr, o_ptr, AM_GOOD | AM_GREAT);
174 (void)drop_near(this->player_ptr, o_ptr, -1, y, x);
179 * @brief 現在フロアに残っている敵モンスターの数を返す /
180 * @return 現在の敵モンスターの数
182 int QuestCompletionChecker::count_all_hostile_monsters()
184 auto *floor_ptr = this->player_ptr->current_floor_ptr;
186 for (auto x = 0; x < floor_ptr->width; ++x) {
187 for (auto y = 0; y < floor_ptr->height; ++y) {
188 auto m_idx = floor_ptr->grid_array[y][x].m_idx;
189 if ((m_idx > 0) && is_hostile(&floor_ptr->m_list[m_idx])) {