root/games/larn/main.c
/*      $NetBSD: main.c,v 1.27 2021/05/02 12:50:45 rillig Exp $ */

/* main.c                */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: main.c,v 1.27 2021/05/02 12:50:45 rillig Exp $");
#endif                          /* not lint */

#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "header.h"
#include "extern.h"

static void showstr(void);
static void t_setup(int);
static void t_endup(int);
static void showwear(void);
static void showwield(void);
static void showread(void);
static void showeat(void);
static void showquaff(void);
static void show1(int, const char *[]);
static void randmonst(void);
static void parse(void);
static void run(int);
static void wield(void);
static void ydhi(int);
static void ycwi(int);
static void wear(void);
static void dropobj(void);
static void readscr(void);
static void eatcookie(void);
static void quaff(void);
static int whatitem(const char *);

static char     copyright[] = "\nLarn is copyrighted 1986 by Noah Morgan.\n";
int             srcount = 0;    /* line counter for showstr()    */
int             dropflag = 0;   /* if 1 then don't lookforobject() next round */
int             rmst = 80;      /* random monster creation counter               */
int             userid;         /* the players login user id number */
gid_t           gid, egid;      /* used for security */
u_char          nowelcome = 0, nomove = 0;      /* if (nomove) then don't
                                                 * count next iteration as a
                                                 * move */
static char     viewflag = 0;
/*
 * if viewflag then we have done a 99 stay here and don't showcell in the
 * main loop
 */
u_char          restorflag = 0; /* 1 means restore has been done         */
static char     cmdhelp[] = "\
Cmd line format: larn [-slicnh] [-o<optsfile>] [-##] [++]\n\
  -s   show the scoreboard\n\
  -l   show the logfile (wizard id only)\n\
  -i   show scoreboard with inventories of dead characters\n\
  -c   create new scoreboard (wizard id only)\n\
  -n   suppress welcome message on starting game\n\
  -##  specify level of difficulty (example: -5)\n\
  -h   print this help text\n\
  ++   restore game from checkpoint file\n\
  -o<optsfile>   specify .larnopts filename to be used instead of \"~/.larnopts\"\n\
";
#ifdef VT100
static char    *termtypes[] = {"vt100", "vt101", "vt102", "vt103", "vt125",
        "vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340",
"vt341"};
#endif  /* VT100 */
/*
        ************
        MAIN PROGRAM
        ************
 */
