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 *);
56 static void szero(char *);
65 main(int argc
, char **argv
)
78 * first task is to identify the player
81 init_term(); /* setup the terminal (find out what type) for termcap */
83 /* try to get login name */
84 if (((ptr
= getlogin()) == NULL
) || (*ptr
== 0)) {
85 /* can we get it from /etc/passwd? */
86 if ((pwe
= getpwuid(getuid())) != NULL
)
88 else if ((ptr
= getenv("USER")) == NULL
)
89 if ((ptr
= getenv("LOGNAME")) == NULL
) {
90 noone
: write(2, "Can't find your logname. Who Are You?\n", 39);
100 * second task is to prepare the pathnames the player will need
102 strcpy(loginname
, ptr
); /* save loginname of the user for logging purposes */
103 strcpy(logname
, ptr
); /* this will be overwritten with the players name */
104 if ((ptr
= getenv("HOME")) == NULL
)
106 strcpy(savefilename
, ptr
);
107 strcat(savefilename
, "/Larn.sav"); /* save file name in home directory */
108 sprintf(optsfile
, "%s/.larnopts", ptr
); /* the .larnopts filename */
111 * now malloc the memory for the dungeon
113 cell
= malloc(sizeof(struct cel
) * (MAXLEVEL
+ MAXVLEVEL
) * MAXX
* MAXY
);
114 if (cell
== NULL
) /* malloc failure */
116 lpbuf
= malloc((5 * BUFBIG
) >> 2); /* output buffer */
117 inbuffer
= malloc((5 * MAXIBUF
) >> 2); /* output buffer */
118 if ((lpbuf
== NULL
) || (inbuffer
== NULL
)) /* malloc() failure */
122 newgame(); /* set the initial clock */
127 * check terminal type to avoid users who have not vt100 type terminals
129 ttype
= getenv("TERM");
130 for (j
= 1, i
= 0; i
< sizeof(termtypes
) / sizeof(char *); i
++)
131 if (strcmp(ttype
, termtypes
[i
]) == 0) {
136 lprcat("Sorry, Larn needs a VT100 family terminal for all it's features.\n");
143 * now make scoreboard if it is not there (don't clear)
145 if (stat(scorefile
, &sb
) < 0 || sb
.st_size
== 0) /* not there */
149 * now process the command line arguments
151 for (i
= 1; i
< argc
; i
++) {
152 if (argv
[i
][0] == '-')
153 switch (argv
[i
][1]) {
156 exit(0); /* show scoreboard */
158 case 'l': /* show log file */
164 exit(0); /* show all scoreboard */
166 case 'c': /* anyone with password can create scoreboard */
167 lprcat("Preparing to initialize the scoreboard.\n");
168 if (getpassword() != 0) { /* make new scoreboard */
175 case 'n': /* no welcome msg */
189 case '9': /* for hardness */
190 sscanf(&argv
[i
][1], "%d", &hard
);
193 case 'h': /* print out command line arguments */
194 write(1, cmdhelp
, sizeof(cmdhelp
));
197 case 'o': /* specify a .larnopts filename */
198 strncpy(optsfile
, argv
[i
] + 2, 127);
202 printf("Unknown option <%s>\n", argv
[i
]);
206 if (argv
[i
][0] == '+') {
209 if (argv
[i
][1] == '+') {
211 restoregame(ckpfile
); /* restore checkpointed game */
217 readopts(); /* read the options file if there is one */
221 userid
= geteuid(); /* obtain the user's effective id number */
223 userid
= getplid(logname
); /* obtain the players id number */
224 #endif /* UIDSCORE */
226 write(2, "Can't obtain playerid\n", 22);
232 * this section of code causes the program to look like something else to ps
234 if (strcmp(psname
, argv
[0])) { /* if a different process name only */
235 if ((i
= access(psname
, 1)) < 0) { /* link not there */
236 if (link(argv
[0], psname
) >= 0) {
244 for (i
= 1; i
< argc
; i
++) {
245 szero(argv
[i
]); /* zero the argument to avoid ps snooping */
247 #endif /* HIDEBYLINK */
249 if (access(savefilename
, 0) == 0) { /* restore game if need to */
253 restoregame(savefilename
); /* restore last game */
255 sigsetup(); /* trap all needed signals */
256 sethard(hard
); /* set up the desired difficulty */
257 setupvt100(); /* setup the terminal special mode */
258 if (c
[HP
] == 0) { /* create new game */
259 makeplayer(); /* make the character that will play */
260 newcavelevel(0);/* make the dungeon */
261 predostuff
= 1; /* tell signals that we are in the welcome screen */
263 welcome(); /* welcome the player to the game */
265 drawscreen(); /* show the initial dungeon */
266 predostuff
= 2; /* tell the trap functions that they must do
267 * a showplayer() from here on */
269 nice(1); /* games should be run niced */
271 yrepcount
= hit2flag
= 0;
273 if (dropflag
== 0) /* see if there is an object here */
275 else /* don't show it just dropped an item */
281 } /* move the monsters */
283 showcell(playerx
, playery
);
285 viewflag
= 0; /* show stuff around player */
288 hitflag
= hit3flag
= 0;
290 bot_linex(); /* update bottom line */
296 } /* get commands and make moves */
297 regen(); /* regenerate hp and spells */
298 if (c
[TIMESTOP
] == 0)
300 rmst
= 120 - (level
<< 2);
301 fillmonst(makemonst(level
));
309 show character's inventory
315 for (number
= 3, i
= 0; i
< 26; i
++)
316 if (iven
[i
]) /* count items in inventory */
329 nosignal
= 1; /* don't allow ^c etc */
331 lprintf(".) %d gold pieces", (long)c
[GOLD
]);
334 for (k
= 26; k
>= 0; k
--)
336 for (i
= 22; i
< 84; i
++)
337 for (j
= 0; j
<= k
; j
++)
343 lprintf("\nElapsed time is %d. You have %d mobuls left", (long)((gtime
+ 99) / 100 + 1), (long)((TIMELIMIT
- gtime
) / 100));
349 * subroutine to clear screen depending on # lines to display
354 if (count
< 20) { /* how do we clear the screen? */
364 * subroutine to restore normal display screen depending on t_setup()
369 if (count
< 18) /* how did we clear the screen? */
370 draws(0, MAXX
, 0, (count
> MAXY
) ? MAXY
: count
);
378 function to show the things player is wearing only
383 int i
, j
, sigsav
, count
;
385 nosignal
= 1; /* don't allow ^c etc */
388 for (count
= 2, j
= 0; j
<= 26; j
++) /* count number of items we will display */
389 if ((i
= iven
[j
]) != 0)
405 for (i
= 22; i
< 84; i
++)
406 for (j
= 0; j
<= 26; j
++)
426 function to show the things player can wield only
431 int i
, j
, sigsav
, count
;
433 nosignal
= 1; /* don't allow ^c etc */
436 for (count
= 2, j
= 0; j
<= 26; j
++) /* count how many items */
437 if ((i
= iven
[j
]) != 0)
458 for (i
= 22; i
< 84; i
++)
459 for (j
= 0; j
<= 26; j
++)
484 * function to show the things player can read only
489 int i
, j
, sigsav
, count
;
491 nosignal
= 1; /* don't allow ^c etc */
494 for (count
= 2, j
= 0; j
<= 26; j
++)
502 for (i
= 22; i
< 84; i
++)
503 for (j
= 0; j
<= 26; j
++)
516 * function to show the things player can eat only
521 int i
, j
, sigsav
, count
;
523 nosignal
= 1; /* don't allow ^c etc */
526 for (count
= 2, j
= 0; j
<= 26; j
++)
533 for (i
= 22; i
< 84; i
++)
534 for (j
= 0; j
<= 26; j
++)
546 function to show the things player can quaff only
551 int i
, j
, sigsav
, count
;
553 nosignal
= 1; /* don't allow ^c etc */
556 for (count
= 2, j
= 0; j
<= 26; j
++)
563 for (i
= 22; i
< 84; i
++)
564 for (j
= 0; j
<= 26; j
++)
576 show1(int idx
, const char *str2
[])
578 lprintf("\n%c) %s", idx
+ 'a', objectname
[(int)iven
[idx
]]);
579 if (str2
!= NULL
&& str2
[ivenarg
[idx
]][0] != 0)
580 lprintf(" of%s", str2
[ivenarg
[idx
]]);
588 show1(idx
, potionname
);
591 show1(idx
, scrollname
);
609 lprintf("\n%c) %s", idx
+ 'a', objectname
[(int)iven
[idx
]]);
610 if (ivenarg
[idx
] > 0)
611 lprintf(" + %d", (long)ivenarg
[idx
]);
612 else if (ivenarg
[idx
] < 0)
613 lprintf(" %d", (long)ivenarg
[idx
]);
617 lprcat(" (weapon in hand)");
618 if ((c
[WEAR
] == idx
) || (c
[SHIELD
] == idx
))
619 lprcat(" (being worn)");
620 if (++srcount
>= 22) {
628 subroutine to randomly create monsters if needed
633 if (c
[TIMESTOP
]) /* don't make monsters if time is stopped */
636 rmst
= 120 - (level
<< 2);
637 fillmonst(makemonst(level
));
644 get and execute a command
652 switch (k
) { /* get the token from the input and switch on it */
679 return; /* northeast */
682 return; /* northeast */
685 return; /* northwest */
688 return; /* northwest */
691 return; /* southeast */
694 return; /* southeast */
697 return; /* southwest */
700 return; /* southwest */
705 return; /* stay here */
710 return; /* wield a weapon */
715 return; /* wear armor */
721 lprcat("\nYou can't read anything when you're blind!");
722 } else if (c
[TIMESTOP
] == 0)
724 return; /* to read a scroll */
728 if (c
[TIMESTOP
] == 0)
730 return; /* quaff a potion */
734 if (c
[TIMESTOP
] == 0)
736 return; /* to drop an object */
741 return; /* cast a spell */
751 if (c
[TIMESTOP
] == 0)
753 return; /* to eat a fortune cookie */
759 return; /* list spells and scrolls */
765 return; /* give the help screen */
769 lprcat("Saving . . .");
771 savegame(savefilename
);
773 died(-257); /* save the game - doesn't return */
782 lprcat("\nAs yet, you don't have enough experience to use teleportation");
783 return; /* teleport yourself */
785 case '^': /* identify traps */
786 flag
= yrepcount
= 0;
789 for (j
= playery
- 1; j
< playery
+ 2; j
++) {
794 for (i
= playerx
- 1; i
< playerx
+ 2; i
++) {
799 switch (item
[i
][j
]) {
805 lprcat(objectname
[(int)item
[i
][j
]]);
811 lprcat("\nNo traps are visible");
815 case '_': /* this is the fudge player password for wizard mode */
819 if (userid
!= wisid
) {
820 lprcat("Sorry, you are not empowered to be a wizard.\n");
821 scbr(); /* system("stty -echo cbreak"); */
825 if (getpassword() == 0) {
826 scbr(); /* system("stty -echo cbreak"); */
830 scbr(); /* system("stty -echo cbreak"); */
831 for (i
= 0; i
< 6; i
++)
833 iven
[0] = iven
[1] = 0;
838 c
[WEAR
] = c
[SHIELD
] = -1;
839 raiseexperience(6000000L);
840 c
[AWARENESS
] += 25000;
843 for (i
= 0; i
< MAXY
; i
++)
844 for (j
= 0; j
< MAXX
; j
++)
846 for (i
= 0; i
< SPNUM
; i
++)
848 for (i
= 0; i
< MAXSCROLL
; i
++)
849 scrollname
[i
] = scrollhide
[i
];
850 for (i
= 0; i
< MAXPOTION
; i
++)
851 potionname
[i
] = potionhide
[i
];
853 for (i
= 0; i
< MAXSCROLL
; i
++)
854 if (strlen(scrollname
[i
]) > 2) { /* no null items */
855 item
[i
][0] = OSCROLL
;
858 for (i
= MAXX
- 1; i
> MAXX
- 1 - MAXPOTION
; i
--)
859 if (strlen(potionname
[i
- MAXX
+ MAXPOTION
]) > 2) { /* no null items */
860 item
[i
][0] = OPOTION
;
861 iarg
[i
][0] = i
- MAXX
+ MAXPOTION
;
863 for (i
= 1; i
< MAXY
; i
++) {
867 for (i
= MAXY
; i
< MAXY
+ MAXX
; i
++) {
868 item
[i
- MAXY
][MAXY
- 1] = i
;
869 iarg
[i
- MAXY
][MAXY
- 1] = 0;
871 for (i
= MAXX
+ MAXY
; i
< MAXX
+ MAXY
+ MAXY
; i
++) {
872 item
[MAXX
- 1][i
- MAXX
- MAXY
] = i
;
873 iarg
[MAXX
- 1][i
- MAXX
- MAXY
] = 0;
883 if (c
[SHIELD
] != -1) {
885 lprcat("\nYour shield is off");
887 } else if (c
[WEAR
] != -1) {
889 lprcat("\nYour armor is off");
892 lprcat("\nYou aren't wearing anything");
897 lprintf("\nThe stuff you are carrying presently weighs %d pounds", (long)packweight());
906 lprintf("\nCaverns of Larn, Version %d.%d, Diff=%d", (long)VERSION
, (long)SUBVERSION
, (long)c
[HARDGAME
]);
935 } /* create diagnostic file */
941 if (outstanding_taxes
> 0)
942 lprintf("\nYou presently owe %d gp in taxes.", (long)outstanding_taxes
);
944 lprcat("\nYou do not owe any taxes.");
955 movemonst(); /* move the monsters */
977 showcell(playerx
, playery
);
982 function to wield a weapon
989 if ((i
= whatitem("wield")) == '\33')
994 else if (iven
[i
- 'a'] == 0) {
997 } else if (iven
[i
- 'a'] == OPOTION
) {
1000 } else if (iven
[i
- 'a'] == OSCROLL
) {
1003 } else if ((c
[SHIELD
] != -1) && (iven
[i
- 'a'] == O2SWORD
)) {
1004 lprcat("\nBut one arm is busy with your shield!");
1008 if (iven
[i
- 'a'] == OLANCE
)
1020 common routine to say you don't have an item
1026 lprintf("\nYou don't have item %c!", x
);
1033 lprintf("\nYou can't wield item %c!", x
);
1037 function to wear armor
1044 if ((i
= whatitem("wear")) == '\33')
1050 switch (iven
[i
- 'a']) {
1062 if (c
[WEAR
] != -1) {
1063 lprcat("\nYou're already wearing some armor");
1070 if (c
[SHIELD
] != -1) {
1071 lprcat("\nYou are already wearing a shield");
1074 if (iven
[c
[WIELD
]] == O2SWORD
) {
1075 lprcat("\nYour hands are busy with the two handed sword!");
1078 c
[SHIELD
] = i
- 'a';
1082 lprcat("\nYou can't wear that!");
1089 function to drop an object
1097 p
= &item
[playerx
][playery
];
1099 if ((i
= whatitem("drop")) == '\33')
1104 if (i
== '.') { /* drop some gold */
1106 lprcat("\nThere's something here already!");
1111 lprcat("How much gold do you drop? ");
1112 if ((amt
= readnum((long)c
[GOLD
])) == 0)
1114 if (amt
> c
[GOLD
]) {
1115 lprcat("\nYou don't have that much!");
1121 } else if (amt
<= 327670L) {
1125 } else if (amt
<= 3276700L) {
1129 } else if (amt
<= 32767000L) {
1139 lprintf("You drop %d gold pieces", (long)amt
);
1140 iarg
[playerx
][playery
] = i
;
1142 know
[playerx
][playery
] = 0;
1146 drop_object(i
- 'a');
1153 * readscr() Subroutine to read a scroll one is carrying
1160 if ((i
= whatitem("read")) == '\33')
1166 if (iven
[i
- 'a'] == OSCROLL
) {
1167 read_scroll(ivenarg
[i
- 'a']);
1171 if (iven
[i
- 'a'] == OBOOK
) {
1172 readbook(ivenarg
[i
- 'a']);
1176 if (iven
[i
- 'a'] == 0) {
1180 lprcat("\nThere's nothing on it to read");
1188 * subroutine to eat a cookie one is carrying
1197 if ((i
= whatitem("eat")) == '\33')
1203 if (iven
[i
- 'a'] == OCOOKIE
) {
1204 lprcat("\nThe cookie was delicious.");
1206 if (!c
[BLINDCOUNT
]) {
1207 if ((p
= fortune()) != NULL
) {
1208 lprcat(" Inside you find a scrap of paper that says:\n");
1214 if (iven
[i
- 'a'] == 0) {
1218 lprcat("\nYou can't eat that!");
1226 * subroutine to quaff a potion one is carrying
1233 if ((i
= whatitem("quaff")) == '\33')
1239 if (iven
[i
- 'a'] == OPOTION
) {
1240 quaffpotion(ivenarg
[i
- 'a']);
1244 if (iven
[i
- 'a'] == 0) {
1248 lprcat("\nYou wouldn't want to quaff that, would you? ");
1256 function to ask what player wants to do
1259 whatitem(const char *str
)
1263 lprintf("\nWhat do you want to %s [* for all] ? ", str
);
1265 while (i
> 'z' || (i
< 'a' && i
!= '*' && i
!= '\33' && i
!= '.'))
1273 subroutine to get a number from the player
1274 and allow * to mean return amt, else return the number entered
1280 unsigned long amt
= 0;
1282 if ((i
= getchr()) == '*')
1283 amt
= mx
; /* allow him to say * for all gold */
1291 if ((i
<= '9') && (i
>= '0') && (amt
< 99999999))
1292 amt
= amt
* 10 + i
- '0';
1301 * routine to zero every byte in a string
1309 #endif /* HIDEBYLINK */