OSDN Git Service

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