int
main(int argc, char **argv)
{
        int    i;
        int             hard;
        const char     *ptr = 0;
        struct passwd  *pwe;

        i = 0;
        egid = getegid();
        gid = getgid();
        setegid(gid);           /* give up "games" if we have it */
        /*
         *      first task is to identify the player
         */
#ifndef VT100
        init_term();            /* setup the terminal (find out what type)
                                 * for termcap */
#endif  /* VT100 */
        /* try to get login name */
        if (((ptr = getlogin()) == 0) || (*ptr == 0)) {
                /* can we get it from /etc/passwd? */
                if ((pwe = getpwuid(getuid())) != NULL)
                        ptr = pwe->pw_name;
                else if ((ptr = getenv("USER")) == 0)
                        if ((ptr = getenv("LOGNAME")) == 0) {
                noone:          write(2, "Can't find your logname.  Who Are You?\n", 39);
                                exit(1);
                        }
        }
        if (ptr == 0)
                goto noone;
        if (strlen(ptr) == 0)
                goto noone;
        /*
         *      second task is to prepare the pathnames the player will need
         */
        strcpy(loginname, ptr); /* save loginname of the user for logging
                                 * purposes */
        strcpy(logname, ptr);   /* this will be overwritten with the players
                                 * name */
        if ((ptr = getenv("HOME")) == NULL)
                ptr = ".";
        strcpy(savefilename, ptr);
        strcat(savefilename, "/Larn.sav");      /* save file name in home
                                                 * directory */
        snprintf(optsfile, sizeof(optsfile), "%s/.larnopts", ptr);
        /* the .larnopts filename */

        /*
         *      now malloc the memory for the dungeon
         */
        cell = (struct cel *) malloc(sizeof(struct cel) * (MAXLEVEL + MAXVLEVEL) * MAXX * MAXY);
        if (cell == 0)
                died(-285);     /* malloc failure */
        lpbuf = malloc((5 * BUFBIG) >> 2);      /* output buffer */
        inbuffer = malloc((5 * MAXIBUF) >> 2);  /* output buffer */
        if ((lpbuf == 0) || (inbuffer == 0))
                died(-285);     /* malloc() failure */

        lcreat((char *) 0);
        newgame();              /* set the initial clock  */
        hard = -1;

#ifdef VT100
        /*
         *      check terminal type to avoid users who have not vt100 type terminals
         */
        ttype = getenv("TERM");
        for (j = 1, i = 0; i < sizeof(termtypes) / sizeof(char *); i++)
                if (strcmp(ttype, termtypes[i]) == 0) {
                        j = 0;
                        break;
                }
        if (j) {
                lprcat("Sorry, Larn needs a VT100 family terminal for all its features.\n");
                lflush();
                exit(1);
        }
#endif  /* VT100 */

        /*
         *      now make scoreboard if it is not there (don't clear)
         */
        if (access(scorefile, 0) == -1) /* not there */
                makeboard();

        /*
         *      now process the command line arguments
         */
        for (i = 1; i < argc; i++) {
                if (argv[i][0] == '-')
                        switch (argv[i][1]) {
                        case 's':
                                showscores();
                                exit(0);        /* show scoreboard   */

                        case 'l':       /* show log file     */
                                diedlog();
                                exit(0);

                        case 'i':
                                showallscores();
                                exit(0);        /* show all scoreboard */

                        case 'c':       /* anyone with password can create
                                         * scoreboard */
                                lprcat("Preparing to initialize the scoreboard.\n");
                                if (getpassword() != 0) {       /* make new scoreboard */
                                        makeboard();
                                        lprc('\n');
                                        showscores();
                                }
                                exit(0);

                        case 'n':       /* no welcome msg        */
                                nowelcome = 1;
                                argv[i][0] = 0;
                                break;

                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':       /* for hardness */
                                sscanf(&argv[i][1], "%d", &hard);
                                break;

                        case 'h':       /* print out command line arguments */
                                write(1, cmdhelp, sizeof(cmdhelp));
                                exit(0);

                        case 'o':       /* specify a .larnopts filename */
                                strncpy(optsfile, argv[i] + 2, 127);
                                break;

                        default:
                                printf("Unknown option <%s>\n", argv[i]);
                                exit(1);
                        };

                if (argv[i][0] == '+') {
                        clear();
                        restorflag = 1;
                        if (argv[i][1] == '+') {
                                hitflag = 1;
                                restoregame(ckpfile);   /* restore checkpointed
                                                         * game */
                        }
                        i = argc;
                }
        }

        readopts();             /* read the options file if there is one */


#ifdef UIDSCORE
        userid = geteuid();     /* obtain the user's effective id number */
#else   /* UIDSCORE */
        userid = getplid(logname);      /* obtain the players id number */
#endif  /* UIDSCORE */
        if (userid < 0) {
                write(2, "Can't obtain playerid\n", 22);
                exit(1);
        }
#ifdef HIDEBYLINK
        /*
         *      this section of code causes the program to look like something else to ps
         */
        if (strcmp(psname, argv[0])) {  /* if a different process name only */
                if ((i = access(psname, 1)) < 0) {      /* link not there */
                        if (link(argv[0], psname) >= 0) {
                                argv[0] = psname;
                                execv(psname, argv);
                        }
                } else
                        unlink(psname);
        }
        for (i = 1; i < argc; i++) {
                szero(argv[i]); /* zero the argument to avoid ps snooping */
        }
#endif  /* HIDEBYLINK */

        if (access(savefilename, 0) == 0) {     /* restore game if need to */
                clear();
                restorflag = 1;
                hitflag = 1;
                restoregame(savefilename);      /* restore last game     */
        }
        sigsetup();             /* trap all needed signals       */
        sethard(hard);          /* set up the desired difficulty                                 */
        setupvt100();           /* setup the terminal special mode                               */
        if (c[HP] == 0) {       /* create new game */
                makeplayer();   /* make the character that will play                     */
                newcavelevel(0);/* make the dungeon                                                      */
                predostuff = 1; /* tell signals that we are in the welcome
                                 * screen */
                if (nowelcome == 0)
                        welcome();      /* welcome the player to the game */
        }
        drawscreen();           /* show the initial dungeon                                      */
        predostuff = 2;         /* tell the trap functions that they must do
                                 * a showplayer() from here on */
#if 0
        nice(1);                /* games should be run niced */
#endif
        yrepcount = hit2flag = 0;
        while (1) {
                if (dropflag == 0)
                        lookforobject();        /* see if there is an object
                                                 * here  */
                else
                        dropflag = 0;   /* don't show it just dropped an item */
                if (hitflag == 0) {
                        if (c[HASTEMONST])
                                movemonst();
                        movemonst();
                }               /* move the monsters             */
                if (viewflag == 0)
                        showcell(playerx, playery);
                else
                        viewflag = 0;   /* show stuff around player      */
                if (hit3flag)
                        flushall();
                hitflag = hit3flag = 0;
                nomove = 1;
                bot_linex();    /* update bottom line */
                while (nomove) {
                        if (hit3flag)
                                flushall();
                        nomove = 0;
                        parse();
                }               /* get commands and make moves   */
                regen();        /* regenerate hp and spells                      */
                if (c[TIMESTOP] == 0)
                        if (--rmst <= 0) {
                                rmst = 120 - (level << 2);
                                fillmonst(makemonst(level));
                        }
        }
}


