OSDN Git Service

eaba6ab2fdeb7eedb39bebfde41be8c9aaa9417c
[jnethack/source.git] / src / allmain.c
1 /* NetHack 3.6  allmain.c       $NHDT-Date: 1555552624 2019/04/18 01:57:04 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.100 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2012. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 /* various code that was replicated in *main.c */
12
13 #include "hack.h"
14 #include <ctype.h>
15
16 #ifndef NO_SIGNAL
17 #include <signal.h>
18 #endif
19
20 #ifdef POSITIONBAR
21 STATIC_DCL void NDECL(do_positionbar);
22 #endif
23 STATIC_DCL void FDECL(regen_hp, (int));
24 STATIC_DCL void FDECL(interrupt_multi, (const char *));
25 STATIC_DCL void FDECL(debug_fields, (const char *));
26
27 void
28 moveloop(resuming)
29 boolean resuming;
30 {
31 #if defined(MICRO) || defined(WIN32)
32     char ch;
33     int abort_lev;
34 #endif
35     int moveamt = 0, wtcap = 0, change = 0;
36     boolean monscanmove = FALSE;
37
38     /* Note:  these initializers don't do anything except guarantee that
39             we're linked properly.
40     */
41     decl_init();
42     monst_init();
43     objects_init();
44
45     /* if a save file created in normal mode is now being restored in
46        explore mode, treat it as normal restore followed by 'X' command
47        to use up the save file and require confirmation for explore mode */
48     if (resuming && iflags.deferred_X)
49         (void) enter_explore_mode();
50
51     /* side-effects from the real world */
52     flags.moonphase = phase_of_the_moon();
53     if (flags.moonphase == FULL_MOON) {
54 /*JP
55         You("are lucky!  Full moon tonight.");
56 */
57         pline("\83\89\83b\83L\81[\81I\8d¡\94Ó\82Í\96\9e\8c\8e\82¾\81D");
58         change_luck(1);
59     } else if (flags.moonphase == NEW_MOON) {
60 /*JP
61         pline("Be careful!  New moon tonight.");
62 */
63         pline("\92\8d\88Ó\82µ\82ë\81I\8d¡\94Ó\82Í\90V\8c\8e\82¾\81D");
64     }
65     flags.friday13 = friday_13th();
66     if (flags.friday13) {
67 /*JP
68         pline("Watch out!  Bad things can happen on Friday the 13th.");
69 */
70         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") ;
71         change_luck(-1);
72     }
73
74     if (!resuming) { /* new game */
75         context.rndencode = rnd(9000);
76         set_wear((struct obj *) 0); /* for side-effects of starting gear */
77         (void) pickup(1);      /* autopickup at initial location */
78     }
79     context.botlx = TRUE; /* for STATUS_HILITES */
80     update_inventory(); /* for perm_invent */
81     if (resuming) { /* restoring old game */
82         read_engr_at(u.ux, u.uy); /* subset of pickup() */
83     }
84
85     (void) encumber_msg(); /* in case they auto-picked up something */
86     if (defer_see_monsters) {
87         defer_see_monsters = FALSE;
88         see_monsters();
89     }
90     initrack();
91
92     u.uz0.dlevel = u.uz.dlevel;
93     youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */
94     context.move = 0;
95
96     program_state.in_moveloop = 1;
97     for (;;) {
98 #ifdef SAFERHANGUP
99         if (program_state.done_hup)
100             end_of_input();
101 #endif
102         get_nh_event();
103 #ifdef POSITIONBAR
104         do_positionbar();
105 #endif
106
107         if (context.move) {
108             /* actual time passed */
109             youmonst.movement -= NORMAL_SPEED;
110
111             do { /* hero can't move this turn loop */
112                 wtcap = encumber_msg();
113
114                 context.mon_moving = TRUE;
115                 do {
116                     monscanmove = movemon();
117                     if (youmonst.movement >= NORMAL_SPEED)
118                         break; /* it's now your turn */
119                 } while (monscanmove);
120                 context.mon_moving = FALSE;
121
122                 if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
123                     /* both hero and monsters are out of steam this round */
124                     struct monst *mtmp;
125
126                     /* set up for a new turn */
127                     mcalcdistress(); /* adjust monsters' trap, blind, etc */
128
129                     /* reallocate movement rations to monsters; don't need
130                        to skip dead monsters here because they will have
131                        been purged at end of their previous round of moving */
132                     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
133                         mtmp->movement += mcalcmove(mtmp);
134
135                     /* occasionally add another monster; since this takes
136                        place after movement has been allotted, the new
137                        monster effectively loses its first turn */
138                     if (!rn2(u.uevent.udemigod ? 25
139                              : (depth(&u.uz) > depth(&stronghold_level)) ? 50
140                                : 70))
141                         (void) makemon((struct permonst *) 0, 0, 0,
142                                        NO_MM_FLAGS);
143
144                     /* calculate how much time passed. */
145                     if (u.usteed && u.umoved) {
146                         /* your speed doesn't augment steed's speed */
147                         moveamt = mcalcmove(u.usteed);
148                     } else {
149                         moveamt = youmonst.data->mmove;
150
151                         if (Very_fast) { /* speed boots, potion, or spell */
152                             /* gain a free action on 2/3 of turns */
153                             if (rn2(3) != 0)
154                                 moveamt += NORMAL_SPEED;
155                         } else if (Fast) { /* intrinsic */
156                             /* gain a free action on 1/3 of turns */
157                             if (rn2(3) == 0)
158                                 moveamt += NORMAL_SPEED;
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                         iflags.time_botl = TRUE;
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,
206                      * the end-of-prayer calculation messes up on this.
207                      * Another possible result is rehumanization, which
208                      * requires that encumbrance and movement rate be
209                      * recalculated.
210                      */
211                     if (u.uinvulnerable) {
212                         /* for the moment at least, you're in tiptop shape */
213                         wtcap = UNENCUMBERED;
214                     } else if (!Upolyd ? (u.uhp < u.uhpmax)
215                                        : (u.mh < u.mhmax
216                                           || youmonst.data->mlet == S_EEL)) {
217                         /* maybe heal */
218                         regen_hp(wtcap);
219                     }
220
221                     /* moving around while encumbered is hard work */
222                     if (wtcap > MOD_ENCUMBER && u.umoved) {
223                         if (!(wtcap < EXT_ENCUMBER ? moves % 30
224                                                    : moves % 10)) {
225                             if (Upolyd && u.mh > 1) {
226                                 u.mh--;
227                                 context.botl = TRUE;
228                             } else if (!Upolyd && u.uhp > 1) {
229                                 u.uhp--;
230                                 context.botl = TRUE;
231                             } else {
232 /*JP
233                                 You("pass out from exertion!");
234 */
235                                 pline("\94æ\98J\82Å\88Ó\8e¯\82ð\8e¸\82Á\82½\81I");
236                                 exercise(A_CON, FALSE);
237                                 fall_asleep(-10, FALSE);
238                             }
239                         }
240                     }
241
242                     if (u.uen < u.uenmax
243                         && ((wtcap < MOD_ENCUMBER
244                              && (!(moves % ((MAXULEV + 8 - u.ulevel)
245                                             * (Role_if(PM_WIZARD) ? 3 : 4)
246                                             / 6)))) || Energy_regeneration)) {
247                         u.uen += rn1(
248                             (int) (ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1, 1);
249                         if (u.uen > u.uenmax)
250                             u.uen = u.uenmax;
251                         context.botl = TRUE;
252                         if (u.uen == u.uenmax)
253 /*JP
254                             interrupt_multi("You feel full of energy.");
255 */
256                             interrupt_multi("\83G\83l\83\8b\83M\81[\82ª\89ñ\95\9c\82µ\82½\81D");
257                     }
258
259                     if (!u.uinvulnerable) {
260                         if (Teleportation && !rn2(85)) {
261                             xchar old_ux = u.ux, old_uy = u.uy;
262
263                             tele();
264                             if (u.ux != old_ux || u.uy != old_uy) {
265                                 if (!next_to_u()) {
266                                     check_leash(old_ux, old_uy);
267                                 }
268                                 /* clear doagain keystrokes */
269                                 pushch(0);
270                                 savech(0);
271                             }
272                         }
273                         /* delayed change may not be valid anymore */
274                         if ((change == 1 && !Polymorph)
275                             || (change == 2 && u.ulycn == NON_PM))
276                             change = 0;
277                         if (Polymorph && !rn2(100))
278                             change = 1;
279                         else if (u.ulycn >= LOW_PM && !Upolyd
280                                  && !rn2(80 - (20 * night())))
281                             change = 2;
282                         if (change && !Unchanging) {
283                             if (multi >= 0) {
284                                 stop_occupation();
285                                 if (change == 1)
286                                     polyself(0);
287                                 else
288                                     you_were();
289                                 change = 0;
290                             }
291                         }
292                     }
293
294                     if (Searching && multi >= 0)
295                         (void) dosearch0(1);
296                     if (Warning)
297                         warnreveal();
298                     mkot_trap_warn();
299                     dosounds();
300                     do_storms();
301                     gethungry();
302                     age_spells();
303                     exerchk();
304                     invault();
305                     if (u.uhave.amulet)
306                         amulet();
307                     if (!rn2(40 + (int) (ACURR(A_DEX) * 3)))
308                         u_wipe_engr(rnd(3));
309                     if (u.uevent.udemigod && !u.uinvulnerable) {
310                         if (u.udg_cnt)
311                             u.udg_cnt--;
312                         if (!u.udg_cnt) {
313                             intervene();
314                             u.udg_cnt = rn1(200, 50);
315                         }
316                     }
317                     restore_attrib();
318                     /* underwater and waterlevel vision are done here */
319                     if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
320                         movebubbles();
321                     else if (Is_firelevel(&u.uz))
322                         fumaroles();
323                     else if (Underwater)
324                         under_water(0);
325                     /* vision while buried done here */
326                     else if (u.uburied)
327                         under_ground(0);
328
329                     /* when immobile, count is in turns */
330                     if (multi < 0) {
331                         if (++multi == 0) { /* finished yet? */
332                             unmul((char *) 0);
333                             /* if unmul caused a level change, take it now */
334                             if (u.utotype)
335                                 deferred_goto();
336                         }
337                     }
338                 }
339             } while (youmonst.movement < NORMAL_SPEED); /* hero can't move */
340
341             /******************************************/
342             /* once-per-hero-took-time things go here */
343             /******************************************/
344
345 #ifdef STATUS_HILITES
346             if (iflags.hilite_delta)
347                 status_eval_next_unhilite();
348 #endif
349             if (context.bypasses)
350                 clear_bypasses();
351             if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz)
352                 && !BClairvoyant && !(moves % 15) && !rn2(2))
353                 do_vicinity_map((struct obj *) 0);
354             if (u.utrap && u.utraptype == TT_LAVA)
355                 sink_into_lava();
356             /* when/if hero escapes from lava, he can't just stay there */
357             else if (!u.umoved)
358                 (void) pooleffects(FALSE);
359
360         } /* actual time passed */
361
362         /****************************************/
363         /* once-per-player-input things go here */
364         /****************************************/
365
366         clear_splitobjs();
367         find_ac();
368         if (!context.mv || Blind) {
369             /* redo monsters if hallu or wearing a helm of telepathy */
370             if (Hallucination) { /* update screen randomly */
371                 see_monsters();
372                 see_objects();
373                 see_traps();
374                 if (u.uswallow)
375                     swallowed(0);
376             } else if (Unblind_telepat) {
377                 see_monsters();
378             } else if (Warning || Warn_of_mon)
379                 see_monsters();
380
381             if (vision_full_recalc)
382                 vision_recalc(0); /* vision! */
383         }
384         if (context.botl || context.botlx) {
385             bot();
386             curs_on_u();
387         } else if (iflags.time_botl) {
388             timebot();
389             curs_on_u();
390         }
391
392         context.move = 1;
393
394         if (multi >= 0 && occupation) {
395 #if defined(MICRO) || defined(WIN32)
396             abort_lev = 0;
397             if (kbhit()) {
398                 if ((ch = pgetchar()) == ABORT)
399                     abort_lev++;
400                 else
401                     pushch(ch);
402             }
403             if (!abort_lev && (*occupation)() == 0)
404 #else
405             if ((*occupation)() == 0)
406 #endif
407                 occupation = 0;
408             if (
409 #if defined(MICRO) || defined(WIN32)
410                 abort_lev ||
411 #endif
412                 monster_nearby()) {
413                 stop_occupation();
414                 reset_eat();
415             }
416 #if defined(MICRO) || defined(WIN32)
417             if (!(++occtime % 7))
418                 display_nhwindow(WIN_MAP, FALSE);
419 #endif
420             continue;
421         }
422
423         if (iflags.sanity_check || iflags.debug_fuzzer)
424             sanity_check();
425
426 #ifdef CLIPPING
427         /* just before rhack */
428         cliparound(u.ux, u.uy);
429 #endif
430
431         u.umoved = FALSE;
432
433         if (multi > 0) {
434             lookaround();
435             if (!multi) {
436                 /* lookaround may clear multi */
437                 context.move = 0;
438                 if (flags.time)
439                     context.botl = TRUE;
440                 continue;
441             }
442             if (context.mv) {
443                 if (multi < COLNO && !--multi)
444                     context.travel = context.travel1 = context.mv =
445                         context.run = 0;
446                 domove();
447             } else {
448                 --multi;
449                 rhack(save_cm);
450             }
451         } else if (multi == 0) {
452 #ifdef MAIL
453             ckmailstatus();
454 #endif
455             rhack((char *) 0);
456         }
457         if (u.utotype)       /* change dungeon level */
458             deferred_goto(); /* after rhack() */
459         /* !context.move here: multiple movement command stopped */
460         else if (flags.time && (!context.move || !context.mv))
461             context.botl = TRUE;
462
463         if (vision_full_recalc)
464             vision_recalc(0); /* vision! */
465         /* when running in non-tport mode, this gets done through domove() */
466         if ((!context.run || flags.runmode == RUN_TPORT)
467             && (multi && (!context.travel ? !(multi % 7) : !(moves % 7L)))) {
468             if (flags.time && context.run)
469                 context.botl = TRUE;
470             /* [should this be flush_screen() instead?] */
471             display_nhwindow(WIN_MAP, FALSE);
472         }
473     }
474 }
475
476 /* maybe recover some lost health (or lose some when an eel out of water) */
477 STATIC_OVL void
478 regen_hp(wtcap)
479 int wtcap;
480 {
481     int heal = 0;
482     boolean reached_full = FALSE,
483             encumbrance_ok = (wtcap < MOD_ENCUMBER || !u.umoved);
484
485     if (Upolyd) {
486         if (u.mh < 1) { /* shouldn't happen... */
487             rehumanize();
488         } else if (youmonst.data->mlet == S_EEL
489                    && !is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz)) {
490             /* eel out of water loses hp, similar to monster eels;
491                as hp gets lower, rate of further loss slows down */
492             if (u.mh > 1 && !Regeneration && rn2(u.mh) > rn2(8)
493                 && (!Half_physical_damage || !(moves % 2L)))
494                 heal = -1;
495         } else if (u.mh < u.mhmax) {
496             if (Regeneration || (encumbrance_ok && !(moves % 20L)))
497                 heal = 1;
498         }
499         if (heal) {
500             context.botl = TRUE;
501             u.mh += heal;
502             reached_full = (u.mh == u.mhmax);
503         }
504
505     /* !Upolyd */
506     } else {
507         /* [when this code was in-line within moveloop(), there was
508            no !Upolyd check here, so poly'd hero recovered lost u.uhp
509            once u.mh reached u.mhmax; that may have been convenient
510            for the player, but it didn't make sense for gameplay...] */
511         if (u.uhp < u.uhpmax && (encumbrance_ok || Regeneration)) {
512             if (u.ulevel > 9) {
513                 if (!(moves % 3L)) {
514                     int Con = (int) ACURR(A_CON);
515
516                     if (Con <= 12) {
517                         heal = 1;
518                     } else {
519                         heal = rnd(Con);
520                         if (heal > u.ulevel - 9)
521                             heal = u.ulevel - 9;
522                     }
523                 }
524             } else { /* u.ulevel <= 9 */
525                 if (!(moves % (long) ((MAXULEV + 12) / (u.ulevel + 2) + 1)))
526                     heal = 1;
527             }
528             if (Regeneration && !heal)
529                 heal = 1;
530
531             if (heal) {
532                 context.botl = TRUE;
533                 u.uhp += heal;
534                 if (u.uhp > u.uhpmax)
535                     u.uhp = u.uhpmax;
536                 /* stop voluntary multi-turn activity if now fully healed */
537                 reached_full = (u.uhp == u.uhpmax);
538             }
539         }
540     }
541
542     if (reached_full)
543 /*JP
544         interrupt_multi("You are in full health.");
545 */
546         interrupt_multi("\91Ì\97Í\82ª\89ñ\95\9c\82µ\82½\81D");
547 }
548
549 void
550 stop_occupation()
551 {
552     if (occupation) {
553         if (!maybe_finished_meal(TRUE))
554 /*JP
555             You("stop %s.", occtxt);
556 */
557             You("%s\82Ì\82ð\92\86\92f\82µ\82½\81D", occtxt);
558         occupation = 0;
559         context.botl = TRUE; /* in case u.uhs changed */
560         nomul(0);
561         pushch(0);
562     } else if (multi >= 0) {
563         nomul(0);
564     }
565 }
566
567 void
568 display_gamewindows()
569 {
570     WIN_MESSAGE = create_nhwindow(NHW_MESSAGE);
571     if (VIA_WINDOWPORT()) {
572         status_initialize(0);
573     } else {
574         WIN_STATUS = create_nhwindow(NHW_STATUS);
575     }
576     WIN_MAP = create_nhwindow(NHW_MAP);
577     WIN_INVEN = create_nhwindow(NHW_MENU);
578     /* in case of early quit where WIN_INVEN could be destroyed before
579        ever having been used, use it here to pacify the Qt interface */
580     start_menu(WIN_INVEN), end_menu(WIN_INVEN, (char *) 0);
581
582 #ifdef MAC
583     /* This _is_ the right place for this - maybe we will
584      * have to split display_gamewindows into create_gamewindows
585      * and show_gamewindows to get rid of this ifdef...
586      */
587     if (!strcmp(windowprocs.name, "mac"))
588         SanePositions();
589 #endif
590
591     /*
592      * The mac port is not DEPENDENT on the order of these
593      * displays, but it looks a lot better this way...
594      */
595 #ifndef STATUS_HILITES
596     display_nhwindow(WIN_STATUS, FALSE);
597 #endif
598     display_nhwindow(WIN_MESSAGE, FALSE);
599     clear_glyph_buffer();
600     display_nhwindow(WIN_MAP, FALSE);
601 }
602
603 void
604 newgame()
605 {
606     int i;
607
608 #ifdef MFLOPPY
609     gameDiskPrompt();
610 #endif
611
612     context.botlx = TRUE;
613     context.ident = 1;
614     context.stethoscope_move = -1L;
615     context.warnlevel = 1;
616     context.next_attrib_check = 600L; /* arbitrary first setting */
617     context.tribute.enabled = TRUE;   /* turn on 3.6 tributes    */
618     context.tribute.tributesz = sizeof(struct tribute_info);
619
620     for (i = LOW_PM; i < NUMMONS; i++)
621         mvitals[i].mvflags = mons[i].geno & G_NOCORPSE;
622
623     init_objects(); /* must be before u_init() */
624
625     flags.pantheon = -1; /* role_init() will reset this */
626     role_init();         /* must be before init_dungeons(), u_init(),
627                           * and init_artifacts() */
628
629     init_dungeons();  /* must be before u_init() to avoid rndmonst()
630                        * creating odd monsters for any tins and eggs
631                        * in hero's initial inventory */
632     init_artifacts(); /* before u_init() in case $WIZKIT specifies
633                        * any artifacts */
634     u_init();
635
636 #ifndef NO_SIGNAL
637     (void) signal(SIGINT, (SIG_RET_TYPE) done1);
638 #endif
639 #ifdef NEWS
640     if (iflags.news)
641         display_file(NEWS, FALSE);
642 #endif
643     load_qtlist();          /* load up the quest text info */
644     /* quest_init();  --  Now part of role_init() */
645
646     mklev();
647     u_on_upstairs();
648     if (wizard)
649         obj_delivery(FALSE); /* finish wizkit */
650     vision_reset();          /* set up internals for level (after mklev) */
651     check_special_room(FALSE);
652
653     if (MON_AT(u.ux, u.uy))
654         mnexto(m_at(u.ux, u.uy));
655     (void) makedog();
656     docrt();
657
658     if (flags.legacy) {
659         flush_screen(1);
660         com_pager(1);
661     }
662
663     urealtime.realtime = 0L;
664     urealtime.start_timing = getnow();
665 #ifdef INSURANCE
666     save_currentstate();
667 #endif
668     program_state.something_worth_saving++; /* useful data now exists */
669
670     /* Success! */
671     welcome(TRUE);
672     return;
673 }
674
675 /* show "welcome [back] to nethack" message at program startup */
676 void
677 welcome(new_game)
678 boolean new_game; /* false => restoring an old game */
679 {
680     char buf[BUFSZ];
681     boolean currentgend = Upolyd ? u.mfemale : flags.female;
682
683     /* skip "welcome back" if restoring a doomed character */
684     if (!new_game && Upolyd && ugenocided()) {
685         /* death via self-genocide is pending */
686 /*JP
687         pline("You're back, but you still feel %s inside.", udeadinside());
688 */
689         pline("\82 \82È\82½\82Í\8bA\82Á\82Ä\82«\82½\82ª\81C\8d°\82ª%s\82Ü\82Ü\82¾\81D", udeadinside());
690         return;
691     }
692
693     /*
694      * The "welcome back" message always describes your innate form
695      * even when polymorphed or wearing a helm of opposite alignment.
696      * Alignment is shown unconditionally for new games; for restores
697      * it's only shown if it has changed from its original value.
698      * Sex is shown for new games except when it is redundant; for
699      * restores it's only shown if different from its original value.
700      */
701     *buf = '\0';
702     if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT])
703 /*JP
704         Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL]));
705 */
706         Sprintf(eos(buf), "%s", align_str(u.ualignbase[A_ORIGINAL]));
707     if (!urole.name.f
708         && (new_game
709                 ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE)
710                 : currentgend != flags.initgend))
711 /*JP
712         Sprintf(eos(buf), " %s", genders[currentgend].adj);
713 */
714         Sprintf(eos(buf), "\82Ì%s", genders[currentgend].adj);
715
716 #if 0 /*JP*/
717     pline(new_game ? "%s %s, welcome to NetHack!  You are a%s %s %s."
718                    : "%s %s, the%s %s %s, welcome back to NetHack!",
719           Hello((struct monst *) 0), plname, buf, urace.adj,
720           (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
721 #else
722     if(new_game){
723         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",
724               Hello((struct monst *) 0), urace.adj,
725               (currentgend && urole.name.f) ? urole.name.f : urole.name.m,
726               buf);
727     } else {
728         pline("%s\81CNetHack\82Ì\90¢\8aE\82Ö\81I\82 \82È\82½\82Í%s%s\82¾\81I",
729               Hello((struct monst *) 0), urace.adj,
730               (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
731     }
732 #endif
733 }
734
735 #ifdef POSITIONBAR
736 STATIC_DCL void
737 do_positionbar()
738 {
739     static char pbar[COLNO];
740     char *p;
741
742     p = pbar;
743     /* up stairway */
744     if (upstair.sx
745         && (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
746                 == S_upstair
747             || glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph)
748                    == S_upladder)) {
749         *p++ = '<';
750         *p++ = upstair.sx;
751     }
752     if (sstairs.sx
753         && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
754                 == S_upstair
755             || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
756                    == S_upladder)) {
757         *p++ = '<';
758         *p++ = sstairs.sx;
759     }
760
761     /* down stairway */
762     if (dnstair.sx
763         && (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
764                 == S_dnstair
765             || glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph)
766                    == S_dnladder)) {
767         *p++ = '>';
768         *p++ = dnstair.sx;
769     }
770     if (sstairs.sx
771         && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
772                 == S_dnstair
773             || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph)
774                    == S_dnladder)) {
775         *p++ = '>';
776         *p++ = sstairs.sx;
777     }
778
779     /* hero location */
780     if (u.ux) {
781         *p++ = '@';
782         *p++ = u.ux;
783     }
784     /* fence post */
785     *p = 0;
786
787     update_positionbar(pbar);
788 }
789 #endif
790
791 STATIC_DCL void
792 interrupt_multi(msg)
793 const char *msg;
794 {
795     if (multi > 0 && !context.travel && !context.run) {
796         nomul(0);
797         if (flags.verbose && msg)
798             Norep("%s", msg);
799     }
800 }
801
802 /*
803  * Argument processing helpers - for xxmain() to share
804  * and call.
805  *
806  * These should return TRUE if the argument matched,
807  * whether the processing of the argument was
808  * successful or not.
809  *
810  * Most of these do their thing, then after returning
811  * to xxmain(), the code exits without starting a game.
812  *
813  */
814
815 static struct early_opt earlyopts[] = {
816     {ARG_DEBUG, "debug", 5, TRUE},
817     {ARG_VERSION, "version", 4, TRUE},
818 #ifdef WIN32
819     {ARG_WINDOWS, "windows", 4, TRUE},
820 #endif
821 };
822
823 #ifdef WIN32
824 extern int FDECL(windows_early_options, (const char *));
825 #endif
826
827 /*
828  * Returns:
829  *    0 = no match
830  *    1 = found and skip past this argument
831  *    2 = found and trigger immediate exit
832  */
833
834 int
835 argcheck(argc, argv, e_arg)
836 int argc;
837 char *argv[];
838 enum earlyarg e_arg;
839 {
840     int i, idx;
841     boolean match = FALSE;
842     char *userea = (char *)0;
843     const char *dashdash = "";
844
845     for (idx = 0; idx < SIZE(earlyopts); idx++) {
846         if (earlyopts[idx].e == e_arg)
847             break;
848     }
849     if ((idx >= SIZE(earlyopts)) || (argc <= 1))
850             return FALSE;
851
852     for (i = 0; i < argc; ++i) {
853         if (argv[i][0] != '-')
854             continue;
855         if (argv[i][1] == '-') {
856             userea = &argv[i][2];
857             dashdash = "-";
858         } else {
859             userea = &argv[i][1];
860         }
861         match = match_optname(userea, earlyopts[idx].name,
862                               earlyopts[idx].minlength,
863                               earlyopts[idx].valallowed);
864         if (match) break;
865     }
866
867     if (match) {
868         const char *extended_opt = index(userea, ':');
869
870         if (!extended_opt)
871             extended_opt = index(userea, '=');
872         switch(e_arg) {
873         case ARG_DEBUG:
874             if (extended_opt) {
875                 extended_opt++;
876                 debug_fields(extended_opt);
877             }
878             return 1;
879         case ARG_VERSION: {
880             boolean insert_into_pastebuf = FALSE;
881
882             if (extended_opt) {
883                 extended_opt++;
884                 if (match_optname(extended_opt, "paste", 5, FALSE)) {
885                     insert_into_pastebuf = TRUE;
886                 } else {
887                     raw_printf(
888                    "-%sversion can only be extended with -%sversion:paste.\n",
889                                dashdash, dashdash);
890                     return TRUE;
891                 }
892             }
893             early_version_info(insert_into_pastebuf);
894             return 2;
895         }
896 #ifdef WIN32
897         case ARG_WINDOWS: {
898             if (extended_opt) {
899                 extended_opt++;
900                 return windows_early_options(extended_opt);
901             }
902         }
903 #endif
904         default:
905             break;
906         }
907     };
908     return FALSE;
909 }
910
911 /*
912  * These are internal controls to aid developers with
913  * testing and debugging particular aspects of the code.
914  * They are not player options and the only place they
915  * are documented is right here. No gameplay is altered.
916  *
917  * test             - test whether this parser is working
918  * ttystatus        - TTY:
919  * immediateflips   - WIN32: turn off display performance
920  *                    optimization so that display output
921  *                    can be debugged without buffering.
922  */
923 void
924 debug_fields(opts)
925 const char *opts;
926 {
927     char *op;
928     boolean negated = FALSE;
929
930     while ((op = index(opts, ',')) != 0) {
931         *op++ = 0;
932         /* recurse */
933         debug_fields(op);
934     }
935     if (strlen(opts) > BUFSZ / 2)
936         return;
937
938
939     /* strip leading and trailing white space */
940     while (isspace((uchar) *opts))
941         opts++;
942     op = eos((char *) opts);
943     while (--op >= opts && isspace((uchar) *op))
944         *op = '\0';
945
946     if (!*opts) {
947         /* empty */
948         return;
949     }
950     while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
951         if (*opts == '!')
952             opts++;
953         else
954             opts += 2;
955         negated = !negated;
956     }
957     if (match_optname(opts, "test", 4, FALSE))
958         iflags.debug.test = negated ? FALSE : TRUE;
959 #ifdef TTY_GRAPHICS
960     if (match_optname(opts, "ttystatus", 9, FALSE))
961         iflags.debug.ttystatus = negated ? FALSE : TRUE;
962 #endif
963 #ifdef WIN32
964     if (match_optname(opts, "immediateflips", 14, FALSE))
965         iflags.debug.immediateflips = negated ? FALSE : TRUE;
966 #endif
967     return;
968 }
969 /*allmain.c*/