OSDN Git Service

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