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 "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"
55 * @param caster_ptr プレーヤーへの参照ポインタ
59 void wiz_lite(player_type *caster_ptr, bool ninja)
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))
66 if (object_is_held_monster(o_ptr))
68 o_ptr->marked |= OM_FOUND;
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];
77 /* Memorize terrain of the grid */
78 g_ptr->info |= (CAVE_KNOWN);
80 /* Feature code (applying "mimic" field) */
81 FEAT_IDX feat = get_feat_mimic(g_ptr);
83 f_ptr = &f_info[feat];
85 /* Process all non-walls */
86 if (has_flag(f_ptr->flags, FF_WALL))
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].flags1 & DF1_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 |= (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 |= (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].flags1 & DF1_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 /* All non-walls are "checked" */
208 if (has_flag(f_ptr->flags, FF_WALL))
211 /* Memorize normal features */
212 if (has_flag(f_ptr->flags, FF_REMEMBER)) {
213 /* Memorize the object */
214 g_ptr->info |= (CAVE_MARK);
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]];
221 /* Feature code (applying "mimic" field) */
222 feat = get_feat_mimic(g_ptr);
223 f_ptr = &f_info[feat];
225 /* Memorize walls (etc) */
226 if (has_flag(f_ptr->flags, FF_REMEMBER)) {
227 /* Memorize the walls */
228 g_ptr->info |= (CAVE_MARK);
234 caster_ptr->redraw |= (PR_MAP);
235 caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
239 * @brief *破壊*処理を行う / The spell of destruction
243 * @param in_generate ダンジョンフロア生成中の処理ならばTRUE
244 * @return 効力があった場合TRUEを返す
247 * This spell "deletes" monsters (instead of "killing" them).
249 * Later we may use one function for both "destruction" and
250 * "earthquake" by using the "full" to select "destruction".
253 bool destroy_area(player_type *caster_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate)
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) {
261 /* Lose monster light */
263 clear_mon_lite(floor_ptr);
265 /* Big area of affect */
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))
272 /* Extract the distance */
273 int k = distance(y1, x1, y, x);
275 /* Stay in the circle of death */
279 g_ptr = &floor_ptr->grid_array[y][x];
281 /* Lose room and vault */
282 g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
284 /* Lose light and knowledge */
285 g_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
287 if (!in_generate) /* Normal */
290 g_ptr->info &= ~(CAVE_UNSAFE);
292 /* Hack -- Notice player affect */
293 if (player_bold(caster_ptr, y, x)) {
294 /* Hurt the player later */
297 /* Do not hurt this grid */
302 /* Hack -- Skip the epicenter */
303 if ((y == y1) && (x == x1))
307 monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
308 monster_race *r_ptr = &r_info[m_ptr->r_idx];
310 if (in_generate) /* In generation */
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;
318 /* Try to teleport away quest monsters */
319 if (!teleport_away(caster_ptr, g_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR))
322 if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) {
323 GAME_TEXT m_name[MAX_NLEN];
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);
329 /* Delete the monster (if any) */
330 delete_monster(caster_ptr, y, x);
334 /* During generation, destroyed artifacts are "preserved" */
335 if (preserve_mode || in_generate) {
336 OBJECT_IDX this_o_idx, next_o_idx = 0;
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) {
341 o_ptr = &floor_ptr->o_list[this_o_idx];
342 next_o_idx = o_ptr->next_o_idx;
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;
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);
354 } else if (in_generate && cheat_peek && o_ptr->art_name) {
356 _("ランダム・アーティファクトの1つは生成中に*破壊*された。", "One of the random artifacts was *destroyed* during generation."));
361 delete_all_items_from_floor(caster_ptr, y, x);
363 /* Destroy "non-permanent" grids */
364 if (cave_has_flag_grid(g_ptr, FF_PERMANENT))
367 /* Wall (or floor) type */
368 int t = randint0(200);
370 if (!in_generate) /* Normal */
373 /* Create granite wall */
374 cave_set_feat(caster_ptr, y, x, feat_granite);
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);
383 cave_set_feat(caster_ptr, y, x, feat_ground_type[randint0(100)]);
390 /* Create granite wall */
391 place_grid(caster_ptr, g_ptr, GB_EXTRA);
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;
400 place_grid(caster_ptr, g_ptr, GB_FLOOR);
403 /* Clear garbage of hidden trap or door */
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))
417 /* Extract the distance */
418 int k = distance(y1, x1, y, x);
420 /* Stay in the circle of death */
424 g_ptr = &floor_ptr->grid_array[y][x];
426 if (is_mirror_grid(g_ptr)) {
427 g_ptr->info |= CAVE_GLOW;
431 if ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
438 for (i = 0; i < 9; i++) {
441 if (!in_bounds2(floor_ptr, yy, xx))
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;
452 /* Hack -- Affect player */
454 msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!"));
456 /* Blind the player */
457 if (!caster_ptr->resist_blind && !has_resist_lite(caster_ptr)) {
459 (void)set_blind(caster_ptr, caster_ptr->blind + 10 + randint1(10));
463 forget_flow(floor_ptr);
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);
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);