/*
        showstr()

        show character's inventory
 */
static void
showstr(void)
{
        int    i, number;
        for (number = 3, i = 0; i < 26; i++)
                if (iven[i])
                        number++;       /* count items in inventory */
        t_setup(number);
        qshowstr();
        t_endup(number);
}

void
qshowstr(void)
{
        int    i, j, k, sigsav;
        srcount = 0;
        sigsav = nosignal;
        nosignal = 1;           /* don't allow ^c etc */
        if (c[GOLD]) {
                lprintf(".)   %ld gold pieces", (long) c[GOLD]);
                srcount++;
        }
        for (k = 26; k >= 0; k--)
                if (iven[k]) {
                        for (i = 22; i < 84; i++)
                                for (j = 0; j <= k; j++)
                                        if (i == iven[j])
                                                show3(j);
                        k = 0;
                }
        lprintf("\nElapsed time is %ld.  You have %ld mobuls left", (long) ((gltime + 99) / 100 + 1), (long) ((TIMELIMIT - gltime) / 100));
        more();
        nosignal = sigsav;
}

/*
 *      subroutine to clear screen depending on # lines to display
 */
static void
t_setup(int count)
{
        if (count < 20) {       /* how do we clear the screen? */
                cl_up(79, count);
                cursor(1, 1);
        } else {
                resetscroll();
                clear();
        }
}

/*
 *      subroutine to restore normal display screen depending on t_setup()
 */
static void
t_endup(int count)
{
        if (count < 18)         /* how did we clear the screen? */
                draws(0, MAXX, 0, (count > MAXY) ? MAXY : count);
        else {
                drawscreen();
                setscroll();
        }
}

/*
        function to show the things player is wearing only
 */
static void
showwear(void)
{
        int    i, j, sigsav, count;
        sigsav = nosignal;
        nosignal = 1;           /* don't allow ^c etc */
        srcount = 0;

        for (count = 2, j = 0; j <= 26; j++)    /* count number of items we
                                                 * will display */
                if ((i = iven[j]) != 0)
                        switch (i) {
                        case OLEATHER:
                        case OPLATE:
                        case OCHAIN:
                        case ORING:
                        case OSTUDLEATHER:
                        case OSPLINT:
                        case OPLATEARMOR:
                        case OSSPLATE:
                        case OSHIELD:
                                count++;
                        };

        t_setup(count);

        for (i = 22; i < 84; i++)
                for (j = 0; j <= 26; j++)
                        if (i == iven[j])
                                switch (i) {
                                case OLEATHER:
                                case OPLATE:
                                case OCHAIN:
                                case ORING:
                                case OSTUDLEATHER:
                                case OSPLINT:
                                case OPLATEARMOR:
                                case OSSPLATE:
                                case OSHIELD:
                                        show3(j);
                                };
        more();
        nosignal = sigsav;
        t_endup(count);
}

/*
        function to show the things player can wield only
 */
