OSDN Git Service

Modify travel command
[hengband/hengband.git] / src / floors.c
1 /* File: floors.c */
2
3 /* Purpose: management of the saved floor */
4
5 /*
6  * Copyright (c) 2002  Mogami
7  *
8  * This software may be copied and distributed for educational, research, and
9  * not for profit purposes provided that this copyright and statement are
10  * included in all such copies.
11  */
12
13 #include "angband.h"
14 #include "grid.h"
15
16
17 static s16b new_floor_id;       /* floor_id of the destination */
18 static u32b change_floor_mode;  /* Mode flags for changing floor */
19 static u32b latest_visit_mark;  /* Max number of visit_mark */
20
21
22 /*
23  * Initialize saved_floors array.  Make sure that old temporal files
24  * are not remaining as gurbages.
25  */
26 void init_saved_floors(bool force)
27 {
28         char floor_savefile[1024];
29         int i;
30         int fd = -1;
31         int mode = 0644;
32
33 #ifdef SET_UID
34 # ifdef SECURE
35         /* Get "games" permissions */
36         beGames();
37 # endif
38 #endif
39
40         for (i = 0; i < MAX_SAVED_FLOORS; i++)
41         {
42                 saved_floor_type *sf_ptr = &saved_floors[i];
43
44                 /* File name */
45                 sprintf(floor_savefile, "%s.F%02d", savefile, i);
46
47                 /* Grab permissions */
48                 safe_setuid_grab();
49
50                 /* Try to create the file */
51                 fd = fd_make(floor_savefile, mode);
52
53                 /* Drop permissions */
54                 safe_setuid_drop();
55
56                 /* Failed! */
57                 if (fd < 0)
58                 {
59                         if (!force)
60                         {
61 #ifdef JP
62                                 msg_print("¥¨¥é¡¼¡§¸Å¤¤¥Æ¥ó¥Ý¥é¥ê¡¦¥Õ¥¡¥¤¥ë¤¬»Ä¤Ã¤Æ¤¤¤Þ¤¹¡£");
63                                 msg_print("ÊѶòÈÚÅܤòÆó½Å¤Ëµ¯Æ°¤·¤Æ¤¤¤Ê¤¤¤«³Îǧ¤·¤Æ¤¯¤À¤µ¤¤¡£");
64                                 msg_print("²áµî¤ËÊѶòÈÚÅܤ¬¥¯¥é¥Ã¥·¥å¤·¤¿¾ì¹ç¤Ï°ì»þ¥Õ¥¡¥¤¥ë¤ò");
65                                 msg_print("¶¯À©Åª¤Ëºï½ü¤·¤Æ¼Â¹Ô¤ò³¤±¤é¤ì¤Þ¤¹¡£");
66                                 if (!get_check("¶¯À©Åª¤Ëºï½ü¤·¤Æ¤â¤è¤í¤·¤¤¤Ç¤¹¤«¡©")) quit("¼Â¹ÔÃæ»ß");
67 #else
68                                 msg_print("Error: There are old temporal files.");
69                                 msg_print("Make sure you are not running two game processes simultaneously.");
70                                 msg_print("If the temporal files are garbages of old crashed process, ");
71                                 msg_print("you can delete it safely.");
72                                 if (!get_check("Do you delete old temporal files? ")) quit("Aborted.");
73 #endif
74                                 force = TRUE;
75                         }
76                 }
77                 else
78                 {
79                         /* Close the "fd" */
80                         (void)fd_close(fd);
81                 }
82
83                 /* Grab permissions */
84                 safe_setuid_grab();
85
86                 /* Simply kill the temporal file */ 
87                 (void)fd_kill(floor_savefile);
88
89                 /* Drop permissions */
90                 safe_setuid_drop();
91
92                 sf_ptr->floor_id = 0;
93         }
94
95         /* No floor_id used yet (No.0 is reserved to indicate non existance) */
96         max_floor_id = 1;
97
98         /* vist_mark is from 1 */
99         latest_visit_mark = 1;
100
101         /* A sign to mark temporal files */
102         saved_floor_file_sign = time(NULL);
103
104         /* No next floor yet */
105         new_floor_id = 0;
106
107         /* No change floor mode yet */
108         change_floor_mode = 0;
109
110 #ifdef SET_UID
111 # ifdef SECURE
112         /* Drop "games" permissions */
113         bePlayer();
114 # endif
115 #endif
116 }
117
118
119 /*
120  * Kill temporal files
121  * Should be called just before the game quit.
122  */
123 void clear_saved_floor_files(void)
124 {
125         char floor_savefile[1024];
126         int i;
127
128 #ifdef SET_UID
129 # ifdef SECURE
130         /* Get "games" permissions */
131         beGames();
132 # endif
133 #endif
134
135         for (i = 0; i < MAX_SAVED_FLOORS; i++)
136         {
137                 saved_floor_type *sf_ptr = &saved_floors[i];
138
139                 /* No temporal file */
140                 if (!sf_ptr->floor_id) continue;
141                 if (sf_ptr->floor_id == p_ptr->floor_id) continue;
142
143                 /* File name */
144                 sprintf(floor_savefile, "%s.F%02d", savefile, i);
145
146                 /* Grab permissions */
147                 safe_setuid_grab();
148
149                 /* Simply kill the temporal file */ 
150                 (void)fd_kill(floor_savefile);
151
152                 /* Drop permissions */
153                 safe_setuid_drop();
154         }
155
156 #ifdef SET_UID
157 # ifdef SECURE
158         /* Drop "games" permissions */
159         bePlayer();
160 # endif
161 #endif
162 }
163
164
165 /*
166  * Get a pointer for an item of the saved_floors array.
167  */
168 saved_floor_type *get_sf_ptr(s16b floor_id)
169 {
170         int i;
171
172         /* floor_id No.0 indicates no floor */
173         if (!floor_id) return NULL;
174
175         for (i = 0; i < MAX_SAVED_FLOORS; i++)
176         {
177                 saved_floor_type *sf_ptr = &saved_floors[i];
178
179                 if (sf_ptr->floor_id == floor_id) return sf_ptr;
180         }
181
182         /* None found */
183         return NULL;
184 }
185
186
187 /*
188  * kill a saved floor and get an empty space
189  */
190 static void kill_saved_floor(saved_floor_type *sf_ptr)
191 {
192         char floor_savefile[1024];
193
194         /* Paranoia */
195         if (!sf_ptr) return;
196
197         /* Already empty */
198         if (!sf_ptr->floor_id) return;
199
200         if (sf_ptr->floor_id == p_ptr->floor_id)
201         {
202                 /* Kill current floor */
203                 p_ptr->floor_id = 0;
204
205                 /* Current floor doesn't have temporal file */
206         }
207         else 
208         {
209                 /* File name */
210                 sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id);
211
212                 /* Grab permissions */
213                 safe_setuid_grab();
214
215                 /* Simply kill the temporal file */ 
216                 (void)fd_kill(floor_savefile);
217
218                 /* Drop permissions */
219                 safe_setuid_drop();
220         }
221
222         /* No longer exists */
223         sf_ptr->floor_id = 0;
224 }
225
226
227 /*
228  * Initialize new saved floor and get its floor id.  If number of
229  * saved floors are already MAX_SAVED_FLOORS, kill the oldest one.
230  */
231 s16b get_new_floor_id(void)
232 {
233         saved_floor_type *sf_ptr;
234         int i;
235
236         /* Look for empty space */
237         for (i = 0; i < MAX_SAVED_FLOORS; i++)
238         {
239                 sf_ptr = &saved_floors[i];
240
241                 if (!sf_ptr->floor_id) break;
242         }
243
244         /* None found */
245         if (i == MAX_SAVED_FLOORS)
246         {
247                 int oldest = 0;
248                 u32b oldest_visit = 0xffffffffL;
249
250                 /* Search for oldest */
251                 for (i = 0; i < MAX_SAVED_FLOORS; i++)
252                 {
253                         sf_ptr = &saved_floors[i];
254
255                         /* Don't kill current floor */
256                         if (sf_ptr->floor_id == p_ptr->floor_id) continue;
257
258                         /* Don't kill newer */
259                         if (sf_ptr->visit_mark > oldest_visit) continue;
260
261                         oldest = i;
262                         oldest_visit = sf_ptr->visit_mark;
263                 }
264
265                 /* Kill oldest saved floor */
266                 sf_ptr = &saved_floors[oldest];
267                 kill_saved_floor(sf_ptr);
268
269                 /* Use it */
270                 i = oldest;
271         }
272
273         /* Prepare new floor data */
274         sf_ptr->savefile_id = i;
275         sf_ptr->floor_id = max_floor_id;
276         sf_ptr->last_visit = 0;
277         sf_ptr->upper_floor_id = 0;
278         sf_ptr->lower_floor_id = 0;
279         sf_ptr->visit_mark = latest_visit_mark++;
280
281         /* sf_ptr->dun_level may be changed later */
282         sf_ptr->dun_level = dun_level;
283
284
285         /* Increment number of floor_id */
286         if (max_floor_id < MAX_SHORT) max_floor_id++;
287
288         /* 32767 floor_ids are all used up!  Re-use ancient IDs */
289         else max_floor_id = 1;
290
291         return sf_ptr->floor_id;
292 }
293
294
295 /*
296  * Prepare mode flags of changing floor
297  */
298 void prepare_change_floor_mode(u32b mode)
299 {
300         change_floor_mode |= mode;
301 }
302
303
304 /*
305  * Builds the dead end
306  */
307 static void build_dead_end(void)
308 {
309         int x,y;
310
311         /* Clear and empty the cave */
312         clear_cave();
313
314         /* Fill the arrays of floors and walls in the good proportions */
315         set_floor_and_wall(0);
316
317         /* Smallest area */
318         cur_hgt = SCREEN_HGT;
319         cur_wid = SCREEN_WID;
320
321         /* Filled with permanent walls */
322         for (y = 0; y < MAX_HGT; y++)
323         {
324                 for (x = 0; x < MAX_WID; x++)
325                 {
326                         /* Create "solid" perma-wall */
327                         place_solid_perm_bold(y, x);
328                 }
329         }
330
331         /* Place at center of the floor */
332         py = cur_hgt / 2;
333         px = cur_wid / 2;
334
335         /* Give one square */
336         place_floor_bold(py, px);
337
338         wipe_generate_cave_flags();
339 }
340
341
342 /* Maximum number of preservable pets */
343 #define MAX_PARTY_MON 21
344
345 static monster_type party_mon[MAX_PARTY_MON];
346
347
348 /*
349  * Preserve_pets
350  */
351 static void preserve_pet(void)
352 {
353         int num, i;
354
355         for (num = 0; num < MAX_PARTY_MON; num++)
356         {
357                 party_mon[num].r_idx = 0;
358         }
359
360         if (p_ptr->riding)
361         {
362                 monster_type *m_ptr = &m_list[p_ptr->riding];
363
364                 /* Pet of other pet don't follow. */
365                 if (m_ptr->parent_m_idx)
366                 {
367                         p_ptr->riding = 0;
368                         p_ptr->pet_extra_flags &= ~(PF_RYOUTE);
369                         p_ptr->riding_ryoute = p_ptr->old_riding_ryoute = FALSE;
370                 }
371                 else
372                 {
373                         /* Preserve the mount */
374                         (void)COPY(&party_mon[0], m_ptr, monster_type);
375
376                         /* Delete from this floor */
377                         delete_monster_idx(p_ptr->riding);
378                 }
379         }
380
381         /*
382          * If player is in wild mode, no pets are preserved
383          * except a monster whom player riding
384          */
385         if (!p_ptr->wild_mode && !p_ptr->inside_arena && !p_ptr->inside_battle)
386         {
387                 for (i = m_max - 1, num = 1; (i >= 1 && num < MAX_PARTY_MON); i--)
388                 {
389                         monster_type *m_ptr = &m_list[i];
390
391                         if (!m_ptr->r_idx) continue;
392                         if (!is_pet(m_ptr)) continue;
393                         if (i == p_ptr->riding) continue;
394
395                         if (reinit_wilderness)
396                         {
397                                 /* Don't lose sight of pets when getting a Quest */
398                         }
399                         else
400                         {
401                                 int dis = distance(py, px, m_ptr->fy, m_ptr->fx);
402
403                                 /* Confused (etc.) monsters don't follow. */
404                                 if (MON_CONFUSED(m_ptr) || MON_STUNNED(m_ptr) || MON_CSLEEP(m_ptr)) continue;
405
406                                 /* Pet of other pet don't follow. */
407                                 if (m_ptr->parent_m_idx) continue;
408
409                                 /*
410                                  * Pets with nickname will follow even from 3 blocks away
411                                  * when you or the pet can see the other.
412                                  */
413                                 if (m_ptr->nickname && 
414                                     ((player_has_los_bold(m_ptr->fy, m_ptr->fx) && projectable(py, px, m_ptr->fy, m_ptr->fx)) ||
415                                      (los(m_ptr->fy, m_ptr->fx, py, px) && projectable(m_ptr->fy, m_ptr->fx, py, px))))
416                                 {
417                                         if (dis > 3) continue;
418                                 }
419                                 else
420                                 {
421                                         if (dis > 1) continue;
422                                 }
423                         }
424
425                         (void)COPY(&party_mon[num], &m_list[i], monster_type);
426
427                         num++;
428
429                         /* Delete from this floor */
430                         delete_monster_idx(i);
431                 }
432         }
433
434         if (record_named_pet)
435         {
436                 for (i = m_max - 1; i >=1; i--)
437                 {
438                         monster_type *m_ptr = &m_list[i];
439                         char m_name[80];
440
441                         if (!m_ptr->r_idx) continue;
442                         if (!is_pet(m_ptr)) continue;
443                         if (!m_ptr->nickname) continue;
444                         if (p_ptr->riding == i) continue;
445
446                         monster_desc(m_name, m_ptr, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE);
447                         do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_MOVED, m_name);
448                 }
449         }
450
451
452         /* Pet of other pet may disappear. */
453         for (i = m_max - 1; i >=1; i--)
454         {
455                 monster_type *m_ptr = &m_list[i];
456
457                 /* Are there its parent? */
458                 if (m_ptr->parent_m_idx && !m_list[m_ptr->parent_m_idx].r_idx)
459                 {
460                         /* Its parent have gone, it also goes away. */
461
462                         if (is_seen(m_ptr))
463                         {
464                                 char m_name[80];
465
466                                 /* Acquire the monster name */
467                                 monster_desc(m_name, m_ptr, 0);
468
469 #ifdef JP
470                                 msg_format("%s¤Ï¾Ã¤¨µî¤Ã¤¿¡ª", m_name);
471 #else
472                                 msg_format("%^s disappears!", m_name);
473 #endif
474                         }
475
476                         /* Delete the monster */
477                         delete_monster_idx(i);
478                 }
479         }
480 }
481
482
483 /*
484  * Pre-calculate the racial counters of preserved pets
485  * To prevent multiple generation of unique monster who is the minion of player
486  */
487 void precalc_cur_num_of_pet(void)
488 {
489         monster_type *m_ptr;
490         int i;
491         int max_num = p_ptr->wild_mode ? 1 : MAX_PARTY_MON;
492
493         for (i = 0; i < max_num; i++)
494         {
495                 m_ptr = &party_mon[i];
496
497                 /* Skip empty monsters */
498                 if (!m_ptr->r_idx) continue;
499
500                 /* Hack -- Increase the racial counter */
501                 real_r_ptr(m_ptr)->cur_num++;
502         }
503 }
504
505
506 /*
507  * Place preserved pet monsters on new floor
508  */
509 static void place_pet(void)
510 {
511         int i;
512         int max_num = p_ptr->wild_mode ? 1 : MAX_PARTY_MON;
513
514         for (i = 0; i < max_num; i++)
515         {
516                 int cy, cx, m_idx;
517
518                 if (!(party_mon[i].r_idx)) continue;
519
520                 if (i == 0)
521                 {
522                         m_idx = m_pop();
523                         p_ptr->riding = m_idx;
524                         if (m_idx)
525                         {
526                                 cy = py;
527                                 cx = px;
528                         }
529                 }
530                 else
531                 {
532                         int j, d;
533
534                         for (d = 1; d < 6; d++)
535                         {
536                                 for (j = 1000; j > 0; j--)
537                                 {
538                                         scatter(&cy, &cx, py, px, d, 0);
539                                         if (monster_can_enter(cy, cx, &r_info[party_mon[i].r_idx], 0)) break;
540                                 }
541                                 if (j) break;
542                         }
543                         m_idx = (d == 6) ? 0 : m_pop();
544                 }
545
546                 if (m_idx)
547                 {
548                         monster_type *m_ptr = &m_list[m_idx];
549                         monster_race *r_ptr;
550
551                         cave[cy][cx].m_idx = m_idx;
552
553                         m_ptr->r_idx = party_mon[i].r_idx;
554
555                         /* Copy all member of the structure */
556                         *m_ptr = party_mon[i];
557                         r_ptr = real_r_ptr(m_ptr);
558
559                         m_ptr->fy = cy;
560                         m_ptr->fx = cx;
561                         m_ptr->ml = TRUE;
562                         m_ptr->mtimed[MTIMED_CSLEEP] = 0;
563
564                         /* Paranoia */
565                         m_ptr->hold_o_idx = 0;
566                         m_ptr->target_y = 0;
567
568                         if ((r_ptr->flags1 & RF1_FORCE_SLEEP) && !ironman_nightmare)
569                         {
570                                 /* Monster is still being nice */
571                                 m_ptr->mflag |= (MFLAG_NICE);
572
573                                 /* Must repair monsters */
574                                 repair_monsters = TRUE;
575                         }
576
577                         /* Update the monster */
578                         update_mon(m_idx, TRUE);
579                         lite_spot(cy, cx);
580
581                         /* Pre-calculated in precalc_cur_num_of_pet() */
582                         /* r_ptr->cur_num++; */
583
584                         /* Hack -- Count the number of "reproducers" */
585                         if (r_ptr->flags2 & RF2_MULTIPLY) num_repro++;
586
587                         /* Hack -- Notice new multi-hued monsters */
588                         {
589                                 monster_race *ap_r_ptr = &r_info[m_ptr->ap_r_idx];
590                                 if (ap_r_ptr->flags1 & (RF1_ATTR_MULTI | RF1_SHAPECHANGER))
591                                         shimmer_monsters = TRUE;
592                         }
593                 }
594                 else
595                 {
596                         monster_type *m_ptr = &party_mon[i];
597                         monster_race *r_ptr = real_r_ptr(m_ptr);
598                         char m_name[80];
599
600                         monster_desc(m_name, m_ptr, 0);
601 #ifdef JP
602                         msg_format("%s¤È¤Ï¤°¤ì¤Æ¤·¤Þ¤Ã¤¿¡£", m_name);
603 #else
604                         msg_format("You have lost sight of %s.", m_name);
605 #endif
606                         if (record_named_pet && m_ptr->nickname)
607                         {
608                                 monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE);
609                                 do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_LOST_SIGHT, m_name);
610                         }
611
612                         /* Pre-calculated in precalc_cur_num_of_pet(), but need to decrease */
613                         if (r_ptr->cur_num) r_ptr->cur_num--;
614                 }
615         }
616
617         /* For accuracy of precalc_cur_num_of_pet() */
618         (void)C_WIPE(party_mon, MAX_PARTY_MON, monster_type);
619 }
620
621
622 /*
623  * Hack -- Update location of unique monsters and artifacts
624  *
625  * The r_ptr->floor_id and a_ptr->floor_id are not updated correctly
626  * while new floor creation since dungeons may be re-created by
627  * auto-scum option.
628  */
629 static void update_unique_artifact(s16b cur_floor_id)
630 {
631         int i;
632
633         /* Maintain unique monsters */
634         for (i = 1; i < m_max; i++)
635         {
636                 monster_race *r_ptr;
637                 monster_type *m_ptr = &m_list[i];
638
639                 /* Skip dead monsters */
640                 if (!m_ptr->r_idx) continue;
641
642                 /* Extract real monster race */
643                 r_ptr = real_r_ptr(m_ptr);
644
645                 /* Memorize location of the unique monster */
646                 if ((r_ptr->flags1 & RF1_UNIQUE) ||
647                     (r_ptr->flags7 & RF7_NAZGUL))
648                 {
649                         r_ptr->floor_id = cur_floor_id;
650                 }
651         }
652
653         /* Maintain artifatcs */
654         for (i = 1; i < o_max; i++)
655         {
656                 object_type *o_ptr = &o_list[i];
657
658                 /* Skip dead objects */
659                 if (!o_ptr->k_idx) continue;
660
661                 /* Memorize location of the artifact */
662                 if (object_is_fixed_artifact(o_ptr))
663                 {
664                         a_info[o_ptr->name1].floor_id = cur_floor_id;
665                 }
666         }
667 }
668
669
670 /*
671  * When a monster is at a place where player will return,
672  * Get out of the my way!
673  */
674 static void get_out_monster(void)
675 {
676         int tries = 0;
677         int dis = 1;
678         int oy = py;
679         int ox = px;
680         int m_idx = cave[oy][ox].m_idx;
681
682         /* Nothing to do if no monster */
683         if (!m_idx) return;
684
685         /* Look until done */
686         while (TRUE)
687         {
688                 monster_type *m_ptr;
689
690                 /* Pick a (possibly illegal) location */
691                 int ny = rand_spread(oy, dis);
692                 int nx = rand_spread(ox, dis);
693
694                 tries++;
695
696                 /* Stop after 1000 tries */
697                 if (tries > 10000) return;
698
699                 /*
700                  * Increase distance after doing enough tries
701                  * compared to area of possible space
702                  */
703                 if (tries > 20 * dis * dis) dis++;
704
705                 /* Ignore illegal locations */
706                 if (!in_bounds(ny, nx)) continue;
707
708                 /* Require "empty" floor space */
709                 if (!cave_empty_bold(ny, nx)) continue;
710
711                 /* Hack -- no teleport onto glyph of warding */
712                 if (is_glyph_grid(&cave[ny][nx])) continue;
713                 if (is_explosive_rune_grid(&cave[ny][nx])) continue;
714
715                 /* ...nor onto the Pattern */
716                 if (pattern_tile(ny, nx)) continue;
717
718                 /*** It's a good place ***/
719
720                 m_ptr = &m_list[m_idx];
721
722                 /* Update the old location */
723                 cave[oy][ox].m_idx = 0;
724
725                 /* Update the new location */
726                 cave[ny][nx].m_idx = m_idx;
727
728                 /* Move the monster */
729                 m_ptr->fy = ny;
730                 m_ptr->fx = nx; 
731
732                 /* No need to do update_mon() */
733
734                 /* Success */
735                 return;
736         }
737 }
738
739
740 /*
741  * Is this feature has special meaning (except floor_id) with c_ptr->special?
742  */
743 #define feat_uses_special(F) (have_flag(f_info[(F)].flags, FF_SPECIAL))
744
745
746 /*
747  * Virtually teleport onto the stairs that is connecting between two
748  * floors.
749  *
750  * Teleport level spell and trap doors will always lead the player to
751  * the one of the floors connected by the one of the stairs in the
752  * current floor.
753  */
754 static void locate_connected_stairs(saved_floor_type *sf_ptr)
755 {
756         int x, y, sx = 0, sy = 0;
757         int x_table[20];
758         int y_table[20];
759         int num = 0;
760         int i;
761
762         /* Search usable stairs */
763         for (y = 0; y < cur_hgt; y++)
764         {
765                 for (x = 0; x < cur_wid; x++)
766                 {
767                         cave_type *c_ptr = &cave[y][x];
768                         feature_type *f_ptr = &f_info[c_ptr->feat];
769                         bool ok = FALSE;
770
771                         if (change_floor_mode & CFM_UP)
772                         {
773                                 if (have_flag(f_ptr->flags, FF_LESS) && have_flag(f_ptr->flags, FF_STAIRS) &&
774                                     !have_flag(f_ptr->flags, FF_SPECIAL))
775                                 {
776                                         ok = TRUE;
777
778                                         /* Found fixed stairs? */
779                                         if (c_ptr->special &&
780                                             c_ptr->special == sf_ptr->upper_floor_id)
781                                         {
782                                                 sx = x;
783                                                 sy = y;
784                                         }
785                                 }
786                         }
787
788                         else if (change_floor_mode & CFM_DOWN)
789                         {
790                                 if (have_flag(f_ptr->flags, FF_MORE) && have_flag(f_ptr->flags, FF_STAIRS) &&
791                                     !have_flag(f_ptr->flags, FF_SPECIAL))
792                                 {
793                                         ok = TRUE;
794
795                                         /* Found fixed stairs */
796                                         if (c_ptr->special &&
797                                             c_ptr->special == sf_ptr->lower_floor_id)
798                                         {
799                                                 sx = x;
800                                                 sy = y;
801                                         }
802                                 }
803                         }
804
805                         else
806                         {
807                                 if (have_flag(f_ptr->flags, FF_BLDG))
808                                 {
809                                         ok = TRUE;
810                                 }
811                         }
812
813                         if (ok && (num < 20))
814                         {
815                                 x_table[num] = x;
816                                 y_table[num] = y;
817                                 num++;
818                         }
819                 }
820         }
821
822         if (sx)
823         {
824                 /* Already fixed */
825                 py = sy;
826                 px = sx;
827         }
828         else if (!num)
829         {
830                 /* No stairs found! -- No return */
831                 prepare_change_floor_mode(CFM_RAND_PLACE | CFM_NO_RETURN);
832
833                 /* Mega Hack -- It's not the stairs you enter.  Disable it.  */
834                 if (!feat_uses_special(cave[py][px].feat)) cave[py][px].special = 0;
835         }
836         else
837         {
838                 /* Choose random one */
839                 i = randint0(num);
840
841                 /* Point stair location */
842                 py = y_table[i];
843                 px = x_table[i];
844         }
845 }
846
847 /*
848  * Maintain quest monsters, mark next floor_id at stairs, save current
849  * floor, and prepare to enter next floor.
850  */
851 void leave_floor(void)
852 {
853         cave_type *c_ptr = NULL;
854         feature_type *f_ptr;
855         saved_floor_type *sf_ptr;
856         int quest_r_idx = 0;
857         int i;
858
859         /* Preserve pets and prepare to take these to next floor */
860         preserve_pet();
861
862         /* Remove all mirrors without explosion */
863         remove_all_mirrors(FALSE);
864
865         if (p_ptr->special_defense & NINJA_S_STEALTH) set_superstealth(FALSE);
866
867         /* New floor is not yet prepared */
868         new_floor_id = 0;
869
870         /* Temporary get a floor_id (for Arena) */
871         if (!p_ptr->floor_id &&
872             (change_floor_mode & CFM_SAVE_FLOORS) &&
873             !(change_floor_mode & CFM_NO_RETURN))
874         {
875             /* Get temporal floor_id */
876             p_ptr->floor_id = get_new_floor_id();
877         }
878
879
880         /* Search the quest monster index */
881         for (i = 0; i < max_quests; i++)
882         {
883                 if ((quest[i].status == QUEST_STATUS_TAKEN) &&
884                     ((quest[i].type == QUEST_TYPE_KILL_LEVEL) ||
885                     (quest[i].type == QUEST_TYPE_RANDOM)) &&
886                     (quest[i].level == dun_level) &&
887                     (dungeon_type == quest[i].dungeon) &&
888                     !(quest[i].flags & QUEST_FLAG_PRESET))
889                 {
890                         quest_r_idx = quest[i].r_idx;
891                 }
892         }
893
894         /* Maintain quest monsters */
895         for (i = 1; i < m_max; i++)
896         {
897                 monster_race *r_ptr;
898                 monster_type *m_ptr = &m_list[i];
899
900                 /* Skip dead monsters */
901                 if (!m_ptr->r_idx) continue;
902
903                 /* Only maintain quest monsters */
904                 if (quest_r_idx != m_ptr->r_idx) continue;
905
906                 /* Extract real monster race */
907                 r_ptr = real_r_ptr(m_ptr);
908
909                 /* Ignore unique monsters */
910                 if ((r_ptr->flags1 & RF1_UNIQUE) ||
911                     (r_ptr->flags7 & RF7_NAZGUL)) continue;
912
913                 /* Delete non-unique quest monsters */
914                 delete_monster_idx(i);
915         }
916
917         /* Check if there is a same item */
918         for (i = 0; i < INVEN_PACK; i++)
919         {
920                 object_type *o_ptr = &inventory[i];
921
922                 /* Skip dead objects */
923                 if (!o_ptr->k_idx) continue;
924
925                 /* Delete old memorized location of the artifact */
926                 if (object_is_fixed_artifact(o_ptr))
927                 {
928                         a_info[o_ptr->name1].floor_id = 0;
929                 }
930         }
931
932         /* Extract current floor info or NULL */
933         sf_ptr = get_sf_ptr(p_ptr->floor_id);
934
935         /* Choose random stairs */
936         if ((change_floor_mode & CFM_RAND_CONNECT) && p_ptr->floor_id)
937         {
938                 locate_connected_stairs(sf_ptr);
939         }
940
941         /* Extract new dungeon level */
942         if (change_floor_mode & CFM_SAVE_FLOORS)
943         {
944                 /* Extract stair position */
945                 c_ptr = &cave[py][px];
946                 f_ptr = &f_info[c_ptr->feat];
947
948                 /* Get back to old saved floor? */
949                 if (c_ptr->special && !have_flag(f_ptr->flags, FF_SPECIAL) && get_sf_ptr(c_ptr->special))
950                 {
951                         /* Saved floor is exist.  Use it. */
952                         new_floor_id = c_ptr->special;
953                 }
954
955                 /* Mark shaft up/down */
956                 if (have_flag(f_ptr->flags, FF_STAIRS) && have_flag(f_ptr->flags, FF_SHAFT))
957                 {
958                         prepare_change_floor_mode(CFM_SHAFT);
959                 }
960         }
961
962         /* Climb up/down some sort of stairs */
963         if (change_floor_mode & (CFM_DOWN | CFM_UP))
964         {
965                 int move_num = 0;
966
967                 /* Extract level movement number */
968                 if (change_floor_mode & CFM_DOWN) move_num = 1;
969                 else if (change_floor_mode & CFM_UP) move_num = -1;
970
971                 /* Shafts are deeper than normal stairs */
972                 if (change_floor_mode & CFM_SHAFT)
973                         move_num += SGN(move_num);
974
975                 /* Get out from or Enter the dungeon */
976                 if (change_floor_mode & CFM_DOWN)
977                 {
978                         if (!dun_level)
979                                 move_num = d_info[dungeon_type].mindepth;
980                 }
981                 else if (change_floor_mode & CFM_UP)
982                 {
983                         if (dun_level + move_num < d_info[dungeon_type].mindepth)
984                                 move_num = -dun_level;
985                 }
986
987                 dun_level += move_num;
988         }
989
990         /* Leaving the dungeon to town */
991         if (!dun_level && dungeon_type)
992         {
993                 p_ptr->leaving_dungeon = TRUE;
994                 if (!vanilla_town && !lite_town)
995                 {
996                         p_ptr->wilderness_y = d_info[dungeon_type].dy;
997                         p_ptr->wilderness_x = d_info[dungeon_type].dx;
998                 }
999                 p_ptr->recall_dungeon = dungeon_type;
1000                 dungeon_type = 0;
1001
1002                 /* Reach to the surface -- Clear all saved floors */
1003                 change_floor_mode &= ~CFM_SAVE_FLOORS;
1004         }
1005
1006         /* Kill some old saved floors */
1007         if (!(change_floor_mode & CFM_SAVE_FLOORS))
1008         {
1009                 int i;
1010
1011                 /* Kill all saved floors */
1012                 for (i = 0; i < MAX_SAVED_FLOORS; i++)
1013                         kill_saved_floor(&saved_floors[i]);
1014
1015                 /* Reset visit_mark count */
1016                 latest_visit_mark = 1;
1017         }
1018         else if (change_floor_mode & CFM_NO_RETURN)
1019         {
1020                 /* Kill current floor */
1021                 kill_saved_floor(sf_ptr);
1022         }
1023
1024         /* No current floor -- Left/Enter dungeon etc... */
1025         if (!p_ptr->floor_id)
1026         {
1027                 /* No longer need to save current floor */
1028                 return;
1029         }
1030
1031
1032         /* Mark next floor_id on the previous floor */
1033         if (!new_floor_id)
1034         {
1035                 /* Get new id */
1036                 new_floor_id = get_new_floor_id();
1037
1038                 /* Connect from here */
1039                 if (c_ptr && !feat_uses_special(c_ptr->feat))
1040                 {
1041                         c_ptr->special = new_floor_id;
1042                 }
1043         }
1044
1045         /* Fix connection -- level teleportation or trap door */
1046         if (change_floor_mode & CFM_RAND_CONNECT)
1047         {
1048                 if (change_floor_mode & CFM_UP)
1049                         sf_ptr->upper_floor_id = new_floor_id;
1050                 else if (change_floor_mode & CFM_DOWN)
1051                         sf_ptr->lower_floor_id = new_floor_id;
1052         }
1053
1054         /* If you can return, you need to save previous floor */
1055         if ((change_floor_mode & CFM_SAVE_FLOORS) &&
1056             !(change_floor_mode & CFM_NO_RETURN))
1057         {
1058                 /* Get out of the my way! */
1059                 get_out_monster();
1060
1061                 /* Record the last visit turn of current floor */
1062                 sf_ptr->last_visit = turn;
1063
1064                 /* Forget the lite */
1065                 forget_lite();
1066
1067                 /* Forget the view */
1068                 forget_view();
1069
1070                 /* Forget the view */
1071                 clear_mon_lite();
1072
1073                 /* Save current floor */
1074                 if (!save_floor(sf_ptr, 0))
1075                 {
1076                         /* Save failed -- No return */
1077                         prepare_change_floor_mode(CFM_NO_RETURN);
1078
1079                         /* Kill current floor */
1080                         kill_saved_floor(get_sf_ptr(p_ptr->floor_id));
1081                 }
1082         }
1083 }
1084
1085
1086 /*
1087  * Enter new floor.  If the floor is an old saved floor, it will be
1088  * restored from the temporal file.  If the floor is new one, new cave
1089  * will be generated.
1090  */
1091 void change_floor(void)
1092 {
1093         saved_floor_type *sf_ptr;
1094         bool loaded = FALSE;
1095
1096         /* The dungeon is not ready */
1097         character_dungeon = FALSE;
1098
1099         /* No longer in the trap detecteded region */
1100         p_ptr->dtrap = FALSE;
1101
1102         /* Mega-Hack -- no panel yet */
1103         panel_row_min = 0;
1104         panel_row_max = 0;
1105         panel_col_min = 0;
1106         panel_col_max = 0;
1107
1108         /* Mega-Hack -- not ambushed on the wildness? */
1109         ambush_flag = FALSE;
1110
1111         /* No saved floors (On the surface etc.) */
1112         if (!(change_floor_mode & CFM_SAVE_FLOORS) &&
1113             !(change_floor_mode & CFM_FIRST_FLOOR))
1114         {
1115                 /* Create cave */
1116                 generate_cave();
1117
1118                 /* Paranoia -- No new saved floor */
1119                 new_floor_id = 0;
1120         }
1121
1122         /* In the dungeon */
1123         else
1124         {
1125                 /* No floor_id yet */
1126                 if (!new_floor_id)
1127                 {
1128                         /* Get new id */
1129                         new_floor_id = get_new_floor_id();
1130                 }
1131
1132                 /* Pointer for infomations of new floor */
1133                 sf_ptr = get_sf_ptr(new_floor_id);
1134
1135                 /* Try to restore old floor */
1136                 if (sf_ptr->last_visit)
1137                 {
1138                         /* Old saved floor is exist */
1139                         if (load_floor(sf_ptr, 0))
1140                         {
1141                                 loaded = TRUE;
1142
1143                                 /* Forbid return stairs */
1144                                 if (change_floor_mode & CFM_NO_RETURN)
1145                                 {
1146                                         cave_type *c_ptr = &cave[py][px];
1147
1148                                         if (!feat_uses_special(c_ptr->feat))
1149                                         {
1150                                                 if (change_floor_mode & (CFM_DOWN | CFM_UP))
1151                                                 {
1152                                                         /* Reset to floor */
1153                                                         c_ptr->feat = floor_type[randint0(100)];
1154                                                 }
1155
1156                                                 c_ptr->special = 0;
1157                                         }
1158                                 }
1159                         }
1160                 }
1161
1162                 /*
1163                  * Set lower/upper_floor_id of new floor when the new
1164                  * floor is right-above/right-under the current floor.
1165                  *
1166                  * Stair creation/Teleport level/Trap door will take
1167                  * you the same floor when you used it later again.
1168                  */
1169                 if (p_ptr->floor_id)
1170                 {
1171                         saved_floor_type *cur_sf_ptr = get_sf_ptr(p_ptr->floor_id);
1172
1173                         if (change_floor_mode & CFM_UP)
1174                         {
1175                                 /* New floor is right-above */
1176                                 if (cur_sf_ptr->upper_floor_id == new_floor_id)
1177                                         sf_ptr->lower_floor_id = p_ptr->floor_id;
1178                         }
1179                         else if (change_floor_mode & CFM_DOWN)
1180                         {
1181                                 /* New floor is right-under */
1182                                 if (cur_sf_ptr->lower_floor_id == new_floor_id)
1183                                         sf_ptr->upper_floor_id = p_ptr->floor_id;
1184                         }
1185                 }
1186
1187                 /* Break connection to killed floor */
1188                 else
1189                 {
1190                         if (change_floor_mode & CFM_UP)
1191                                 sf_ptr->lower_floor_id = 0;
1192                         else if (change_floor_mode & CFM_DOWN)
1193                                 sf_ptr->upper_floor_id = 0;
1194                 }
1195
1196                 /* Maintain monsters and artifacts */
1197                 if (loaded)
1198                 {
1199                         int i;
1200                         s32b tmp_last_visit = sf_ptr->last_visit;
1201                         s32b absence_ticks;
1202                         int alloc_chance = d_info[dungeon_type].max_m_alloc_chance;
1203                         int alloc_times;
1204
1205                         while (tmp_last_visit > turn) tmp_last_visit -= TURNS_PER_TICK * TOWN_DAWN;
1206                         absence_ticks = (turn - tmp_last_visit) / TURNS_PER_TICK;
1207
1208                         /* Maintain monsters */
1209                         for (i = 1; i < m_max; i++)
1210                         {
1211                                 monster_race *r_ptr;
1212                                 monster_type *m_ptr = &m_list[i];
1213
1214                                 /* Skip dead monsters */
1215                                 if (!m_ptr->r_idx) continue;
1216
1217                                 if (!is_pet(m_ptr))
1218                                 {
1219                                         /* Restore HP */
1220                                         m_ptr->hp = m_ptr->maxhp = m_ptr->max_maxhp;
1221
1222                                         /* Remove timed status (except MTIMED_CSLEEP) */
1223                                         (void)set_monster_fast(i, 0);
1224                                         (void)set_monster_slow(i, 0);
1225                                         (void)set_monster_stunned(i, 0);
1226                                         (void)set_monster_confused(i, 0);
1227                                         (void)set_monster_monfear(i, 0);
1228                                         (void)set_monster_invulner(i, 0, FALSE);
1229                                 }
1230
1231                                 /* Extract real monster race */
1232                                 r_ptr = real_r_ptr(m_ptr);
1233
1234                                 /* Ignore non-unique */
1235                                 if (!(r_ptr->flags1 & RF1_UNIQUE) &&
1236                                     !(r_ptr->flags7 & RF7_NAZGUL)) continue;
1237
1238                                 /* Appear at a different floor? */
1239                                 if (r_ptr->floor_id != new_floor_id)
1240                                 {
1241                                         /* Disapper from here */
1242                                         delete_monster_idx(i);
1243                                 }
1244                         }
1245
1246                         /* Maintain artifatcs */
1247                         for (i = 1; i < o_max; i++)
1248                         {
1249                                 object_type *o_ptr = &o_list[i];
1250
1251                                 /* Skip dead objects */
1252                                 if (!o_ptr->k_idx) continue;
1253
1254                                 /* Ignore non-artifact */
1255                                 if (!object_is_fixed_artifact(o_ptr)) continue;
1256
1257                                 /* Appear at a different floor? */
1258                                 if (a_info[o_ptr->name1].floor_id != new_floor_id)
1259                                 {
1260                                         /* Disappear from here */
1261                                         delete_object_idx(i);
1262                                 }
1263                                 else
1264                                 {
1265                                         /* Cancel preserve */
1266                                         a_info[o_ptr->name1].cur_num = 1;
1267                                 }
1268                         }
1269
1270                         (void)place_quest_monsters();
1271
1272                         /* Place some random monsters */
1273                         alloc_times = absence_ticks / alloc_chance;
1274
1275                         if (randint0(alloc_chance) < (absence_ticks % alloc_chance))
1276                                 alloc_times++;
1277
1278                         for (i = 0; i < alloc_times; i++)
1279                         {
1280                                 /* Make a (group of) new monster */
1281                                 (void)alloc_monster(0, 0);
1282                         }
1283                 }
1284
1285                 /* New floor_id or failed to restore */
1286                 else /* if (!loaded) */
1287                 {
1288                         if (sf_ptr->last_visit)
1289                         {
1290                                 /* Temporal file is broken? */
1291 #ifdef JP
1292                                 msg_print("³¬ÃʤϹԤ­»ß¤Þ¤ê¤À¤Ã¤¿¡£");
1293 #else
1294                                 msg_print("The staircases come to a dead end...");
1295 #endif
1296
1297                                 /* Create simple dead end */
1298                                 build_dead_end();
1299
1300                                 /* Break connection */
1301                                 if (change_floor_mode & CFM_UP)
1302                                 {
1303                                         sf_ptr->upper_floor_id = 0;
1304                                 }
1305                                 else if (change_floor_mode & CFM_DOWN)
1306                                 {
1307                                         sf_ptr->lower_floor_id = 0;
1308                                 }
1309                         }
1310                         else
1311                         {
1312                                 /* Newly create cave */
1313                                 generate_cave();
1314                         }
1315
1316                         /* Record last visit turn */
1317                         sf_ptr->last_visit = turn;
1318
1319                         /* Set correct dun_level value */
1320                         sf_ptr->dun_level = dun_level;
1321
1322                         /* Create connected stairs */
1323                         if (!(change_floor_mode & CFM_NO_RETURN))
1324                         {
1325                                 /* Extract stair position */
1326                                 cave_type *c_ptr = &cave[py][px];
1327
1328                                 /*** Create connected stairs ***/
1329
1330                                 /* No stairs down from Quest */
1331                                 if ((change_floor_mode & CFM_UP) && !quest_number(dun_level))
1332                                 {
1333                                         c_ptr->feat = (change_floor_mode & CFM_SHAFT) ? feat_state(feat_down_stair, FF_SHAFT) : feat_down_stair;
1334                                 }
1335
1336                                 /* No stairs up when ironman_downward */
1337                                 else if ((change_floor_mode & CFM_DOWN) && !ironman_downward)
1338                                 {
1339                                         c_ptr->feat = (change_floor_mode & CFM_SHAFT) ? feat_state(feat_up_stair, FF_SHAFT) : feat_up_stair;
1340                                 }
1341
1342                                 /* Paranoia -- Clear mimic */
1343                                 c_ptr->mimic = 0;
1344
1345                                 /* Connect to previous floor */
1346                                 c_ptr->special = p_ptr->floor_id;
1347                         }
1348                 }
1349
1350                 /* Arrive at random grid */
1351                 if (change_floor_mode & (CFM_RAND_PLACE))
1352                 {
1353                         (void)new_player_spot();
1354                 }
1355
1356                 /* You see stairs blocked */
1357                 else if ((change_floor_mode & CFM_NO_RETURN) &&
1358                          (change_floor_mode & (CFM_DOWN | CFM_UP)))
1359                 {
1360                         if (!p_ptr->blind)
1361                         {
1362 #ifdef JP
1363                                 msg_print("ÆÍÁ³³¬Ãʤ¬ºÉ¤¬¤ì¤Æ¤·¤Þ¤Ã¤¿¡£");
1364 #else
1365                                 msg_print("Suddenly the stairs is blocked!");
1366 #endif
1367                         }
1368                         else
1369                         {
1370 #ifdef JP
1371                                 msg_print("¥´¥È¥´¥È¤È²¿¤«²»¤¬¤·¤¿¡£");
1372 #else
1373                                 msg_print("You hear some noises.");
1374 #endif
1375                         }
1376                 }
1377
1378                 /*
1379                  * Update visit mark
1380                  *
1381                  * The "turn" is not always different number because
1382                  * the level teleport doesn't take any turn.  Use
1383                  * visit mark instead of last visit turn to find the
1384                  * oldest saved floor.
1385                  */
1386                 sf_ptr->visit_mark = latest_visit_mark++;
1387         }
1388
1389         /* Place preserved pet monsters */
1390         place_pet();
1391
1392         /* Reset travel target place */
1393         forget_travel_flow();
1394
1395         /* Hack -- maintain unique and artifacts */
1396         update_unique_artifact(new_floor_id);
1397
1398         /* Now the player is in new floor */
1399         p_ptr->floor_id = new_floor_id;
1400
1401         /* The dungeon is ready */
1402         character_dungeon = TRUE;
1403
1404         /* Hack -- Munchkin characters always get whole map */
1405         if (p_ptr->pseikaku == SEIKAKU_MUNCHKIN)
1406                 wiz_lite((bool)(p_ptr->pclass == CLASS_NINJA));
1407
1408         /* Remember when this level was "created" */
1409         old_turn = turn;
1410
1411         /* No dungeon feeling yet */
1412         p_ptr->feeling_turn = old_turn;
1413         p_ptr->feeling = 0;
1414
1415         /* Clear all flags */
1416         change_floor_mode = 0L;
1417 }
1418
1419
1420
1421 /*
1422  * Create stairs at or move previously created stairs into the player
1423  * location.
1424  */
1425 void stair_creation(void)
1426 {
1427         saved_floor_type *sf_ptr;
1428         saved_floor_type *dest_sf_ptr;
1429
1430         bool up = TRUE;
1431         bool down = TRUE;
1432         s16b dest_floor_id = 0;
1433
1434
1435         /* Forbid up staircases on Ironman mode */
1436         if (ironman_downward) up = FALSE;
1437
1438         /* Forbid down staircases on quest level */
1439         if (quest_number(dun_level) || (dun_level >= d_info[dungeon_type].maxdepth)) down = FALSE;
1440
1441         /* No effect out of standard dungeon floor */
1442         if (!dun_level || (!up && !down) ||
1443             (p_ptr->inside_quest && is_fixed_quest_idx(p_ptr->inside_quest)) ||
1444             p_ptr->inside_arena || p_ptr->inside_battle)
1445         {
1446                 /* arena or quest */
1447 #ifdef JP
1448                 msg_print("¸ú²Ì¤¬¤¢¤ê¤Þ¤»¤ó¡ª");
1449 #else
1450                 msg_print("There is no effect!");
1451 #endif
1452                 return;
1453         }
1454
1455         /* Artifacts resists */
1456         if (!cave_valid_bold(py, px))
1457         {
1458 #ifdef JP
1459                 msg_print("¾²¾å¤Î¥¢¥¤¥Æ¥à¤¬¼öʸ¤òÄ·¤ÍÊÖ¤·¤¿¡£");
1460 #else
1461                 msg_print("The object resists the spell.");
1462 #endif
1463
1464                 return;
1465         }
1466
1467         /* Destroy all objects in the grid */
1468         delete_object(py, px);
1469
1470         /* Extract current floor data */
1471         sf_ptr = get_sf_ptr(p_ptr->floor_id);
1472
1473         /* Paranoia */
1474         if (!sf_ptr)
1475         {
1476                 /* No floor id? -- Create now! */
1477                 p_ptr->floor_id = get_new_floor_id();
1478                 sf_ptr = get_sf_ptr(p_ptr->floor_id);
1479         } 
1480
1481         /* Choose randomly */
1482         if (up && down)
1483         {
1484                 if (randint0(100) < 50) up = FALSE;
1485                 else down = FALSE;
1486         }
1487
1488         /* Destination is already fixed */
1489         if (up)
1490         {
1491                 if (sf_ptr->upper_floor_id) dest_floor_id = sf_ptr->upper_floor_id;
1492         }
1493         else
1494         {
1495                 if (sf_ptr->lower_floor_id) dest_floor_id = sf_ptr->lower_floor_id;
1496         }
1497
1498
1499         /* Search old stairs leading to the destination */
1500         if (dest_floor_id)
1501         {
1502                 int x, y;
1503
1504                 for (y = 0; y < cur_hgt; y++)
1505                 {
1506                         for (x = 0; x < cur_wid; x++)
1507                         {
1508                                 cave_type *c_ptr = &cave[y][x];
1509
1510                                 if (!c_ptr->special) continue;
1511                                 if (feat_uses_special(c_ptr->feat)) continue;
1512                                 if (c_ptr->special != dest_floor_id) continue;
1513
1514                                 /* Remove old stairs */
1515                                 c_ptr->special = 0;
1516                                 cave_set_feat(y, x, floor_type[randint0(100)]);
1517                         }
1518                 }
1519         }
1520
1521         /* No old destination -- Get new one now */
1522         else
1523         {
1524                 dest_floor_id = get_new_floor_id();
1525
1526                 /* Fix it */
1527                 if (up)
1528                         sf_ptr->upper_floor_id = dest_floor_id;
1529                 else
1530                         sf_ptr->lower_floor_id = dest_floor_id;
1531         }
1532
1533         /* Extract destination floor data */
1534         dest_sf_ptr = get_sf_ptr(dest_floor_id);
1535
1536
1537         /* Create a staircase */
1538         if (up)
1539         {
1540                 cave_set_feat(py, px,
1541                         (dest_sf_ptr->last_visit && (dest_sf_ptr->dun_level <= dun_level - 2)) ?
1542                         feat_state(feat_up_stair, FF_SHAFT) : feat_up_stair);
1543         }
1544         else
1545         {
1546                 cave_set_feat(py, px,
1547                         (dest_sf_ptr->last_visit && (dest_sf_ptr->dun_level >= dun_level + 2)) ?
1548                         feat_state(feat_down_stair, FF_SHAFT) : feat_down_stair);
1549         }
1550
1551
1552         /* Connect this stairs to the destination */
1553         cave[py][px].special = dest_floor_id;
1554 }