OSDN Git Service

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