OSDN Git Service

4e1c2b9a940eab231721d566cb9c082066b02abb
[hengband/hengband.git] / src / floor / floor-save.c
1 /*!
2  * @brief 保存された階の管理 / management of the saved floor
3  * @date 2014/01/04
4  * @author
5  * Copyright (c) 2002  Mogami \n
6  * This software may be copied and distributed for educational, research, and \n
7  * not for profit purposes provided that this copyright and statement are \n
8  * included in all such copies. \n
9  * 2014 Deskull rearranged comment for Doxygen. \n
10  */
11
12 #include "floor/floor-save.h"
13 #include "action/travel-execution.h"
14 #include "cmd-building/cmd-building.h"
15 #include "cmd-io/cmd-dump.h"
16 #include "core/asking-player.h"
17 #include "dungeon/dungeon.h"
18 #include "dungeon/quest-monster-placer.h"
19 #include "dungeon/quest.h"
20 #include "floor/cave.h"
21 #include "floor/floor-events.h"
22 #include "floor/floor-generator.h"
23 #include "floor/floor-object.h"
24 #include "floor/floor.h"
25 #include "floor/geometry.h"
26 #include "floor/wild.h"
27 #include "game-option/birth-options.h"
28 #include "game-option/play-record-options.h"
29 #include "grid/feature.h"
30 #include "grid/grid.h"
31 #include "inventory/inventory-slot-types.h"
32 #include "io/files-util.h"
33 #include "io/uid-checker.h"
34 #include "io/write-diary.h"
35 #include "load/floor-loader.h"
36 #include "main/sound-of-music.h"
37 #include "mind/mind-mirror-master.h"
38 #include "mind/mind-ninja.h"
39 #include "monster-floor/monster-generator.h"
40 #include "monster-floor/monster-lite.h"
41 #include "monster-floor/monster-remover.h"
42 #include "monster-floor/monster-summon.h"
43 #include "monster-race/monster-race.h"
44 #include "monster-race/race-flags1.h"
45 #include "monster-race/race-flags2.h"
46 #include "monster-race/race-flags7.h"
47 #include "monster/monster-describer.h"
48 #include "monster/monster-description-types.h"
49 #include "monster/monster-flag-types.h"
50 #include "monster/monster-info.h"
51 #include "monster/monster-list.h"
52 #include "monster/monster-status-setter.h"
53 #include "monster/monster-status.h"
54 #include "monster/monster-update.h"
55 #include "monster/smart-learn-types.h"
56 #include "object-hook/hook-checker.h"
57 #include "object-hook/hook-enchant.h"
58 #include "pet/pet-util.h"
59 #include "player/player-class.h"
60 #include "player/player-personalities-types.h"
61 #include "player/special-defense-types.h"
62 #include "save/floor-writer.h"
63 #include "spell-kind/spells-floor.h"
64 #include "system/artifact-type-definition.h"
65 #include "system/floor-type-definition.h"
66 #include "system/system-variables.h"
67 #include "util/angband-files.h"
68 #include "util/bit-flags-calculator.h"
69 #include "view/display-messages.h"
70 #include "window/main-window-util.h"
71 #include "world/world.h"
72
73 #define MAX_PARTY_MON 21 /*!< フロア移動時に先のフロアに連れて行けるペットの最大数 Maximum number of preservable pets */
74
75 bool repair_monsters;
76 FLOOR_IDX max_floor_id; /*!< Number of floor_id used from birth */
77
78 /*
79  * Sign for current process used in temporary files.
80  * Actually it is the start time of current process.
81  */
82 u32b saved_floor_file_sign;
83 saved_floor_type saved_floors[MAX_SAVED_FLOORS];
84
85 static FLOOR_IDX new_floor_id; /*!<次のフロアのID / floor_id of the destination */
86 static u32b latest_visit_mark; /*!<フロアを渡った回数?(確認中) / Max number of visit_mark */
87 static monster_type party_mon[MAX_PARTY_MON]; /*!< フロア移動に保存するペットモンスターの配列 */
88
89 /*!
90  * @brief 保存フロア配列を初期化する / Initialize saved_floors array.
91  * @param creature_ptr プレーヤーへの参照ポインタ
92  * @param force テンポラリファイルが残っていた場合も警告なしで強制的に削除するフラグ
93  * @details Make sure that old temporary files are not remaining as gurbages.
94  * @return なし
95  */
96 void init_saved_floors(player_type *creature_ptr, bool force)
97 {
98     char floor_savefile[1024];
99     int fd = -1;
100     BIT_FLAGS mode = 0644;
101     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
102         saved_floor_type *sf_ptr = &saved_floors[i];
103         sprintf(floor_savefile, "%s.F%02d", savefile, i);
104         safe_setuid_grab(creature_ptr);
105         fd = fd_make(floor_savefile, mode);
106         safe_setuid_drop();
107         if (fd < 0) {
108             if (!force) {
109                 msg_print(_("エラー:古いテンポラリ・ファイルが残っています。", "Error: There are old temporary files."));
110                 msg_print(_("変愚蛮怒を二重に起動していないか確認してください。", "Make sure you are not running two game processes simultaneously."));
111                 msg_print(_("過去に変愚蛮怒がクラッシュした場合は一時ファイルを", "If the temporary files are garbage from an old crashed process, "));
112                 msg_print(_("強制的に削除して実行を続けられます。", "you can delete them safely."));
113                 if (!get_check(_("強制的に削除してもよろしいですか?", "Do you delete the old temporary files? ")))
114                     quit(_("実行中止", "Aborted."));
115
116                 force = TRUE;
117             }
118         } else
119             (void)fd_close(fd);
120
121         safe_setuid_grab(creature_ptr);
122         (void)fd_kill(floor_savefile);
123         safe_setuid_drop();
124         sf_ptr->floor_id = 0;
125     }
126
127     max_floor_id = 1;
128     latest_visit_mark = 1;
129     saved_floor_file_sign = (u32b)time(NULL);
130     new_floor_id = 0;
131     creature_ptr->change_floor_mode = 0;
132 }
133
134 /*!
135  * @brief 保存フロア用テンポラリファイルを削除する / Kill temporary files
136  * @details Should be called just before the game quit.
137  * @param creature_ptr プレーヤーへの参照ポインタ
138  * @return なし
139  */
140 void clear_saved_floor_files(player_type *creature_ptr)
141 {
142     char floor_savefile[1024];
143     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
144         saved_floor_type *sf_ptr = &saved_floors[i];
145         if ((sf_ptr->floor_id == 0) || (sf_ptr->floor_id == creature_ptr->floor_id))
146             continue;
147
148         sprintf(floor_savefile, "%s.F%02d", savefile, i);
149         safe_setuid_grab(creature_ptr);
150         (void)fd_kill(floor_savefile);
151         safe_setuid_drop();
152     }
153 }
154
155 /*!
156  * @brief 保存フロアIDから参照ポインタを得る / Get a pointer for an item of the saved_floors array.
157  * @param floor_id 保存フロアID
158  * @return IDに対応する保存フロアのポインタ、ない場合はNULLを返す。
159  */
160 saved_floor_type *get_sf_ptr(FLOOR_IDX floor_id)
161 {
162     if (!floor_id)
163         return NULL;
164
165     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
166         saved_floor_type *sf_ptr = &saved_floors[i];
167         if (sf_ptr->floor_id == floor_id)
168             return sf_ptr;
169     }
170
171     return NULL;
172 }
173
174 /*!
175  * @brief 参照ポインタ先の保存フロアを抹消する / kill a saved floor and get an empty space
176  * @param creature_ptr プレーヤーへの参照ポインタ
177  * @param sf_ptr 保存フロアの参照ポインタ
178  * @return なし
179  */
180 static void kill_saved_floor(player_type *creature_ptr, saved_floor_type *sf_ptr)
181 {
182     char floor_savefile[1024];
183     if (!sf_ptr || (sf_ptr->floor_id == 0))
184         return;
185
186     if (sf_ptr->floor_id == creature_ptr->floor_id) {
187         creature_ptr->floor_id = 0;
188         sf_ptr->floor_id = 0;
189         return;
190     }
191
192     sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id);
193     safe_setuid_grab(creature_ptr);
194     (void)fd_kill(floor_savefile);
195     safe_setuid_drop();
196     sf_ptr->floor_id = 0;
197 }
198
199 /*!
200  * @brief 新規に利用可能な保存フロアを返す / Initialize new saved floor and get its floor id.
201  * @param creature_ptr プレーヤーへの参照ポインタ
202  * @return 利用可能な保存フロアID
203  * @details
204  * If number of saved floors are already MAX_SAVED_FLOORS, kill the oldest one.
205  */
206 FLOOR_IDX get_new_floor_id(player_type *creature_ptr)
207 {
208     saved_floor_type *sf_ptr = NULL;
209     FLOOR_IDX i;
210     for (i = 0; i < MAX_SAVED_FLOORS; i++) {
211         sf_ptr = &saved_floors[i];
212         if (!sf_ptr->floor_id)
213             break;
214     }
215
216     if (i == MAX_SAVED_FLOORS) {
217         s16b oldest = 0;
218         u32b oldest_visit = 0xffffffffL;
219         for (i = 0; i < MAX_SAVED_FLOORS; i++) {
220             sf_ptr = &saved_floors[i];
221             if ((sf_ptr->floor_id == creature_ptr->floor_id) || (sf_ptr->visit_mark > oldest_visit))
222                 continue;
223
224             oldest = i;
225             oldest_visit = sf_ptr->visit_mark;
226         }
227
228         sf_ptr = &saved_floors[oldest];
229         kill_saved_floor(creature_ptr, sf_ptr);
230         i = oldest;
231     }
232
233     sf_ptr->savefile_id = i;
234     sf_ptr->floor_id = max_floor_id;
235     sf_ptr->last_visit = 0;
236     sf_ptr->upper_floor_id = 0;
237     sf_ptr->lower_floor_id = 0;
238     sf_ptr->visit_mark = latest_visit_mark++;
239     sf_ptr->dun_level = creature_ptr->current_floor_ptr->dun_level;
240     if (max_floor_id < MAX_SHORT)
241         max_floor_id++;
242     else
243         max_floor_id = 1; // 32767 floor_ids are all used up!  Re-use ancient IDs.
244
245     return sf_ptr->floor_id;
246 }
247
248 /*!
249  * @brief フロア切り替え時の処理フラグを追加する / Prepare mode flags of changing floor
250  * @param creature_ptr プレーヤーへの参照ポインタ
251  * @param mode 追加したい所持フラグ
252  * @return なし
253  */
254 void prepare_change_floor_mode(player_type *creature_ptr, BIT_FLAGS mode) { creature_ptr->change_floor_mode |= mode; }
255
256 /*!
257  * @brief 階段移動先のフロアが生成できない時に簡単な行き止まりマップを作成する / Builds the dead end
258  * @return なし
259  */
260 static void build_dead_end(player_type *creature_ptr)
261 {
262     clear_cave(creature_ptr);
263     creature_ptr->x = creature_ptr->y = 0;
264     set_floor_and_wall(0);
265     creature_ptr->current_floor_ptr->height = SCREEN_HGT;
266     creature_ptr->current_floor_ptr->width = SCREEN_WID;
267     for (POSITION y = 0; y < MAX_HGT; y++)
268         for (POSITION x = 0; x < MAX_WID; x++)
269             place_bold(creature_ptr, y, x, GB_SOLID_PERM);
270
271     creature_ptr->y = creature_ptr->current_floor_ptr->height / 2;
272     creature_ptr->x = creature_ptr->current_floor_ptr->width / 2;
273     place_bold(creature_ptr, creature_ptr->y, creature_ptr->x, GB_FLOOR);
274     wipe_generate_random_floor_flags(creature_ptr->current_floor_ptr);
275 }
276
277 /*!
278  * @brief フロア移動時のペット保存処理 / Preserve_pets
279  * @param master_ptr プレーヤーへの参照ポインタ
280  * @return なし
281  */
282 static void preserve_pet(player_type *master_ptr)
283 {
284     for (MONSTER_IDX party_monster_num = 0; party_monster_num < MAX_PARTY_MON; party_monster_num++)
285         party_mon[party_monster_num].r_idx = 0;
286
287     if (master_ptr->riding) {
288         monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[master_ptr->riding];
289         if (m_ptr->parent_m_idx) {
290             master_ptr->riding = 0;
291             master_ptr->pet_extra_flags &= ~(PF_TWO_HANDS);
292             master_ptr->riding_ryoute = master_ptr->old_riding_ryoute = FALSE;
293         } else {
294             (void)COPY(&party_mon[0], m_ptr, monster_type);
295             delete_monster_idx(master_ptr, master_ptr->riding);
296         }
297     }
298
299     /*
300      * todo 関数分割時の参考とするため、このコメントは残しておく。分割後はnumをparty_monster_numに変更する.
301      * If player is in wild mode, no pets are preserved except a monster whom player riding.
302      */
303     if (!master_ptr->wild_mode && !master_ptr->current_floor_ptr->inside_arena && !master_ptr->phase_out) {
304         for (MONSTER_IDX i = master_ptr->current_floor_ptr->m_max - 1, num = 1; (i >= 1 && num < MAX_PARTY_MON); i--) {
305             monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[i];
306             if (!monster_is_valid(m_ptr) || !is_pet(m_ptr) || (i == master_ptr->riding))
307                 continue;
308
309             if (reinit_wilderness) {
310             } else {
311                 POSITION dis = distance(master_ptr->y, master_ptr->x, m_ptr->fy, m_ptr->fx);
312                 if (monster_confused_remaining(m_ptr) || monster_stunned_remaining(m_ptr) || monster_csleep_remaining(m_ptr) || (m_ptr->parent_m_idx != 0))
313                     continue;
314
315                 if (m_ptr->nickname
316                     && ((player_has_los_bold(master_ptr, m_ptr->fy, m_ptr->fx) && projectable(master_ptr, master_ptr->y, master_ptr->x, m_ptr->fy, m_ptr->fx))
317                         || (los(master_ptr, m_ptr->fy, m_ptr->fx, master_ptr->y, master_ptr->x)
318                             && projectable(master_ptr, m_ptr->fy, m_ptr->fx, master_ptr->y, master_ptr->x)))) {
319                     if (dis > 3)
320                         continue;
321                 } else if (dis > 1)
322                     continue;
323             }
324
325             (void)COPY(&party_mon[num], &master_ptr->current_floor_ptr->m_list[i], monster_type);
326             num++;
327             delete_monster_idx(master_ptr, i);
328         }
329     }
330
331     if (record_named_pet) {
332         for (MONSTER_IDX i = master_ptr->current_floor_ptr->m_max - 1; i >= 1; i--) {
333             monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[i];
334             GAME_TEXT m_name[MAX_NLEN];
335             if (!monster_is_valid(m_ptr) || !is_pet(m_ptr) || !m_ptr->nickname || (master_ptr->riding == i))
336                 continue;
337
338             monster_desc(master_ptr, m_name, m_ptr, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE);
339             exe_write_diary(master_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_MOVED, m_name);
340         }
341     }
342
343     for (MONSTER_IDX i = master_ptr->current_floor_ptr->m_max - 1; i >= 1; i--) {
344         monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[i];
345         if ((m_ptr->parent_m_idx == 0) || (master_ptr->current_floor_ptr->m_list[m_ptr->parent_m_idx].r_idx != 0))
346             continue;
347
348         if (is_seen(master_ptr, m_ptr)) {
349             GAME_TEXT m_name[MAX_NLEN];
350             monster_desc(master_ptr, m_name, m_ptr, 0);
351             msg_format(_("%sは消え去った!", "%^s disappears!"), m_name);
352         }
353
354         delete_monster_idx(master_ptr, i);
355     }
356 }
357
358 /*!
359  * @brief フロア移動時にペットを伴った場合の準備処理 / Pre-calculate the racial counters of preserved pets
360  * @param master_ptr プレーヤーへの参照ポインタ
361  * @return なし
362  * @details
363  * To prevent multiple generation of unique monster who is the minion of player
364  */
365 void precalc_cur_num_of_pet(player_type *player_ptr)
366 {
367     monster_type *m_ptr;
368     int max_num = player_ptr->wild_mode ? 1 : MAX_PARTY_MON;
369     for (int i = 0; i < max_num; i++) {
370         m_ptr = &party_mon[i];
371         if (!monster_is_valid(m_ptr))
372             continue;
373
374         real_r_ptr(m_ptr)->cur_num++;
375     }
376 }
377
378 /*!
379  * @brief 移動先のフロアに伴ったペットを配置する / Place preserved pet monsters on new floor
380  * @param master_ptr プレーヤーへの参照ポインタ
381  * @return なし
382  */
383 static void place_pet(player_type *master_ptr)
384 {
385     int max_num = master_ptr->wild_mode ? 1 : MAX_PARTY_MON;
386     floor_type *floor_ptr = master_ptr->current_floor_ptr;
387     for (int i = 0; i < max_num; i++) {
388         POSITION cy = 0, cx = 0;
389         MONSTER_IDX m_idx;
390         if (!(party_mon[i].r_idx))
391             continue;
392
393         if (i == 0) {
394             m_idx = m_pop(floor_ptr);
395             master_ptr->riding = m_idx;
396             if (m_idx) {
397                 cy = master_ptr->y;
398                 cx = master_ptr->x;
399             }
400         } else {
401             POSITION d;
402             for (d = 1; d < A_MAX; d++) {
403                 int j;
404                 for (j = 1000; j > 0; j--) {
405                     scatter(master_ptr, &cy, &cx, master_ptr->y, master_ptr->x, d, 0);
406                     if (monster_can_enter(master_ptr, cy, cx, &r_info[party_mon[i].r_idx], 0))
407                         break;
408                 }
409
410                 if (j != 0)
411                     break;
412             }
413
414             m_idx = (d == 6) ? 0 : m_pop(floor_ptr);
415         }
416
417         if (m_idx != 0) {
418             monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[m_idx];
419             monster_race *r_ptr;
420             master_ptr->current_floor_ptr->grid_array[cy][cx].m_idx = m_idx;
421             m_ptr->r_idx = party_mon[i].r_idx;
422             *m_ptr = party_mon[i];
423             r_ptr = real_r_ptr(m_ptr);
424             m_ptr->fy = cy;
425             m_ptr->fx = cx;
426             m_ptr->current_floor_ptr = master_ptr->current_floor_ptr;
427             m_ptr->ml = TRUE;
428             m_ptr->mtimed[MTIMED_CSLEEP] = 0;
429             m_ptr->hold_o_idx = 0;
430             m_ptr->target_y = 0;
431             if ((r_ptr->flags1 & RF1_FORCE_SLEEP) && !ironman_nightmare) {
432                 m_ptr->mflag |= (MFLAG_NICE);
433                 repair_monsters = TRUE;
434             }
435
436             update_monster(master_ptr, m_idx, TRUE);
437             lite_spot(master_ptr, cy, cx);
438             if (r_ptr->flags2 & RF2_MULTIPLY)
439                 master_ptr->current_floor_ptr->num_repro++;
440         } else {
441             monster_type *m_ptr = &party_mon[i];
442             monster_race *r_ptr = real_r_ptr(m_ptr);
443             GAME_TEXT m_name[MAX_NLEN];
444             monster_desc(master_ptr, m_name, m_ptr, 0);
445             msg_format(_("%sとはぐれてしまった。", "You have lost sight of %s."), m_name);
446             if (record_named_pet && m_ptr->nickname) {
447                 monster_desc(master_ptr, m_name, m_ptr, MD_INDEF_VISIBLE);
448                 exe_write_diary(master_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_LOST_SIGHT, m_name);
449             }
450
451             if (r_ptr->cur_num)
452                 r_ptr->cur_num--;
453         }
454     }
455
456     (void)C_WIPE(party_mon, MAX_PARTY_MON, monster_type);
457 }
458
459 /*!
460  * @brief ユニークモンスターやアーティファクトの所在フロアを更新する / Hack -- Update location of unique monsters and artifacts
461  * @param cur_floor_id 現在のフロアID
462  * @return なし
463  * @details
464  * The r_ptr->floor_id and a_ptr->floor_id are not updated correctly\n
465  * while new floor creation since dungeons may be re-created by\n
466  * auto-scum option.\n
467  */
468 static void update_unique_artifact(floor_type *floor_ptr, s16b cur_floor_id)
469 {
470     for (int i = 1; i < floor_ptr->m_max; i++) {
471         monster_race *r_ptr;
472         monster_type *m_ptr = &floor_ptr->m_list[i];
473         if (!monster_is_valid(m_ptr))
474             continue;
475
476         r_ptr = real_r_ptr(m_ptr);
477         if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NAZGUL))
478             r_ptr->floor_id = cur_floor_id;
479     }
480
481     for (int i = 1; i < floor_ptr->o_max; i++) {
482         object_type *o_ptr = &floor_ptr->o_list[i];
483         if (!object_is_valid(o_ptr))
484             continue;
485
486         if (object_is_fixed_artifact(o_ptr))
487             a_info[o_ptr->name1].floor_id = cur_floor_id;
488     }
489 }
490
491 /*!
492  * @brief フロア移動時、プレイヤーの移動先モンスターが既にいた場合ランダムな近隣に移動させる / When a monster is at a place where player will return,
493  * @return なし
494  */
495 static void get_out_monster(player_type *protected_ptr)
496 {
497     int tries = 0;
498     POSITION dis = 1;
499     POSITION oy = protected_ptr->y;
500     POSITION ox = protected_ptr->x;
501     floor_type *floor_ptr = protected_ptr->current_floor_ptr;
502     MONSTER_IDX m_idx = floor_ptr->grid_array[oy][ox].m_idx;
503     if (m_idx == 0)
504         return;
505
506     while (TRUE) {
507         monster_type *m_ptr;
508         POSITION ny = rand_spread(oy, dis);
509         POSITION nx = rand_spread(ox, dis);
510         tries++;
511         if (tries > 10000)
512             return;
513
514         if (tries > 20 * dis * dis)
515             dis++;
516
517         if (!in_bounds(floor_ptr, ny, nx) || !is_cave_empty_bold(protected_ptr, ny, nx) || is_glyph_grid(&floor_ptr->grid_array[ny][nx])
518             || is_explosive_rune_grid(&floor_ptr->grid_array[ny][nx]) || pattern_tile(floor_ptr, ny, nx))
519             continue;
520
521         m_ptr = &floor_ptr->m_list[m_idx];
522         floor_ptr->grid_array[oy][ox].m_idx = 0;
523         floor_ptr->grid_array[ny][nx].m_idx = m_idx;
524         m_ptr->fy = ny;
525         m_ptr->fx = nx;
526         return;
527     }
528 }
529
530 /*!
531  * @brief 新フロアに移動元フロアに繋がる階段を配置する / Virtually teleport onto the stairs that is connecting between two floors.
532  * @param sf_ptr 移動元の保存フロア構造体参照ポインタ
533  * @return なし
534  */
535 static void locate_connected_stairs(player_type *creature_ptr, floor_type *floor_ptr, saved_floor_type *sf_ptr, BIT_FLAGS floor_mode)
536 {
537     POSITION sx = 0;
538     POSITION sy = 0;
539     POSITION x_table[20];
540     POSITION y_table[20];
541     int num = 0;
542     for (POSITION y = 0; y < floor_ptr->height; y++) {
543         for (POSITION x = 0; x < floor_ptr->width; x++) {
544             grid_type *g_ptr = &floor_ptr->grid_array[y][x];
545             feature_type *f_ptr = &f_info[g_ptr->feat];
546             bool ok = FALSE;
547             if (floor_mode & CFM_UP) {
548                 if (have_flag(f_ptr->flags, FF_LESS) && have_flag(f_ptr->flags, FF_STAIRS) && !have_flag(f_ptr->flags, FF_SPECIAL)) {
549                     ok = TRUE;
550                     if (g_ptr->special && g_ptr->special == sf_ptr->upper_floor_id) {
551                         sx = x;
552                         sy = y;
553                     }
554                 }
555             } else if (floor_mode & CFM_DOWN) {
556                 if (have_flag(f_ptr->flags, FF_MORE) && have_flag(f_ptr->flags, FF_STAIRS) && !have_flag(f_ptr->flags, FF_SPECIAL)) {
557                     ok = TRUE;
558                     if (g_ptr->special && g_ptr->special == sf_ptr->lower_floor_id) {
559                         sx = x;
560                         sy = y;
561                     }
562                 }
563             } else {
564                 if (have_flag(f_ptr->flags, FF_BLDG)) {
565                     ok = TRUE;
566                 }
567             }
568
569             if (ok && (num < 20)) {
570                 x_table[num] = x;
571                 y_table[num] = y;
572                 num++;
573             }
574         }
575     }
576
577     if (sx) {
578         creature_ptr->y = sy;
579         creature_ptr->x = sx;
580         return;
581     }
582
583     if (num == 0) {
584         prepare_change_floor_mode(creature_ptr, CFM_RAND_PLACE | CFM_NO_RETURN);
585         if (!feat_uses_special(floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].feat))
586             floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].special = 0;
587
588         return;
589     }
590
591     int i = randint0(num);
592     creature_ptr->y = y_table[i];
593     creature_ptr->x = x_table[i];
594 }
595
596 /*!
597  * @brief 現在のフロアを離れるに伴って行なわれる保存処理
598  * / Maintain quest monsters, mark next floor_id at stairs, save current floor, and prepare to enter next floor.
599  * @param creature_ptr プレーヤーへの参照ポインタ
600  * @return なし
601  */
602 void leave_floor(player_type *creature_ptr)
603 {
604     grid_type *g_ptr = NULL;
605     feature_type *f_ptr;
606     saved_floor_type *sf_ptr;
607     MONRACE_IDX quest_r_idx = 0;
608     FLOOR_IDX tmp_floor_idx = 0;
609     preserve_pet(creature_ptr);
610     remove_all_mirrors(creature_ptr, FALSE);
611     if (creature_ptr->special_defense & NINJA_S_STEALTH)
612         set_superstealth(creature_ptr, FALSE);
613
614     new_floor_id = 0;
615     if (!creature_ptr->floor_id && (creature_ptr->change_floor_mode & CFM_SAVE_FLOORS) && !(creature_ptr->change_floor_mode & CFM_NO_RETURN))
616         tmp_floor_idx = get_new_floor_id(creature_ptr);
617
618     for (DUNGEON_IDX i = 0; i < max_q_idx; i++) {
619         if ((quest[i].status == QUEST_STATUS_TAKEN) && ((quest[i].type == QUEST_TYPE_KILL_LEVEL) || (quest[i].type == QUEST_TYPE_RANDOM))
620             && (quest[i].level == creature_ptr->current_floor_ptr->dun_level) && (creature_ptr->dungeon_idx == quest[i].dungeon)
621             && !(quest[i].flags & QUEST_FLAG_PRESET)) {
622             quest_r_idx = quest[i].r_idx;
623         }
624     }
625
626     for (DUNGEON_IDX i = 1; i < creature_ptr->current_floor_ptr->m_max; i++) {
627         monster_race *r_ptr;
628         monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[i];
629         if (!monster_is_valid(m_ptr) || (quest_r_idx != m_ptr->r_idx))
630             continue;
631
632         r_ptr = real_r_ptr(m_ptr);
633         if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NAZGUL))
634             continue;
635
636         delete_monster_idx(creature_ptr, i);
637     }
638
639     for (DUNGEON_IDX i = 0; i < INVEN_PACK; i++) {
640         object_type *o_ptr = &creature_ptr->inventory_list[i];
641         if (!object_is_valid(o_ptr))
642             continue;
643
644         if (object_is_fixed_artifact(o_ptr))
645             a_info[o_ptr->name1].floor_id = 0;
646     }
647
648     sf_ptr = get_sf_ptr(creature_ptr->floor_id);
649     if ((creature_ptr->change_floor_mode & CFM_RAND_CONNECT) && tmp_floor_idx)
650         locate_connected_stairs(creature_ptr, creature_ptr->current_floor_ptr, sf_ptr, creature_ptr->change_floor_mode);
651
652     if (creature_ptr->change_floor_mode & CFM_SAVE_FLOORS) {
653         g_ptr = &creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x];
654         f_ptr = &f_info[g_ptr->feat];
655         if (g_ptr->special && !have_flag(f_ptr->flags, FF_SPECIAL) && get_sf_ptr(g_ptr->special))
656             new_floor_id = g_ptr->special;
657
658         if (have_flag(f_ptr->flags, FF_STAIRS) && have_flag(f_ptr->flags, FF_SHAFT))
659             prepare_change_floor_mode(creature_ptr, CFM_SHAFT);
660     }
661
662     if (creature_ptr->change_floor_mode & (CFM_DOWN | CFM_UP)) {
663         int move_num = 0;
664         if (creature_ptr->change_floor_mode & CFM_DOWN)
665             move_num = 1;
666         else if (creature_ptr->change_floor_mode & CFM_UP)
667             move_num = -1;
668
669         if (creature_ptr->change_floor_mode & CFM_SHAFT)
670             move_num += SGN(move_num);
671
672         if (creature_ptr->change_floor_mode & CFM_DOWN) {
673             if (!creature_ptr->current_floor_ptr->dun_level)
674                 move_num = d_info[creature_ptr->dungeon_idx].mindepth;
675         } else if (creature_ptr->change_floor_mode & CFM_UP) {
676             if (creature_ptr->current_floor_ptr->dun_level + move_num < d_info[creature_ptr->dungeon_idx].mindepth)
677                 move_num = -creature_ptr->current_floor_ptr->dun_level;
678         }
679
680         creature_ptr->current_floor_ptr->dun_level += move_num;
681     }
682
683     if (!creature_ptr->current_floor_ptr->dun_level && creature_ptr->dungeon_idx) {
684         creature_ptr->leaving_dungeon = TRUE;
685         if (!vanilla_town && !lite_town) {
686             creature_ptr->wilderness_y = d_info[creature_ptr->dungeon_idx].dy;
687             creature_ptr->wilderness_x = d_info[creature_ptr->dungeon_idx].dx;
688         }
689
690         creature_ptr->recall_dungeon = creature_ptr->dungeon_idx;
691         creature_ptr->dungeon_idx = 0;
692         creature_ptr->change_floor_mode &= ~CFM_SAVE_FLOORS; // TODO
693     }
694
695     if (!(creature_ptr->change_floor_mode & CFM_SAVE_FLOORS)) {
696         for (DUNGEON_IDX i = 0; i < MAX_SAVED_FLOORS; i++)
697             kill_saved_floor(creature_ptr, &saved_floors[i]);
698
699         latest_visit_mark = 1;
700     } else if (creature_ptr->change_floor_mode & CFM_NO_RETURN) {
701         kill_saved_floor(creature_ptr, sf_ptr);
702     }
703
704     if (creature_ptr->floor_id == 0)
705         return;
706
707     if (new_floor_id == 0) {
708         new_floor_id = get_new_floor_id(creature_ptr);
709         if (g_ptr && !feat_uses_special(g_ptr->feat))
710             g_ptr->special = new_floor_id;
711     }
712
713     if (creature_ptr->change_floor_mode & CFM_RAND_CONNECT) {
714         if (creature_ptr->change_floor_mode & CFM_UP)
715             sf_ptr->upper_floor_id = new_floor_id;
716         else if (creature_ptr->change_floor_mode & CFM_DOWN)
717             sf_ptr->lower_floor_id = new_floor_id;
718     }
719
720     if (((creature_ptr->change_floor_mode & CFM_SAVE_FLOORS) == 0) || ((creature_ptr->change_floor_mode & CFM_NO_RETURN) != 0))
721         return;
722
723     get_out_monster(creature_ptr);
724     sf_ptr->last_visit = current_world_ptr->game_turn;
725     forget_lite(creature_ptr->current_floor_ptr);
726     forget_view(creature_ptr->current_floor_ptr);
727     clear_mon_lite(creature_ptr->current_floor_ptr);
728     if (!save_floor(creature_ptr, sf_ptr, 0)) {
729         prepare_change_floor_mode(creature_ptr, CFM_NO_RETURN);
730         kill_saved_floor(creature_ptr, get_sf_ptr(creature_ptr->floor_id));
731     }
732 }
733
734 /*!
735  * @brief フロアの切り替え処理 / Enter new floor.
736  * @param creature_ptr プレーヤーへの参照ポインタ
737  * @return なし
738  * @details
739  * If the floor is an old saved floor, it will be\n
740  * restored from the temporary file.  If the floor is new one, new floor\n
741  * will be generated.\n
742  */
743 void change_floor(player_type *creature_ptr)
744 {
745     saved_floor_type *sf_ptr;
746     bool loaded = FALSE;
747     current_world_ptr->character_dungeon = FALSE;
748     creature_ptr->dtrap = FALSE;
749     panel_row_min = 0;
750     panel_row_max = 0;
751     panel_col_min = 0;
752     panel_col_max = 0;
753     creature_ptr->ambush_flag = FALSE;
754     if (!(creature_ptr->change_floor_mode & CFM_SAVE_FLOORS) && !(creature_ptr->change_floor_mode & CFM_FIRST_FLOOR)) {
755         generate_floor(creature_ptr);
756         new_floor_id = 0;
757     } else {
758         if (new_floor_id == 0)
759             new_floor_id = get_new_floor_id(creature_ptr);
760
761         sf_ptr = get_sf_ptr(new_floor_id);
762         if (sf_ptr->last_visit) {
763             if (load_floor(creature_ptr, sf_ptr, 0)) {
764                 loaded = TRUE;
765                 if (creature_ptr->change_floor_mode & CFM_NO_RETURN) {
766                     grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x];
767                     if (!feat_uses_special(g_ptr->feat)) {
768                         if (creature_ptr->change_floor_mode & (CFM_DOWN | CFM_UP))
769                             g_ptr->feat = feat_ground_type[randint0(100)];
770
771                         g_ptr->special = 0;
772                     }
773                 }
774             }
775         }
776
777         if (creature_ptr->floor_id != 0) {
778             saved_floor_type *cur_sf_ptr = get_sf_ptr(creature_ptr->floor_id);
779             if (creature_ptr->change_floor_mode & CFM_UP) {
780                 if (cur_sf_ptr->upper_floor_id == new_floor_id)
781                     sf_ptr->lower_floor_id = creature_ptr->floor_id;
782             } else if (creature_ptr->change_floor_mode & CFM_DOWN) {
783                 if (cur_sf_ptr->lower_floor_id == new_floor_id)
784                     sf_ptr->upper_floor_id = creature_ptr->floor_id;
785             }
786         } else {
787             if (creature_ptr->change_floor_mode & CFM_UP)
788                 sf_ptr->lower_floor_id = 0;
789             else if (creature_ptr->change_floor_mode & CFM_DOWN)
790                 sf_ptr->upper_floor_id = 0;
791         }
792
793         if (loaded) {
794             GAME_TURN tmp_last_visit = sf_ptr->last_visit;
795             GAME_TURN absence_ticks;
796             int alloc_chance = d_info[creature_ptr->dungeon_idx].max_m_alloc_chance;
797             GAME_TURN alloc_times;
798             while (tmp_last_visit > current_world_ptr->game_turn)
799                 tmp_last_visit -= TURNS_PER_TICK * TOWN_DAWN;
800
801             absence_ticks = (current_world_ptr->game_turn - tmp_last_visit) / TURNS_PER_TICK;
802             for (MONSTER_IDX i = 1; i < creature_ptr->current_floor_ptr->m_max; i++) {
803                 monster_race *r_ptr;
804                 monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[i];
805                 if (!monster_is_valid(m_ptr))
806                     continue;
807
808                 if (!is_pet(m_ptr)) {
809                     m_ptr->hp = m_ptr->maxhp = m_ptr->max_maxhp;
810                     (void)set_monster_fast(creature_ptr, i, 0);
811                     (void)set_monster_slow(creature_ptr, i, 0);
812                     (void)set_monster_stunned(creature_ptr, i, 0);
813                     (void)set_monster_confused(creature_ptr, i, 0);
814                     (void)set_monster_monfear(creature_ptr, i, 0);
815                     (void)set_monster_invulner(creature_ptr, i, 0, FALSE);
816                 }
817
818                 r_ptr = real_r_ptr(m_ptr);
819                 if (!(r_ptr->flags1 & RF1_UNIQUE) && !(r_ptr->flags7 & RF7_NAZGUL))
820                     continue;
821
822                 if (r_ptr->floor_id != new_floor_id)
823                     delete_monster_idx(creature_ptr, i);
824             }
825
826             for (MONSTER_IDX i = 1; i < creature_ptr->current_floor_ptr->o_max; i++) {
827                 object_type *o_ptr = &creature_ptr->current_floor_ptr->o_list[i];
828                 if (!object_is_valid(o_ptr) || !object_is_fixed_artifact(o_ptr))
829                     continue;
830
831                 if (a_info[o_ptr->name1].floor_id != new_floor_id)
832                     delete_object_idx(creature_ptr, i);
833                 else
834                     a_info[o_ptr->name1].cur_num = 1;
835             }
836
837             (void)place_quest_monsters(creature_ptr);
838             alloc_times = absence_ticks / alloc_chance;
839             if (randint0(alloc_chance) < (absence_ticks % alloc_chance))
840                 alloc_times++;
841
842             for (MONSTER_IDX i = 0; i < alloc_times; i++)
843                 (void)alloc_monster(creature_ptr, 0, 0, summon_specific);
844         } else {
845             if (sf_ptr->last_visit) {
846                 msg_print(_("階段は行き止まりだった。", "The staircases come to a dead end..."));
847                 build_dead_end(creature_ptr);
848                 if (creature_ptr->change_floor_mode & CFM_UP)
849                     sf_ptr->upper_floor_id = 0;
850                 else if (creature_ptr->change_floor_mode & CFM_DOWN)
851                     sf_ptr->lower_floor_id = 0;
852             } else
853                 generate_floor(creature_ptr);
854
855             sf_ptr->last_visit = current_world_ptr->game_turn;
856             sf_ptr->dun_level = creature_ptr->current_floor_ptr->dun_level;
857             if (!(creature_ptr->change_floor_mode & CFM_NO_RETURN)) {
858                 grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x];
859                 if ((creature_ptr->change_floor_mode & CFM_UP) && !quest_number(creature_ptr, creature_ptr->current_floor_ptr->dun_level))
860                     g_ptr->feat = (creature_ptr->change_floor_mode & CFM_SHAFT) ? feat_state(creature_ptr, feat_down_stair, FF_SHAFT) : feat_down_stair;
861                 else if ((creature_ptr->change_floor_mode & CFM_DOWN) && !ironman_downward)
862                     g_ptr->feat = (creature_ptr->change_floor_mode & CFM_SHAFT) ? feat_state(creature_ptr, feat_up_stair, FF_SHAFT) : feat_up_stair;
863
864                 g_ptr->mimic = 0;
865                 g_ptr->special = creature_ptr->floor_id;
866             }
867         }
868
869         if (creature_ptr->change_floor_mode & (CFM_RAND_PLACE)) {
870             (void)new_player_spot(creature_ptr);
871         } else if ((creature_ptr->change_floor_mode & CFM_NO_RETURN) && (creature_ptr->change_floor_mode & (CFM_DOWN | CFM_UP))) {
872             if (!creature_ptr->blind) {
873                 msg_print(_("突然階段が塞がれてしまった。", "Suddenly the stairs is blocked!"));
874             } else {
875                 msg_print(_("ゴトゴトと何か音がした。", "You hear some noises."));
876             }
877         }
878
879         sf_ptr->visit_mark = latest_visit_mark++;
880     }
881
882     place_pet(creature_ptr);
883     forget_travel_flow(creature_ptr->current_floor_ptr);
884     update_unique_artifact(creature_ptr->current_floor_ptr, new_floor_id);
885     creature_ptr->floor_id = new_floor_id;
886     current_world_ptr->character_dungeon = TRUE;
887     if (creature_ptr->pseikaku == PERSONALITY_MUNCHKIN)
888         wiz_lite(creature_ptr, (bool)(creature_ptr->pclass == CLASS_NINJA));
889
890     creature_ptr->current_floor_ptr->generated_turn = current_world_ptr->game_turn;
891     creature_ptr->feeling_turn = creature_ptr->current_floor_ptr->generated_turn;
892     creature_ptr->feeling = 0;
893     creature_ptr->change_floor_mode = 0L;
894     select_floor_music(creature_ptr);
895     creature_ptr->change_floor_mode = 0;
896 }