OSDN Git Service

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