static void
showwield(void)
{
        int    i, j, sigsav, count;
        sigsav = nosignal;
        nosignal = 1;           /* don't allow ^c etc */
        srcount = 0;

        for (count = 2, j = 0; j <= 26; j++)    /* count how many items */
                if ((i = iven[j]) != 0)
                        switch (i) {
                        case ODIAMOND:
                        case ORUBY:
                        case OEMERALD:
                        case OSAPPHIRE:
                        case OBOOK:
                        case OCHEST:
                        case OLARNEYE:
                        case ONOTHEFT:
                        case OSPIRITSCARAB:
                        case OCUBEofUNDEAD:
                        case OPOTION:
                        case OSCROLL:
                                break;
                        default:
                                count++;
                        };

        t_setup(count);

        for (i = 22; i < 84; i++)
                for (j = 0; j <= 26; j++)
                        if (i == iven[j])
                                switch (i) {
                                case ODIAMOND:
                                case ORUBY:
                                case OEMERALD:
                                case OSAPPHIRE:
                                case OBOOK:
                                case OCHEST:
                                case OLARNEYE:
                                case ONOTHEFT:
                                case OSPIRITSCARAB:
                                case OCUBEofUNDEAD:
                                case OPOTION:
                                case OSCROLL:
                                        break;
                                default:
                                        show3(j);
                                };
        more();
        nosignal = sigsav;
        t_endup(count);
}

/*
 *      function to show the things player can read only
 */
static void
showread(void)
{
        int    i, j, sigsav, count;
        sigsav = nosignal;
        nosignal = 1;           /* don't allow ^c etc */
        srcount = 0;

        for (count = 2, j = 0; j <= 26; j++)
                switch (iven[j]) {
                case OBOOK:
                case OSCROLL:
                        count++;
                };
        t_setup(count);

        for (i = 22; i < 84; i++)
                for (j = 0; j <= 26; j++)
                        if (i == iven[j])
                                switch (i) {
                                case OBOOK:
                                case OSCROLL:
                                        show3(j);
                                };
        more();
        nosignal = sigsav;
        t_endup(count);
}

/*
 *      function to show the things player can eat only
 */
static void
showeat(void)
{
        int    i, j, sigsav, count;
        sigsav = nosignal;
        nosignal = 1;           /* don't allow ^c etc */
        srcount = 0;

        for (count = 2, j = 0; j <= 26; j++)
                switch (iven[j]) {
                case OCOOKIE:
                        count++;
                };
        t_setup(count);

        for (i = 22; i < 84; i++)
                for (j = 0; j <= 26; j++)
                        if (i == iven[j])
                                switch (i) {
                                case OCOOKIE:
                                        show3(j);
                                };
        more();
        nosignal = sigsav;
        t_endup(count);
}

/*
        function to show the things player can quaff only
 */
static void
showquaff(void)
{
        int    i, j, sigsav, count;
        sigsav = nosignal;
        nosignal = 1;           /* don't allow ^c etc */
        srcount = 0;

        for (count = 2, j = 0; j <= 26; j++)
                switch (iven[j]) {
                case OPOTION:
                        count++;
                };
        t_setup(count);

        for (i = 22; i < 84; i++)
                for (j = 0; j <= 26; j++)
                        if (i == iven[j])
                                switch (i) {
                                case OPOTION:
                                        show3(j);
                                };
        more();
        nosignal = sigsav;
        t_endup(count);
}

static void
show1(int idx, const char *str2[])
{
        lprintf("\n%c)   %s", idx + 'a', objectname[iven[idx]]);
        if (str2 != 0 && str2[ivenarg[idx]][0] != 0)
                lprintf(" of%s", str2[ivenarg[idx]]);
}

void
show3(int indx)
{
        switch (iven[indx]) {
        case OPOTION:
                show1(indx, potionname);
                break;
        case OSCROLL:
                show1(indx, scrollname);
                break;

        case OLARNEYE:
        case OBOOK:
        case OSPIRITSCARAB:
        case ODIAMOND:
        case ORUBY:
        case OCUBEofUNDEAD:
        case OEMERALD:
        case OCHEST:
        case OCOOKIE:
        case OSAPPHIRE:
        case ONOTHEFT:
                show1(indx, NULL);
                break;

        default:
                lprintf("\n%c)   %s", indx + 'a', objectname[iven[indx]]);
                if (ivenarg[indx] > 0)
                        lprintf(" + %ld", (long) ivenarg[indx]);
                else if (ivenarg[indx] < 0)
                        lprintf(" %ld", (long) ivenarg[indx]);
                break;
        }
        if (c[WIELD] == indx)
                lprcat(" (weapon in hand)");
        if ((c[WEAR] == indx) || (c[SHIELD] == indx))
                lprcat(" (being worn)");
        if (++srcount >= 22) {
                srcount = 0;
                more();
                clear();
        }
}

