1338 lines
26 KiB
C
1338 lines
26 KiB
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 */
|