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/window-redrawer.h"
11 #include "dungeon/dungeon-flag-types.h"
12 #include "dungeon/quest.h"
13 #include "effect/attribute-types.h"
14 #include "flavor/flavor-describer.h"
15 #include "flavor/object-flavor-types.h"
16 #include "floor/cave.h"
17 #include "floor/floor-object.h"
18 #include "floor/floor-save.h"
19 #include "floor/floor-util.h"
20 #include "floor/geometry.h"
21 #include "game-option/birth-options.h"
22 #include "game-option/cheat-options.h"
23 #include "game-option/map-screen-options.h"
24 #include "game-option/play-record-options.h"
25 #include "grid/feature-flag-types.h"
26 #include "grid/feature.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/object-mark-types.h"
40 #include "perception/object-perception.h"
41 #include "player/player-status-flags.h"
42 #include "player/special-defense-types.h"
43 #include "spell-kind/spells-teleport.h"
44 #include "status/bad-status-setter.h"
45 #include "system/artifact-type-definition.h"
46 #include "system/dungeon-info.h"
47 #include "system/floor-type-definition.h"
48 #include "system/grid-type-definition.h"
49 #include "system/item-entity.h"
50 #include "system/monster-entity.h"
51 #include "system/monster-race-info.h"
52 #include "system/player-type-definition.h"
53 #include "system/redrawing-flags-updater.h"
54 #include "system/terrain-type-definition.h"
55 #include "util/bit-flags-calculator.h"
56 #include "view/display-messages.h"
60 * @param player_ptr プレイヤーへの参照ポインタ
63 void wiz_lite(PlayerType *player_ptr, bool ninja)
65 /* Memorize objects */
66 auto &floor = *player_ptr->current_floor_ptr;
67 for (OBJECT_IDX i = 1; i < floor.o_max; i++) {
68 auto *o_ptr = &floor.o_list[i];
69 if (!o_ptr->is_valid()) {
72 if (o_ptr->is_held_by_monster()) {
75 o_ptr->marked.set(OmType::FOUND);
78 /* Scan all normal grids */
79 const auto &terrains = TerrainList::get_instance();
80 for (POSITION y = 1; y < floor.height - 1; y++) {
81 /* Scan all normal grids */
82 for (POSITION x = 1; x < floor.width - 1; x++) {
83 auto *g_ptr = &floor.grid_array[y][x];
85 /* Memorize terrain of the grid */
86 g_ptr->info |= (CAVE_KNOWN);
88 /* Feature code (applying "mimic" field) */
89 FEAT_IDX feat = g_ptr->get_feat_mimic();
90 auto *t_ptr = &terrains[feat];
92 /* Scan all neighbors */
93 for (OBJECT_IDX i = 0; i < 9; i++) {
94 POSITION yy = y + ddy_ddd[i];
95 POSITION xx = x + ddx_ddd[i];
96 g_ptr = &floor.grid_array[yy][xx];
98 /* Feature code (applying "mimic" field) */
99 t_ptr = &terrains[g_ptr->get_feat_mimic()];
101 /* Perma-lite the grid */
102 if (floor.get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS) && !ninja) {
103 g_ptr->info |= (CAVE_GLOW);
106 /* Memorize normal features */
107 if (t_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
108 /* Memorize the grid */
109 g_ptr->info |= (CAVE_MARK);
112 /* Perma-lit grids (newly and previously) */
113 else if (g_ptr->info & CAVE_GLOW) {
114 /* Normally, memorize floors (see above) */
115 if (view_perma_grids && !view_torch_grids) {
116 /* Memorize the grid */
117 g_ptr->info |= (CAVE_MARK);
124 auto &rfu = RedrawingFlagsUpdater::get_instance();
125 rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
126 rfu.set_flag(MainWindowRedrawingFlag::MAP);
127 static constexpr auto flags_swrf = {
128 SubWindowRedrawingFlag::OVERHEAD,
129 SubWindowRedrawingFlag::DUNGEON,
130 SubWindowRedrawingFlag::FOUND_ITEMS,
132 rfu.set_flags(flags_swrf);
133 if (floor.grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
134 set_superstealth(player_ptr, false);
139 * Forget the dungeon map (ala "Thinking of Maud...").
141 void wiz_dark(PlayerType *player_ptr)
143 /* Forget every grid */
144 for (POSITION y = 1; y < player_ptr->current_floor_ptr->height - 1; y++) {
145 for (POSITION x = 1; x < player_ptr->current_floor_ptr->width - 1; x++) {
146 auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
148 /* Process the grid */
149 g_ptr->info &= ~(CAVE_MARK | CAVE_IN_DETECT | CAVE_KNOWN);
150 g_ptr->info |= (CAVE_UNSAFE);
154 /* Forget every grid on horizontal edge */
155 for (POSITION x = 0; x < player_ptr->current_floor_ptr->width; x++) {
156 player_ptr->current_floor_ptr->grid_array[0][x].info &= ~(CAVE_MARK);
157 player_ptr->current_floor_ptr->grid_array[player_ptr->current_floor_ptr->height - 1][x].info &= ~(CAVE_MARK);
160 /* Forget every grid on vertical edge */
161 for (POSITION y = 1; y < (player_ptr->current_floor_ptr->height - 1); y++) {
162 player_ptr->current_floor_ptr->grid_array[y][0].info &= ~(CAVE_MARK);
163 player_ptr->current_floor_ptr->grid_array[y][player_ptr->current_floor_ptr->width - 1].info &= ~(CAVE_MARK);
166 /* Forget all objects */
167 for (OBJECT_IDX i = 1; i < player_ptr->current_floor_ptr->o_max; i++) {
168 auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i];
170 if (!o_ptr->is_valid()) {
173 if (o_ptr->is_held_by_monster()) {
177 /* Forget the object */
178 // 意図としては OmType::TOUCHED を維持しつつ OmType::FOUND を消す事と思われるが一応元のロジックを維持しておく
179 o_ptr->marked &= { OmType::TOUCHED };
182 /* Forget travel route when we have forgotten map */
183 forget_travel_flow(player_ptr->current_floor_ptr);
185 auto &rfu = RedrawingFlagsUpdater::get_instance();
186 static constexpr auto flags_srf = {
187 StatusRecalculatingFlag::UN_VIEW,
188 StatusRecalculatingFlag::UN_LITE,
189 StatusRecalculatingFlag::VIEW,
190 StatusRecalculatingFlag::LITE,
191 StatusRecalculatingFlag::MONSTER_LITE,
192 StatusRecalculatingFlag::MONSTER_STATUSES,
194 rfu.set_flags(flags_srf);
195 rfu.set_flag(MainWindowRedrawingFlag::MAP);
196 static constexpr auto flags_swrf = {
197 SubWindowRedrawingFlag::OVERHEAD,
198 SubWindowRedrawingFlag::DUNGEON,
199 SubWindowRedrawingFlag::FOUND_ITEMS,
201 rfu.set_flags(flags_swrf);
205 * Hack -- map the current panel (plus some) ala "magic mapping"
207 void map_area(PlayerType *player_ptr, POSITION range)
209 auto &floor = *player_ptr->current_floor_ptr;
210 if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
215 const auto &terrains = TerrainList::get_instance();
216 for (POSITION y = 1; y < floor.height - 1; y++) {
217 for (POSITION x = 1; x < floor.width - 1; x++) {
218 if (distance(player_ptr->y, player_ptr->x, y, x) > range) {
223 g_ptr = &floor.grid_array[y][x];
225 /* Memorize terrain of the grid */
226 g_ptr->info |= (CAVE_KNOWN);
228 /* Feature code (applying "mimic" field) */
229 FEAT_IDX feat = g_ptr->get_feat_mimic();
230 auto *t_ptr = &terrains[feat];
232 /* Memorize normal features */
233 if (t_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
234 /* Memorize the object */
235 g_ptr->info |= (CAVE_MARK);
238 /* Memorize known walls */
239 for (int i = 0; i < 8; i++) {
240 g_ptr = &floor.grid_array[y + ddy_ddd[i]][x + ddx_ddd[i]];
242 /* Feature code (applying "mimic" field) */
243 feat = g_ptr->get_feat_mimic();
244 t_ptr = &terrains[feat];
246 /* Memorize walls (etc) */
247 if (t_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
248 /* Memorize the walls */
249 g_ptr->info |= (CAVE_MARK);
255 auto &rfu = RedrawingFlagsUpdater::get_instance();
256 rfu.set_flag(MainWindowRedrawingFlag::MAP);
257 static constexpr auto flags_swrf = {
258 SubWindowRedrawingFlag::OVERHEAD,
259 SubWindowRedrawingFlag::DUNGEON,
261 rfu.set_flags(flags_swrf);
265 * @brief *破壊*処理を行う / The spell of destruction
269 * @param in_generate ダンジョンフロア生成中の処理ならばTRUE
270 * @return 効力があった場合TRUEを返す
273 * This spell "deletes" monsters (instead of "killing" them).
275 * Later we may use one function for both "destruction" and
276 * "earthquake" by using the "full" to select "destruction".
279 bool destroy_area(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate)
281 /* Prevent destruction of quest levels and town */
282 auto *floor_ptr = player_ptr->current_floor_ptr;
283 if ((floor_ptr->is_in_quest() && QuestType::is_fixed(floor_ptr->quest_number)) || !floor_ptr->dun_level) {
287 /* Lose monster light */
289 clear_mon_lite(floor_ptr);
292 /* Big area of affect */
294 for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
295 for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
296 if (!in_bounds(floor_ptr, y, x)) {
300 /* Extract the distance */
301 int k = distance(y1, x1, y, x);
303 /* Stay in the circle of death */
308 g_ptr = &floor_ptr->grid_array[y][x];
310 /* Lose room and vault */
311 g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
313 /* Lose light and knowledge */
314 g_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
316 if (!in_generate) /* Normal */
319 g_ptr->info &= ~(CAVE_UNSAFE);
321 /* Hack -- Notice player affect */
322 if (player_bold(player_ptr, y, x)) {
323 /* Hurt the player later */
326 /* Do not hurt this grid */
331 /* Hack -- Skip the epicenter */
332 if ((y == y1) && (x == x1)) {
337 auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
338 auto *r_ptr = &m_ptr->get_monrace();
340 if (in_generate) /* In generation */
342 /* Delete the monster (if any) */
343 delete_monster(player_ptr, y, x);
344 } else if (r_ptr->flags1 & RF1_QUESTOR) {
345 /* Heal the monster */
346 m_ptr->hp = m_ptr->maxhp;
348 /* Try to teleport away quest monsters */
349 if (!teleport_away(player_ptr, g_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR)) {
353 if (record_named_pet && m_ptr->is_named_pet()) {
354 const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
355 exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name);
358 /* Delete the monster (if any) */
359 delete_monster(player_ptr, y, x);
363 /* During generation, destroyed artifacts are "preserved" */
364 if (preserve_mode || in_generate) {
365 /* Scan all objects in the grid */
366 for (const auto this_o_idx : g_ptr->o_idx_list) {
368 o_ptr = &floor_ptr->o_list[this_o_idx];
370 /* Hack -- Preserve unknown artifacts */
371 if (o_ptr->is_fixed_artifact() && (!o_ptr->is_known() || in_generate)) {
372 o_ptr->get_fixed_artifact().is_generated = false;
374 if (in_generate && cheat_peek) {
375 const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_NAME_ONLY | OD_STORE));
376 msg_format(_("伝説のアイテム (%s) は生成中に*破壊*された。", "Artifact (%s) was *destroyed* during generation."), item_name.data());
378 } else if (in_generate && cheat_peek && o_ptr->is_random_artifact()) {
380 _("ランダム・アーティファクトの1つは生成中に*破壊*された。", "One of the random artifacts was *destroyed* during generation."));
385 delete_all_items_from_floor(player_ptr, y, x);
387 /* Destroy "non-permanent" grids */
388 if (g_ptr->cave_has_flag(TerrainCharacteristics::PERMANENT)) {
392 /* Wall (or floor) type */
393 int t = randint0(200);
395 if (!in_generate) /* Normal */
398 /* Create granite wall */
399 cave_set_feat(player_ptr, y, x, feat_granite);
401 /* Create quartz vein */
402 cave_set_feat(player_ptr, y, x, feat_quartz_vein);
403 } else if (t < 100) {
404 /* Create magma vein */
405 cave_set_feat(player_ptr, y, x, feat_magma_vein);
408 cave_set_feat(player_ptr, y, x, rand_choice(feat_ground_type));
415 /* Create granite wall */
416 place_grid(player_ptr, g_ptr, GB_EXTRA);
418 /* Create quartz vein */
419 g_ptr->feat = feat_quartz_vein;
420 } else if (t < 100) {
421 /* Create magma vein */
422 g_ptr->feat = feat_magma_vein;
425 place_grid(player_ptr, g_ptr, GB_FLOOR);
428 /* Clear garbage of hidden trap or door */
437 /* Process "re-glowing" */
438 for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
439 for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
440 if (!in_bounds(floor_ptr, y, x)) {
444 /* Extract the distance */
445 int k = distance(y1, x1, y, x);
447 /* Stay in the circle of death */
452 g_ptr = &floor_ptr->grid_array[y][x];
454 if (g_ptr->is_mirror()) {
455 g_ptr->info |= CAVE_GLOW;
459 if (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
467 for (i = 0; i < 9; i++) {
470 if (!in_bounds2(floor_ptr, yy, xx)) {
473 cc_ptr = &floor_ptr->grid_array[yy][xx];
474 if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(TerrainCharacteristics::GLOW)) {
475 g_ptr->info |= CAVE_GLOW;
483 msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!"));
484 if (!has_resist_blind(player_ptr) && !has_resist_lite(player_ptr)) {
485 (void)BadStatusSetter(player_ptr).mod_blindness(10 + randint1(10));
489 forget_flow(floor_ptr);
490 auto &rfu = RedrawingFlagsUpdater::get_instance();
491 static constexpr auto flags_srf = {
492 StatusRecalculatingFlag::UN_VIEW,
493 StatusRecalculatingFlag::UN_LITE,
494 StatusRecalculatingFlag::VIEW,
495 StatusRecalculatingFlag::LITE,
496 StatusRecalculatingFlag::FLOW,
497 StatusRecalculatingFlag::MONSTER_LITE,
498 StatusRecalculatingFlag::MONSTER_STATUSES,
500 rfu.set_flags(flags_srf);
501 rfu.set_flag(MainWindowRedrawingFlag::MAP);
502 static constexpr auto flags_swrf = {
503 SubWindowRedrawingFlag::OVERHEAD,
504 SubWindowRedrawingFlag::DUNGEON,
506 rfu.set_flags(flags_swrf);
507 if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
508 set_superstealth(player_ptr, false);