OSDN Git Service

Merge pull request #2723 from Hourier/Fix-History-Generator-Humand
[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/quest.h"
15 #include "effect/attribute-types.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-flag-types.h"
28 #include "grid/feature.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/object-mark-types.h"
42 #include "perception/object-perception.h"
43 #include "player/player-status-flags.h"
44 #include "player/special-defense-types.h"
45 #include "spell-kind/spells-teleport.h"
46 #include "status/bad-status-setter.h"
47 #include "system/artifact-type-definition.h"
48 #include "system/dungeon-info.h"
49 #include "system/floor-type-definition.h"
50 #include "system/grid-type-definition.h"
51 #include "system/monster-race-definition.h"
52 #include "system/monster-type-definition.h"
53 #include "system/player-type-definition.h"
54 #include "util/bit-flags-calculator.h"
55 #include "view/display-messages.h"
56
57 /*
58  * @brief 啓蒙/陽光召喚処理
59  * @param player_ptr プレイヤーへの参照ポインタ
60  * @param ninja 忍者かどうか
61  */
62 void wiz_lite(PlayerType *player_ptr, bool ninja)
63 {
64     /* Memorize objects */
65     for (OBJECT_IDX i = 1; i < player_ptr->current_floor_ptr->o_max; i++) {
66         auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i];
67         if (!o_ptr->is_valid()) {
68             continue;
69         }
70         if (o_ptr->is_held_by_monster()) {
71             continue;
72         }
73         o_ptr->marked |= OM_FOUND;
74     }
75
76     /* Scan all normal grids */
77     for (POSITION y = 1; y < player_ptr->current_floor_ptr->height - 1; y++) {
78         /* Scan all normal grids */
79         for (POSITION x = 1; x < player_ptr->current_floor_ptr->width - 1; x++) {
80             auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
81
82             /* Memorize terrain of the grid */
83             g_ptr->info |= (CAVE_KNOWN);
84
85             /* Feature code (applying "mimic" field) */
86             FEAT_IDX feat = g_ptr->get_feat_mimic();
87             terrain_type *f_ptr;
88             f_ptr = &terrains_info[feat];
89
90             /* Scan all neighbors */
91             for (OBJECT_IDX i = 0; i < 9; i++) {
92                 POSITION yy = y + ddy_ddd[i];
93                 POSITION xx = x + ddx_ddd[i];
94                 g_ptr = &player_ptr->current_floor_ptr->grid_array[yy][xx];
95
96                 /* Feature code (applying "mimic" field) */
97                 f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
98
99                 /* Perma-lite the grid */
100                 if (dungeons_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS) && !ninja) {
101                     g_ptr->info |= (CAVE_GLOW);
102                 }
103
104                 /* Memorize normal features */
105                 if (f_ptr->flags.has(FloorFeatureType::REMEMBER)) {
106                     /* Memorize the grid */
107                     g_ptr->info |= (CAVE_MARK);
108                 }
109
110                 /* Perma-lit grids (newly and previously) */
111                 else if (g_ptr->info & CAVE_GLOW) {
112                     /* Normally, memorize floors (see above) */
113                     if (view_perma_grids && !view_torch_grids) {
114                         /* Memorize the grid */
115                         g_ptr->info |= (CAVE_MARK);
116                     }
117                 }
118             }
119         }
120     }
121
122     player_ptr->update |= (PU_MONSTERS);
123     player_ptr->redraw |= (PR_MAP);
124     player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
125
126     if (player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
127         set_superstealth(player_ptr, false);
128     }
129 }
130
131 /*
132  * Forget the dungeon map (ala "Thinking of Maud...").
133  */
134 void wiz_dark(PlayerType *player_ptr)
135 {
136     /* Forget every grid */
137     for (POSITION y = 1; y < player_ptr->current_floor_ptr->height - 1; y++) {
138         for (POSITION x = 1; x < player_ptr->current_floor_ptr->width - 1; x++) {
139             auto *g_ptr = &player_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 < player_ptr->current_floor_ptr->width; x++) {
149         player_ptr->current_floor_ptr->grid_array[0][x].info &= ~(CAVE_MARK);
150         player_ptr->current_floor_ptr->grid_array[player_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 < (player_ptr->current_floor_ptr->height - 1); y++) {
155         player_ptr->current_floor_ptr->grid_array[y][0].info &= ~(CAVE_MARK);
156         player_ptr->current_floor_ptr->grid_array[y][player_ptr->current_floor_ptr->width - 1].info &= ~(CAVE_MARK);
157     }
158
159     /* Forget all objects */
160     for (OBJECT_IDX i = 1; i < player_ptr->current_floor_ptr->o_max; i++) {
161         auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i];
162
163         if (!o_ptr->is_valid()) {
164             continue;
165         }
166         if (o_ptr->is_held_by_monster()) {
167             continue;
168         }
169
170         /* Forget the object */
171         o_ptr->marked &= OM_TOUCHED;
172     }
173
174     /* Forget travel route when we have forgotten map */
175     forget_travel_flow(player_ptr->current_floor_ptr);
176
177     player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
178     player_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE);
179     player_ptr->update |= (PU_MONSTERS);
180     player_ptr->redraw |= (PR_MAP);
181     player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
182 }
183
184 /*
185  * Hack -- map the current panel (plus some) ala "magic mapping"
186  */
187 void map_area(PlayerType *player_ptr, POSITION range)
188 {
189     if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
190         range /= 3;
191     }
192
193     /* Scan that area */
194     for (POSITION y = 1; y < player_ptr->current_floor_ptr->height - 1; y++) {
195         for (POSITION x = 1; x < player_ptr->current_floor_ptr->width - 1; x++) {
196             if (distance(player_ptr->y, player_ptr->x, y, x) > range) {
197                 continue;
198             }
199
200             grid_type *g_ptr;
201             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
202
203             /* Memorize terrain of the grid */
204             g_ptr->info |= (CAVE_KNOWN);
205
206             /* Feature code (applying "mimic" field) */
207             FEAT_IDX feat = g_ptr->get_feat_mimic();
208             terrain_type *f_ptr;
209             f_ptr = &terrains_info[feat];
210
211             /* Memorize normal features */
212             if (f_ptr->flags.has(FloorFeatureType::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 = &player_ptr->current_floor_ptr->grid_array[y + ddy_ddd[i]][x + ddx_ddd[i]];
220
221                 /* Feature code (applying "mimic" field) */
222                 feat = g_ptr->get_feat_mimic();
223                 f_ptr = &terrains_info[feat];
224
225                 /* Memorize walls (etc) */
226                 if (f_ptr->flags.has(FloorFeatureType::REMEMBER)) {
227                     /* Memorize the walls */
228                     g_ptr->info |= (CAVE_MARK);
229                 }
230             }
231         }
232     }
233
234     player_ptr->redraw |= (PR_MAP);
235     player_ptr->window_flags |= (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(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate)
254 {
255     /* Prevent destruction of quest levels and town */
256     auto *floor_ptr = player_ptr->current_floor_ptr;
257     if ((inside_quest(floor_ptr->quest_number) && quest_type::is_fixed(floor_ptr->quest_number)) || !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
266     /* Big area of affect */
267     bool flag = false;
268     for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
269         for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
270             if (!in_bounds(floor_ptr, y, x)) {
271                 continue;
272             }
273
274             /* Extract the distance */
275             int k = distance(y1, x1, y, x);
276
277             /* Stay in the circle of death */
278             if (k > r) {
279                 continue;
280             }
281             grid_type *g_ptr;
282             g_ptr = &floor_ptr->grid_array[y][x];
283
284             /* Lose room and vault */
285             g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
286
287             /* Lose light and knowledge */
288             g_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
289
290             if (!in_generate) /* Normal */
291             {
292                 /* Lose unsafety */
293                 g_ptr->info &= ~(CAVE_UNSAFE);
294
295                 /* Hack -- Notice player affect */
296                 if (player_bold(player_ptr, y, x)) {
297                     /* Hurt the player later */
298                     flag = true;
299
300                     /* Do not hurt this grid */
301                     continue;
302                 }
303             }
304
305             /* Hack -- Skip the epicenter */
306             if ((y == y1) && (x == x1)) {
307                 continue;
308             }
309
310             if (g_ptr->m_idx) {
311                 auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
312                 auto *r_ptr = &monraces_info[m_ptr->r_idx];
313
314                 if (in_generate) /* In generation */
315                 {
316                     /* Delete the monster (if any) */
317                     delete_monster(player_ptr, y, x);
318                 } else if (r_ptr->flags1 & RF1_QUESTOR) {
319                     /* Heal the monster */
320                     m_ptr->hp = m_ptr->maxhp;
321
322                     /* Try to teleport away quest monsters */
323                     if (!teleport_away(player_ptr, g_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR)) {
324                         continue;
325                     }
326                 } else {
327                     if (record_named_pet && m_ptr->is_pet() && m_ptr->nickname) {
328                         GAME_TEXT m_name[MAX_NLEN];
329
330                         monster_desc(player_ptr, m_name, m_ptr, MD_INDEF_VISIBLE);
331                         exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name);
332                     }
333
334                     /* Delete the monster (if any) */
335                     delete_monster(player_ptr, y, x);
336                 }
337             }
338
339             /* During generation, destroyed artifacts are "preserved" */
340             if (preserve_mode || in_generate) {
341                 /* Scan all objects in the grid */
342                 for (const auto this_o_idx : g_ptr->o_idx_list) {
343                     ObjectType *o_ptr;
344                     o_ptr = &floor_ptr->o_list[this_o_idx];
345
346                     /* Hack -- Preserve unknown artifacts */
347                     if (o_ptr->is_fixed_artifact() && (!o_ptr->is_known() || in_generate)) {
348                         artifacts_info.at(o_ptr->fixed_artifact_idx).is_generated = false;
349
350                         if (in_generate && cheat_peek) {
351                             GAME_TEXT o_name[MAX_NLEN];
352                             describe_flavor(player_ptr, o_name, o_ptr, (OD_NAME_ONLY | OD_STORE));
353                             msg_format(_("伝説のアイテム (%s) は生成中に*破壊*された。", "Artifact (%s) was *destroyed* during generation."), o_name);
354                         }
355                     } else if (in_generate && cheat_peek && o_ptr->art_name) {
356                         msg_print(
357                             _("ランダム・アーティファクトの1つは生成中に*破壊*された。", "One of the random artifacts was *destroyed* during generation."));
358                     }
359                 }
360             }
361
362             delete_all_items_from_floor(player_ptr, y, x);
363
364             /* Destroy "non-permanent" grids */
365             if (g_ptr->cave_has_flag(FloorFeatureType::PERMANENT)) {
366                 continue;
367             }
368
369             /* Wall (or floor) type */
370             int t = randint0(200);
371
372             if (!in_generate) /* Normal */
373             {
374                 if (t < 20) {
375                     /* Create granite wall */
376                     cave_set_feat(player_ptr, y, x, feat_granite);
377                 } else if (t < 70) {
378                     /* Create quartz vein */
379                     cave_set_feat(player_ptr, y, x, feat_quartz_vein);
380                 } else if (t < 100) {
381                     /* Create magma vein */
382                     cave_set_feat(player_ptr, y, x, feat_magma_vein);
383                 } else {
384                     /* Create floor */
385                     cave_set_feat(player_ptr, y, x, feat_ground_type[randint0(100)]);
386                 }
387
388                 continue;
389             }
390
391             if (t < 20) {
392                 /* Create granite wall */
393                 place_grid(player_ptr, g_ptr, GB_EXTRA);
394             } else if (t < 70) {
395                 /* Create quartz vein */
396                 g_ptr->feat = feat_quartz_vein;
397             } else if (t < 100) {
398                 /* Create magma vein */
399                 g_ptr->feat = feat_magma_vein;
400             } else {
401                 /* Create floor */
402                 place_grid(player_ptr, g_ptr, GB_FLOOR);
403             }
404
405             /* Clear garbage of hidden trap or door */
406             g_ptr->mimic = 0;
407         }
408     }
409
410     if (in_generate) {
411         return true;
412     }
413
414     /* Process "re-glowing" */
415     for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
416         for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
417             if (!in_bounds(floor_ptr, y, x)) {
418                 continue;
419             }
420
421             /* Extract the distance */
422             int k = distance(y1, x1, y, x);
423
424             /* Stay in the circle of death */
425             if (k > r) {
426                 continue;
427             }
428             grid_type *g_ptr;
429             g_ptr = &floor_ptr->grid_array[y][x];
430
431             if (g_ptr->is_mirror()) {
432                 g_ptr->info |= CAVE_GLOW;
433                 continue;
434             }
435
436             if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
437                 continue;
438             }
439
440             DIRECTION i;
441             POSITION yy, xx;
442             grid_type *cc_ptr;
443
444             for (i = 0; i < 9; i++) {
445                 yy = y + ddy_ddd[i];
446                 xx = x + ddx_ddd[i];
447                 if (!in_bounds2(floor_ptr, yy, xx)) {
448                     continue;
449                 }
450                 cc_ptr = &floor_ptr->grid_array[yy][xx];
451                 if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(FloorFeatureType::GLOW)) {
452                     g_ptr->info |= CAVE_GLOW;
453                     break;
454                 }
455             }
456         }
457     }
458
459     if (flag) {
460         msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!"));
461         if (!has_resist_blind(player_ptr) && !has_resist_lite(player_ptr)) {
462             (void)BadStatusSetter(player_ptr).mod_blindness(10 + randint1(10));
463         }
464     }
465
466     forget_flow(floor_ptr);
467
468     /* Mega-Hack -- Forget the view and lite */
469     player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS);
470     player_ptr->redraw |= (PR_MAP);
471     player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
472
473     if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
474         set_superstealth(player_ptr, false);
475     }
476
477     return true;
478 }