OSDN Git Service

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