/*
        subroutine to randomly create monsters if needed
 */
static void
randmonst(void)
{
        if (c[TIMESTOP])
                return;         /* don't make monsters if time is stopped        */
        if (--rmst <= 0) {
                rmst = 120 - (level << 2);
                fillmonst(makemonst(level));
        }
}



/*
        parse()

        get and execute a command
 */
static void
parse(void)
{
        int    i, j, k, flag;
        while (1) {
                k = yylex();
                switch (k) {    /* get the token from the input and switch on
                                 * it    */
                case 'h':
                        moveplayer(4);
                        return; /* west          */
                case 'H':
                        run(4);
                        return; /* west          */
                case 'l':
                        moveplayer(2);
                        return; /* east          */
                case 'L':
                        run(2);
                        return; /* east          */
                case 'j':
                        moveplayer(1);
                        return; /* south                 */
                case 'J':
                        run(1);
                        return; /* south                 */
                case 'k':
                        moveplayer(3);
                        return; /* north                 */
                case 'K':
                        run(3);
                        return; /* north                 */
                case 'u':
                        moveplayer(5);
                        return; /* northeast     */
                case 'U':
                        run(5);
                        return; /* northeast     */
                case 'y':
                        moveplayer(6);
                        return; /* northwest     */
                case 'Y':
                        run(6);
                        return; /* northwest     */
                case 'n':
                        moveplayer(7);
                        return; /* southeast     */
                case 'N':
                        run(7);
                        return; /* southeast     */
                case 'b':
                        moveplayer(8);
                        return; /* southwest     */
                case 'B':
                        run(8);
                        return; /* southwest     */

                case '.':
                        if (yrepcount)
                                viewflag = 1;
                        return; /* stay here             */

                case 'w':
                        yrepcount = 0;
                        wield();
                        return; /* wield a weapon */

                case 'W':
                        yrepcount = 0;
                        wear();
                        return; /* wear armor    */

                case 'r':
                        yrepcount = 0;
                        if (c[BLINDCOUNT]) {
                                cursors();
                                lprcat("\nYou can't read anything when you're blind!");
                        } else if (c[TIMESTOP] == 0)
                                readscr();
                        return; /* to read a scroll      */

                case 'q':
                        yrepcount = 0;
                        if (c[TIMESTOP] == 0)
                                quaff();
                        return; /* quaff a potion                */

                case 'd':
                        yrepcount = 0;
                        if (c[TIMESTOP] == 0)
                                dropobj();
                        return; /* to drop an object     */

                case 'c':
                        yrepcount = 0;
                        cast();
                        return; /* cast a spell  */

                case 'i':
                        yrepcount = 0;
                        nomove = 1;
                        showstr();
                        return; /* status                */

                case 'e':
                        yrepcount = 0;
                        if (c[TIMESTOP] == 0)
                                eatcookie();
                        return; /* to eat a fortune cookie */

                case 'D':
                        yrepcount = 0;
                        seemagic(0);
                        nomove = 1;
                        return; /* list spells and scrolls */

                case '?':
                        yrepcount = 0;
                        help();
                        nomove = 1;
                        return; /* give the help screen */

                case 'S':
                        clear();
                        lprcat("Saving . . .");
                        lflush();
                        savegame(savefilename);
                        wizard = 1;
                        died(-257);     /* save the game - doesn't return        */
                        __unreachable();

                case 'Z':
                        yrepcount = 0;
                        if (c[LEVEL] > 9) {
                                oteleport(1);
                                return;
                        }
                        cursors();
                        lprcat("\nAs yet, you don't have enough experience to use teleportation");
                        return; /* teleport yourself     */

                case '^':       /* identify traps */
                        flag = yrepcount = 0;
                        cursors();
                        lprc('\n');
                        for (j = playery - 1; j < playery + 2; j++) {
                                if (j < 0)
                                        j = 0;
                                if (j >= MAXY)
                                        break;
                                for (i = playerx - 1; i < playerx + 2; i++) {
                                        if (i < 0)
                                                i = 0;
                                        if (i >= MAXX)
                                                break;
                                        switch (item[i][j]) {
                                        case OTRAPDOOR:
                                        case ODARTRAP:
                                        case OTRAPARROW:
                                        case OTELEPORTER:
                                                lprcat("\nIt's ");
                                                lprcat(objectname[item[i][j]]);
                                                flag++;
                                        };
                                }
                        }
                        if (flag == 0)
                                lprcat("\nNo traps are visible");
                        return;

#if WIZID
                case '_':       /* this is the fudge player password for
                                 * wizard mode */
                        yrepcount = 0;
                        cursors();
                        nomove = 1;
                        if (userid != wisid) {
                                lprcat("Sorry, you are not empowered to be a wizard.\n");
                                scbr(); /* system("stty -echo cbreak"); */
                                lflush();
                                return;
                        }
                        if (getpassword() == 0) {
                                scbr(); /* system("stty -echo cbreak"); */
                                return;
                        }
                        wizard = 1;
                        scbr(); /* system("stty -echo cbreak"); */
                        for (i = 0; i < 6; i++)
                                c[i] = 70;
                        iven[0] = iven[1] = 0;
                        take(OPROTRING, 50);
                        take(OLANCE, 25);
                        c[WIELD] = 1;
                        c[LANCEDEATH] = 1;
                        c[WEAR] = c[SHIELD] = -1;
                        raiseexperience(6000000L);
                        c[AWARENESS] += 25000;
                        {
                                int    i, j;
                                for (i = 0; i < MAXY; i++)
                                        for (j = 0; j < MAXX; j++)
                                                know[j][i] = 1;
                                for (i = 0; i < SPNUM; i++)
                                        spelknow[i] = 1;
                                for (i = 0; i < MAXSCROLL; i++)
                                        scrollname[i] = scrollhide[i];
                                for (i = 0; i < MAXPOTION; i++)
                                        potionname[i] = potionhide[i];
                        }
                        for (i = 0; i < MAXSCROLL; i++)
                                if (strlen(scrollname[i]) > 2) {        /* no null items */
                                        item[i][0] = OSCROLL;
                                        iarg[i][0] = i;
                                }
                        for (i = MAXX - 1; i > MAXX - 1 - MAXPOTION; i--)
                                if (strlen(potionname[i - MAXX + MAXPOTION]) > 2) {     /* no null items */
                                        item[i][0] = OPOTION;
                                        iarg[i][0] = i - MAXX + MAXPOTION;
                                }
                        for (i = 1; i < MAXY; i++) {
                                item[0][i] = i;
                                iarg[0][i] = 0;
                        }
                        for (i = MAXY; i < MAXY + MAXX; i++) {
                                item[i - MAXY][MAXY - 1] = i;
                                iarg[i - MAXY][MAXY - 1] = 0;
                        }
                        for (i = MAXX + MAXY; i < MAXX + MAXY + MAXY; i++) {
                                item[MAXX - 1][i - MAXX - MAXY] = i;
                                iarg[MAXX - 1][i - MAXX - MAXY] = 0;
                        }
                        c[GOLD] += 25000;
                        drawscreen();
                        return;
#endif

                case 'T':
                        yrepcount = 0;
                        cursors();
                        if (c[SHIELD] != -1) {
                                c[SHIELD] = -1;
                                lprcat("\nYour shield is off");
                                bottomline();
                        } else if (c[WEAR] != -1) {
                                c[WEAR] = -1;
                                lprcat("\nYour armor is off");
                                bottomline();
                        } else
                                lprcat("\nYou aren't wearing anything");
                        return;

                case 'g':
                        cursors();
                        lprintf("\nThe stuff you are carrying presently weighs %ld pounds", (long) packweight());
                        /* FALLTHROUGH */
                case ' ':
                        yrepcount = 0;
                        nomove = 1;
                        return;

                case 'v':
                        yrepcount = 0;
                        cursors();
                        lprintf("\nCaverns of Larn, Version %ld.%ld, Diff=%ld",
                                (long) VERSION, (long) SUBVERSION,
                                (long) c[HARDGAME]);
                        if (wizard)
                                lprcat(" Wizard");
                        nomove = 1;
                        if (cheat)
                                lprcat(" Cheater");
                        lprcat(copyright);
                        return;

                case 'Q':
                        yrepcount = 0;
                        quit();
                        nomove = 1;
                        return; /* quit          */

                case 'L' - 64:
                        yrepcount = 0;
                        drawscreen();
                        nomove = 1;
                        return; /* look          */

#if WIZID
#ifdef EXTRA
                case 'A':
                        yrepcount = 0;
                        nomove = 1;
                        if (wizard) {
                                diag();
                                return;
                        }       /* create diagnostic file */
                        return;
#endif
#endif
                case 'P':
                        cursors();
                        if (outstanding_taxes > 0)
                                lprintf("\nYou presently owe %ld gp in taxes.",
                                        (long) outstanding_taxes);
                        else
                                lprcat("\nYou do not owe any taxes.");
                        return;
                };
        }
}

