2 * @brief フロアに影響のある魔法の処理
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"
60 * @param caster_ptr プレーヤーへの参照ポインタ
63 void wiz_lite(player_type *caster_ptr, bool ninja)
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))
70 if (object_is_held_monster(o_ptr))
72 o_ptr->marked |= OM_FOUND;
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];
81 /* Memorize terrain of the grid */
82 g_ptr->info |= (CAVE_KNOWN);
84 /* Feature code (applying "mimic" field) */
85 FEAT_IDX feat = get_feat_mimic(g_ptr);
87 f_ptr = &f_info[feat];
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];
95 /* Feature code (applying "mimic" field) */
96 f_ptr = &f_info[get_feat_mimic(g_ptr)];
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);
103 /* Memorize normal features */
104 if (has_flag(f_ptr->flags, FF_REMEMBER)) {
105 /* Memorize the grid */
106 g_ptr->info |= (CAVE_MARK);
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);
121 caster_ptr->update |= (PU_MONSTERS);
122 caster_ptr->redraw |= (PR_MAP);
123 caster_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
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);
132 * Forget the dungeon map (ala "Thinking of Maud...").
134 void wiz_dark(player_type *caster_ptr)
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];
141 /* Process the grid */
142 g_ptr->info &= ~(CAVE_MARK | CAVE_IN_DETECT | CAVE_KNOWN);
143 g_ptr->info |= (CAVE_UNSAFE);
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);
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);
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];
163 if (!object_is_valid(o_ptr))
165 if (object_is_held_monster(o_ptr))
168 /* Forget the object */
169 o_ptr->marked &= OM_TOUCHED;
172 /* Forget travel route when we have forgotten map */
173 forget_travel_flow(caster_ptr->current_floor_ptr);
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);
183 * Hack -- map the current panel (plus some) ala "magic mapping"
185 void map_area(player_type *caster_ptr, POSITION range)
187 if (d_info[caster_ptr->dungeon_idx].flags.has(DF::DARKNESS))
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)
197 g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
199 /* Memorize terrain of the grid */
200 g_ptr->info |= (CAVE_KNOWN);
202 /* Feature code (applying "mimic" field) */
203 FEAT_IDX feat = get_feat_mimic(g_ptr);
205 f_ptr = &f_info[feat];
207 /* Memorize normal features */
208 if (has_flag(f_ptr->flags, FF_REMEMBER)) {
209 /* Memorize the object */
210 g_ptr->info |= (CAVE_MARK);
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]];
217 /* Feature code (applying "mimic" field) */
218 feat = get_feat_mimic(g_ptr);
219 f_ptr = &f_info[feat];
221 /* Memorize walls (etc) */
222 if (has_flag(f_ptr->flags, FF_REMEMBER)) {
223 /* Memorize the walls */
224 g_ptr->info |= (CAVE_MARK);
230 caster_ptr->redraw |= (PR_MAP);
231 caster_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
235 * @brief *破壊*処理を行う / The spell of destruction
239 * @param in_generate ダンジョンフロア生成中の処理ならばTRUE
240 * @return 効力があった場合TRUEを返す
243 * This spell "deletes" monsters (instead of "killing" them).
245 * Later we may use one function for both "destruction" and
246 * "earthquake" by using the "full" to select "destruction".
249 bool destroy_area(player_type *caster_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate)
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) {
257 /* Lose monster light */
259 clear_mon_lite(floor_ptr);
261 /* Big area of affect */
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))
268 /* Extract the distance */
269 int k = distance(y1, x1, y, x);
271 /* Stay in the circle of death */
275 g_ptr = &floor_ptr->grid_array[y][x];
277 /* Lose room and vault */
278 g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
280 /* Lose light and knowledge */
281 g_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
283 if (!in_generate) /* Normal */
286 g_ptr->info &= ~(CAVE_UNSAFE);
288 /* Hack -- Notice player affect */
289 if (player_bold(caster_ptr, y, x)) {
290 /* Hurt the player later */
293 /* Do not hurt this grid */
298 /* Hack -- Skip the epicenter */
299 if ((y == y1) && (x == x1))
303 monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
304 monster_race *r_ptr = &r_info[m_ptr->r_idx];
306 if (in_generate) /* In generation */
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;
314 /* Try to teleport away quest monsters */
315 if (!teleport_away(caster_ptr, g_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR))
318 if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) {
319 GAME_TEXT m_name[MAX_NLEN];
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);
325 /* Delete the monster (if any) */
326 delete_monster(caster_ptr, y, x);
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) {
335 o_ptr = &floor_ptr->o_list[this_o_idx];
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;
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);
347 } else if (in_generate && cheat_peek && o_ptr->art_name) {
349 _("ランダム・アーティファクトの1つは生成中に*破壊*された。", "One of the random artifacts was *destroyed* during generation."));
354 delete_all_items_from_floor(caster_ptr, y, x);
356 /* Destroy "non-permanent" grids */
357 if (cave_has_flag_grid(g_ptr, FF_PERMANENT))
360 /* Wall (or floor) type */
361 int t = randint0(200);
363 if (!in_generate) /* Normal */
366 /* Create granite wall */
367 cave_set_feat(caster_ptr, y, x, feat_granite);
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);
376 cave_set_feat(caster_ptr, y, x, feat_ground_type[randint0(100)]);
383 /* Create granite wall */
384 place_grid(caster_ptr, g_ptr, GB_EXTRA);
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;
393 place_grid(caster_ptr, g_ptr, GB_FLOOR);
396 /* Clear garbage of hidden trap or door */
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))
410 /* Extract the distance */
411 int k = distance(y1, x1, y, x);
413 /* Stay in the circle of death */
417 g_ptr = &floor_ptr->grid_array[y][x];
419 if (is_mirror_grid(g_ptr)) {
420 g_ptr->info |= CAVE_GLOW;
424 if (d_info[floor_ptr->dungeon_idx].flags.has(DF::DARKNESS))
431 for (i = 0; i < 9; i++) {
434 if (!in_bounds2(floor_ptr, yy, xx))
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;
445 /* Hack -- Affect player */
447 msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!"));
449 /* Blind the player */
450 if (!has_resist_blind(caster_ptr) && !has_resist_lite(caster_ptr)) {
452 (void)set_blind(caster_ptr, caster_ptr->blind + 10 + randint1(10));
456 forget_flow(floor_ptr);
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);
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);