1 #include "effect/effect-feature.h"
2 #include "core/player-update-types.h"
3 #include "dungeon/dungeon-flag-types.h"
4 #include "dungeon/dungeon.h"
5 #include "effect/effect-characteristics.h"
6 #include "effect/effect-processor.h" // 暫定、後で消す.
7 #include "floor/cave.h"
8 #include "floor/geometry.h"
9 #include "grid/feature.h"
10 #include "grid/grid.h"
11 #include "grid/trap.h"
12 #include "main/sound-definitions-table.h"
13 #include "main/sound-of-music.h"
14 #include "mind/mind-elementalist.h"
15 #include "mind/mind-ninja.h"
16 #include "monster/monster-update.h"
17 #include "player/special-defense-types.h"
18 #include "room/door-definition.h"
19 #include "spell-class/spells-mirror-master.h"
20 #include "system/floor-type-definition.h"
21 #include "system/grid-type-definition.h"
22 #include "system/player-type-definition.h"
23 #include "timed-effect/player-blindness.h"
24 #include "timed-effect/timed-effects.h"
25 #include "util/bit-flags-calculator.h"
26 #include "view/display-messages.h"
27 #include "world/world.h"
30 * Determine if a "legal" grid is an "naked" floor grid
32 * Line 1 -- forbid non-clean gird
33 * Line 2 -- forbid monsters
34 * Line 3 -- forbid the player
36 static bool cave_naked_bold(PlayerType *player_ptr, POSITION y, POSITION x)
38 auto *floor_ptr = player_ptr->current_floor_ptr;
39 return cave_clean_bold(floor_ptr, y, x) && (floor_ptr->grid_array[y][x].m_idx == 0) && !player_bold(player_ptr, y, x);
43 * @brief 汎用的なビーム/ボルト/ボール系による地形効果処理 / We are called from "project()" to "damage" terrain features
44 * @param player_ptr プレイヤーへの参照ポインタ
45 * @param who 魔法を発動したモンスター(0ならばプレイヤー) / Index of "source" monster (zero for "player")
46 * @param r 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
47 * @param y 目標Y座標 / Target y location (or location to travel "towards")
48 * @param x 目標X座標 / Target x location (or location to travel "towards")
49 * @param dam 基本威力 / Base damage roll to apply to affected monsters (or player)
50 * @param typ 効果属性 / Type of damage to apply to monsters (and objects)
51 * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the projection were observed, else FALSE
54 * We are called both for "beam" effects and "ball" effects.
56 * The "r" parameter is the "distance from ground zero".
58 * Note that we determine if the player can "see" anything that happens
59 * by taking into account: blindness, line-of-sight, and illumination.
61 * We return "TRUE" if the effect of the projection is "obvious".
63 * We also "see" grids which are "memorized", probably a hack
65 * Perhaps we should affect doors?
68 bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType typ)
70 auto *floor_ptr = player_ptr->current_floor_ptr;
71 auto *g_ptr = &floor_ptr->grid_array[y][x];
72 auto *f_ptr = &terrains_info[g_ptr->feat];
75 bool known = player_has_los_bold(player_ptr, y, x);
78 dam = (dam + r) / (r + 1);
80 if (f_ptr->flags.has(FloorFeatureType::TREE)) {
83 case AttributeType::POIS:
84 case AttributeType::NUKE:
85 case AttributeType::DEATH_RAY:
86 message = _("枯れた", "was blasted.");
88 case AttributeType::TIME:
89 message = _("縮んだ", "shrank.");
91 case AttributeType::ACID:
92 message = _("溶けた", "melted.");
94 case AttributeType::COLD:
95 case AttributeType::ICE:
96 message = _("凍り、砕け散った", "was frozen and smashed.");
98 case AttributeType::FIRE:
99 case AttributeType::ELEC:
100 case AttributeType::PLASMA:
101 message = _("燃えた", "burns up!");
103 case AttributeType::METEOR:
104 case AttributeType::CHAOS:
105 case AttributeType::MANA:
106 case AttributeType::SEEKER:
107 case AttributeType::SUPER_RAY:
108 case AttributeType::SHARDS:
109 case AttributeType::ROCKET:
110 case AttributeType::SOUND:
111 case AttributeType::DISENCHANT:
112 case AttributeType::FORCE:
113 case AttributeType::GRAVITY:
114 message = _("粉砕された", "was crushed.");
116 case AttributeType::VOID_MAGIC:
117 message = _("消滅した", "vanished.");
125 msg_format(_("木は%s。", "A tree %s"), message);
126 cave_set_feat(player_ptr, y, x, one_in_(3) ? feat_brake : feat_grass);
129 if (g_ptr->is_mark()) {
135 /* Analyze the type */
137 /* Ignore most effects */
138 case AttributeType::CAPTURE:
139 case AttributeType::HAND_DOOM:
140 case AttributeType::CAUSE_1:
141 case AttributeType::CAUSE_2:
142 case AttributeType::CAUSE_3:
143 case AttributeType::CAUSE_4:
144 case AttributeType::MIND_BLAST:
145 case AttributeType::BRAIN_SMASH:
146 case AttributeType::DRAIN_MANA:
147 case AttributeType::PSY_SPEAR:
148 case AttributeType::FORCE:
149 case AttributeType::HOLY_FIRE:
150 case AttributeType::HELL_FIRE:
151 case AttributeType::PSI:
152 case AttributeType::PSI_DRAIN:
153 case AttributeType::TELEKINESIS:
154 case AttributeType::DOMINATION:
155 case AttributeType::IDENTIFY:
156 case AttributeType::ATTACK:
157 case AttributeType::ACID:
158 case AttributeType::ELEC:
159 case AttributeType::COLD:
160 case AttributeType::ICE:
161 case AttributeType::FIRE:
162 case AttributeType::PLASMA:
163 case AttributeType::METEOR:
164 case AttributeType::CHAOS:
165 case AttributeType::MANA:
166 case AttributeType::SEEKER:
167 case AttributeType::SUPER_RAY: {
170 case AttributeType::KILL_TRAP: {
171 if (is_hidden_door(player_ptr, g_ptr)) {
172 disclose_grid(player_ptr, y, x);
178 if (is_trap(player_ptr, g_ptr->feat)) {
180 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
184 cave_alter_feat(player_ptr, y, x, FloorFeatureType::DISARM);
187 if (is_closed_door(player_ptr, g_ptr->feat) && f_ptr->power && f_ptr->flags.has(FloorFeatureType::OPEN)) {
188 FEAT_IDX old_feat = g_ptr->feat;
189 cave_alter_feat(player_ptr, y, x, FloorFeatureType::DISARM);
190 if (known && (old_feat != g_ptr->feat)) {
191 msg_print(_("カチッと音がした!", "Click!"));
196 if (player_ptr->effects()->blindness()->is_blind() || !player_has_los_bold(player_ptr, y, x)) {
200 g_ptr->info &= ~(CAVE_UNSAFE);
201 lite_spot(player_ptr, y, x);
205 case AttributeType::KILL_DOOR: {
206 if (is_trap(player_ptr, g_ptr->feat) || f_ptr->flags.has(FloorFeatureType::DOOR)) {
208 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
212 cave_alter_feat(player_ptr, y, x, FloorFeatureType::TUNNEL);
215 if (player_ptr->effects()->blindness()->is_blind() || !player_has_los_bold(player_ptr, y, x)) {
219 g_ptr->info &= ~(CAVE_UNSAFE);
220 lite_spot(player_ptr, y, x);
224 case AttributeType::JAM_DOOR: {
225 if (f_ptr->flags.has_not(FloorFeatureType::SPIKE)) {
229 int16_t old_mimic = g_ptr->mimic;
230 terrain_type *mimic_f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
232 cave_alter_feat(player_ptr, y, x, FloorFeatureType::SPIKE);
233 g_ptr->mimic = old_mimic;
235 note_spot(player_ptr, y, x);
236 lite_spot(player_ptr, y, x);
238 if (!known || mimic_f_ptr->flags.has_not(FloorFeatureType::OPEN)) {
242 msg_format(_("%sに何かがつっかえて開かなくなった。", "The %s seems stuck."), mimic_f_ptr->name.c_str());
246 case AttributeType::KILL_WALL: {
247 if (f_ptr->flags.has_not(FloorFeatureType::HURT_ROCK)) {
251 if (known && g_ptr->is_mark()) {
252 msg_format(_("%sが溶けて泥になった!", "The %s turns into mud!"), terrains_info[g_ptr->get_feat_mimic()].name.c_str());
256 cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
257 player_ptr->update |= (PU_FLOW);
260 case AttributeType::MAKE_DOOR: {
261 if (!cave_naked_bold(player_ptr, y, x)) {
264 if (player_bold(player_ptr, y, x)) {
267 cave_set_feat(player_ptr, y, x, feat_door[DOOR_DOOR].closed);
268 if (g_ptr->is_mark()) {
273 case AttributeType::MAKE_TRAP: {
274 place_trap(player_ptr, y, x);
277 case AttributeType::MAKE_TREE: {
278 if (!cave_naked_bold(player_ptr, y, x)) {
281 if (player_bold(player_ptr, y, x)) {
284 cave_set_feat(player_ptr, y, x, feat_tree);
285 if (g_ptr->is_mark()) {
290 case AttributeType::MAKE_RUNE_PROTECTION: {
291 if (!cave_naked_bold(player_ptr, y, x)) {
294 g_ptr->info |= CAVE_OBJECT;
295 g_ptr->mimic = feat_rune_protection;
296 note_spot(player_ptr, y, x);
297 lite_spot(player_ptr, y, x);
300 case AttributeType::STONE_WALL: {
301 if (!cave_naked_bold(player_ptr, y, x)) {
304 if (player_bold(player_ptr, y, x)) {
307 cave_set_feat(player_ptr, y, x, feat_granite);
310 case AttributeType::LAVA_FLOW: {
311 if (f_ptr->flags.has(FloorFeatureType::PERMANENT)) {
315 if (f_ptr->flags.has_not(FloorFeatureType::FLOOR)) {
318 cave_set_feat(player_ptr, y, x, feat_shallow_lava);
320 cave_set_feat(player_ptr, y, x, feat_deep_lava);
325 case AttributeType::WATER_FLOW: {
326 if (f_ptr->flags.has(FloorFeatureType::PERMANENT)) {
330 if (f_ptr->flags.has_not(FloorFeatureType::FLOOR)) {
333 cave_set_feat(player_ptr, y, x, feat_shallow_water);
335 cave_set_feat(player_ptr, y, x, feat_deep_water);
340 case AttributeType::LITE_WEAK:
341 case AttributeType::LITE: {
342 if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
346 g_ptr->info |= (CAVE_GLOW);
347 note_spot(player_ptr, y, x);
348 lite_spot(player_ptr, y, x);
349 update_local_illumination(player_ptr, y, x);
351 if (player_can_see_bold(player_ptr, y, x)) {
355 update_monster(player_ptr, g_ptr->m_idx, false);
358 if (player_bold(player_ptr, y, x)) {
359 set_superstealth(player_ptr, false);
364 case AttributeType::DARK_WEAK:
365 case AttributeType::DARK:
366 case AttributeType::ABYSS: {
367 bool do_dark = !player_ptr->phase_out && !g_ptr->is_mirror();
372 if ((floor_ptr->dun_level > 0) || !is_daytime()) {
373 for (int j = 0; j < 9; j++) {
374 int by = y + ddy_ddd[j];
375 int bx = x + ddx_ddd[j];
377 if (!in_bounds2(floor_ptr, by, bx)) {
381 grid_type *cc_ptr = &floor_ptr->grid_array[by][bx];
382 if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(FloorFeatureType::GLOW)) {
393 g_ptr->info &= ~(CAVE_GLOW);
395 /* Hack -- Forget "boring" grids */
396 if (f_ptr->flags.has_not(FloorFeatureType::REMEMBER) || has_element_resist(player_ptr, ElementRealmType::DARKNESS, 1)) {
398 g_ptr->info &= ~(CAVE_MARK);
399 note_spot(player_ptr, y, x);
402 lite_spot(player_ptr, y, x);
404 update_local_illumination(player_ptr, y, x);
406 if (player_can_see_bold(player_ptr, y, x)) {
410 update_monster(player_ptr, g_ptr->m_idx, false);
415 case AttributeType::SHARDS:
416 case AttributeType::ROCKET: {
417 if (g_ptr->is_mirror()) {
418 msg_print(_("鏡が割れた!", "The mirror was shattered!"));
420 SpellsMirrorMaster(player_ptr).remove_mirror(y, x);
421 project(player_ptr, 0, 2, y, x, player_ptr->lev / 2 + 5, AttributeType::SHARDS,
422 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI));
425 if (f_ptr->flags.has_not(FloorFeatureType::GLASS) || f_ptr->flags.has(FloorFeatureType::PERMANENT) || (dam < 50)) {
429 if (known && (g_ptr->is_mark())) {
430 msg_format(_("%sが割れた!", "The %s crumbled!"), terrains_info[g_ptr->get_feat_mimic()].name.c_str());
434 cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
435 player_ptr->update |= (PU_FLOW);
438 case AttributeType::SOUND: {
439 if (g_ptr->is_mirror() && player_ptr->lev < 40) {
440 msg_print(_("鏡が割れた!", "The mirror was shattered!"));
442 SpellsMirrorMaster(player_ptr).remove_mirror(y, x);
443 project(player_ptr, 0, 2, y, x, player_ptr->lev / 2 + 5, AttributeType::SHARDS,
444 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI));
447 if (f_ptr->flags.has_not(FloorFeatureType::GLASS) || f_ptr->flags.has(FloorFeatureType::PERMANENT) || (dam < 200)) {
451 if (known && (g_ptr->is_mark())) {
452 msg_format(_("%sが割れた!", "The %s crumbled!"), terrains_info[g_ptr->get_feat_mimic()].name.c_str());
456 cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
457 player_ptr->update |= (PU_FLOW);
460 case AttributeType::DISINTEGRATE: {
461 if (g_ptr->is_mirror() || g_ptr->is_rune_protection() || g_ptr->is_rune_explosion()) {
462 SpellsMirrorMaster(player_ptr).remove_mirror(y, x);
465 if (f_ptr->flags.has_not(FloorFeatureType::HURT_DISI) || f_ptr->flags.has(FloorFeatureType::PERMANENT)) {
469 cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_DISI);
470 player_ptr->update |= (PU_FLOW);
477 lite_spot(player_ptr, y, x);