void
parse2(void)
{
        if (c[HASTEMONST])
                movemonst();
        movemonst();            /* move the monsters             */
        randmonst();
        regen();
}

static void
run(int dir)
{
        int    i;
        i = 1;
        while (i) {
                i = moveplayer(dir);
                if (i > 0) {
                        if (c[HASTEMONST])
                                movemonst();
                        movemonst();
                        randmonst();
                        regen();
                }
                if (hitflag)
                        i = 0;
                if (i != 0)
                        showcell(playerx, playery);
        }
}

/*
        function to wield a weapon
 */
static void
wield(void)
{
        int    i;
        while (1) {
                if ((i = whatitem("wield")) == '\33')
                        return;
                if (i != '.') {
                        if (i == '*')
                                showwield();
                        else if (iven[i - 'a'] == 0) {
                                ydhi(i);
                                return;
                        } else if (iven[i - 'a'] == OPOTION) {
                                ycwi(i);
                                return;
                        } else if (iven[i - 'a'] == OSCROLL) {
                                ycwi(i);
                                return;
                        } else if ((c[SHIELD] != -1) && (iven[i - 'a'] == O2SWORD)) {
                                lprcat("\nBut one arm is busy with your shield!");
                                return;
                        } else {
                                c[WIELD] = i - 'a';
                                if (iven[i - 'a'] == OLANCE)
                                        c[LANCEDEATH] = 1;
                                else
                                        c[LANCEDEATH] = 0;
                                bottomline();
                                return;
                        }
                }
        }
}

