OSDN Git Service

[Refactor] #40514 player_type の resist_sound 変数を廃止. / Abolished the resist_sound...
[hengband/hengband.git] / src / spell-kind / spells-floor.c
1 /*!
2  * @brief フロアに影響のある魔法の処理
3  * @date 2019/02/21
4  * @author deskull
5  */
6
7 #include "spell-kind/spells-floor.h"
8 #include "action/travel-execution.h"
9 #include "cmd-io/cmd-dump.h"
10 #include "core/player-redraw-types.h"
11 #include "core/player-update-types.h"
12 #include "core/window-redrawer.h"
13 #include "dungeon/dungeon-flag-types.h"
14 #include "dungeon/dungeon.h"
15 #include "dungeon/quest.h"
16 #include "flavor/flavor-describer.h"
17 #include "flavor/object-flavor-types.h"
18 #include "floor/cave.h"
19 #include "floor/floor-object.h"
20 #include "floor/floor-save.h"
21 #include "floor/floor-util.h"
22 #include "game-option/birth-options.h"
23 #include "game-option/cheat-options.h"
24 #include "game-option/map-screen-options.h"
25 #include "game-option/play-record-options.h"
26 #include "grid/feature-flag-types.h"
27 #include "grid/grid.h"
28 #include "io/write-diary.h"
29 #include "mind/mind-ninja.h"
30 #include "monster-floor/monster-lite.h"
31 #include "monster-race/monster-race.h"
32 #include "monster-race/race-flags1.h"
33 #include "monster/monster-describer.h"
34 #include "monster/monster-description-types.h"
35 #include "monster/monster-info.h"
36 #include "monster/monster-status.h"
37 #include "monster/smart-learn-types.h"
38 #include "object-enchant/special-object-flags.h"
39 #include "object-hook/hook-checker.h"
40 #include "object-hook/hook-enchant.h"
41 #include "object/object-mark-types.h"
42 #include "perception/object-perception.h"
43 #include "player/special-defense-types.h"
44 #include "spell-kind/spells-teleport.h"
45 #include "spell/spell-types.h"
46 #include "status/bad-status-setter.h"
47 #include "system/artifact-type-definition.h"
48 #include "system/floor-type-definition.h"
49 #include "util/bit-flags-calculator.h"
50 #include "view/display-messages.h"
51
52 /*
53  * @brief 啓蒙/陽光召喚処理
54  * @param caster_ptr プレーヤーへの参照ポインタ
55  * @param ninja 忍者かどうか
56  * @return なし
57  */
58 void wiz_lite(player_type *caster_ptr, bool ninja)
59 {
60     /* Memorize objects */
61     for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
62         object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
63         if (!object_is_valid(o_ptr))
64             continue;
65         if (object_is_held_monster(o_ptr))
66             continue;
67         o_ptr->marked |= OM_FOUND;
68     }
69
70     /* Scan all normal grids */
71     for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++) {
72         /* Scan all normal grids */
73         for (POSITION x = 1; x < caster_ptr->current_floor_ptr->width - 1; x++) {
74             grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
75
76             /* Memorize terrain of the grid */
77             g_ptr->info |= (CAVE_KNOWN);
78
79             /* Feature code (applying "mimic" field) */
80             FEAT_IDX feat = get_feat_mimic(g_ptr);
81             feature_type *f_ptr;
82             f_ptr = &f_info[feat];
83
84             /* Process all non-walls */
85             if (has_flag(f_ptr->flags, FF_WALL))
86                 continue;
87
88             /* Scan all neighbors */
89             for (OBJECT_IDX i = 0; i < 9; i++) {
90                 POSITION yy = y + ddy_ddd[i];
91                 POSITION xx = x + ddx_ddd[i];
92                 g_ptr = &caster_ptr->current_floor_ptr->grid_array[yy][xx];
93
94                 /* Feature code (applying "mimic" field) */
95                 f_ptr = &f_info[get_feat_mimic(g_ptr)];
96
97                 /* Perma-lite the grid */
98                 if (!(d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS) && !ninja) {
99                     g_ptr->info |= (CAVE_GLOW);
100                 }
101
102                 /* Memorize normal features */
103                 if (has_flag(f_ptr->flags, FF_REMEMBER)) {
104                     /* Memorize the grid */
105                     g_ptr->info |= (CAVE_MARK);
106                 }
107
108                 /* Perma-lit grids (newly and previously) */
109                 else if (g_ptr->info & CAVE_GLOW) {
110                     /* Normally, memorize floors (see above) */
111                     if (view_perma_grids && !view_torch_grids) {
112                         /* Memorize the grid */
113                         g_ptr->info |= (CAVE_MARK);
114                     }
115                 }
116             }
117         }
118     }
119
120     caster_ptr->update |= (PU_MONSTERS);
121     caster_ptr->redraw |= (PR_MAP);
122     caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
123
124     if (caster_ptr->special_defense & NINJA_S_STEALTH) {
125         if (caster_ptr->current_floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info & CAVE_GLOW)
126             set_superstealth(caster_ptr, FALSE);
127     }
128 }
129
130 /*
131  * Forget the dungeon map (ala "Thinking of Maud...").
132  */
133 void wiz_dark(player_type *caster_ptr)
134 {
135     /* Forget every grid */
136     for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++) {
137         for (POSITION x = 1; x < caster_ptr->current_floor_ptr->width - 1; x++) {
138             grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
139
140             /* Process the grid */
141             g_ptr->info &= ~(CAVE_MARK | CAVE_IN_DETECT | CAVE_KNOWN);
142             g_ptr->info |= (CAVE_UNSAFE);
143         }
144     }
145
146     /* Forget every grid on horizontal edge */
147     for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++) {
148         caster_ptr->current_floor_ptr->grid_array[0][x].info &= ~(CAVE_MARK);
149         caster_ptr->current_floor_ptr->grid_array[caster_ptr->current_floor_ptr->height - 1][x].info &= ~(CAVE_MARK);
150     }
151
152     /* Forget every grid on vertical edge */
153     for (POSITION y = 1; y < (caster_ptr->current_floor_ptr->height - 1); y++) {
154         caster_ptr->current_floor_ptr->grid_array[y][0].info &= ~(CAVE_MARK);
155         caster_ptr->current_floor_ptr->grid_array[y][caster_ptr->current_floor_ptr->width - 1].info &= ~(CAVE_MARK);
156     }
157
158     /* Forget all objects */
159     for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
160         object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
161
162         if (!object_is_valid(o_ptr))
163             continue;
164         if (object_is_held_monster(o_ptr))
165             continue;
166
167         /* Forget the object */
168         o_ptr->marked &= OM_TOUCHED;
169     }
170
171     /* Forget travel route when we have forgotten map */
172     forget_travel_flow(caster_ptr->current_floor_ptr);
173
174     caster_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
175     caster_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE);
176     caster_ptr->update |= (PU_MONSTERS);
177     caster_ptr->redraw |= (PR_MAP);
178     caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
179 }
180
181 /*
182  * Hack -- map the current panel (plus some) ala "magic mapping"
183  */
184 void map_area(player_type *caster_ptr, POSITION range)
185 {
186     if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS)
187         range /= 3;
188
189     /* Scan that area */
190     for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++) {
191         for (POSITION x = 1; x < caster_ptr->current_floor_ptr->width - 1; x++) {
192             if (distance(caster_ptr->y, caster_ptr->x, y, x) > range)
193                 continue;
194
195             grid_type *g_ptr;
196             g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
197
198             /* Memorize terrain of the grid */
199             g_ptr->info |= (CAVE_KNOWN);
200
201             /* Feature code (applying "mimic" field) */
202             FEAT_IDX feat = get_feat_mimic(g_ptr);
203             feature_type *f_ptr;
204             f_ptr = &f_info[feat];
205
206             /* All non-walls are "checked" */
207             if (has_flag(f_ptr->flags, FF_WALL))
208                 continue;
209
210             /* Memorize normal features */
211             if (has_flag(f_ptr->flags, FF_REMEMBER)) {
212                 /* Memorize the object */
213                 g_ptr->info |= (CAVE_MARK);
214             }
215
216             /* Memorize known walls */
217             for (int i = 0; i < 8; i++) {
218                 g_ptr = &caster_ptr->current_floor_ptr->grid_array[y + ddy_ddd[i]][x + ddx_ddd[i]];
219
220                 /* Feature code (applying "mimic" field) */
221                 feat = get_feat_mimic(g_ptr);
222                 f_ptr = &f_info[feat];
223
224                 /* Memorize walls (etc) */
225                 if (has_flag(f_ptr->flags, FF_REMEMBER)) {
226                     /* Memorize the walls */
227                     g_ptr->info |= (CAVE_MARK);
228                 }
229             }
230         }
231     }
232
233     caster_ptr->redraw |= (PR_MAP);
234     caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
235 }
236
237 /*!
238  * @brief *破壊*処理を行う / The spell of destruction
239  * @param y1 破壊の中心Y座標
240  * @param x1 破壊の中心X座標
241  * @param r 破壊の半径
242  * @param in_generate ダンジョンフロア生成中の処理ならばTRUE
243  * @return 効力があった場合TRUEを返す
244  * @details
245  * <pre>
246  * This spell "deletes" monsters (instead of "killing" them).
247  *
248  * Later we may use one function for both "destruction" and
249  * "earthquake" by using the "full" to select "destruction".
250  * </pre>
251  */
252 bool destroy_area(player_type *caster_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate)
253 {
254     /* Prevent destruction of quest levels and town */
255     floor_type *floor_ptr = caster_ptr->current_floor_ptr;
256     if ((floor_ptr->inside_quest && is_fixed_quest_idx(floor_ptr->inside_quest)) || !floor_ptr->dun_level) {
257         return FALSE;
258     }
259
260     /* Lose monster light */
261     if (!in_generate)
262         clear_mon_lite(floor_ptr);
263
264     /* Big area of affect */
265     bool flag = FALSE;
266     for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
267         for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
268             if (!in_bounds(floor_ptr, y, x))
269                 continue;
270
271             /* Extract the distance */
272             int k = distance(y1, x1, y, x);
273
274             /* Stay in the circle of death */
275             if (k > r)
276                 continue;
277             grid_type *g_ptr;
278             g_ptr = &floor_ptr->grid_array[y][x];
279
280             /* Lose room and vault */
281             g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
282
283             /* Lose light and knowledge */
284             g_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
285
286             if (!in_generate) /* Normal */
287             {
288                 /* Lose unsafety */
289                 g_ptr->info &= ~(CAVE_UNSAFE);
290
291                 /* Hack -- Notice player affect */
292                 if (player_bold(caster_ptr, y, x)) {
293                     /* Hurt the player later */
294                     flag = TRUE;
295
296                     /* Do not hurt this grid */
297                     continue;
298                 }
299             }
300
301             /* Hack -- Skip the epicenter */
302             if ((y == y1) && (x == x1))
303                 continue;
304
305             if (g_ptr->m_idx) {
306                 monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
307                 monster_race *r_ptr = &r_info[m_ptr->r_idx];
308
309                 if (in_generate) /* In generation */
310                 {
311                     /* Delete the monster (if any) */
312                     delete_monster(caster_ptr, y, x);
313                 } else if (r_ptr->flags1 & RF1_QUESTOR) {
314                     /* Heal the monster */
315                     m_ptr->hp = m_ptr->maxhp;
316
317                     /* Try to teleport away quest monsters */
318                     if (!teleport_away(caster_ptr, g_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR))
319                         continue;
320                 } else {
321                     if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) {
322                         GAME_TEXT m_name[MAX_NLEN];
323
324                         monster_desc(caster_ptr, m_name, m_ptr, MD_INDEF_VISIBLE);
325                         exe_write_diary(caster_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name);
326                     }
327
328                     /* Delete the monster (if any) */
329                     delete_monster(caster_ptr, y, x);
330                 }
331             }
332
333             /* During generation, destroyed artifacts are "preserved" */
334             if (preserve_mode || in_generate) {
335                 OBJECT_IDX this_o_idx, next_o_idx = 0;
336
337                 /* Scan all objects in the grid */
338                 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
339                     object_type *o_ptr;
340                     o_ptr = &floor_ptr->o_list[this_o_idx];
341                     next_o_idx = o_ptr->next_o_idx;
342
343                     /* Hack -- Preserve unknown artifacts */
344                     if (object_is_fixed_artifact(o_ptr) && (!object_is_known(o_ptr) || in_generate)) {
345                         /* Mega-Hack -- Preserve the artifact */
346                         a_info[o_ptr->name1].cur_num = 0;
347
348                         if (in_generate && cheat_peek) {
349                             GAME_TEXT o_name[MAX_NLEN];
350                             describe_flavor(caster_ptr, o_name, o_ptr, (OD_NAME_ONLY | OD_STORE));
351                             msg_format(_("伝説のアイテム (%s) は生成中に*破壊*された。", "Artifact (%s) was *destroyed* during generation."), o_name);
352                         }
353                     } else if (in_generate && cheat_peek && o_ptr->art_name) {
354                         msg_print(
355                             _("ランダム・アーティファクトの1つは生成中に*破壊*された。", "One of the random artifacts was *destroyed* during generation."));
356                     }
357                 }
358             }
359
360             delete_all_items_from_floor(caster_ptr, y, x);
361
362             /* Destroy "non-permanent" grids */
363             if (cave_has_flag_grid(g_ptr, FF_PERMANENT))
364                 continue;
365
366             /* Wall (or floor) type */
367             int t = randint0(200);
368
369             if (!in_generate) /* Normal */
370             {
371                 if (t < 20) {
372                     /* Create granite wall */
373                     cave_set_feat(caster_ptr, y, x, feat_granite);
374                 } else if (t < 70) {
375                     /* Create quartz vein */
376                     cave_set_feat(caster_ptr, y, x, feat_quartz_vein);
377                 } else if (t < 100) {
378                     /* Create magma vein */
379                     cave_set_feat(caster_ptr, y, x, feat_magma_vein);
380                 } else {
381                     /* Create floor */
382                     cave_set_feat(caster_ptr, y, x, feat_ground_type[randint0(100)]);
383                 }
384
385                 continue;
386             }
387
388             if (t < 20) {
389                 /* Create granite wall */
390                 place_grid(caster_ptr, g_ptr, GB_EXTRA);
391             } else if (t < 70) {
392                 /* Create quartz vein */
393                 g_ptr->feat = feat_quartz_vein;
394             } else if (t < 100) {
395                 /* Create magma vein */
396                 g_ptr->feat = feat_magma_vein;
397             } else {
398                 /* Create floor */
399                 place_grid(caster_ptr, g_ptr, GB_FLOOR);
400             }
401
402             /* Clear garbage of hidden trap or door */
403             g_ptr->mimic = 0;
404         }
405     }
406
407     if (in_generate)
408         return TRUE;
409
410     /* Process "re-glowing" */
411     for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
412         for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
413             if (!in_bounds(floor_ptr, y, x))
414                 continue;
415
416             /* Extract the distance */
417             int k = distance(y1, x1, y, x);
418
419             /* Stay in the circle of death */
420             if (k > r)
421                 continue;
422             grid_type *g_ptr;
423             g_ptr = &floor_ptr->grid_array[y][x];
424
425             if (is_mirror_grid(g_ptr)) {
426                 g_ptr->info |= CAVE_GLOW;
427                 continue;
428             }
429
430             if ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
431                 continue;
432
433             DIRECTION i;
434             POSITION yy, xx;
435             grid_type *cc_ptr;
436
437             for (i = 0; i < 9; i++) {
438                 yy = y + ddy_ddd[i];
439                 xx = x + ddx_ddd[i];
440                 if (!in_bounds2(floor_ptr, yy, xx))
441                     continue;
442                 cc_ptr = &floor_ptr->grid_array[yy][xx];
443                 if (has_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) {
444                     g_ptr->info |= CAVE_GLOW;
445                     break;
446                 }
447             }
448         }
449     }
450
451     /* Hack -- Affect player */
452     if (flag) {
453         msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!"));
454
455         /* Blind the player */
456         if (!caster_ptr->resist_blind && !caster_ptr->resist_lite) {
457             /* Become blind */
458             (void)set_blind(caster_ptr, caster_ptr->blind + 10 + randint1(10));
459         }
460     }
461
462     forget_flow(floor_ptr);
463
464     /* Mega-Hack -- Forget the view and lite */
465     caster_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS);
466     caster_ptr->redraw |= (PR_MAP);
467     caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
468
469     if (caster_ptr->special_defense & NINJA_S_STEALTH) {
470         if (floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info & CAVE_GLOW)
471             set_superstealth(caster_ptr, FALSE);
472     }
473
474     return TRUE;
475 }