OSDN Git Service

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