OSDN Git Service

Merge pull request #1512 from Hourier/feature/Rename-Doxygen-Player-Pointer
[hengbandforosx/hengbandosx.git] / src / spell-kind / earthquake.cpp
1 #include "spell-kind/earthquake.h"
2 #include "core/player-redraw-types.h"
3 #include "core/player-update-types.h"
4 #include "core/window-redrawer.h"
5 #include "dungeon/dungeon-flag-types.h"
6 #include "dungeon/dungeon.h"
7 #include "dungeon/quest.h"
8 #include "floor/cave.h"
9 #include "floor/floor-object.h"
10 #include "floor/geometry.h"
11 #include "game-option/play-record-options.h"
12 #include "game-option/text-display-options.h"
13 #include "grid/feature-flag-types.h"
14 #include "grid/feature.h"
15 #include "grid/grid.h"
16 #include "grid/stair.h"
17 #include "io/write-diary.h"
18 #include "mind/mind-ninja.h"
19 #include "monster-floor/monster-lite.h"
20 #include "monster-race/monster-race.h"
21 #include "monster-race/race-flags1.h"
22 #include "monster-race/race-flags2.h"
23 #include "monster/monster-describer.h"
24 #include "monster/monster-description-types.h"
25 #include "monster/monster-info.h"
26 #include "monster/monster-status-setter.h"
27 #include "monster/monster-update.h"
28 #include "monster/smart-learn-types.h"
29 #include "player/player-damage.h"
30 #include "player/player-move.h"
31 #include "player/player-status-flags.h"
32 #include "player/special-defense-types.h"
33 #include "status/bad-status-setter.h"
34 #include "system/floor-type-definition.h"
35 #include "system/grid-type-definition.h"
36 #include "system/monster-race-definition.h"
37 #include "system/monster-type-definition.h"
38 #include "system/player-type-definition.h"
39 #include "util/bit-flags-calculator.h"
40 #include "view/display-messages.h"
41
42 /*!
43  * @brief 地震処理
44  * Induce an "earthquake" of the given radius at the given location.
45  * @param player_ptrプレイヤーへの参照ポインタ
46  * @param cy 中心Y座標
47  * @param cx 中心X座標
48  * @param r 効果半径
49  * @param m_idx 地震を起こしたモンスターID(0ならばプレイヤー)
50  * @return 効力があった場合TRUEを返す
51  */
52 bool earthquake(player_type *player_ptr, POSITION cy, POSITION cx, POSITION r, MONSTER_IDX m_idx)
53 {
54     floor_type *floor_ptr = player_ptr->current_floor_ptr;
55     if ((floor_ptr->inside_quest && is_fixed_quest_idx(floor_ptr->inside_quest)) || !floor_ptr->dun_level) {
56         return false;
57     }
58
59     if (r > 12)
60         r = 12;
61
62     bool map[32][32];
63     for (POSITION y = 0; y < 32; y++) {
64         for (POSITION x = 0; x < 32; x++) {
65             map[y][x] = false;
66         }
67     }
68
69     int damage = 0;
70     bool hurt = false;
71     for (POSITION dy = -r; dy <= r; dy++) {
72         for (POSITION dx = -r; dx <= r; dx++) {
73             POSITION yy = cy + dy;
74             POSITION xx = cx + dx;
75
76             if (!in_bounds(floor_ptr, yy, xx))
77                 continue;
78
79             if (distance(cy, cx, yy, xx) > r)
80                 continue;
81
82             grid_type *g_ptr;
83             g_ptr = &floor_ptr->grid_array[yy][xx];
84             g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY | CAVE_UNSAFE);
85             g_ptr->info &= ~(CAVE_GLOW | CAVE_MARK | CAVE_KNOWN);
86             if (!dx && !dy)
87                 continue;
88
89             if (randint0(100) < 85)
90                 continue;
91
92             map[16 + yy - cy][16 + xx - cx] = true;
93             if (player_bold(player_ptr, yy, xx))
94                 hurt = true;
95         }
96     }
97
98     int sn = 0;
99     POSITION sy = 0, sx = 0;
100     if (hurt && !has_pass_wall(player_ptr) && !has_kill_wall(player_ptr)) {
101         for (DIRECTION i = 0; i < 8; i++) {
102             POSITION y = player_ptr->y + ddy_ddd[i];
103             POSITION x = player_ptr->x + ddx_ddd[i];
104             if (!is_cave_empty_bold(player_ptr, y, x))
105                 continue;
106
107             if (map[16 + y - cy][16 + x - cx])
108                 continue;
109
110             if (floor_ptr->grid_array[y][x].m_idx)
111                 continue;
112
113             sn++;
114             if (randint0(sn) > 0)
115                 continue;
116
117             sy = y;
118             sx = x;
119         }
120
121         switch (randint1(3)) {
122         case 1: {
123             msg_print(_("ダンジョンの壁が崩れた!", "The dungeon's ceiling collapses!"));
124             break;
125         }
126         case 2: {
127             msg_print(_("ダンジョンの床が不自然にねじ曲がった!", "The dungeon's floor twists in an unnatural way!"));
128             break;
129         }
130         default: {
131             msg_print(_("ダンジョンが揺れた!崩れた岩が頭に降ってきた!", "The dungeon quakes!  You are pummeled with debris!"));
132             break;
133         }
134         }
135
136         if (!sn) {
137             msg_print(_("あなたはひどい怪我を負った!", "You are severely crushed!"));
138             damage = 200;
139         } else {
140             switch (randint1(3)) {
141             case 1: {
142                 msg_print(_("降り注ぐ岩をうまく避けた!", "You nimbly dodge the blast!"));
143                 damage = 0;
144                 break;
145             }
146             case 2: {
147                 msg_print(_("岩石があなたに直撃した!", "You are bashed by rubble!"));
148                 damage = damroll(10, 4);
149                 (void)set_stun(player_ptr, player_ptr->stun + randint1(50));
150                 break;
151             }
152             case 3: {
153                 msg_print(_("あなたは床と壁との間に挟まれてしまった!", "You are crushed between the floor and ceiling!"));
154                 damage = damroll(10, 4);
155                 (void)set_stun(player_ptr, player_ptr->stun + randint1(50));
156                 break;
157             }
158             }
159
160             (void)move_player_effect(player_ptr, sy, sx, MPE_DONT_PICKUP);
161         }
162
163         map[16 + player_ptr->y - cy][16 + player_ptr->x - cx] = false;
164         if (damage) {
165             concptr killer;
166
167             if (m_idx) {
168                 GAME_TEXT m_name[MAX_NLEN];
169                 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
170                 monster_desc(player_ptr, m_name, m_ptr, MD_WRONGDOER_NAME);
171                 killer = format(_("%sの起こした地震", "an earthquake caused by %s"), m_name);
172             } else {
173                 killer = _("地震", "an earthquake");
174             }
175
176             take_hit(player_ptr, DAMAGE_ATTACK, damage, killer);
177         }
178     }
179
180     for (POSITION dy = -r; dy <= r; dy++) {
181         for (POSITION dx = -r; dx <= r; dx++) {
182             POSITION yy = cy + dy;
183             POSITION xx = cx + dx;
184             if (!map[16 + yy - cy][16 + xx - cx])
185                 continue;
186
187             grid_type *gg_ptr;
188             gg_ptr = &floor_ptr->grid_array[yy][xx];
189             if (gg_ptr->m_idx == player_ptr->riding)
190                 continue;
191
192             if (!gg_ptr->m_idx)
193                 continue;
194
195             monster_type *m_ptr = &floor_ptr->m_list[gg_ptr->m_idx];
196             monster_race *r_ptr = &r_info[m_ptr->r_idx];
197             if (r_ptr->flags1 & RF1_QUESTOR) {
198                 map[16 + yy - cy][16 + xx - cx] = false;
199                 continue;
200             }
201
202             if ((r_ptr->flags2 & RF2_KILL_WALL) || (r_ptr->flags2 & RF2_PASS_WALL))
203                 continue;
204
205             GAME_TEXT m_name[MAX_NLEN];
206             sn = 0;
207             if (none_bits(r_ptr->flags1, RF1_NEVER_MOVE)) {
208                 for (DIRECTION i = 0; i < 8; i++) {
209                     POSITION y = yy + ddy_ddd[i];
210                     POSITION x = xx + ddx_ddd[i];
211                     if (!is_cave_empty_bold(player_ptr, y, x))
212                         continue;
213
214                     auto *g_ptr = &floor_ptr->grid_array[y][x];
215                     if (g_ptr->is_rune_protection())
216                         continue;
217
218                     if (g_ptr->is_rune_explosion())
219                         continue;
220
221                     if (pattern_tile(floor_ptr, y, x))
222                         continue;
223
224                     if (map[16 + y - cy][16 + x - cx])
225                         continue;
226
227                     if (floor_ptr->grid_array[y][x].m_idx)
228                         continue;
229
230                     if (player_bold(player_ptr, y, x))
231                         continue;
232
233                     sn++;
234
235                     if (randint0(sn) > 0)
236                         continue;
237
238                     sy = y;
239                     sx = x;
240                 }
241             }
242
243             monster_desc(player_ptr, m_name, m_ptr, 0);
244             if (!ignore_unview || is_seen(player_ptr, m_ptr))
245                 msg_format(_("%^sは苦痛で泣きわめいた!", "%^s wails out in pain!"), m_name);
246
247             damage = (sn ? damroll(4, 8) : (m_ptr->hp + 1));
248             (void)set_monster_csleep(player_ptr, gg_ptr->m_idx, 0);
249             m_ptr->hp -= damage;
250             if (m_ptr->hp < 0) {
251                 if (!ignore_unview || is_seen(player_ptr, m_ptr))
252                     msg_format(_("%^sは岩石に埋もれてしまった!", "%^s is embedded in the rock!"), m_name);
253
254                 if (gg_ptr->m_idx) {
255                     if (record_named_pet && is_pet(&floor_ptr->m_list[gg_ptr->m_idx]) && floor_ptr->m_list[gg_ptr->m_idx].nickname) {
256                         char m2_name[MAX_NLEN];
257
258                         monster_desc(player_ptr, m2_name, m_ptr, MD_INDEF_VISIBLE);
259                         exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_EARTHQUAKE, m2_name);
260                     }
261                 }
262
263                 delete_monster(player_ptr, yy, xx);
264                 sn = 0;
265             }
266
267             if (sn == 0)
268                 continue;
269
270             IDX m_idx_aux = floor_ptr->grid_array[yy][xx].m_idx;
271             floor_ptr->grid_array[yy][xx].m_idx = 0;
272             floor_ptr->grid_array[sy][sx].m_idx = m_idx_aux;
273             m_ptr->fy = sy;
274             m_ptr->fx = sx;
275             update_monster(player_ptr, m_idx_aux, true);
276             lite_spot(player_ptr, yy, xx);
277             lite_spot(player_ptr, sy, sx);
278         }
279     }
280
281     clear_mon_lite(floor_ptr);
282     for (POSITION dy = -r; dy <= r; dy++) {
283         for (POSITION dx = -r; dx <= r; dx++) {
284             POSITION yy = cy + dy;
285             POSITION xx = cx + dx;
286             if (!map[16 + yy - cy][16 + xx - cx])
287                 continue;
288
289             if (!cave_valid_bold(floor_ptr, yy, xx))
290                 continue;
291
292             delete_all_items_from_floor(player_ptr, yy, xx);
293             int t = cave_has_flag_bold(floor_ptr, yy, xx, FF::PROJECT) ? randint0(100) : 200;
294             if (t < 20) {
295                 cave_set_feat(player_ptr, yy, xx, feat_granite);
296                 continue;
297             }
298
299             if (t < 70) {
300                 cave_set_feat(player_ptr, yy, xx, feat_quartz_vein);
301                 continue;
302             }
303
304             if (t < 100) {
305                 cave_set_feat(player_ptr, yy, xx, feat_magma_vein);
306                 continue;
307             }
308
309             cave_set_feat(player_ptr, yy, xx, feat_ground_type[randint0(100)]);
310         }
311     }
312
313     for (POSITION dy = -r; dy <= r; dy++) {
314         for (POSITION dx = -r; dx <= r; dx++) {
315             POSITION yy = cy + dy;
316             POSITION xx = cx + dx;
317             if (!in_bounds(floor_ptr, yy, xx))
318                 continue;
319
320             if (distance(cy, cx, yy, xx) > r)
321                 continue;
322
323             auto *g_ptr = &floor_ptr->grid_array[yy][xx];
324             if (g_ptr->is_mirror()) {
325                 g_ptr->info |= CAVE_GLOW;
326                 continue;
327             }
328
329             if (d_info[player_ptr->dungeon_idx].flags.has(DF::DARKNESS))
330                 continue;
331
332             grid_type *cc_ptr;
333             for (DIRECTION ii = 0; ii < 9; ii++) {
334                 POSITION yyy = yy + ddy_ddd[ii];
335                 POSITION xxx = xx + ddx_ddd[ii];
336                 if (!in_bounds2(floor_ptr, yyy, xxx))
337                     continue;
338                 cc_ptr = &floor_ptr->grid_array[yyy][xxx];
339                 if (f_info[cc_ptr->get_feat_mimic()].flags.has(FF::GLOW)) {
340                     g_ptr->info |= CAVE_GLOW;
341                     break;
342                 }
343             }
344         }
345     }
346
347     player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS);
348     player_ptr->redraw |= (PR_HEALTH | PR_UHEALTH | PR_MAP);
349     player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
350     if (player_ptr->special_defense & NINJA_S_STEALTH) {
351         if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW)
352             set_superstealth(player_ptr, false);
353     }
354
355     return true;
356 }