OSDN Git Service

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