/*
        common routine to say you don't have an item
 */
static void
ydhi(int x)
{
        cursors();
        lprintf("\nYou don't have item %c!", x);
}
static void
ycwi(int x)
{
        cursors();
        lprintf("\nYou can't wield item %c!", x);
}

/*
        function to wear armor
 */
static void
wear(void)
{
        int    i;
        while (1) {
                if ((i = whatitem("wear")) == '\33')
                        return;
                if (i != '.') {
                        if (i == '*')
                                showwear();
                        else
                                switch (iven[i - 'a']) {
                                case 0:
                                        ydhi(i);
                                        return;
                                case OLEATHER:
                                case OCHAIN:
                                case OPLATE:
                                case OSTUDLEATHER:
                                case ORING:
                                case OSPLINT:
                                case OPLATEARMOR:
                                case OSSPLATE:
                                        if (c[WEAR] != -1) {
                                                lprcat("\nYou're already wearing some armor");
                                                return;
                                        }
                                        c[WEAR] = i - 'a';
                                        bottomline();
                                        return;
                                case OSHIELD:
                                        if (c[SHIELD] != -1) {
                                                lprcat("\nYou are already wearing a shield");
                                                return;
                                        }
                                        if (iven[c[WIELD]] == O2SWORD) {
                                                lprcat("\nYour hands are busy with the two handed sword!");
                                                return;
                                        }
                                        c[SHIELD] = i - 'a';
                                        bottomline();
                                        return;
                                default:
                                        lprcat("\nYou can't wear that!");
                                };
                }
        }
}

/*
        function to drop an object
 */
static void
dropobj(void)
{
        int    i;
        unsigned char  *p;
        long            amt;
        p = &item[playerx][playery];
        while (1) {
                if ((i = whatitem("drop")) == '\33')
                        return;
                if (i == '*')
                        showstr();
                else {
                        if (i == '.') { /* drop some gold */
                                if (*p) {
                                        lprcat("\nThere's something here already!");
                                        return;
                                }
                                lprcat("\n\n");
                                cl_dn(1, 23);
                                lprcat("How much gold do you drop? ");
                                if ((amt = readnum((long) c[GOLD])) == 0)
                                        return;
                                if (amt > c[GOLD]) {
                                        lprcat("\nYou don't have that much!");
                                        return;
                                }
                                if (amt <= 32767) {
                                        *p = OGOLDPILE;
                                        i = amt;
                                } else if (amt <= 327670L) {
                                        *p = ODGOLD;
                                        i = amt / 10;
                                        amt = 10 * i;
                                } else if (amt <= 3276700L) {
                                        *p = OMAXGOLD;
                                        i = amt / 100;
                                        amt = 100 * i;
                                } else if (amt <= 32767000L) {
                                        *p = OKGOLD;
                                        i = amt / 1000;
                                        amt = 1000 * i;
                                } else {
                                        *p = OKGOLD;
                                        i = 32767;
                                        amt = 32767000L;
                                }
                                c[GOLD] -= amt;
                                lprintf("You drop %ld gold pieces", (long)amt);
                                iarg[playerx][playery] = i;
                                bottomgold();
                                know[playerx][playery] = 0;
                                dropflag = 1;
                                return;
                        }
                        drop_object(i - 'a');
                        return;
                }
        }
}

