1 /* $FreeBSD: src/games/larn/main.c,v 1.9 1999/11/30 03:48:59 billf Exp $ */
7 static const char copyright[] = "\nLarn is copyrighted 1986 by Noah Morgan.\n";
8 int srcount = 0; /* line counter for showstr() */
9 int dropflag = 0; /* if 1 then don't lookforobject() next round */
10 int rmst = 80; /* random monster creation counter */
11 int userid; /* the players login user id number */
12 char nowelcome = 0, nomove = 0; /* if (nomove) then don't count next iteration as a move */
13 static char viewflag = 0;
14 /* if viewflag then we have done a 99 stay here and don't showcell in the main loop */
15 char restorflag=0; /* 1 means restore has been done */
16 static char cmdhelp[] = "\
17 Cmd line format: larn [-slicnh] [-o<optsifle>] [-##] [++]\n\
18 -s show the scoreboard\n\
19 -l show the logfile (wizard id only)\n\
20 -i show scoreboard with inventories of dead characters\n\
21 -c create new scoreboard (wizard id only)\n\
22 -n suppress welcome message on starting game\n\
23 -## specify level of difficulty (example: -5)\n\
24 -h print this help text\n\
25 ++ restore game from checkpoint file\n\
26 -o<optsfile> specify .larnopts filename to be used instead of \"~/.larnopts\"\n\
29 static const char *termtypes[] = { "vt100", "vt101", "vt102", "vt103", "vt125",
30 "vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340",
34 static void showstr(void);
35 static void t_setup(int);
36 static void t_endup(int);
37 static void showwear(void);
38 static void showwield(void);
39 static void showread(void);
40 static void showeat(void);
41 static void showquaff(void);
42 static void show1(int, const char **);
43 static void randmonst(void);
44 static void parse(void);
46 static void wield(void);
47 static void ydhi(int);
48 static void ycwi(int);
49 static void wear(void);
50 static void dropobj(void);
51 static void readscr(void);
52 static void eatcookie(void);
53 static void quaff(void);
54 static int whatitem(const char *);
62 main(int argc, char **argv)
75 * first task is to identify the player
78 init_term(); /* setup the terminal (find out what type) for termcap */
80 /* try to get login name */
81 if (((ptr = getlogin()) == NULL) || (*ptr == 0)) {
82 /* can we get it from /etc/passwd? */
83 if ((pwe = getpwuid(getuid())) != NULL)
85 else if ((ptr = getenv("USER")) == NULL)
86 if ((ptr = getenv("LOGNAME")) == NULL) {
87 noone: write(2, "Can't find your logname. Who Are You?\n", 39);
97 * second task is to prepare the pathnames the player will need
99 strcpy(loginname, ptr); /* save loginname of the user for logging purposes */
100 strcpy(logname, ptr); /* this will be overwritten with the players name */
101 if ((ptr = getenv("HOME")) == NULL)
103 strcpy(savefilename, ptr);
104 strcat(savefilename, "/Larn.sav"); /* save file name in home directory */
105 sprintf(optsfile, "%s/.larnopts", ptr); /* the .larnopts filename */
108 * now malloc the memory for the dungeon
110 cell = malloc(sizeof(struct cel) * (MAXLEVEL + MAXVLEVEL) * MAXX * MAXY);
111 if (cell == NULL) /* malloc failure */
113 lpbuf = malloc((5 * BUFBIG) >> 2); /* output buffer */
114 inbuffer = malloc((5 * MAXIBUF) >> 2); /* output buffer */
115 if ((lpbuf == NULL) || (inbuffer == NULL)) /* malloc() failure */
119 newgame(); /* set the initial clock */
124 * check terminal type to avoid users who have not vt100 type terminals
126 ttype = getenv("TERM");
127 for (j = 1, i = 0; i < sizeof(termtypes) / sizeof(char *); i++)
128 if (strcmp(ttype, termtypes[i]) == 0) {
133 lprcat("Sorry, Larn needs a VT100 family terminal for all its features.\n");
140 * now make scoreboard if it is not there (don't clear)
142 if (stat(scorefile, &sb) < 0 || sb.st_size == 0) /* not there */
146 * now process the command line arguments
148 for (i = 1; i < argc; i++) {
149 if (argv[i][0] == '-')
150 switch (argv[i][1]) {
153 exit(0); /* show scoreboard */
155 case 'l': /* show log file */
161 exit(0); /* show all scoreboard */
163 case 'c': /* anyone with password can create scoreboard */
164 lprcat("Preparing to initialize the scoreboard.\n");
165 if (getpassword() != 0) { /* make new scoreboard */
172 case 'n': /* no welcome msg */
186 case '9': /* for hardness */
187 sscanf(&argv[i][1], "%d", &hard);
190 case 'h': /* print out command line arguments */
191 write(1, cmdhelp, sizeof(cmdhelp));
194 case 'o': /* specify a .larnopts filename */
195 strncpy(optsfile, argv[i] + 2, 127);
199 printf("Unknown option <%s>\n", argv[i]);
203 if (argv[i][0] == '+') {
206 if (argv[i][1] == '+') {
208 restoregame(ckpfile); /* restore checkpointed game */
214 readopts(); /* read the options file if there is one */
218 userid = geteuid(); /* obtain the user's effective id number */
220 userid = getplid(logname); /* obtain the players id number */
221 #endif /* UIDSCORE */
223 write(2, "Can't obtain playerid\n", 22);
227 if (access(savefilename, 0) == 0) { /* restore game if need to */
231 restoregame(savefilename); /* restore last game */
233 sigsetup(); /* trap all needed signals */
234 sethard(hard); /* set up the desired difficulty */
235 setupvt100(); /* setup the terminal special mode */
236 if (c[HP] == 0) { /* create new game */
237 makeplayer(); /* make the character that will play */
238 newcavelevel(0);/* make the dungeon */
239 predostuff = 1; /* tell signals that we are in the welcome screen */
241 welcome(); /* welcome the player to the game */
243 drawscreen(); /* show the initial dungeon */
244 predostuff = 2; /* tell the trap functions that they must do
245 * a showplayer() from here on */
247 nice(1); /* games should be run niced */
249 yrepcount = hit2flag = 0;
251 if (dropflag == 0) /* see if there is an object here */
253 else /* don't show it just dropped an item */
259 } /* move the monsters */
261 showcell(playerx, playery);
263 viewflag = 0; /* show stuff around player */
266 hitflag = hit3flag = 0;
268 bot_linex(); /* update bottom line */
274 } /* get commands and make moves */
275 regen(); /* regenerate hp and spells */
276 if (c[TIMESTOP] == 0)
278 rmst = 120 - (level << 2);
279 fillmonst(makemonst(level));
287 show character's inventory
293 for (number = 3, i = 0; i < 26; i++)
294 if (iven[i]) /* count items in inventory */
307 nosignal = 1; /* don't allow ^c etc */
309 lprintf(".) %d gold pieces", (long)c[GOLD]);
312 for (k = 26; k >= 0; k--)
314 for (i = 22; i < 84; i++)
315 for (j = 0; j <= k; j++)
321 lprintf("\nElapsed time is %d. You have %d mobuls left", (long)((gtime + 99) / 100 + 1), (long)((TIMELIMIT - gtime) / 100));
327 * subroutine to clear screen depending on # lines to display
332 if (count < 20) { /* how do we clear the screen? */
342 * subroutine to restore normal display screen depending on t_setup()
347 if (count < 18) /* how did we clear the screen? */
348 draws(0, MAXX, 0, (count > MAXY) ? MAXY : count);
356 function to show the things player is wearing only
361 int i, j, sigsav, count;
363 nosignal = 1; /* don't allow ^c etc */
366 for (count = 2, j = 0; j <= 26; j++) /* count number of items we will display */
367 if ((i = iven[j]) != 0)
383 for (i = 22; i < 84; i++)
384 for (j = 0; j <= 26; j++)
404 function to show the things player can wield only
409 int i, j, sigsav, count;
411 nosignal = 1; /* don't allow ^c etc */
414 for (count = 2, j = 0; j <= 26; j++) /* count how many items */
415 if ((i = iven[j]) != 0)
436 for (i = 22; i < 84; i++)
437 for (j = 0; j <= 26; j++)
462 * function to show the things player can read only
467 int i, j, sigsav, count;
469 nosignal = 1; /* don't allow ^c etc */
472 for (count = 2, j = 0; j <= 26; j++)
480 for (i = 22; i < 84; i++)
481 for (j = 0; j <= 26; j++)
494 * function to show the things player can eat only
499 int i, j, sigsav, count;
501 nosignal = 1; /* don't allow ^c etc */
504 for (count = 2, j = 0; j <= 26; j++)
511 for (i = 22; i < 84; i++)
512 for (j = 0; j <= 26; j++)
524 function to show the things player can quaff only
529 int i, j, sigsav, count;
531 nosignal = 1; /* don't allow ^c etc */
534 for (count = 2, j = 0; j <= 26; j++)
541 for (i = 22; i < 84; i++)
542 for (j = 0; j <= 26; j++)
554 show1(int idx, const char *str2[])
556 lprintf("\n%c) %s", idx + 'a', objectname[(int)iven[idx]]);
557 if (str2 != NULL && str2[ivenarg[idx]][0] != 0)
558 lprintf(" of%s", str2[ivenarg[idx]]);
566 show1(idx, potionname);
569 show1(idx, scrollname);
587 lprintf("\n%c) %s", idx + 'a', objectname[(int)iven[idx]]);
588 if (ivenarg[idx] > 0)
589 lprintf(" + %d", (long)ivenarg[idx]);
590 else if (ivenarg[idx] < 0)
591 lprintf(" %d", (long)ivenarg[idx]);
595 lprcat(" (weapon in hand)");
596 if ((c[WEAR] == idx) || (c[SHIELD] == idx))
597 lprcat(" (being worn)");
598 if (++srcount >= 22) {
606 subroutine to randomly create monsters if needed
611 if (c[TIMESTOP]) /* don't make monsters if time is stopped */
614 rmst = 120 - (level << 2);
615 fillmonst(makemonst(level));
622 get and execute a command
630 switch (k) { /* get the token from the input and switch on it */
657 return; /* northeast */
660 return; /* northeast */
663 return; /* northwest */
666 return; /* northwest */
669 return; /* southeast */
672 return; /* southeast */
675 return; /* southwest */
678 return; /* southwest */
683 return; /* stay here */
688 return; /* wield a weapon */
693 return; /* wear armor */
699 lprcat("\nYou can't read anything when you're blind!");
700 } else if (c[TIMESTOP] == 0)
702 return; /* to read a scroll */
706 if (c[TIMESTOP] == 0)
708 return; /* quaff a potion */
712 if (c[TIMESTOP] == 0)
714 return; /* to drop an object */
719 return; /* cast a spell */
729 if (c[TIMESTOP] == 0)
731 return; /* to eat a fortune cookie */
737 return; /* list spells and scrolls */
743 return; /* give the help screen */
747 lprcat("Saving . . .");
749 savegame(savefilename);
751 died(-257); /* save the game - doesn't return */
752 exit(1); /* hint for a compiler */
761 lprcat("\nAs yet, you don't have enough experience to use teleportation");
762 return; /* teleport yourself */
764 case '^': /* identify traps */
765 flag = yrepcount = 0;
768 for (j = playery - 1; j < playery + 2; j++) {
773 for (i = playerx - 1; i < playerx + 2; i++) {
778 switch (item[i][j]) {
784 lprcat(objectname[(int)item[i][j]]);
790 lprcat("\nNo traps are visible");
794 case '_': /* this is the fudge player password for wizard mode */
798 if (userid != wisid) {
799 lprcat("Sorry, you are not empowered to be a wizard.\n");
800 scbr(); /* system("stty -echo cbreak"); */
804 if (getpassword() == 0) {
805 scbr(); /* system("stty -echo cbreak"); */
809 scbr(); /* system("stty -echo cbreak"); */
810 for (i = 0; i < 6; i++)
812 iven[0] = iven[1] = 0;
817 c[WEAR] = c[SHIELD] = -1;
818 raiseexperience(6000000L);
819 c[AWARENESS] += 25000;
822 for (i = 0; i < MAXY; i++)
823 for (j = 0; j < MAXX; j++)
825 for (i = 0; i < SPNUM; i++)
827 for (i = 0; i < MAXSCROLL; i++)
828 scrollname[i] = scrollhide[i];
829 for (i = 0; i < MAXPOTION; i++)
830 potionname[i] = potionhide[i];
832 for (i = 0; i < MAXSCROLL; i++)
833 if (strlen(scrollname[i]) > 2) { /* no null items */
834 item[i][0] = OSCROLL;
837 for (i = MAXX - 1; i > MAXX - 1 - MAXPOTION; i--)
838 if (strlen(potionname[i - MAXX + MAXPOTION]) > 2) { /* no null items */
839 item[i][0] = OPOTION;
840 iarg[i][0] = i - MAXX + MAXPOTION;
842 for (i = 1; i < MAXY; i++) {
846 for (i = MAXY; i < MAXY + MAXX; i++) {
847 item[i - MAXY][MAXY - 1] = i;
848 iarg[i - MAXY][MAXY - 1] = 0;
850 for (i = MAXX + MAXY; i < MAXX + MAXY + MAXY; i++) {
851 item[MAXX - 1][i - MAXX - MAXY] = i;
852 iarg[MAXX - 1][i - MAXX - MAXY] = 0;
862 if (c[SHIELD] != -1) {
864 lprcat("\nYour shield is off");
866 } else if (c[WEAR] != -1) {
868 lprcat("\nYour armor is off");
871 lprcat("\nYou aren't wearing anything");
876 lprintf("\nThe stuff you are carrying presently weighs %d pounds", (long)packweight());
886 lprintf("\nCaverns of Larn, Version %d.%d, Diff=%d",
887 (long)VERSION, (long)SUBVERSION, (long)c[HARDGAME]);
916 } /* create diagnostic file */
922 if (outstanding_taxes > 0)
923 lprintf("\nYou presently owe %d gp in taxes.", (long)outstanding_taxes);
925 lprcat("\nYou do not owe any taxes.");
936 movemonst(); /* move the monsters */
958 showcell(playerx, playery);
963 function to wield a weapon
970 if ((i = whatitem("wield")) == '\33')
975 else if (iven[i - 'a'] == 0) {
978 } else if (iven[i - 'a'] == OPOTION) {
981 } else if (iven[i - 'a'] == OSCROLL) {
984 } else if ((c[SHIELD] != -1) && (iven[i - 'a'] == O2SWORD)) {
985 lprcat("\nBut one arm is busy with your shield!");
989 if (iven[i - 'a'] == OLANCE)
1001 common routine to say you don't have an item
1007 lprintf("\nYou don't have item %c!", x);
1014 lprintf("\nYou can't wield item %c!", x);
1018 function to wear armor
1025 if ((i = whatitem("wear")) == '\33')
1031 switch (iven[i - 'a']) {
1043 if (c[WEAR] != -1) {
1044 lprcat("\nYou're already wearing some armor");
1051 if (c[SHIELD] != -1) {
1052 lprcat("\nYou are already wearing a shield");
1055 if (iven[c[WIELD]] == O2SWORD) {
1056 lprcat("\nYour hands are busy with the two handed sword!");
1059 c[SHIELD] = i - 'a';
1063 lprcat("\nYou can't wear that!");
1070 function to drop an object
1078 p = &item[playerx][playery];
1080 if ((i = whatitem("drop")) == '\33')
1085 if (i == '.') { /* drop some gold */
1087 lprcat("\nThere's something here already!");
1092 lprcat("How much gold do you drop? ");
1093 if ((amt = readnum((long)c[GOLD])) == 0)
1095 if (amt > c[GOLD]) {
1096 lprcat("\nYou don't have that much!");
1102 } else if (amt <= 327670L) {
1106 } else if (amt <= 3276700L) {
1110 } else if (amt <= 32767000L) {
1120 lprintf("You drop %d gold pieces", (long)amt);
1121 iarg[playerx][playery] = i;
1123 know[playerx][playery] = 0;
1127 drop_object(i - 'a');
1134 * readscr() Subroutine to read a scroll one is carrying
1141 if ((i = whatitem("read")) == '\33')
1147 if (iven[i - 'a'] == OSCROLL) {
1148 read_scroll(ivenarg[i - 'a']);
1152 if (iven[i - 'a'] == OBOOK) {
1153 readbook(ivenarg[i - 'a']);
1157 if (iven[i - 'a'] == 0) {
1161 lprcat("\nThere's nothing on it to read");
1169 * subroutine to eat a cookie one is carrying
1178 if ((i = whatitem("eat")) == '\33')
1184 if (iven[i - 'a'] == OCOOKIE) {
1185 lprcat("\nThe cookie was delicious.");
1187 if (!c[BLINDCOUNT]) {
1188 if ((p = fortune()) != NULL) {
1189 lprcat(" Inside you find a scrap of paper that says:\n");
1195 if (iven[i - 'a'] == 0) {
1199 lprcat("\nYou can't eat that!");
1207 * subroutine to quaff a potion one is carrying
1214 if ((i = whatitem("quaff")) == '\33')
1220 if (iven[i - 'a'] == OPOTION) {
1221 quaffpotion(ivenarg[i - 'a']);
1225 if (iven[i - 'a'] == 0) {
1229 lprcat("\nYou wouldn't want to quaff that, would you? ");
1237 function to ask what player wants to do
1240 whatitem(const char *str)
1244 lprintf("\nWhat do you want to %s [* for all] ? ", str);
1246 while (i > 'z' || (i < 'a' && i != '*' && i != '\33' && i != '.'))
1254 subroutine to get a number from the player
1255 and allow * to mean return amt, else return the number entered
1261 unsigned long amt = 0;
1263 if ((i = getchr()) == '*')
1264 amt = mx; /* allow him to say * for all gold */
1272 if ((i <= '9') && (i >= '0') && (amt < 99999999))
1273 amt = amt * 10 + i - '0';