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/quest.h"
7 #include "floor/cave.h"
8 #include "floor/floor-object.h"
9 #include "floor/geometry.h"
10 #include "game-option/play-record-options.h"
11 #include "game-option/text-display-options.h"
12 #include "grid/feature-flag-types.h"
13 #include "grid/feature.h"
14 #include "grid/grid.h"
15 #include "grid/stair.h"
16 #include "io/write-diary.h"
17 #include "mind/mind-ninja.h"
18 #include "monster-floor/monster-lite.h"
19 #include "monster-race/monster-race.h"
20 #include "monster-race/race-flags1.h"
21 #include "monster-race/race-flags2.h"
22 #include "monster/monster-describer.h"
23 #include "monster/monster-description-types.h"
24 #include "monster/monster-info.h"
25 #include "monster/monster-status-setter.h"
26 #include "monster/monster-update.h"
27 #include "monster/smart-learn-types.h"
28 #include "player/player-damage.h"
29 #include "player/player-move.h"
30 #include "player/player-status-flags.h"
31 #include "player/special-defense-types.h"
32 #include "status/bad-status-setter.h"
33 #include "system/dungeon-info.h"
34 #include "system/floor-type-definition.h"
35 #include "system/grid-type-definition.h"
36 #include "system/monster-entity.h"
37 #include "system/monster-race-info.h"
38 #include "system/player-type-definition.h"
39 #include "system/terrain-type-definition.h"
40 #include "util/bit-flags-calculator.h"
41 #include "view/display-messages.h"
45 * Induce an "earthquake" of the given radius at the given location.
46 * @param player_ptrプレイヤーへの参照ポインタ
50 * @param m_idx 地震を起こしたモンスターID(0ならばプレイヤー)
51 * @return 効力があった場合TRUEを返す
53 bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MONSTER_IDX m_idx)
55 auto *floor_ptr = player_ptr->current_floor_ptr;
56 if ((inside_quest(floor_ptr->quest_number) && quest_type::is_fixed(floor_ptr->quest_number)) || !floor_ptr->dun_level) {
65 for (POSITION y = 0; y < 32; y++) {
66 for (POSITION x = 0; x < 32; x++) {
73 for (POSITION dy = -r; dy <= r; dy++) {
74 for (POSITION dx = -r; dx <= r; dx++) {
75 POSITION yy = cy + dy;
76 POSITION xx = cx + dx;
78 if (!in_bounds(floor_ptr, yy, xx)) {
82 if (distance(cy, cx, yy, xx) > r) {
87 g_ptr = &floor_ptr->grid_array[yy][xx];
88 g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY | CAVE_UNSAFE);
89 g_ptr->info &= ~(CAVE_GLOW | CAVE_MARK | CAVE_KNOWN);
94 if (randint0(100) < 85) {
98 map[16 + yy - cy][16 + xx - cx] = true;
99 if (player_bold(player_ptr, yy, xx)) {
106 POSITION sy = 0, sx = 0;
107 if (hurt && !has_pass_wall(player_ptr) && !has_kill_wall(player_ptr)) {
108 for (DIRECTION i = 0; i < 8; i++) {
109 POSITION y = player_ptr->y + ddy_ddd[i];
110 POSITION x = player_ptr->x + ddx_ddd[i];
111 if (!is_cave_empty_bold(player_ptr, y, x)) {
115 if (map[16 + y - cy][16 + x - cx]) {
119 if (floor_ptr->grid_array[y][x].m_idx) {
124 if (randint0(sn) > 0) {
132 switch (randint1(3)) {
134 msg_print(_("ダンジョンの壁が崩れた!", "The dungeon's ceiling collapses!"));
138 msg_print(_("ダンジョンの床が不自然にねじ曲がった!", "The dungeon's floor twists in an unnatural way!"));
142 msg_print(_("ダンジョンが揺れた!崩れた岩が頭に降ってきた!", "The dungeon quakes! You are pummeled with debris!"));
148 msg_print(_("あなたはひどい怪我を負った!", "You are severely crushed!"));
151 BadStatusSetter bss(player_ptr);
152 switch (randint1(3)) {
154 msg_print(_("降り注ぐ岩をうまく避けた!", "You nimbly dodge the blast!"));
159 msg_print(_("岩石があなたに直撃した!", "You are bashed by rubble!"));
160 damage = damroll(10, 4);
161 (void)bss.mod_stun(randint1(50));
165 msg_print(_("あなたは床と壁との間に挟まれてしまった!", "You are crushed between the floor and ceiling!"));
166 damage = damroll(10, 4);
167 (void)bss.mod_stun(randint1(50));
172 (void)move_player_effect(player_ptr, sy, sx, MPE_DONT_PICKUP);
175 map[16 + player_ptr->y - cy][16 + player_ptr->x - cx] = false;
180 auto *m_ptr = &floor_ptr->m_list[m_idx];
181 const auto m_name = monster_desc(player_ptr, m_ptr, MD_WRONGDOER_NAME);
182 killer = format(_("%sの起こした地震", "an earthquake caused by %s"), m_name.data());
184 killer = _("地震", "an earthquake");
187 take_hit(player_ptr, DAMAGE_ATTACK, damage, killer.data());
191 for (POSITION dy = -r; dy <= r; dy++) {
192 for (POSITION dx = -r; dx <= r; dx++) {
193 POSITION yy = cy + dy;
194 POSITION xx = cx + dx;
195 if (!map[16 + yy - cy][16 + xx - cx]) {
200 gg_ptr = &floor_ptr->grid_array[yy][xx];
201 if (gg_ptr->m_idx == player_ptr->riding) {
205 if (!gg_ptr->m_idx) {
209 auto *m_ptr = &floor_ptr->m_list[gg_ptr->m_idx];
210 auto *r_ptr = &monraces_info[m_ptr->r_idx];
211 if (r_ptr->flags1 & RF1_QUESTOR) {
212 map[16 + yy - cy][16 + xx - cx] = false;
216 if (r_ptr->feature_flags.has(MonsterFeatureType::KILL_WALL) || r_ptr->feature_flags.has(MonsterFeatureType::PASS_WALL)) {
221 if (r_ptr->behavior_flags.has_not(MonsterBehaviorType::NEVER_MOVE)) {
222 for (DIRECTION i = 0; i < 8; i++) {
223 POSITION y = yy + ddy_ddd[i];
224 POSITION x = xx + ddx_ddd[i];
225 if (!is_cave_empty_bold(player_ptr, y, x)) {
229 auto *g_ptr = &floor_ptr->grid_array[y][x];
230 if (g_ptr->is_rune_protection()) {
234 if (g_ptr->is_rune_explosion()) {
238 if (pattern_tile(floor_ptr, y, x)) {
242 if (map[16 + y - cy][16 + x - cx]) {
246 if (floor_ptr->grid_array[y][x].m_idx) {
250 if (player_bold(player_ptr, y, x)) {
256 if (randint0(sn) > 0) {
265 const auto m_name = monster_desc(player_ptr, m_ptr, 0);
266 if (!ignore_unview || is_seen(player_ptr, m_ptr)) {
267 msg_format(_("%^sは苦痛で泣きわめいた!", "%^s wails out in pain!"), m_name.data());
270 damage = (sn ? damroll(4, 8) : (m_ptr->hp + 1));
271 (void)set_monster_csleep(player_ptr, gg_ptr->m_idx, 0);
274 if (!ignore_unview || is_seen(player_ptr, m_ptr)) {
275 msg_format(_("%^sは岩石に埋もれてしまった!", "%^s is embedded in the rock!"), m_name.data());
279 const auto &m_ref = floor_ptr->m_list[gg_ptr->m_idx];
280 if (record_named_pet && m_ref.is_named_pet()) {
281 const auto m2_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
282 exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_EARTHQUAKE, m2_name.data());
286 delete_monster(player_ptr, yy, xx);
294 IDX m_idx_aux = floor_ptr->grid_array[yy][xx].m_idx;
295 floor_ptr->grid_array[yy][xx].m_idx = 0;
296 floor_ptr->grid_array[sy][sx].m_idx = m_idx_aux;
299 update_monster(player_ptr, m_idx_aux, true);
300 lite_spot(player_ptr, yy, xx);
301 lite_spot(player_ptr, sy, sx);
305 clear_mon_lite(floor_ptr);
306 for (POSITION dy = -r; dy <= r; dy++) {
307 for (POSITION dx = -r; dx <= r; dx++) {
308 POSITION yy = cy + dy;
309 POSITION xx = cx + dx;
310 if (!map[16 + yy - cy][16 + xx - cx]) {
314 if (!cave_valid_bold(floor_ptr, yy, xx)) {
318 delete_all_items_from_floor(player_ptr, yy, xx);
319 int t = cave_has_flag_bold(floor_ptr, yy, xx, TerrainCharacteristics::PROJECT) ? randint0(100) : 200;
321 cave_set_feat(player_ptr, yy, xx, feat_granite);
326 cave_set_feat(player_ptr, yy, xx, feat_quartz_vein);
331 cave_set_feat(player_ptr, yy, xx, feat_magma_vein);
335 cave_set_feat(player_ptr, yy, xx, feat_ground_type[randint0(100)]);
339 for (POSITION dy = -r; dy <= r; dy++) {
340 for (POSITION dx = -r; dx <= r; dx++) {
341 POSITION yy = cy + dy;
342 POSITION xx = cx + dx;
343 if (!in_bounds(floor_ptr, yy, xx)) {
347 if (distance(cy, cx, yy, xx) > r) {
351 auto *g_ptr = &floor_ptr->grid_array[yy][xx];
352 if (g_ptr->is_mirror()) {
353 g_ptr->info |= CAVE_GLOW;
357 if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
362 for (DIRECTION ii = 0; ii < 9; ii++) {
363 POSITION yyy = yy + ddy_ddd[ii];
364 POSITION xxx = xx + ddx_ddd[ii];
365 if (!in_bounds2(floor_ptr, yyy, xxx)) {
368 cc_ptr = &floor_ptr->grid_array[yyy][xxx];
369 if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(TerrainCharacteristics::GLOW)) {
370 g_ptr->info |= CAVE_GLOW;
377 player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS);
378 player_ptr->redraw |= (PR_HEALTH | PR_UHEALTH | PR_MAP);
379 player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
380 if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
381 set_superstealth(player_ptr, false);