OSDN Git Service

[Refactor] EFFECT_IDの削除
[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 "system/floor-type-definition.h"
20 #include "system/grid-type-definition.h"
21 #include "system/player-type-definition.h"
22 #include "util/bit-flags-calculator.h"
23 #include "view/display-messages.h"
24 #include "world/world.h"
25
26 /*
27  * Determine if a "legal" grid is an "naked" floor grid
28  *
29  * Line 1 -- forbid non-clean gird
30  * Line 2 -- forbid monsters
31  * Line 3 -- forbid the player
32  */
33 static bool cave_naked_bold(PlayerType *player_ptr, POSITION y, POSITION x)
34 {
35     floor_type *floor_ptr = player_ptr->current_floor_ptr;
36     return cave_clean_bold(floor_ptr, y, x) && (floor_ptr->grid_array[y][x].m_idx == 0) && !player_bold(player_ptr, y, x);
37 }
38
39 /*!
40  * @brief 汎用的なビーム/ボルト/ボール系による地形効果処理 / We are called from "project()" to "damage" terrain features
41  * @param player_ptr プレイヤーへの参照ポインタ
42  * @param who 魔法を発動したモンスター(0ならばプレイヤー) / Index of "source" monster (zero for "player")
43  * @param r 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
44  * @param y 目標Y座標 / Target y location (or location to travel "towards")
45  * @param x 目標X座標 / Target x location (or location to travel "towards")
46  * @param dam 基本威力 / Base damage roll to apply to affected monsters (or player)
47  * @param typ 効果属性 / Type of damage to apply to monsters (and objects)
48  * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the projection were observed, else FALSE
49  * @details
50  * <pre>
51  * We are called both for "beam" effects and "ball" effects.
52  *
53  * The "r" parameter is the "distance from ground zero".
54  *
55  * Note that we determine if the player can "see" anything that happens
56  * by taking into account: blindness, line-of-sight, and illumination.
57  *
58  * We return "TRUE" if the effect of the projection is "obvious".
59  *
60  * We also "see" grids which are "memorized", probably a hack
61  *
62  * Perhaps we should affect doors?
63  * </pre>
64  */
65 bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, HIT_POINT dam, AttributeType typ)
66 {
67     floor_type *floor_ptr = player_ptr->current_floor_ptr;
68     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
69     feature_type *f_ptr = &f_info[g_ptr->feat];
70
71     bool obvious = false;
72     bool known = player_has_los_bold(player_ptr, y, x);
73
74     who = who ? who : 0;
75     dam = (dam + r) / (r + 1);
76
77     if (f_ptr->flags.has(FloorFeatureType::TREE)) {
78         concptr message;
79         switch (typ) {
80         case AttributeType::POIS:
81         case AttributeType::NUKE:
82         case AttributeType::DEATH_RAY:
83             message = _("枯れた", "was blasted.");
84             break;
85         case AttributeType::TIME:
86             message = _("縮んだ", "shrank.");
87             break;
88         case AttributeType::ACID:
89             message = _("溶けた", "melted.");
90             break;
91         case AttributeType::COLD:
92         case AttributeType::ICE:
93             message = _("凍り、砕け散った", "was frozen and smashed.");
94             break;
95         case AttributeType::FIRE:
96         case AttributeType::ELEC:
97         case AttributeType::PLASMA:
98             message = _("燃えた", "burns up!");
99             break;
100         case AttributeType::METEOR:
101         case AttributeType::CHAOS:
102         case AttributeType::MANA:
103         case AttributeType::SEEKER:
104         case AttributeType::SUPER_RAY:
105         case AttributeType::SHARDS:
106         case AttributeType::ROCKET:
107         case AttributeType::SOUND:
108         case AttributeType::DISENCHANT:
109         case AttributeType::FORCE:
110         case AttributeType::GRAVITY:
111             message = _("粉砕された", "was crushed.");
112             break;
113         case AttributeType::VOID_MAGIC:
114             message = _("消滅した", "vanished.");
115             break;
116         default:
117             message = nullptr;
118             break;
119         }
120
121         if (message) {
122             msg_format(_("木は%s。", "A tree %s"), message);
123             cave_set_feat(player_ptr, y, x, one_in_(3) ? feat_brake : feat_grass);
124
125             /* Observe */
126             if (g_ptr->is_mark())
127                 obvious = true;
128         }
129     }
130
131     /* Analyze the type */
132     switch (typ) {
133         /* Ignore most effects */
134     case AttributeType::CAPTURE:
135     case AttributeType::HAND_DOOM:
136     case AttributeType::CAUSE_1:
137     case AttributeType::CAUSE_2:
138     case AttributeType::CAUSE_3:
139     case AttributeType::CAUSE_4:
140     case AttributeType::MIND_BLAST:
141     case AttributeType::BRAIN_SMASH:
142     case AttributeType::DRAIN_MANA:
143     case AttributeType::PSY_SPEAR:
144     case AttributeType::FORCE:
145     case AttributeType::HOLY_FIRE:
146     case AttributeType::HELL_FIRE:
147     case AttributeType::PSI:
148     case AttributeType::PSI_DRAIN:
149     case AttributeType::TELEKINESIS:
150     case AttributeType::DOMINATION:
151     case AttributeType::IDENTIFY:
152     case AttributeType::ATTACK:
153     case AttributeType::ACID:
154     case AttributeType::ELEC:
155     case AttributeType::COLD:
156     case AttributeType::ICE:
157     case AttributeType::FIRE:
158     case AttributeType::PLASMA:
159     case AttributeType::METEOR:
160     case AttributeType::CHAOS:
161     case AttributeType::MANA:
162     case AttributeType::SEEKER:
163     case AttributeType::SUPER_RAY: {
164         break;
165     }
166     case AttributeType::KILL_TRAP: {
167         if (is_hidden_door(player_ptr, g_ptr)) {
168             disclose_grid(player_ptr, y, x);
169             if (known) {
170                 obvious = true;
171             }
172         }
173
174         if (is_trap(player_ptr, g_ptr->feat)) {
175             if (known) {
176                 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
177                 obvious = true;
178             }
179
180             cave_alter_feat(player_ptr, y, x, FloorFeatureType::DISARM);
181         }
182
183         if (is_closed_door(player_ptr, g_ptr->feat) && f_ptr->power && f_ptr->flags.has(FloorFeatureType::OPEN)) {
184             FEAT_IDX old_feat = g_ptr->feat;
185             cave_alter_feat(player_ptr, y, x, FloorFeatureType::DISARM);
186             if (known && (old_feat != g_ptr->feat)) {
187                 msg_print(_("カチッと音がした!", "Click!"));
188                 obvious = true;
189             }
190         }
191
192         if (player_ptr->blind || !player_has_los_bold(player_ptr, y, x))
193             break;
194
195         g_ptr->info &= ~(CAVE_UNSAFE);
196         lite_spot(player_ptr, y, x);
197         obvious = true;
198         break;
199     }
200     case AttributeType::KILL_DOOR: {
201         if (is_trap(player_ptr, g_ptr->feat) || f_ptr->flags.has(FloorFeatureType::DOOR)) {
202             if (known) {
203                 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
204                 obvious = true;
205             }
206
207             cave_alter_feat(player_ptr, y, x, FloorFeatureType::TUNNEL);
208         }
209
210         if (player_ptr->blind || !player_has_los_bold(player_ptr, y, x))
211             break;
212
213         g_ptr->info &= ~(CAVE_UNSAFE);
214         lite_spot(player_ptr, y, x);
215         obvious = true;
216         break;
217     }
218     case AttributeType::JAM_DOOR: {
219         if (f_ptr->flags.has_not(FloorFeatureType::SPIKE))
220             break;
221
222         int16_t old_mimic = g_ptr->mimic;
223         feature_type *mimic_f_ptr = &f_info[g_ptr->get_feat_mimic()];
224
225         cave_alter_feat(player_ptr, y, x, FloorFeatureType::SPIKE);
226         g_ptr->mimic = old_mimic;
227
228         note_spot(player_ptr, y, x);
229         lite_spot(player_ptr, y, x);
230
231         if (!known || mimic_f_ptr->flags.has_not(FloorFeatureType::OPEN))
232             break;
233
234         msg_format(_("%sに何かがつっかえて開かなくなった。", "The %s seems stuck."), mimic_f_ptr->name.c_str());
235         obvious = true;
236         break;
237     }
238     case AttributeType::KILL_WALL: {
239         if (f_ptr->flags.has_not(FloorFeatureType::HURT_ROCK))
240             break;
241
242         if (known && g_ptr->is_mark()) {
243             msg_format(_("%sが溶けて泥になった!", "The %s turns into mud!"), f_info[g_ptr->get_feat_mimic()].name.c_str());
244             obvious = true;
245         }
246
247         cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
248         player_ptr->update |= (PU_FLOW);
249         break;
250     }
251     case AttributeType::MAKE_DOOR: {
252         if (!cave_naked_bold(player_ptr, y, x))
253             break;
254         if (player_bold(player_ptr, y, x))
255             break;
256         cave_set_feat(player_ptr, y, x, feat_door[DOOR_DOOR].closed);
257         if (g_ptr->is_mark())
258             obvious = true;
259         break;
260     }
261     case AttributeType::MAKE_TRAP: {
262         place_trap(player_ptr, y, x);
263         break;
264     }
265     case AttributeType::MAKE_TREE: {
266         if (!cave_naked_bold(player_ptr, y, x))
267             break;
268         if (player_bold(player_ptr, y, x))
269             break;
270         cave_set_feat(player_ptr, y, x, feat_tree);
271         if (g_ptr->is_mark())
272             obvious = true;
273         break;
274     }
275     case AttributeType::MAKE_RUNE_PROTECTION: {
276         if (!cave_naked_bold(player_ptr, y, x))
277             break;
278         g_ptr->info |= CAVE_OBJECT;
279         g_ptr->mimic = feat_rune_protection;
280         note_spot(player_ptr, y, x);
281         lite_spot(player_ptr, y, x);
282         break;
283     }
284     case AttributeType::STONE_WALL: {
285         if (!cave_naked_bold(player_ptr, y, x))
286             break;
287         if (player_bold(player_ptr, y, x))
288             break;
289         cave_set_feat(player_ptr, y, x, feat_granite);
290         break;
291     }
292     case AttributeType::LAVA_FLOW: {
293         if (f_ptr->flags.has(FloorFeatureType::PERMANENT))
294             break;
295         if (dam == 1) {
296             if (f_ptr->flags.has_not(FloorFeatureType::FLOOR))
297                 break;
298             cave_set_feat(player_ptr, y, x, feat_shallow_lava);
299         } else if (dam) {
300             cave_set_feat(player_ptr, y, x, feat_deep_lava);
301         }
302
303         break;
304     }
305     case AttributeType::WATER_FLOW: {
306         if (f_ptr->flags.has(FloorFeatureType::PERMANENT))
307             break;
308         if (dam == 1) {
309             if (f_ptr->flags.has_not(FloorFeatureType::FLOOR))
310                 break;
311             cave_set_feat(player_ptr, y, x, feat_shallow_water);
312         } else if (dam) {
313             cave_set_feat(player_ptr, y, x, feat_deep_water);
314         }
315
316         break;
317     }
318     case AttributeType::LITE_WEAK:
319     case AttributeType::LITE: {
320         if (d_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS))
321             break;
322
323         g_ptr->info |= (CAVE_GLOW);
324         note_spot(player_ptr, y, x);
325         lite_spot(player_ptr, y, x);
326         update_local_illumination(player_ptr, y, x);
327
328         if (player_can_see_bold(player_ptr, y, x))
329             obvious = true;
330         if (g_ptr->m_idx)
331             update_monster(player_ptr, g_ptr->m_idx, false);
332
333         if (player_bold(player_ptr, y, x)) {
334             set_superstealth(player_ptr, false);
335         }
336
337         break;
338     }
339     case AttributeType::DARK_WEAK:
340     case AttributeType::DARK:
341     case AttributeType::ABYSS: {
342         bool do_dark = !player_ptr->phase_out && !g_ptr->is_mirror();
343         if (!do_dark)
344             break;
345
346         if ((floor_ptr->dun_level > 0) || !is_daytime()) {
347             for (int j = 0; j < 9; j++) {
348                 int by = y + ddy_ddd[j];
349                 int bx = x + ddx_ddd[j];
350
351                 if (!in_bounds2(floor_ptr, by, bx))
352                     continue;
353
354                 grid_type *cc_ptr = &floor_ptr->grid_array[by][bx];
355                 if (f_info[cc_ptr->get_feat_mimic()].flags.has(FloorFeatureType::GLOW)) {
356                     do_dark = false;
357                     break;
358                 }
359             }
360
361             if (!do_dark)
362                 break;
363         }
364
365         g_ptr->info &= ~(CAVE_GLOW);
366
367         /* Hack -- Forget "boring" grids */
368         if (f_ptr->flags.has_not(FloorFeatureType::REMEMBER) || has_element_resist(player_ptr, ElementRealmType::DARKNESS, 1)) {
369             /* Forget */
370             g_ptr->info &= ~(CAVE_MARK);
371             note_spot(player_ptr, y, x);
372         }
373
374         lite_spot(player_ptr, y, x);
375
376         update_local_illumination(player_ptr, y, x);
377
378         if (player_can_see_bold(player_ptr, y, x))
379             obvious = true;
380         if (g_ptr->m_idx)
381             update_monster(player_ptr, g_ptr->m_idx, false);
382
383         break;
384     }
385     case AttributeType::SHARDS:
386     case AttributeType::ROCKET: {
387         if (g_ptr->is_mirror()) {
388             msg_print(_("鏡が割れた!", "The mirror was shattered!"));
389             sound(SOUND_GLASS);
390             remove_mirror(player_ptr, y, x);
391             project(player_ptr, 0, 2, y, x, player_ptr->lev / 2 + 5, AttributeType::SHARDS,
392                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI));
393         }
394
395         if (f_ptr->flags.has_not(FloorFeatureType::GLASS) || f_ptr->flags.has(FloorFeatureType::PERMANENT) || (dam < 50))
396             break;
397
398         if (known && (g_ptr->is_mark())) {
399             msg_format(_("%sが割れた!", "The %s crumbled!"), f_info[g_ptr->get_feat_mimic()].name.c_str());
400             sound(SOUND_GLASS);
401         }
402
403         cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
404         player_ptr->update |= (PU_FLOW);
405         break;
406     }
407     case AttributeType::SOUND: {
408         if (g_ptr->is_mirror() && player_ptr->lev < 40) {
409             msg_print(_("鏡が割れた!", "The mirror was shattered!"));
410             sound(SOUND_GLASS);
411             remove_mirror(player_ptr, y, x);
412             project(player_ptr, 0, 2, y, x, player_ptr->lev / 2 + 5, AttributeType::SHARDS,
413                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI));
414         }
415
416         if (f_ptr->flags.has_not(FloorFeatureType::GLASS) || f_ptr->flags.has(FloorFeatureType::PERMANENT) || (dam < 200))
417             break;
418
419         if (known && (g_ptr->is_mark())) {
420             msg_format(_("%sが割れた!", "The %s crumbled!"), f_info[g_ptr->get_feat_mimic()].name.c_str());
421             sound(SOUND_GLASS);
422         }
423
424         cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_ROCK);
425         player_ptr->update |= (PU_FLOW);
426         break;
427     }
428     case AttributeType::DISINTEGRATE: {
429         if (g_ptr->is_mirror() || g_ptr->is_rune_protection() || g_ptr->is_rune_explosion())
430             remove_mirror(player_ptr, y, x);
431
432         if (f_ptr->flags.has_not(FloorFeatureType::HURT_DISI) || f_ptr->flags.has(FloorFeatureType::PERMANENT))
433             break;
434
435         cave_alter_feat(player_ptr, y, x, FloorFeatureType::HURT_DISI);
436         player_ptr->update |= (PU_FLOW);
437         break;
438     }
439     default:
440         break;
441     }
442
443     lite_spot(player_ptr, y, x);
444     return (obvious);
445 }