OSDN Git Service

[Refactor] #1710 Definitions QUEST_STATUS_* to enum class QuestStatusType
[hengbandforosx/hengbandosx.git] / src / dungeon / quest-completion-checker.cpp
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"
19
20 QuestCompletionChecker::QuestCompletionChecker(player_type *player_ptr, monster_type *m_ptr)
21     : player_ptr(player_ptr)
22     , m_ptr(m_ptr)
23 {
24 }
25
26 /*!
27  * @brief 特定の敵を倒した際にクエスト達成処理 /
28  * Check for "Quest" completion when a quest monster is killed or charmed.
29  * @param player_ptr プレイヤーへの参照ポインタ
30  * @param m_ptr 撃破したモンスターの構造体参照ポインタ
31  */
32 void QuestCompletionChecker::complete()
33 {
34     auto *floor_ptr = this->player_ptr->current_floor_ptr;
35     auto quest_num = floor_ptr->inside_quest;
36     if (!quest_num) {
37         short i;
38         for (i = max_q_idx - 1; i > 0; i--) {
39             auto *const q_ptr = &quest[i];
40             if (q_ptr->status != QuestStatusType::TAKEN) {
41                 continue;
42             }
43
44             if (q_ptr->flags & QUEST_FLAG_PRESET) {
45                 continue;
46             }
47
48             if ((q_ptr->level != floor_ptr->dun_level) && (q_ptr->type != QUEST_TYPE_KILL_ANY_LEVEL)) {
49                 continue;
50             }
51
52             if ((q_ptr->type == QUEST_TYPE_FIND_ARTIFACT) || (q_ptr->type == QUEST_TYPE_FIND_EXIT)) {
53                 continue;
54             }
55
56             if ((q_ptr->type == QUEST_TYPE_KILL_NUMBER) || (q_ptr->type == QUEST_TYPE_TOWER) || (q_ptr->type == QUEST_TYPE_KILL_ALL)) {
57                 break;
58             }
59
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)) {
61                 break;
62             }
63         }
64
65         quest_num = i;
66     }
67
68     auto create_stairs = false;
69     auto reward = false;
70     if ((quest_num > 0) && (quest[quest_num].status == QuestStatusType::TAKEN)) {
71         auto *const q_ptr = &quest[quest_num];
72         switch (q_ptr->type) {
73         case QUEST_TYPE_KILL_NUMBER:
74             q_ptr->cur_num++;
75             if (q_ptr->cur_num >= q_ptr->num_mon) {
76                 complete_quest(this->player_ptr, quest_num);
77                 q_ptr->cur_num = 0;
78             }
79
80             break;
81         case QUEST_TYPE_KILL_ALL:
82             if (!is_hostile(this->m_ptr) || (this->count_all_hostile_monsters() != 1)) {
83                 break;
84             }
85
86             if (q_ptr->flags & QUEST_FLAG_SILENT) {
87                 q_ptr->status = QuestStatusType::FINISHED;
88             } else {
89                 complete_quest(this->player_ptr, quest_num);
90             }
91
92             break;
93         case QUEST_TYPE_KILL_LEVEL:
94         case QUEST_TYPE_RANDOM:
95             if (q_ptr->r_idx != this->m_ptr->r_idx) {
96                 break;
97             }
98
99             q_ptr->cur_num++;
100             if (q_ptr->cur_num < q_ptr->max_num) {
101                 break;
102             }
103
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;
108             }
109
110             if ((quest_num == QUEST_OBERON) || (quest_num == QUEST_SERPENT)) {
111                 q_ptr->status = QuestStatusType::FINISHED;
112             }
113
114             if (q_ptr->type == QUEST_TYPE_RANDOM) {
115                 reward = true;
116                 q_ptr->status = QuestStatusType::FINISHED;
117             }
118
119             break;
120         case QUEST_TYPE_KILL_ANY_LEVEL:
121             q_ptr->cur_num++;
122             if (q_ptr->cur_num >= q_ptr->max_num) {
123                 complete_quest(this->player_ptr, quest_num);
124                 q_ptr->cur_num = 0;
125             }
126
127             break;
128         case QUEST_TYPE_TOWER:
129             if (!is_hostile(this->m_ptr)) {
130                 break;
131             }
132
133             if (this->count_all_hostile_monsters() == 1) {
134                 q_ptr->status = QuestStatusType::STAGE_COMPLETED;
135                 if ((quest[QUEST_TOWER1].status == QuestStatusType::STAGE_COMPLETED) && (quest[QUEST_TOWER2].status == QuestStatusType::STAGE_COMPLETED)
136                     && (quest[QUEST_TOWER3].status == QuestStatusType::STAGE_COMPLETED)) {
137                     complete_quest(this->player_ptr, QUEST_TOWER1);
138                 }
139             }
140
141             break;
142         default:
143             break;
144         }
145     }
146
147     auto y = this->m_ptr->fy;
148     auto x = this->m_ptr->fx;
149     if (create_stairs) {
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()) {
152             int ny;
153             int nx;
154             scatter(this->player_ptr, &ny, &nx, y, x, 1, PROJECT_NONE);
155             y = ny;
156             x = nx;
157             g_ptr = &floor_ptr->grid_array[y][x];
158         }
159
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;
163     }
164
165     if (!reward) {
166         return;
167     }
168
169     object_type forge;
170     auto *o_ptr = &forge;
171     for (auto i = 0; i < (floor_ptr->dun_level / 15) + 1; i++) {
172         o_ptr->wipe();
173         make_object(this->player_ptr, o_ptr, AM_GOOD | AM_GREAT);
174         (void)drop_near(this->player_ptr, o_ptr, -1, y, x);
175     }
176 }
177
178 /*!
179  * @brief 現在フロアに残っている敵モンスターの数を返す /
180  * @return 現在の敵モンスターの数
181  */
182 int QuestCompletionChecker::count_all_hostile_monsters()
183 {
184     auto *floor_ptr = this->player_ptr->current_floor_ptr;
185     auto number_mon = 0;
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])) {
190                 ++number_mon;
191             }
192         }
193     }
194
195     return number_mon;
196 }