OSDN Git Service

Merge pull request #2706 from Hourier/Rename-Edit-Files
[hengbandforosx/hengbandosx.git] / src / effect / effect-feature.cpp
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"
28
29 /*
30  * Determine if a "legal" grid is an "naked" floor grid
31  *
32  * Line 1 -- forbid non-clean gird
33  * Line 2 -- forbid monsters
34  * Line 3 -- forbid the player
35  */
36 static bool cave_naked_bold(PlayerType *player_ptr, POSITION y, POSITION x)
37 {
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);
40 }
41
42 /*!
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
52  * @details
53  * <pre>
54  * We are called both for "beam" effects and "ball" effects.
55  *
56  * The "r" parameter is the "distance from ground zero".
57  *
58  * Note that we determine if the player can "see" anything that happens
59  * by taking into account: blindness, line-of-sight, and illumination.
60  *
61  * We return "TRUE" if the effect of the projection is "obvious".
62  *
63  * We also "see" grids which are "memorized", probably a hack
64  *
65  * Perhaps we should affect doors?
66  * </pre>
67  */
68 bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType typ)
69 {
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];
73
74     bool obvious = false;
75     bool known = player_has_los_bold(player_ptr, y, x);
76
77     who = who ? who : 0;
78     dam = (dam + r) / (r + 1);
79
80     if (f_ptr->flags.has(FloorFeatureType::TREE)) {
81         concptr message;
82         switch (typ) {
83         case AttributeType::POIS:
84         case AttributeType::NUKE:
85         case AttributeType::DEATH_RAY:
86             message = _("枯れた", "was blasted.");
87             break;
88         case AttributeType::TIME:
89             message = _("縮んだ", "shrank.");
90             break;
91         case AttributeType::ACID:
92             message = _("溶けた", "melted.");
93             break;
94         case AttributeType::COLD:
95         case AttributeType::ICE:
96             message = _("凍り、砕け散った", "was frozen and smashed.");
97             break;
98         case AttributeType::FIRE:
99         case AttributeType::ELEC:
100         case AttributeType::PLASMA:
101             message = _("燃えた", "burns up!");
102             break;
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.");
115             break;
116         case AttributeType::VOID_MAGIC:
117             message = _("消滅した", "vanished.");
118             break;
119         default:
120             message = nullptr;
121             break;
122         }
123
124         if (message) {
125             msg_format(_("木は%s。", "A tree %s"), message);
126             cave_set_feat(player_ptr, y, x, one_in_(3) ? feat_brake : feat_grass);
127
128             /* Observe */
129             if (g_ptr->is_mark()) {
130                 obvious = true;
131             }
132         }
133     }
134
135     /* Analyze the type */
136     switch (typ) {
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: {
168         break;
169     }
170     case AttributeType::KILL_TRAP: {
171         if (is_hidden_door(player_ptr, g_ptr)) {
172             disclose_grid(player_ptr, y, x);
173             if (known) {
174                 obvious = true;
175             }
176         }
177
178         if (is_trap(player_ptr, g_ptr->feat)) {
179             if (known) {
180                 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
181                 obvious = true;
182             }
183
184             cave_alter_feat(player_ptr, y, x, FloorFeatureType::DISARM);
185         }
186
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!"));
192                 obvious = true;
193             }
194         }
195
196         if (player_ptr->effects()->blindness()->is_blind() || !player_has_los_bold(player_ptr, y, x)) {
197             break;
198         }
199
200         g_ptr->info &= ~(CAVE_UNSAFE);
201         lite_spot(player_ptr, y, x);
202         obvious = true;
203         break;
204     }
205     case AttributeType::KILL_DOOR: {
206         if (is_trap(player_ptr, g_ptr->feat) || f_ptr->flags.has(FloorFeatureType::DOOR)) {
207             if (known) {
208                 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
209                 obvious = true;
210             }
211
212             cave_alter_feat(player_ptr, y, x, FloorFeatureType::TUNNEL);
213         }
214
215         if (player_ptr->effects()->blindness()->is_blind() || !player_has_los_bold(player_ptr, y, x)) {
216             break;
217         }
218
219         g_ptr->info &= ~(CAVE_UNSAFE);
220         lite_spot(player_ptr, y, x);
221         obvious = true;
222         break;
223     }
224     case AttributeType::JAM_DOOR: {
225         if (f_ptr->flags.has_not(FloorFeatureType::SPIKE)) {
226             break;
227         }
228
229         int16_t old_mimic = g_ptr->mimic;
230         terrain_type *mimic_f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
231
232         cave_alter_feat(player_ptr, y, x, FloorFeatureType::SPIKE);
233         g_ptr->mimic = old_mimic;
234
235         note_spot(player_ptr, y, x);
236         lite_spot(player_ptr, y, x);
237
238         if (!known || mimic_f_ptr->flags.has_not(FloorFeatureType::OPEN)) {
239             break;
240         }
241
242         msg_format(_("%sに何かがつっかえて開かなくなった。", "The %s seems stuck."), mimic_f_ptr->name.c_str());
243         obvious = true;
244         break;
245     }
246     case AttributeType::KILL_WALL: {
247         if (f_ptr->flags.has_not(FloorFeatureType::HURT_ROCK)) {
248             break;
249         }
250
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());
253             obvious = true;
254         }
255
256         cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
257         player_ptr->update |= (PU_FLOW);
258         break;
259     }
260     case AttributeType::MAKE_DOOR: {
261         if (!cave_naked_bold(player_ptr, y, x)) {
262             break;
263         }
264         if (player_bold(player_ptr, y, x)) {
265             break;
266         }
267         cave_set_feat(player_ptr, y, x, feat_door[DOOR_DOOR].closed);
268         if (g_ptr->is_mark()) {
269             obvious = true;
270         }
271         break;
272     }
273     case AttributeType::MAKE_TRAP: {
274         place_trap(player_ptr, y, x);
275         break;
276     }
277     case AttributeType::MAKE_TREE: {
278         if (!cave_naked_bold(player_ptr, y, x)) {
279             break;
280         }
281         if (player_bold(player_ptr, y, x)) {
282             break;
283         }
284         cave_set_feat(player_ptr, y, x, feat_tree);
285         if (g_ptr->is_mark()) {
286             obvious = true;
287         }
288         break;
289     }
290     case AttributeType::MAKE_RUNE_PROTECTION: {
291         if (!cave_naked_bold(player_ptr, y, x)) {
292             break;
293         }
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);
298         break;
299     }
300     case AttributeType::STONE_WALL: {
301         if (!cave_naked_bold(player_ptr, y, x)) {
302             break;
303         }
304         if (player_bold(player_ptr, y, x)) {
305             break;
306         }
307         cave_set_feat(player_ptr, y, x, feat_granite);
308         break;
309     }
310     case AttributeType::LAVA_FLOW: {
311         if (f_ptr->flags.has(FloorFeatureType::PERMANENT)) {
312             break;
313         }
314         if (dam == 1) {
315             if (f_ptr->flags.has_not(FloorFeatureType::FLOOR)) {
316                 break;
317             }
318             cave_set_feat(player_ptr, y, x, feat_shallow_lava);
319         } else if (dam) {
320             cave_set_feat(player_ptr, y, x, feat_deep_lava);
321         }
322
323         break;
324     }
325     case AttributeType::WATER_FLOW: {
326         if (f_ptr->flags.has(FloorFeatureType::PERMANENT)) {
327             break;
328         }
329         if (dam == 1) {
330             if (f_ptr->flags.has_not(FloorFeatureType::FLOOR)) {
331                 break;
332             }
333             cave_set_feat(player_ptr, y, x, feat_shallow_water);
334         } else if (dam) {
335             cave_set_feat(player_ptr, y, x, feat_deep_water);
336         }
337
338         break;
339     }
340     case AttributeType::LITE_WEAK:
341     case AttributeType::LITE: {
342         if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
343             break;
344         }
345
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);
350
351         if (player_can_see_bold(player_ptr, y, x)) {
352             obvious = true;
353         }
354         if (g_ptr->m_idx) {
355             update_monster(player_ptr, g_ptr->m_idx, false);
356         }
357
358         if (player_bold(player_ptr, y, x)) {
359             set_superstealth(player_ptr, false);
360         }
361
362         break;
363     }
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();
368         if (!do_dark) {
369             break;
370         }
371
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];
376
377                 if (!in_bounds2(floor_ptr, by, bx)) {
378                     continue;
379                 }
380
381                 grid_type *cc_ptr = &floor_ptr->grid_array[by][bx];
382                 if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(FloorFeatureType::GLOW)) {
383                     do_dark = false;
384                     break;
385                 }
386             }
387
388             if (!do_dark) {
389                 break;
390             }
391         }
392
393         g_ptr->info &= ~(CAVE_GLOW);
394
395         /* Hack -- Forget "boring" grids */
396         if (f_ptr->flags.has_not(FloorFeatureType::REMEMBER) || has_element_resist(player_ptr, ElementRealmType::DARKNESS, 1)) {
397             /* Forget */
398             g_ptr->info &= ~(CAVE_MARK);
399             note_spot(player_ptr, y, x);
400         }
401
402         lite_spot(player_ptr, y, x);
403
404         update_local_illumination(player_ptr, y, x);
405
406         if (player_can_see_bold(player_ptr, y, x)) {
407             obvious = true;
408         }
409         if (g_ptr->m_idx) {
410             update_monster(player_ptr, g_ptr->m_idx, false);
411         }
412
413         break;
414     }
415     case AttributeType::SHARDS:
416     case AttributeType::ROCKET: {
417         if (g_ptr->is_mirror()) {
418             msg_print(_("鏡が割れた!", "The mirror was shattered!"));
419             sound(SOUND_GLASS);
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));
423         }
424
425         if (f_ptr->flags.has_not(FloorFeatureType::GLASS) || f_ptr->flags.has(FloorFeatureType::PERMANENT) || (dam < 50)) {
426             break;
427         }
428
429         if (known && (g_ptr->is_mark())) {
430             msg_format(_("%sが割れた!", "The %s crumbled!"), terrains_info[g_ptr->get_feat_mimic()].name.c_str());
431             sound(SOUND_GLASS);
432         }
433
434         cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
435         player_ptr->update |= (PU_FLOW);
436         break;
437     }
438     case AttributeType::SOUND: {
439         if (g_ptr->is_mirror() && player_ptr->lev < 40) {
440             msg_print(_("鏡が割れた!", "The mirror was shattered!"));
441             sound(SOUND_GLASS);
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));
445         }
446
447         if (f_ptr->flags.has_not(FloorFeatureType::GLASS) || f_ptr->flags.has(FloorFeatureType::PERMANENT) || (dam < 200)) {
448             break;
449         }
450
451         if (known && (g_ptr->is_mark())) {
452             msg_format(_("%sが割れた!", "The %s crumbled!"), terrains_info[g_ptr->get_feat_mimic()].name.c_str());
453             sound(SOUND_GLASS);
454         }
455
456         cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
457         player_ptr->update |= (PU_FLOW);
458         break;
459     }
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);
463         }
464
465         if (f_ptr->flags.has_not(FloorFeatureType::HURT_DISI) || f_ptr->flags.has(FloorFeatureType::PERMANENT)) {
466             break;
467         }
468
469         cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_DISI);
470         player_ptr->update |= (PU_FLOW);
471         break;
472     }
473     default:
474         break;
475     }
476
477     lite_spot(player_ptr, y, x);
478     return obvious;
479 }