/*
 *      readscr()               Subroutine to read a scroll one is carrying
 */
static void
readscr(void)
{
        int    i;
        while (1) {
                if ((i = whatitem("read")) == '\33')
                        return;
                if (i != '.') {
                        if (i == '*')
                                showread();
                        else {
                                if (iven[i - 'a'] == OSCROLL) {
                                        read_scroll(ivenarg[i - 'a']);
                                        iven[i - 'a'] = 0;
                                        return;
                                }
                                if (iven[i - 'a'] == OBOOK) {
                                        readbook(ivenarg[i - 'a']);
                                        iven[i - 'a'] = 0;
                                        return;
                                }
                                if (iven[i - 'a'] == 0) {
                                        ydhi(i);
                                        return;
                                }
                                lprcat("\nThere's nothing on it to read");
                                return;
                        }
                }
        }
}

/*
 *      subroutine to eat a cookie one is carrying
 */
static void
eatcookie(void)
{
        const char *p;
        int i;

        while (1) {
                if ((i = whatitem("eat")) == '\33')
                        return;
                if (i != '.') {
                        if (i == '*')
                                showeat();
                        else {
                                if (iven[i - 'a'] == OCOOKIE) {
                                        lprcat("\nThe cookie was delicious.");
                                        iven[i - 'a'] = 0;
                                        if (!c[BLINDCOUNT]) {
                                                if ((p = fortune()) != NULL) {
                                                        lprcat("  Inside you find a scrap of paper that says:\n");
                                                        lprcat(p);
                                                }
                                        }
                                        return;
                                }
                                if (iven[i - 'a'] == 0) {
                                        ydhi(i);
                                        return;
                                }
                                lprcat("\nYou can't eat that!");
                                return;
                        }
                }
        }
}

/*
 *      subroutine to quaff a potion one is carrying
 */
static void
quaff(void)
{
        int    i;
        while (1) {
                if ((i = whatitem("quaff")) == '\33')
                        return;
                if (i != '.') {
                        if (i == '*')
                                showquaff();
                        else {
                                if (iven[i - 'a'] == OPOTION) {
                                        quaffpotion(ivenarg[i - 'a']);
                                        iven[i - 'a'] = 0;
                                        return;
                                }
                                if (iven[i - 'a'] == 0) {
                                        ydhi(i);
                                        return;
                                }
                                lprcat("\nYou wouldn't want to quaff that, would you? ");
                                return;
                        }
                }
        }
}

/*
        function to ask what player wants to do
 */
static int
whatitem(const char *str)
{
        int             i;
        cursors();
        lprintf("\nWhat do you want to %s [* for all] ? ", str);
        i = 0;
        while (i > 'z' || (i < 'a' && i != '*' && i != '\33' && i != '.'))
                i = ttgetch();
        if (i == '\33')
                lprcat(" aborted");
        return (i);
}

/*
        subroutine to get a number from the player
        and allow * to mean return amt, else return the number entered
 */
unsigned long
readnum(long mx)
{
        int    i;
        unsigned long amt = 0;
        sncbr();
        if ((i = ttgetch()) == '*')
                amt = mx;       /* allow him to say * for all gold */
        else
                while (i != '\n') {
                        if (i == '\033') {
                                scbr();
                                lprcat(" aborted");
                                return (0);
                        }
                        if ((i <= '9') && (i >= '0') && (amt < 99999999))
                                amt = amt * 10 + i - '0';
                        i = ttgetch();
                }
        scbr();
        return (amt);
}

#ifdef HIDEBYLINK
/*
 *      routine to zero every byte in a string
 */
void
szero(str)
        char  *str;
{
        while (*str)
                *str++ = 0;
}
#endif  /* HIDEBYLINK */