OSDN Git Service

fix #36223
[jnethack/source.git] / src / allmain.c
1 /* NetHack 3.6  allmain.c       $NHDT-Date: 1446975459 2015/11/08 09:37:39 $  $NHDT-Branch: master $:$NHDT-Revision: 1.66 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016            */
8 /* JNetHack may be freely redistributed.  See license for details. */
9
10 /* various code that was replicated in *main.c */
11
12 #include "hack.h"
13
14 #ifndef NO_SIGNAL
15 #include <signal.h>
16 #endif
17
18 #ifdef POSITIONBAR
19 STATIC_DCL void NDECL(do_positionbar);
20 #endif
21
22 void
23 moveloop(resuming)
24 boolean resuming;
25 {
26 #if defined(MICRO) || defined(WIN32)
27     char ch;
28     int abort_lev;
29 #endif
30     int moveamt = 0, wtcap = 0, change = 0;
31     boolean monscanmove = FALSE;
32
33     /* Note:  these initializers don't do anything except guarantee that
34             we're linked properly.
35     */
36     decl_init();
37     monst_init();
38     monstr_init(); /* monster strengths */
39     objects_init();
40
41     if (wizard)
42         add_debug_extended_commands();
43
44     /* if a save file created in normal mode is now being restored in
45        explore mode, treat it as normal restore followed by 'X' command
46        to use up the save file and require confirmation for explore mode */
47     if (resuming && iflags.deferred_X)
48         (void) enter_explore_mode();
49
50     /* side-effects from the real world */
51     flags.moonphase = phase_of_the_moon();
52     if (flags.moonphase == FULL_MOON) {
53 /*JP
54         You("are lucky!  Full moon tonight.");
55 */
56         pline("\83\89\83b\83L\81[\81I\8d¡\94Ó\82Í\96\9e\8c\8e\82¾\81D");
57         change_luck(1);
58     } else if (flags.moonphase == NEW_MOON) {
59 /*JP
60         pline("Be careful!  New moon tonight.");
61 */
62         pline("\92\8d\88Ó\82µ\82ë\81I\8d¡\94Ó\82Í\90V\8c\8e\82¾\81D");
63     }
64     flags.friday13 = friday_13th();
65     if (flags.friday13) {
66 /*JP
67         pline("Watch out!  Bad things can happen on Friday the 13th.");
68 */
69         pline("\97p\90S\82µ\82ë\81I\82P\82R\93ú\82Ì\8bà\97j\93ú\82É\82Í\82æ\82­\82È\82¢\82±\82Æ\82ª\82 \82é\81D") ;
70         change_luck(-1);
71     }
72
73     if (!resuming) { /* new game */
74         context.rndencode = rnd(9000);
75         set_wear((struct obj *) 0); /* for side-effects of starting gear */
76         (void) pickup(1);      /* autopickup at initial location */
77     } else {                   /* restore old game */
78 #ifndef WIN32
79         update_inventory(); /* for perm_invent */
80 #endif
81         read_engr_at(u.ux, u.uy); /* subset of pickup() */
82     }
83 #ifdef WIN32
84     update_inventory(); /* for perm_invent */
85 #endif
86
87     (void) encumber_msg(); /* in case they auto-picked up something */
88     if (defer_see_monsters) {
89         defer_see_monsters = FALSE;
90         see_monsters();
91     }
92     initrack();
93
94     u.uz0.dlevel = u.uz.dlevel;
95     youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */
96     context.move = 0;
97
98     program_state.in_moveloop = 1;
99     for (;;) {
100 #ifdef SAFERHANGUP
101         if (program_state.done_hup)
102             end_of_input();
103 #endif
104         get_nh_event();
105 #ifdef POSITIONBAR
106         do_positionbar();
107 #endif
108
109         if (context.move) {
110             /* actual time passed */
111             youmonst.movement -= NORMAL_SPEED;
112
113             do { /* hero can't move this turn loop */
114                 wtcap = encumber_msg();
115
116                 context.mon_moving = TRUE;
117                 do {
118                     monscanmove = movemon();
119                     if (youmonst.movement >= NORMAL_SPEED)
120                         break; /* it's now your turn */
121                 } while (monscanmove);
122                 context.mon_moving = FALSE;
123
124                 if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
125                     /* both you and the monsters are out of steam this round
126                      */
127                     /* set up for a new turn */
128                     struct monst *mtmp;
129                     mcalcdistress(); /* adjust monsters' trap, blind, etc */
130
131                     /* reallocate movement rations to monsters */
132                     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
133                         mtmp->movement += mcalcmove(mtmp);
134
135                     if (!rn2(u.uevent.udemigod
136                                  ? 25
137                                  : (depth(&u.uz) > depth(&stronghold_level))
138                                        ? 50
139                                        : 70))
140                         (void) makemon((struct permonst *) 0, 0, 0,
141                                        NO_MM_FLAGS);
142
143                     /* calculate how much time passed. */
144                     if (u.usteed && u.umoved) {
145                         /* your speed doesn't augment steed's speed */
146                         moveamt = mcalcmove(u.usteed);
147                     } else {
148                         moveamt = youmonst.data->mmove;
149
150                         if (Very_fast) { /* speed boots or potion */
151                             /* average movement is 1.67 times normal */
152                             moveamt += NORMAL_SPEED / 2;
153                             if (rn2(3) == 0)
154                                 moveamt += NORMAL_SPEED / 2;
155                         } else if (Fast) {
156                             /* average movement is 1.33 times normal */
157                             if (rn2(3) != 0)
158                                 moveamt += NORMAL_SPEED / 2;
159                         }
160                     }
161
162                     switch (wtcap) {
163                     case UNENCUMBERED:
164                         break;
165                     case SLT_ENCUMBER:
166                         moveamt -= (moveamt / 4);
167                         break;
168                     case MOD_ENCUMBER:
169                         moveamt -= (moveamt / 2);
170                         break;
171                     case HVY_ENCUMBER:
172                         moveamt -= ((moveamt * 3) / 4);
173                         break;
174                     case EXT_ENCUMBER:
175                         moveamt -= ((moveamt * 7) / 8);
176                         break;
177                     default:
178                         break;
179                     }
180
181                     youmonst.movement += moveamt;
182                     if (youmonst.movement < 0)
183                         youmonst.movement = 0;
184                     settrack();
185
186                     monstermoves++;
187                     moves++;
188
189                     /********************************/
190                     /* once-per-turn things go here */
191                     /********************************/
192
193                     if (Glib)
194                         glibr();
195                     nh_timeout();
196                     run_regions();
197
198                     if (u.ublesscnt)
199                         u.ublesscnt--;
200                     if (flags.time && !context.run)
201                         context.botl = 1;
202
203                     /* One possible result of prayer is healing.  Whether or
204                      * not you get healed depends on your current hit points.
205                      * If you are allowed to regenerate during the prayer, the
206                      * end-of-prayer calculation messes up on this.
207                      * Another possible result is rehumanization, which
208                      * requires
209                      * that encumbrance and movement rate be recalculated.
210                      */
211                     if (u.uinvulnerable) {
212                         /* for the moment at least, you're in tiptop shape */
213                         wtcap = UNENCUMBERED;
214                     } else if (Upolyd && youmonst.data->mlet == S_EEL
215                                && !is_pool(u.ux, u.uy)
216                                && !Is_waterlevel(&u.uz)) {
217                         /* eel out of water loses hp, same as for monsters;
218                            as hp gets lower, rate of further loss slows down
219                            */
220                         if (u.mh > 1 && rn2(u.mh) > rn2(8)
221                             && (!Half_physical_damage || !(moves % 2L))) {
222                             u.mh--;
223                             context.botl = 1;
224                         } else if (u.mh < 1)
225                             rehumanize();
226                     } else if (Upolyd && u.mh < u.mhmax) {
227                         if (u.mh < 1)
228                             rehumanize();
229                         else if (Regeneration
230                                  || (wtcap < MOD_ENCUMBER && !(moves % 20))) {
231                             context.botl = 1;
232                             u.mh++;
233                         }
234                     } else if (u.uhp < u.uhpmax
235                                && (wtcap < MOD_ENCUMBER || !u.umoved
236                                    || Regeneration)) {
237                         if (u.ulevel > 9 && !(moves % 3)) {
238                             int heal, Con = (int) ACURR(A_CON);
239
240                             if (Con <= 12) {
241                                 heal = 1;
242                             } else {
243                                 heal = rnd(Con);
244                                 if (heal > u.ulevel - 9)
245                                     heal = u.ulevel - 9;
246                             }
247                             context.botl = 1;
248                             u.uhp += heal;
249                             if (u.uhp > u.uhpmax)
250                                 u.uhp = u.uhpmax;
251                         } else if (Regeneration
252                                    || (u.ulevel <= 9
253                                        && !(moves
254                                             % ((MAXULEV + 12) / (u.ulevel + 2)
255                                                + 1)))) {
256                             context.botl = 1;
257                             u.uhp++;
258                         }
259                     }
260
261                     /* moving around while encumbered is hard work */
262                     if (wtcap > MOD_ENCUMBER && u.umoved) {
263                         if (!(wtcap < EXT_ENCUMBER ? moves % 30
264                                                    : moves % 10)) {
265                             if (Upolyd && u.mh > 1) {
266                                 u.mh--;
267                             } else if (!Upolyd && u.uhp > 1) {
268                                 u.uhp--;
269                             } else {
270 /*JP
271                                 You("pass out from exertion!");
272 */
273                                 pline("\94æ\98J\82Å\88Ó\8e¯\82ð\8e¸\82Á\82½\81I");
274                                 exercise(A_CON, FALSE);
275                                 fall_asleep(-10, FALSE);
276                             }
277                         }
278                     }
279
280                     if ((u.uen < u.uenmax)
281                         && ((wtcap < MOD_ENCUMBER
282                              && (!(moves % ((MAXULEV + 8 - u.ulevel)
283                                             * (Role_if(PM_WIZARD) ? 3 : 4)
284                                             / 6)))) || Energy_regeneration)) {
285                         u.uen += rn1(
286                             (int) (ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1, 1);
287                         if (u.uen > u.uenmax)
288                             u.uen = u.uenmax;
289                         context.botl = 1;
290                     }
291
292                     if (!u.uinvulnerable) {
293                         if (Teleportation && !rn2(85)) {
294                             xchar old_ux = u.ux, old_uy = u.uy;
295                             tele();
296                             if (u.ux != old_ux || u.uy != old_uy) {
297                                 if (!next_to_u()) {
298                                     check_leash(old_ux, old_uy);
299                                 }
300                                 /* clear doagain keystrokes */
301                                 pushch(0);
302                                 savech(0);
303                             }
304                         }
305                         /* delayed change may not be valid anymore */
306                         if ((change == 1 && !Polymorph)
307                             || (change == 2 && u.ulycn == NON_PM))
308                             change = 0;
309                         if (Polymorph && !rn2(100))
310                             change = 1;
311                         else if (u.ulycn >= LOW_PM && !Upolyd
312                                  && !rn2(80 - (20 * night())))
313                             change = 2;
314                         if (change && !Unchanging) {
315                             if (multi >= 0) {
316                                 if (occupation)
317                                     stop_occupation();
318                                 else
319                                     nomul(0);
320                                 if (change == 1)
321                                     polyself(0);
322                                 else
323                                     you_were();
324                                 change = 0;
325                             }
326                         }
327                     }
328
329                     if (Searching && multi >= 0)
330                         (void) dosearch0(1);
331                     dosounds();
332                     do_storms();
333                     gethungry();
334                     age_spells();
335                     exerchk();
336                     invault();
337                     if (u.uhave.amulet)
338                         amulet();
339                     if (!rn2(40 + (int) (ACURR(A_DEX) * 3)))
340                         u_wipe_engr(rnd(3));
341                     if (u.uevent.udemigod && !u.uinvulnerable) {
342                         if (u.udg_cnt)
343                             u.udg_cnt--;
344                         if (!u.udg_cnt) {
345                             intervene();
346                             u.udg_cnt = rn1(200, 50);
347                         }
348                     }
349                     restore_attrib();
350                     /* underwater and waterlevel vision are done here */
351                     if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
352                         movebubbles();
353                     else if (Is_firelevel(&u.uz))
354                         fumaroles();
355                     else if (Underwater)
356                         under_water(0);
357                     /* vision while buried done here */
358                     else if (u.uburied)
359                         under_ground(0);
360
361                     /* when immobile, count is in turns */
362                     if (multi < 0) {
363                         if (++multi == 0) { /* finished yet? */
364                             unmul((char *) 0);
365                             /* if unmul caused a level change, take it now */
366                             if (u.utotype)
367                                 deferred_goto();
368                         }
369                     }
370                 }
371             } while (youmonst.movement
372                      < NORMAL_SPEED); /* hero can't move loop */
373
374             /******************************************/
375             /* once-per-hero-took-time things go here */
376             /******************************************/
377
378             if (context.bypasses)
379                 clear_bypasses();
380             if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz)
381                 && !BClairvoyant && !(moves % 15) && !rn2(2))
382                 do_vicinity_map();
383             if (u.utrap && u.utraptype == TT_LAVA)
384                 sink_into_lava();
385             /* when/if hero escapes from lava, he can't just stay there */
386             else if (!u.umoved)
387                 (void) pooleffects(FALSE);
388
389         } /* actual time passed */
390
391         /****************************************/
392         /* once-per-player-input things go here */
393         /****************************************/
394
395         clear_splitobjs();
396         find_ac();
397         if (!context.mv || Blind) {
398             /* redo monsters if hallu or wearing a helm of telepathy */
399             if (Hallucination) { /* update screen randomly */
400                 see_monsters();
401                 see_objects();
402                 see_traps();
403                 if (u.uswallow)
404                     swallowed(0);
405             } else if (Unblind_telepat) {
406                 see_monsters();
407             } else if (Warning || Warn_of_mon)
408                 see_monsters();
409
410             if (vision_full_recalc)
411                 vision_recalc(0); /* vision! */
412         }
413         if (context.botl || context.botlx) {
414             bot();
415             curs_on_u();
416         }
417
418         context.move = 1;
419
420         if (multi >= 0 && occupation) {
421 #if defined(MICRO) || defined(WIN32)
422             abort_lev = 0;
423             if (kbhit()) {
424                 if ((ch = pgetchar()) == ABORT)
425                     abort_lev++;
426                 else
427                     pushch(ch);
428             }
429             if (!abort_lev && (*occupation)() == 0)
430 #else
431             if ((*occupation)() == 0)
432 #endif
433                 occupation = 0;
434             if (
435 #if defined(MICRO) || defined(WIN32)
436                 abort_lev ||
437 #endif
438                 monster_nearby()) {
439                 stop_occupation();
440                 reset_eat();
441             }
442 #if defined(MICRO) || defined(WIN32)
443             if (!(++occtime % 7))
444                 display_nhwindow(WIN_MAP, FALSE);
445 #endif
446             continue;
447         }
448
449         if (iflags.sanity_check)
450             sanity_check();
451
452 #ifdef CLIPPING
453         /* just before rhack */
454         cliparound(u.ux, u.uy);
455 #endif
456
457         u.umoved = FALSE;
458
459         if (multi > 0) {
460             lookaround();
461             if (!multi) {
462                 /* lookaround may clear multi */
463                 context.move = 0;
464                 if (flags.time)
465                     context.botl = 1;
466                 continue;
467             }
468             if (context.mv) {
469                 if (multi < COLNO && !--multi)
470                     context.travel = context.travel1 = context.mv =
471                         context.run = 0;
472                 domove();
473             } else {
474                 --multi;
475                 rhack(save_cm);
476             }
477         } else if (multi == 0) {
478 #ifdef MAIL
479             ckmailstatus();
480 #endif
481             rhack((char *) 0);
482         }
483         if (u.utotype)       /* change dungeon level */
484             deferred_goto(); /* after rhack() */
485         /* !context.move here: multiple movement command stopped */
486         else if (flags.time && (!context.move || !context.mv))
487             context.botl = 1;
488
489         if (vision_full_recalc)
490             vision_recalc(0); /* vision! */
491         /* when running in non-tport mode, this gets done through domove() */
492         if ((!context.run || flags.runmode == RUN_TPORT)
493             && (multi && (!context.travel ? !(multi % 7) : !(moves % 7L)))) {
494             if (flags.time && context.run)
495                 context.botl = 1;
496             display_nhwindow(WIN_MAP, FALSE);
497         }
498     }
499 }
500
501 void
502 stop_occupation()
503 {
504     if (occupation) {
505         if (!maybe_finished_meal(TRUE))
506 /*JP
507             You("stop %s.", occtxt);
508 */
509             You("%s\82Ì\82ð\92\86\92f\82µ\82½\81D", occtxt);
510         occupation = 0;
511         context.botl = 1; /* in case u.uhs changed */
512         nomul(0);
513         pushch(0);
514     }
515 }
516
517 void
518 display_gamewindows()
519 {
520     WIN_MESSAGE = create_nhwindow(NHW_MESSAGE);
521 #ifdef STATUS_VIA_WINDOWPORT
522     status_initialize(0);
523 #else
524     WIN_STATUS = create_nhwindow(NHW_STATUS);
525 #endif
526     WIN_MAP = create_nhwindow(NHW_MAP);
527     WIN_INVEN = create_nhwindow(NHW_MENU);
528
529 #ifdef MAC
530     /* This _is_ the right place for this - maybe we will
531      * have to split display_gamewindows into create_gamewindows
532      * and show_gamewindows to get rid of this ifdef...
533      */
534     if (!strcmp(windowprocs.name, "mac"))
535         SanePositions();
536 #endif
537
538     /*
539      * The mac port is not DEPENDENT on the order of these
540      * displays, but it looks a lot better this way...
541      */
542 #ifndef STATUS_VIA_WINDOWPORT
543     display_nhwindow(WIN_STATUS, FALSE);
544 #endif
545     display_nhwindow(WIN_MESSAGE, FALSE);
546     clear_glyph_buffer();
547     display_nhwindow(WIN_MAP, FALSE);
548 }
549
550 void
551 newgame()
552 {
553     int i;
554
555 #ifdef MFLOPPY
556     gameDiskPrompt();
557 #endif
558
559     context.botlx = 1;
560     context.ident = 1;
561     context.stethoscope_move = -1L;
562     context.warnlevel = 1;
563     context.next_attrib_check = 600L; /* arbitrary first setting */
564     context.tribute.enabled = TRUE;   /* turn on 3.6 tributes    */
565     context.tribute.tributesz = sizeof(struct tribute_info);
566
567     for (i = 0; i < NUMMONS; i++)
568         mvitals[i].mvflags = mons[i].geno & G_NOCORPSE;
569
570     init_objects(); /* must be before u_init() */
571
572     flags.pantheon = -1; /* role_init() will reset this */
573     role_init();         /* must be before init_dungeons(), u_init(),
574                           * and init_artifacts() */
575
576     init_dungeons();  /* must be before u_init() to avoid rndmonst()
577                        * creating odd monsters for any tins and eggs
578                        * in hero's initial inventory */
579     init_artifacts(); /* before u_init() in case $WIZKIT specifies
580                        * any artifacts */
581     u_init();
582
583 #ifndef NO_SIGNAL
584     (void) signal(SIGINT, (SIG_RET_TYPE) done1);
585 #endif
586 #ifdef NEWS
587     if (iflags.news)
588         display_file(NEWS, FALSE);
589 #endif
590     load_qtlist();          /* load up the quest text info */
591     /* quest_init();  --  Now part of role_init() */
592
593     mklev();
594     u_on_upstairs();
595     if (wizard)
596         obj_delivery(FALSE); /* finish wizkit */
597     vision_reset();          /* set up internals for level (after mklev) */
598     check_special_room(FALSE);
599
600     if (MON_AT(u.ux, u.uy))
601         mnexto(m_at(u.ux, u.uy));
602     (void) makedog();
603     docrt();
604
605     if (flags.legacy) {
606         flush_screen(1);
607         com_pager(1);
608     }
609
610     urealtime.realtime = 0L;
611     urealtime.start_timing = getnow();
612 #ifdef INSURANCE
613     save_currentstate();
614 #endif
615     program_state.something_worth_saving++; /* useful data now exists */
616
617     /* Success! */
618     welcome(TRUE);
619     return;
620 }
621
622 /* show "welcome [back] to nethack" message at program startup */
623 void
624 welcome(new_game)
625 boolean new_game; /* false => restoring an old game */
626 {
627     char buf[BUFSZ];
628     boolean currentgend = Upolyd ? u.mfemale : flags.female;
629
630     /*
631      * The "welcome back" message always describes your innate form
632      * even when polymorphed or wearing a helm of opposite alignment.
633      * Alignment is shown unconditionally for new games; for restores
634      * it's only shown if it has changed from its original value.
635      * Sex is shown for new games except when it is redundant; for
636      * restores it's only shown if different from its original value.
637      */
638     *buf = '\0';
639     if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT])
640 /*JP
641         Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL]));
642 */
643         Sprintf(eos(buf), "%s", align_str(u.ualignbase[A_ORIGINAL]));
644     if (!urole.name.f
645         && (new_game
646                 ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE)
647                 : currentgend != flags.initgend))
648 /*JP
649         Sprintf(eos(buf), " %s", genders[currentgend].adj);
650 */
651         Sprintf(eos(buf), "\82Ì%s", genders[currentgend].adj);
652
653 #if 0 /*JP*/
654     pline(new_game ? "%s %s, welcome to NetHack!  You are a%s %s %s."
655                    : "%s %s, the%s %s %s, welcome back to NetHack!",
656           Hello((struct monst *) 0), plname, buf, urace.adj,
657           (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
658 #else
659     if(new_game){
660         pline("%s\81CNetHack\82Ì\90¢\8aE\82Ö\81I\82±\82Ì\83Q\81[\83\80\82Å\82Í\82 \82È\82½\82Í%s%s(%s)\82¾\81D",
661               Hello((struct monst *) 0), urace.adj,
662               (currentgend && urole.name.f) ? urole.name.f : urole.name.m,
663               buf);
664     } else {
665         pline("%s\81CNetHack\82Ì\90¢\8aE\82Ö\81I\82 \82È\82½\82Í%s%s\82¾\81I",
666               Hello((struct monst *) 0), urace.adj,
667               (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
668     }
669 #endif
670 }
671
672 #ifdef POSITIONBAR
673 STATIC_DCL void
674 do_positionbar()
675 {
676     static char pbar[COLNO];
677     char *p;
678
679     p = pbar;
680     /* up stairway */
681     if (upstair.sx
682         && (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
683                 == S_upstair
684             || glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
685                    == S_upladder)) {
686         *p++ = '<';
687         *p++ = upstair.sx;
688     }
689     if (sstairs.sx
690         && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
691                 == S_upstair
692             || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
693                    == S_upladder)) {
694         *p++ = '<';
695         *p++ = sstairs.sx;
696     }
697
698     /* down stairway */
699     if (dnstair.sx
700         && (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
701                 == S_dnstair
702             || glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
703                    == S_dnladder)) {
704         *p++ = '>';
705         *p++ = dnstair.sx;
706     }
707     if (sstairs.sx
708         && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
709                 == S_dnstair
710             || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
711                    == S_dnladder)) {
712         *p++ = '>';
713         *p++ = sstairs.sx;
714     }
715
716     /* hero location */
717     if (u.ux) {
718         *p++ = '@';
719         *p++ = u.ux;
720     }
721     /* fence post */
722     *p = 0;
723
724     update_positionbar(pbar);
725 }
726 #endif
727
728 /*allmain.c*/