OSDN Git Service

[Refactor] #1172 Changed '(FALSE)', 'TRUE);' and 'FALSE);' to '(false)', 'true);...
[hengbandforosx/hengbandosx.git] / src / spell-kind / spells-floor.cpp
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 "floor/geometry.h"
23 #include "game-option/birth-options.h"
24 #include "game-option/cheat-options.h"
25 #include "game-option/map-screen-options.h"
26 #include "game-option/play-record-options.h"
27 #include "grid/feature.h"
28 #include "grid/feature-flag-types.h"
29 #include "grid/grid.h"
30 #include "io/write-diary.h"
31 #include "mind/mind-ninja.h"
32 #include "monster-floor/monster-lite.h"
33 #include "monster-race/monster-race.h"
34 #include "monster-race/race-flags1.h"
35 #include "monster/monster-describer.h"
36 #include "monster/monster-description-types.h"
37 #include "monster/monster-info.h"
38 #include "monster/monster-status.h"
39 #include "monster/smart-learn-types.h"
40 #include "object-enchant/special-object-flags.h"
41 #include "object-hook/hook-checker.h"
42 #include "object-hook/hook-enchant.h"
43 #include "object/object-mark-types.h"
44 #include "perception/object-perception.h"
45 #include "player/special-defense-types.h"
46 #include "player/player-status-flags.h"
47 #include "spell-kind/spells-teleport.h"
48 #include "spell/spell-types.h"
49 #include "status/bad-status-setter.h"
50 #include "system/artifact-type-definition.h"
51 #include "system/floor-type-definition.h"
52 #include "system/monster-race-definition.h"
53 #include "system/monster-type-definition.h"
54 #include "system/player-type-definition.h"
55 #include "util/bit-flags-calculator.h"
56 #include "view/display-messages.h"
57
58 /*
59  * @brief 啓蒙/陽光召喚処理
60  * @param caster_ptr プレーヤーへの参照ポインタ
61  * @param ninja 忍者かどうか
62  */
63 void wiz_lite(player_type *caster_ptr, bool ninja)
64 {
65     /* Memorize objects */
66     for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++) {
67         object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
68         if (!object_is_valid(o_ptr))
69             continue;
70         if (object_is_held_monster(o_ptr))
71             continue;
72         o_ptr->marked |= OM_FOUND;
73     }
74
75     /* Scan all normal grids */
76     for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++) {
77         /* Scan all normal grids */
78         for (POSITION x = 1; x < caster_ptr->current_floor_ptr->width - 1; x++) {
79             grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
80
81             /* Memorize terrain of the grid */
82             g_ptr->info |= (CAVE_KNOWN);
83
84             /* Feature code (applying "mimic" field) */
85             FEAT_IDX feat = get_feat_mimic(g_ptr);
86             feature_type *f_ptr;
87             f_ptr = &f_info[feat];
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].flags.has_not(DF::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_flags |= (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_flags |= (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].flags.has(DF::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             /* Memorize normal features */
208             if (has_flag(f_ptr->flags, FF_REMEMBER)) {
209                 /* Memorize the object */
210                 g_ptr->info |= (CAVE_MARK);
211             }
212
213             /* Memorize known walls */
214             for (int i = 0; i < 8; i++) {
215                 g_ptr = &caster_ptr->current_floor_ptr->grid_array[y + ddy_ddd[i]][x + ddx_ddd[i]];
216
217                 /* Feature code (applying "mimic" field) */
218                 feat = get_feat_mimic(g_ptr);
219                 f_ptr = &f_info[feat];
220
221                 /* Memorize walls (etc) */
222                 if (has_flag(f_ptr->flags, FF_REMEMBER)) {
223                     /* Memorize the walls */
224                     g_ptr->info |= (CAVE_MARK);
225                 }
226             }
227         }
228     }
229
230     caster_ptr->redraw |= (PR_MAP);
231     caster_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
232 }
233
234 /*!
235  * @brief *破壊*処理を行う / The spell of destruction
236  * @param y1 破壊の中心Y座標
237  * @param x1 破壊の中心X座標
238  * @param r 破壊の半径
239  * @param in_generate ダンジョンフロア生成中の処理ならばTRUE
240  * @return 効力があった場合TRUEを返す
241  * @details
242  * <pre>
243  * This spell "deletes" monsters (instead of "killing" them).
244  *
245  * Later we may use one function for both "destruction" and
246  * "earthquake" by using the "full" to select "destruction".
247  * </pre>
248  */
249 bool destroy_area(player_type *caster_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate)
250 {
251     /* Prevent destruction of quest levels and town */
252     floor_type *floor_ptr = caster_ptr->current_floor_ptr;
253     if ((floor_ptr->inside_quest && is_fixed_quest_idx(floor_ptr->inside_quest)) || !floor_ptr->dun_level) {
254         return false;
255     }
256
257     /* Lose monster light */
258     if (!in_generate)
259         clear_mon_lite(floor_ptr);
260
261     /* Big area of affect */
262     bool flag = false;
263     for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
264         for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
265             if (!in_bounds(floor_ptr, y, x))
266                 continue;
267
268             /* Extract the distance */
269             int k = distance(y1, x1, y, x);
270
271             /* Stay in the circle of death */
272             if (k > r)
273                 continue;
274             grid_type *g_ptr;
275             g_ptr = &floor_ptr->grid_array[y][x];
276
277             /* Lose room and vault */
278             g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
279
280             /* Lose light and knowledge */
281             g_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
282
283             if (!in_generate) /* Normal */
284             {
285                 /* Lose unsafety */
286                 g_ptr->info &= ~(CAVE_UNSAFE);
287
288                 /* Hack -- Notice player affect */
289                 if (player_bold(caster_ptr, y, x)) {
290                     /* Hurt the player later */
291                     flag = true;
292
293                     /* Do not hurt this grid */
294                     continue;
295                 }
296             }
297
298             /* Hack -- Skip the epicenter */
299             if ((y == y1) && (x == x1))
300                 continue;
301
302             if (g_ptr->m_idx) {
303                 monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
304                 monster_race *r_ptr = &r_info[m_ptr->r_idx];
305
306                 if (in_generate) /* In generation */
307                 {
308                     /* Delete the monster (if any) */
309                     delete_monster(caster_ptr, y, x);
310                 } else if (r_ptr->flags1 & RF1_QUESTOR) {
311                     /* Heal the monster */
312                     m_ptr->hp = m_ptr->maxhp;
313
314                     /* Try to teleport away quest monsters */
315                     if (!teleport_away(caster_ptr, g_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR))
316                         continue;
317                 } else {
318                     if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) {
319                         GAME_TEXT m_name[MAX_NLEN];
320
321                         monster_desc(caster_ptr, m_name, m_ptr, MD_INDEF_VISIBLE);
322                         exe_write_diary(caster_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name);
323                     }
324
325                     /* Delete the monster (if any) */
326                     delete_monster(caster_ptr, y, x);
327                 }
328             }
329
330             /* During generation, destroyed artifacts are "preserved" */
331             if (preserve_mode || in_generate) {
332                 /* Scan all objects in the grid */
333                 for (const auto this_o_idx : g_ptr->o_idx_list) {
334                     object_type *o_ptr;
335                     o_ptr = &floor_ptr->o_list[this_o_idx];
336
337                     /* Hack -- Preserve unknown artifacts */
338                     if (object_is_fixed_artifact(o_ptr) && (!object_is_known(o_ptr) || in_generate)) {
339                         /* Mega-Hack -- Preserve the artifact */
340                         a_info[o_ptr->name1].cur_num = 0;
341
342                         if (in_generate && cheat_peek) {
343                             GAME_TEXT o_name[MAX_NLEN];
344                             describe_flavor(caster_ptr, o_name, o_ptr, (OD_NAME_ONLY | OD_STORE));
345                             msg_format(_("伝説のアイテム (%s) は生成中に*破壊*された。", "Artifact (%s) was *destroyed* during generation."), o_name);
346                         }
347                     } else if (in_generate && cheat_peek && o_ptr->art_name) {
348                         msg_print(
349                             _("ランダム・アーティファクトの1つは生成中に*破壊*された。", "One of the random artifacts was *destroyed* during generation."));
350                     }
351                 }
352             }
353
354             delete_all_items_from_floor(caster_ptr, y, x);
355
356             /* Destroy "non-permanent" grids */
357             if (cave_has_flag_grid(g_ptr, FF_PERMANENT))
358                 continue;
359
360             /* Wall (or floor) type */
361             int t = randint0(200);
362
363             if (!in_generate) /* Normal */
364             {
365                 if (t < 20) {
366                     /* Create granite wall */
367                     cave_set_feat(caster_ptr, y, x, feat_granite);
368                 } else if (t < 70) {
369                     /* Create quartz vein */
370                     cave_set_feat(caster_ptr, y, x, feat_quartz_vein);
371                 } else if (t < 100) {
372                     /* Create magma vein */
373                     cave_set_feat(caster_ptr, y, x, feat_magma_vein);
374                 } else {
375                     /* Create floor */
376                     cave_set_feat(caster_ptr, y, x, feat_ground_type[randint0(100)]);
377                 }
378
379                 continue;
380             }
381
382             if (t < 20) {
383                 /* Create granite wall */
384                 place_grid(caster_ptr, g_ptr, GB_EXTRA);
385             } else if (t < 70) {
386                 /* Create quartz vein */
387                 g_ptr->feat = feat_quartz_vein;
388             } else if (t < 100) {
389                 /* Create magma vein */
390                 g_ptr->feat = feat_magma_vein;
391             } else {
392                 /* Create floor */
393                 place_grid(caster_ptr, g_ptr, GB_FLOOR);
394             }
395
396             /* Clear garbage of hidden trap or door */
397             g_ptr->mimic = 0;
398         }
399     }
400
401     if (in_generate)
402         return true;
403
404     /* Process "re-glowing" */
405     for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
406         for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
407             if (!in_bounds(floor_ptr, y, x))
408                 continue;
409
410             /* Extract the distance */
411             int k = distance(y1, x1, y, x);
412
413             /* Stay in the circle of death */
414             if (k > r)
415                 continue;
416             grid_type *g_ptr;
417             g_ptr = &floor_ptr->grid_array[y][x];
418
419             if (is_mirror_grid(g_ptr)) {
420                 g_ptr->info |= CAVE_GLOW;
421                 continue;
422             }
423
424             if (d_info[floor_ptr->dungeon_idx].flags.has(DF::DARKNESS))
425                 continue;
426
427             DIRECTION i;
428             POSITION yy, xx;
429             grid_type *cc_ptr;
430
431             for (i = 0; i < 9; i++) {
432                 yy = y + ddy_ddd[i];
433                 xx = x + ddx_ddd[i];
434                 if (!in_bounds2(floor_ptr, yy, xx))
435                     continue;
436                 cc_ptr = &floor_ptr->grid_array[yy][xx];
437                 if (has_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) {
438                     g_ptr->info |= CAVE_GLOW;
439                     break;
440                 }
441             }
442         }
443     }
444
445     /* Hack -- Affect player */
446     if (flag) {
447         msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!"));
448
449         /* Blind the player */
450         if (!has_resist_blind(caster_ptr) && !has_resist_lite(caster_ptr)) {
451             /* Become blind */
452             (void)set_blind(caster_ptr, caster_ptr->blind + 10 + randint1(10));
453         }
454     }
455
456     forget_flow(floor_ptr);
457
458     /* Mega-Hack -- Forget the view and lite */
459     caster_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS);
460     caster_ptr->redraw |= (PR_MAP);
461     caster_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
462
463     if (caster_ptr->special_defense & NINJA_S_STEALTH) {
464         if (floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info & CAVE_GLOW)
465             set_superstealth(caster_ptr, false);
466     }
467
468     return true;
469 }