OSDN Git Service

[Add] @return を不要に書き込んだことによる警告をひとまず置換で修正.
[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 "object/object-generator.h"
14 #include "system/floor-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 /*!
21  * @brief 現在フロアに残っている敵モンスターの数を返す /
22  * @return 現在の敵モンスターの数
23  */
24 static MONSTER_NUMBER count_all_hostile_monsters(floor_type *floor_ptr)
25 {
26     MONSTER_NUMBER number_mon = 0;
27     for (POSITION x = 0; x < floor_ptr->width; ++x) {
28         for (POSITION y = 0; y < floor_ptr->height; ++y) {
29             MONSTER_IDX m_idx = floor_ptr->grid_array[y][x].m_idx;
30             if (m_idx > 0 && is_hostile(&floor_ptr->m_list[m_idx]))
31                 ++number_mon;
32         }
33     }
34
35     return number_mon;
36 }
37
38 /*!
39  * @brief 特定の敵を倒した際にクエスト達成処理 /
40  * Check for "Quest" completion when a quest monster is killed or charmed.
41  * @param player_ptr プレーヤーへの参照ポインタ
42  * @param m_ptr 撃破したモンスターの構造体参照ポインタ
43  */
44 void check_quest_completion(player_type *player_ptr, monster_type *m_ptr)
45 {
46     POSITION y = m_ptr->fy;
47     POSITION x = m_ptr->fx;
48     floor_type *floor_ptr = player_ptr->current_floor_ptr;
49     QUEST_IDX quest_num = floor_ptr->inside_quest;
50     if (!quest_num) {
51         QUEST_IDX i;
52         for (i = max_q_idx - 1; i > 0; i--) {
53             quest_type *const q_ptr = &quest[i];
54             if (q_ptr->status != QUEST_STATUS_TAKEN)
55                 continue;
56
57             if (q_ptr->flags & QUEST_FLAG_PRESET)
58                 continue;
59
60             if ((q_ptr->level != floor_ptr->dun_level) && (q_ptr->type != QUEST_TYPE_KILL_ANY_LEVEL))
61                 continue;
62
63             if ((q_ptr->type == QUEST_TYPE_FIND_ARTIFACT) || (q_ptr->type == QUEST_TYPE_FIND_EXIT))
64                 continue;
65
66             if ((q_ptr->type == QUEST_TYPE_KILL_NUMBER) || (q_ptr->type == QUEST_TYPE_TOWER) || (q_ptr->type == QUEST_TYPE_KILL_ALL))
67                 break;
68
69             if (((q_ptr->type == QUEST_TYPE_KILL_LEVEL) || (q_ptr->type == QUEST_TYPE_KILL_ANY_LEVEL) || (q_ptr->type == QUEST_TYPE_RANDOM))
70                 && (q_ptr->r_idx == m_ptr->r_idx))
71                 break;
72         }
73
74         quest_num = i;
75     }
76
77     bool create_stairs = FALSE;
78     bool reward = FALSE;
79     if (quest_num && (quest[quest_num].status == QUEST_STATUS_TAKEN)) {
80         quest_type *const q_ptr = &quest[quest_num];
81         switch (q_ptr->type) {
82         case QUEST_TYPE_KILL_NUMBER: {
83             q_ptr->cur_num++;
84             if (q_ptr->cur_num >= q_ptr->num_mon) {
85                 complete_quest(player_ptr, quest_num);
86                 q_ptr->cur_num = 0;
87             }
88
89             break;
90         }
91         case QUEST_TYPE_KILL_ALL: {
92             if (!is_hostile(m_ptr) || count_all_hostile_monsters(floor_ptr) != 1)
93                 break;
94
95             if (q_ptr->flags & QUEST_FLAG_SILENT) {
96                 q_ptr->status = QUEST_STATUS_FINISHED;
97             } else {
98                 complete_quest(player_ptr, quest_num);
99             }
100
101             break;
102         }
103         case QUEST_TYPE_KILL_LEVEL:
104         case QUEST_TYPE_RANDOM: {
105             if (q_ptr->r_idx != m_ptr->r_idx)
106                 break;
107
108             q_ptr->cur_num++;
109             if (q_ptr->cur_num < q_ptr->max_num)
110                 break;
111
112             complete_quest(player_ptr, quest_num);
113             if (!(q_ptr->flags & QUEST_FLAG_PRESET)) {
114                 create_stairs = TRUE;
115                 floor_ptr->inside_quest = 0;
116             }
117
118             if ((quest_num == QUEST_OBERON) || (quest_num == QUEST_SERPENT))
119                 q_ptr->status = QUEST_STATUS_FINISHED;
120
121             if (q_ptr->type == QUEST_TYPE_RANDOM) {
122                 reward = TRUE;
123                 q_ptr->status = QUEST_STATUS_FINISHED;
124             }
125
126             break;
127         }
128         case QUEST_TYPE_KILL_ANY_LEVEL: {
129             q_ptr->cur_num++;
130             if (q_ptr->cur_num >= q_ptr->max_num) {
131                 complete_quest(player_ptr, quest_num);
132                 q_ptr->cur_num = 0;
133             }
134
135             break;
136         }
137         case QUEST_TYPE_TOWER: {
138             if (!is_hostile(m_ptr))
139                 break;
140
141             if (count_all_hostile_monsters(floor_ptr) == 1) {
142                 q_ptr->status = QUEST_STATUS_STAGE_COMPLETED;
143
144                 if ((quest[QUEST_TOWER1].status == QUEST_STATUS_STAGE_COMPLETED) && (quest[QUEST_TOWER2].status == QUEST_STATUS_STAGE_COMPLETED)
145                     && (quest[QUEST_TOWER3].status == QUEST_STATUS_STAGE_COMPLETED)) {
146
147                     complete_quest(player_ptr, QUEST_TOWER1);
148                 }
149             }
150
151             break;
152         }
153         }
154     }
155
156     if (create_stairs) {
157         POSITION ny, nx;
158         while (cave_has_flag_bold(floor_ptr, y, x, FF_PERMANENT) || floor_ptr->grid_array[y][x].o_idx || (floor_ptr->grid_array[y][x].info & CAVE_OBJECT)) {
159             scatter(player_ptr, &ny, &nx, y, x, 1, PROJECT_NONE);
160             y = ny;
161             x = nx;
162         }
163
164         msg_print(_("魔法の階段が現れた...", "A magical staircase appears..."));
165         cave_set_feat(player_ptr, y, x, feat_down_stair);
166         player_ptr->update |= PU_FLOW;
167     }
168
169     if (!reward)
170         return;
171
172     object_type forge;
173     object_type *o_ptr;
174     for (int i = 0; i < (floor_ptr->dun_level / 15) + 1; i++) {
175         o_ptr = &forge;
176         object_wipe(o_ptr);
177         make_object(player_ptr, o_ptr, AM_GOOD | AM_GREAT);
178         (void)drop_near(player_ptr, o_ptr, -1, y, x);
179     }
180 }