1 /* $FreeBSD: src/games/larn/main.c,v 1.9 1999/11/30 03:48:59 billf Exp $ */
2 /* $DragonFly: src/games/larn/main.c,v 1.5 2008/06/05 18:06:30 swildner Exp $ */
8 static const char copyright[] = "\nLarn is copyrighted 1986 by Noah Morgan.\n";
9 int srcount = 0; /* line counter for showstr() */
10 int dropflag = 0; /* if 1 then don't lookforobject() next round */
11 int rmst = 80; /* random monster creation counter */
12 int userid; /* the players login user id number */
13 char nowelcome = 0, nomove = 0; /* if (nomove) then don't count next iteration as a move */
14 static char viewflag = 0;
15 /* if viewflag then we have done a 99 stay here and don't showcell in the main loop */
16 char restorflag=0; /* 1 means restore has been done */
17 static char cmdhelp[] = "\
18 Cmd line format: larn [-slicnh] [-o<optsifle>] [-##] [++]\n\
19 -s show the scoreboard\n\
20 -l show the logfile (wizard id only)\n\
21 -i show scoreboard with inventories of dead characters\n\
22 -c create new scoreboard (wizard id only)\n\
23 -n suppress welcome message on starting game\n\
24 -## specify level of difficulty (example: -5)\n\
25 -h print this help text\n\
26 ++ restore game from checkpoint file\n\
27 -o<optsfile> specify .larnopts filename to be used instead of \"~/.larnopts\"\n\
30 static const char *termtypes[] = { "vt100", "vt101", "vt102", "vt103", "vt125",
31 "vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340",
35 static void showstr(void);
36 static void t_setup(int);
37 static void t_endup(int);
38 static void showwear(void);
39 static void showwield(void);
40 static void showread(void);
41 static void showeat(void);
42 static void showquaff(void);
43 static void show1(int, const char **);
44 static void randmonst(void);
45 static void parse(void);
47 static void wield(void);
48 static void ydhi(int);
49 static void ycwi(int);
50 static void wear(void);
51 static void dropobj(void);
52 static void readscr(void);
53 static void eatcookie(void);
54 static void quaff(void);
55 static int whatitem(const char *);
57 static void szero(char *);
66 main(int argc, char **argv)
79 * first task is to identify the player
82 init_term(); /* setup the terminal (find out what type) for termcap */
84 /* try to get login name */
85 if (((ptr = getlogin()) == 0) || (*ptr == 0)) {
86 /* can we get it from /etc/passwd? */
87 if ((pwe = getpwuid(getuid())) != NULL)
89 else if ((ptr = getenv("USER")) == 0)
90 if ((ptr = getenv("LOGNAME")) == 0) {
91 noone: write(2, "Can't find your logname. Who Are You?\n", 39);
101 * second task is to prepare the pathnames the player will need
103 strcpy(loginname, ptr); /* save loginname of the user for logging purposes */
104 strcpy(logname, ptr); /* this will be overwritten with the players name */
105 if ((ptr = getenv("HOME")) == 0)
107 strcpy(savefilename, ptr);
108 strcat(savefilename, "/Larn.sav"); /* save file name in home directory */
109 sprintf(optsfile, "%s/.larnopts", ptr); /* the .larnopts filename */
112 * now malloc the memory for the dungeon
114 cell = malloc(sizeof(struct cel) * (MAXLEVEL + MAXVLEVEL) * MAXX * MAXY);
115 if (cell == NULL) /* malloc failure */
117 lpbuf = malloc((5 * BUFBIG) >> 2); /* output buffer */
118 inbuffer = malloc((5 * MAXIBUF) >> 2); /* output buffer */
119 if ((lpbuf == NULL) || (inbuffer == NULL)) /* malloc() failure */
123 newgame(); /* set the initial clock */
128 * check terminal type to avoid users who have not vt100 type terminals
130 ttype = getenv("TERM");
131 for (j = 1, i = 0; i < sizeof(termtypes) / sizeof(char *); i++)
132 if (strcmp(ttype, termtypes[i]) == 0) {
137 lprcat("Sorry, Larn needs a VT100 family terminal for all it's features.\n");
144 * now make scoreboard if it is not there (don't clear)
146 if (stat(scorefile, &sb) < 0 || sb.st_size == 0) /* not there */
150 * now process the command line arguments
152 for (i = 1; i < argc; i++) {
153 if (argv[i][0] == '-')
154 switch (argv[i][1]) {
157 exit(0); /* show scoreboard */
159 case 'l': /* show log file */
165 exit(0); /* show all scoreboard */
167 case 'c': /* anyone with password can create scoreboard */
168 lprcat("Preparing to initialize the scoreboard.\n");
169 if (getpassword() != 0) { /* make new scoreboard */
176 case 'n': /* no welcome msg */
190 case '9': /* for hardness */
191 sscanf(&argv[i][1], "%d", &hard);
194 case 'h': /* print out command line arguments */
195 write(1, cmdhelp, sizeof(cmdhelp));
198 case 'o': /* specify a .larnopts filename */
199 strncpy(optsfile, argv[i] + 2, 127);
203 printf("Unknown option <%s>\n", argv[i]);
207 if (argv[i][0] == '+') {
210 if (argv[i][1] == '+') {
212 restoregame(ckpfile); /* restore checkpointed game */
218 readopts(); /* read the options file if there is one */
222 userid = geteuid(); /* obtain the user's effective id number */
224 userid = getplid(logname); /* obtain the players id number */
225 #endif /* UIDSCORE */
227 write(2, "Can't obtain playerid\n", 22);
233 * this section of code causes the program to look like something else to ps
235 if (strcmp(psname, argv[0])) { /* if a different process name only */
236 if ((i = access(psname, 1)) < 0) { /* link not there */
237 if (link(argv[0], psname) >= 0) {
245 for (i = 1; i < argc; i++) {
246 szero(argv[i]); /* zero the argument to avoid ps snooping */
248 #endif /* HIDEBYLINK */
250 if (access(savefilename, 0) == 0) { /* restore game if need to */
254 restoregame(savefilename); /* restore last game */
256 sigsetup(); /* trap all needed signals */
257 sethard(hard); /* set up the desired difficulty */
258 setupvt100(); /* setup the terminal special mode */
259 if (c[HP] == 0) { /* create new game */
260 makeplayer(); /* make the character that will play */
261 newcavelevel(0);/* make the dungeon */
262 predostuff = 1; /* tell signals that we are in the welcome screen */
264 welcome(); /* welcome the player to the game */
266 drawscreen(); /* show the initial dungeon */
267 predostuff = 2; /* tell the trap functions that they must do
268 * a showplayer() from here on */
270 nice(1); /* games should be run niced */
272 yrepcount = hit2flag = 0;
274 if (dropflag == 0) /* see if there is an object here */
276 else /* don't show it just dropped an item */
282 } /* move the monsters */
284 showcell(playerx, playery);
286 viewflag = 0; /* show stuff around player */
289 hitflag = hit3flag = 0;
291 bot_linex(); /* update bottom line */
297 } /* get commands and make moves */
298 regen(); /* regenerate hp and spells */
299 if (c[TIMESTOP] == 0)
301 rmst = 120 - (level << 2);
302 fillmonst(makemonst(level));
310 show character's inventory
316 for (number = 3, i = 0; i < 26; i++)
317 if (iven[i]) /* count items in inventory */
330 nosignal = 1; /* don't allow ^c etc */
332 lprintf(".) %d gold pieces", (long)c[GOLD]);
335 for (k = 26; k >= 0; k--)
337 for (i = 22; i < 84; i++)
338 for (j = 0; j <= k; j++)
344 lprintf("\nElapsed time is %d. You have %d mobuls left", (long)((gtime + 99) / 100 + 1), (long)((TIMELIMIT - gtime) / 100));
350 * subroutine to clear screen depending on # lines to display
355 if (count < 20) { /* how do we clear the screen? */
365 * subroutine to restore normal display screen depending on t_setup()
370 if (count < 18) /* how did we clear the screen? */
371 draws(0, MAXX, 0, (count > MAXY) ? MAXY : count);
379 function to show the things player is wearing only
384 int i, j, sigsav, count;
386 nosignal = 1; /* don't allow ^c etc */
389 for (count = 2, j = 0; j <= 26; j++) /* count number of items we will display */
390 if ((i = iven[j]) != 0)
406 for (i = 22; i < 84; i++)
407 for (j = 0; j <= 26; j++)
427 function to show the things player can wield only
432 int i, j, sigsav, count;
434 nosignal = 1; /* don't allow ^c etc */
437 for (count = 2, j = 0; j <= 26; j++) /* count how many items */
438 if ((i = iven[j]) != 0)
459 for (i = 22; i < 84; i++)
460 for (j = 0; j <= 26; j++)
485 * function to show the things player can read only
490 int i, j, sigsav, count;
492 nosignal = 1; /* don't allow ^c etc */
495 for (count = 2, j = 0; j <= 26; j++)
503 for (i = 22; i < 84; i++)
504 for (j = 0; j <= 26; j++)
517 * function to show the things player can eat only
522 int i, j, sigsav, count;
524 nosignal = 1; /* don't allow ^c etc */
527 for (count = 2, j = 0; j <= 26; j++)
534 for (i = 22; i < 84; i++)
535 for (j = 0; j <= 26; j++)
547 function to show the things player can quaff only
552 int i, j, sigsav, count;
554 nosignal = 1; /* don't allow ^c etc */
557 for (count = 2, j = 0; j <= 26; j++)
564 for (i = 22; i < 84; i++)
565 for (j = 0; j <= 26; j++)
577 show1(int idx, const char *str2[])
579 lprintf("\n%c) %s", idx + 'a', objectname[(int)iven[idx]]);
580 if (str2 != NULL && str2[ivenarg[idx]][0] != 0)
581 lprintf(" of%s", str2[ivenarg[idx]]);
589 show1(idx, potionname);
592 show1(idx, scrollname);
610 lprintf("\n%c) %s", idx + 'a', objectname[(int)iven[idx]]);
611 if (ivenarg[idx] > 0)
612 lprintf(" + %d", (long)ivenarg[idx]);
613 else if (ivenarg[idx] < 0)
614 lprintf(" %d", (long)ivenarg[idx]);
618 lprcat(" (weapon in hand)");
619 if ((c[WEAR] == idx) || (c[SHIELD] == idx))
620 lprcat(" (being worn)");
621 if (++srcount >= 22) {
629 subroutine to randomly create monsters if needed
634 if (c[TIMESTOP]) /* don't make monsters if time is stopped */
637 rmst = 120 - (level << 2);
638 fillmonst(makemonst(level));
645 get and execute a command
653 switch (k) { /* get the token from the input and switch on it */
680 return; /* northeast */
683 return; /* northeast */
686 return; /* northwest */
689 return; /* northwest */
692 return; /* southeast */
695 return; /* southeast */
698 return; /* southwest */
701 return; /* southwest */
706 return; /* stay here */
711 return; /* wield a weapon */
716 return; /* wear armor */
722 lprcat("\nYou can't read anything when you're blind!");
723 } else if (c[TIMESTOP] == 0)
725 return; /* to read a scroll */
729 if (c[TIMESTOP] == 0)
731 return; /* quaff a potion */
735 if (c[TIMESTOP] == 0)
737 return; /* to drop an object */
742 return; /* cast a spell */
752 if (c[TIMESTOP] == 0)
754 return; /* to eat a fortune cookie */
760 return; /* list spells and scrolls */
766 return; /* give the help screen */
770 lprcat("Saving . . .");
772 savegame(savefilename);
774 died(-257); /* save the game - doesn't return */
783 lprcat("\nAs yet, you don't have enough experience to use teleportation");
784 return; /* teleport yourself */
786 case '^': /* identify traps */
787 flag = yrepcount = 0;
790 for (j = playery - 1; j < playery + 2; j++) {
795 for (i = playerx - 1; i < playerx + 2; i++) {
800 switch (item[i][j]) {
806 lprcat(objectname[(int)item[i][j]]);
812 lprcat("\nNo traps are visible");
816 case '_': /* this is the fudge player password for wizard mode */
820 if (userid != wisid) {
821 lprcat("Sorry, you are not empowered to be a wizard.\n");
822 scbr(); /* system("stty -echo cbreak"); */
826 if (getpassword() == 0) {
827 scbr(); /* system("stty -echo cbreak"); */
831 scbr(); /* system("stty -echo cbreak"); */
832 for (i = 0; i < 6; i++)
834 iven[0] = iven[1] = 0;
839 c[WEAR] = c[SHIELD] = -1;
840 raiseexperience(6000000L);
841 c[AWARENESS] += 25000;
844 for (i = 0; i < MAXY; i++)
845 for (j = 0; j < MAXX; j++)
847 for (i = 0; i < SPNUM; i++)
849 for (i = 0; i < MAXSCROLL; i++)
850 scrollname[i] = scrollhide[i];
851 for (i = 0; i < MAXPOTION; i++)
852 potionname[i] = potionhide[i];
854 for (i = 0; i < MAXSCROLL; i++)
855 if (strlen(scrollname[i]) > 2) { /* no null items */
856 item[i][0] = OSCROLL;
859 for (i = MAXX - 1; i > MAXX - 1 - MAXPOTION; i--)
860 if (strlen(potionname[i - MAXX + MAXPOTION]) > 2) { /* no null items */
861 item[i][0] = OPOTION;
862 iarg[i][0] = i - MAXX + MAXPOTION;
864 for (i = 1; i < MAXY; i++) {
868 for (i = MAXY; i < MAXY + MAXX; i++) {
869 item[i - MAXY][MAXY - 1] = i;
870 iarg[i - MAXY][MAXY - 1] = 0;
872 for (i = MAXX + MAXY; i < MAXX + MAXY + MAXY; i++) {
873 item[MAXX - 1][i - MAXX - MAXY] = i;
874 iarg[MAXX - 1][i - MAXX - MAXY] = 0;
884 if (c[SHIELD] != -1) {
886 lprcat("\nYour shield is off");
888 } else if (c[WEAR] != -1) {
890 lprcat("\nYour armor is off");
893 lprcat("\nYou aren't wearing anything");
898 lprintf("\nThe stuff you are carrying presently weighs %d pounds", (long)packweight());
907 lprintf("\nCaverns of Larn, Version %d.%d, Diff=%d", (long)VERSION, (long)SUBVERSION, (long)c[HARDGAME]);
936 } /* create diagnostic file */
942 if (outstanding_taxes > 0)
943 lprintf("\nYou presently owe %d gp in taxes.", (long)outstanding_taxes);
945 lprcat("\nYou do not owe any taxes.");
956 movemonst(); /* move the monsters */
978 showcell(playerx, playery);
983 function to wield a weapon
990 if ((i = whatitem("wield")) == '\33')
995 else if (iven[i - 'a'] == 0) {
998 } else if (iven[i - 'a'] == OPOTION) {
1001 } else if (iven[i - 'a'] == OSCROLL) {
1004 } else if ((c[SHIELD] != -1) && (iven[i - 'a'] == O2SWORD)) {
1005 lprcat("\nBut one arm is busy with your shield!");
1009 if (iven[i - 'a'] == OLANCE)
1021 common routine to say you don't have an item
1027 lprintf("\nYou don't have item %c!", x);
1034 lprintf("\nYou can't wield item %c!", x);
1038 function to wear armor
1045 if ((i = whatitem("wear")) == '\33')
1051 switch (iven[i - 'a']) {
1063 if (c[WEAR] != -1) {
1064 lprcat("\nYou're already wearing some armor");
1071 if (c[SHIELD] != -1) {
1072 lprcat("\nYou are already wearing a shield");
1075 if (iven[c[WIELD]] == O2SWORD) {
1076 lprcat("\nYour hands are busy with the two handed sword!");
1079 c[SHIELD] = i - 'a';
1083 lprcat("\nYou can't wear that!");
1090 function to drop an object
1098 p = &item[playerx][playery];
1100 if ((i = whatitem("drop")) == '\33')
1105 if (i == '.') { /* drop some gold */
1107 lprcat("\nThere's something here already!");
1112 lprcat("How much gold do you drop? ");
1113 if ((amt = readnum((long)c[GOLD])) == 0)
1115 if (amt > c[GOLD]) {
1116 lprcat("\nYou don't have that much!");
1122 } else if (amt <= 327670L) {
1126 } else if (amt <= 3276700L) {
1130 } else if (amt <= 32767000L) {
1140 lprintf("You drop %d gold pieces", (long)amt);
1141 iarg[playerx][playery] = i;
1143 know[playerx][playery] = 0;
1147 drop_object(i - 'a');
1154 * readscr() Subroutine to read a scroll one is carrying
1161 if ((i = whatitem("read")) == '\33')
1167 if (iven[i - 'a'] == OSCROLL) {
1168 read_scroll(ivenarg[i - 'a']);
1172 if (iven[i - 'a'] == OBOOK) {
1173 readbook(ivenarg[i - 'a']);
1177 if (iven[i - 'a'] == 0) {
1181 lprcat("\nThere's nothing on it to read");
1189 * subroutine to eat a cookie one is carrying
1198 if ((i = whatitem("eat")) == '\33')
1204 if (iven[i - 'a'] == OCOOKIE) {
1205 lprcat("\nThe cookie was delicious.");
1207 if (!c[BLINDCOUNT]) {
1208 if ((p = fortune()) != NULL) {
1209 lprcat(" Inside you find a scrap of paper that says:\n");
1215 if (iven[i - 'a'] == 0) {
1219 lprcat("\nYou can't eat that!");
1227 * subroutine to quaff a potion one is carrying
1234 if ((i = whatitem("quaff")) == '\33')
1240 if (iven[i - 'a'] == OPOTION) {
1241 quaffpotion(ivenarg[i - 'a']);
1245 if (iven[i - 'a'] == 0) {
1249 lprcat("\nYou wouldn't want to quaff that, would you? ");
1257 function to ask what player wants to do
1260 whatitem(const char *str)
1264 lprintf("\nWhat do you want to %s [* for all] ? ", str);
1266 while (i > 'z' || (i < 'a' && i != '*' && i != '\33' && i != '.'))
1274 subroutine to get a number from the player
1275 and allow * to mean return amt, else return the number entered
1281 unsigned long amt = 0;
1283 if ((i = getchr()) == '*')
1284 amt = mx; /* allow him to say * for all gold */
1292 if ((i <= '9') && (i >= '0') && (amt < 99999999))
1293 amt = amt * 10 + i - '0';
1302 * routine to zero every byte in a string
1310 #endif /* HIDEBYLINK */