]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - larn/main.c
1 /* $NetBSD: main.c,v 1.26 2019/02/03 03:19:25 mrg Exp $ */
6 __RCSID("$NetBSD: main.c,v 1.26 2019/02/03 03:19:25 mrg Exp $");
18 static void showstr(void);
19 static void t_setup(int);
20 static void t_endup(int);
21 static void showwear(void);
22 static void showwield(void);
23 static void showread(void);
24 static void showeat(void);
25 static void showquaff(void);
26 static void show1(int, const char *[]);
27 static void randmonst(void);
28 static void parse(void);
30 static void wield(void);
31 static void ydhi(int);
32 static void ycwi(int);
33 static void wear(void);
34 static void dropobj(void);
35 static void readscr(void);
36 static void eatcookie(void);
37 static void quaff(void);
38 static int whatitem(const char *);
40 #define __unreachable() __builtin_unreachable()
42 static char copyright
[] = "\nLarn is copyrighted 1986 by Noah Morgan.\n";
43 int srcount
= 0; /* line counter for showstr() */
44 int dropflag
= 0; /* if 1 then don't lookforobject() next round */
45 int rmst
= 80; /* random monster creation counter */
46 int userid
; /* the players login user id number */
47 gid_t gid
, egid
; /* used for security */
48 u_char nowelcome
= 0, nomove
= 0; /* if (nomove) then don't
49 * count next iteration as a
51 static char viewflag
= 0;
53 * if viewflag then we have done a 99 stay here and don't showcell in the
56 u_char restorflag
= 0; /* 1 means restore has been done */
57 static char cmdhelp
[] = "\
58 Cmd line format: larn [-slicnh] [-o<optsfile>] [-##] [++]\n\
59 -s show the scoreboard\n\
60 -l show the logfile (wizard id only)\n\
61 -i show scoreboard with inventories of dead characters\n\
62 -c create new scoreboard (wizard id only)\n\
63 -n suppress welcome message on starting game\n\
64 -## specify level of difficulty (example: -5)\n\
65 -h print this help text\n\
66 ++ restore game from checkpoint file\n\
67 -o<optsfile> specify .larnopts filename to be used instead of \"~/.larnopts\"\n\
70 static char *termtypes
[] = {"vt100", "vt101", "vt102", "vt103", "vt125",
71 "vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340",
80 main(int argc
, char **argv
)
90 setegid(gid
); /* give up "games" if we have it */
92 * first task is to identify the player
95 init_term(); /* setup the terminal (find out what type)
98 /* try to get login name */
99 if (((ptr
= getlogin()) == 0) || (*ptr
== 0)) {
100 /* can we get it from /etc/passwd? */
101 if ((pwe
= getpwuid(getuid())) != NULL
)
103 else if ((ptr
= getenv("USER")) == 0)
104 if ((ptr
= getenv("LOGNAME")) == 0) {
105 noone
: write(2, "Can't find your logname. Who Are You?\n", 39);
111 if (strlen(ptr
) == 0)
114 * second task is to prepare the pathnames the player will need
116 strcpy(loginname
, ptr
); /* save loginname of the user for logging
118 strcpy(logname
, ptr
); /* this will be overwritten with the players
120 if ((ptr
= getenv("HOME")) == NULL
)
122 strcpy(savefilename
, ptr
);
123 strcat(savefilename
, "/Larn.sav"); /* save file name in home
125 snprintf(optsfile
, sizeof(optsfile
), "%s/.larnopts", ptr
);
126 /* the .larnopts filename */
129 * now malloc the memory for the dungeon
131 cell
= (struct cel
*) malloc(sizeof(struct cel
) * (MAXLEVEL
+ MAXVLEVEL
) * MAXX
* MAXY
);
133 died(-285); /* malloc failure */
134 lpbuf
= malloc((5 * BUFBIG
) >> 2); /* output buffer */
135 inbuffer
= malloc((5 * MAXIBUF
) >> 2); /* output buffer */
136 if ((lpbuf
== 0) || (inbuffer
== 0))
137 died(-285); /* malloc() failure */
140 newgame(); /* set the initial clock */
145 * check terminal type to avoid users who have not vt100 type terminals
147 ttype
= getenv("TERM");
148 for (j
= 1, i
= 0; i
< sizeof(termtypes
) / sizeof(char *); i
++)
149 if (strcmp(ttype
, termtypes
[i
]) == 0) {
154 lprcat("Sorry, Larn needs a VT100 family terminal for all its features.\n");
161 * now make scoreboard if it is not there (don't clear)
163 if (access(scorefile
, 0) == -1) /* not there */
167 * now process the command line arguments
169 for (i
= 1; i
< argc
; i
++) {
170 if (argv
[i
][0] == '-')
171 switch (argv
[i
][1]) {
174 exit(0); /* show scoreboard */
176 case 'l': /* show log file */
182 exit(0); /* show all scoreboard */
184 case 'c': /* anyone with password can create
186 lprcat("Preparing to initialize the scoreboard.\n");
187 if (getpassword() != 0) { /* make new scoreboard */
194 case 'n': /* no welcome msg */
208 case '9': /* for hardness */
209 sscanf(&argv
[i
][1], "%d", &hard
);
212 case 'h': /* print out command line arguments */
213 write(1, cmdhelp
, sizeof(cmdhelp
));
216 case 'o': /* specify a .larnopts filename */
217 strncpy(optsfile
, argv
[i
] + 2, 127);
221 printf("Unknown option <%s>\n", argv
[i
]);
225 if (argv
[i
][0] == '+') {
228 if (argv
[i
][1] == '+') {
230 restoregame(ckpfile
); /* restore checkpointed
237 readopts(); /* read the options file if there is one */
241 userid
= geteuid(); /* obtain the user's effective id number */
243 userid
= getplid(logname
); /* obtain the players id number */
244 #endif /* UIDSCORE */
246 write(2, "Can't obtain playerid\n", 22);
251 * this section of code causes the program to look like something else to ps
253 if (strcmp(psname
, argv
[0])) { /* if a different process name only */
254 if ((i
= access(psname
, 1)) < 0) { /* link not there */
255 if (link(argv
[0], psname
) >= 0) {
262 for (i
= 1; i
< argc
; i
++) {
263 szero(argv
[i
]); /* zero the argument to avoid ps snooping */
265 #endif /* HIDEBYLINK */
267 if (access(savefilename
, 0) == 0) { /* restore game if need to */
271 restoregame(savefilename
); /* restore last game */
273 sigsetup(); /* trap all needed signals */
274 sethard(hard
); /* set up the desired difficulty */
275 setupvt100(); /* setup the terminal special mode */
276 if (c
[HP
] == 0) { /* create new game */
277 makeplayer(); /* make the character that will play */
278 newcavelevel(0);/* make the dungeon */
279 predostuff
= 1; /* tell signals that we are in the welcome
282 welcome(); /* welcome the player to the game */
284 drawscreen(); /* show the initial dungeon */
285 predostuff
= 2; /* tell the trap functions that they must do
286 * a showplayer() from here on */
288 nice(1); /* games should be run niced */
290 yrepcount
= hit2flag
= 0;
293 lookforobject(); /* see if there is an object
296 dropflag
= 0; /* don't show it just dropped an item */
301 } /* move the monsters */
303 showcell(playerx
, playery
);
305 viewflag
= 0; /* show stuff around player */
308 hitflag
= hit3flag
= 0;
310 bot_linex(); /* update bottom line */
316 } /* get commands and make moves */
317 regen(); /* regenerate hp and spells */
318 if (c
[TIMESTOP
] == 0)
320 rmst
= 120 - (level
<< 2);
321 fillmonst(makemonst(level
));
330 show character's inventory
336 for (number
= 3, i
= 0; i
< 26; i
++)
338 number
++; /* count items in inventory */
350 nosignal
= 1; /* don't allow ^c etc */
352 lprintf(".) %ld gold pieces", (long) c
[GOLD
]);
355 for (k
= 26; k
>= 0; k
--)
357 for (i
= 22; i
< 84; i
++)
358 for (j
= 0; j
<= k
; j
++)
363 lprintf("\nElapsed time is %ld. You have %ld mobuls left", (long) ((gltime
+ 99) / 100 + 1), (long) ((TIMELIMIT
- gltime
) / 100));
369 * subroutine to clear screen depending on # lines to display
374 if (count
< 20) { /* how do we clear the screen? */
384 * subroutine to restore normal display screen depending on t_setup()
389 if (count
< 18) /* how did we clear the screen? */
390 draws(0, MAXX
, 0, (count
> MAXY
) ? MAXY
: count
);
398 function to show the things player is wearing only
403 int i
, j
, sigsav
, count
;
405 nosignal
= 1; /* don't allow ^c etc */
408 for (count
= 2, j
= 0; j
<= 26; j
++) /* count number of items we
410 if ((i
= iven
[j
]) != 0)
426 for (i
= 22; i
< 84; i
++)
427 for (j
= 0; j
<= 26; j
++)
447 function to show the things player can wield only
452 int i
, j
, sigsav
, count
;
454 nosignal
= 1; /* don't allow ^c etc */
457 for (count
= 2, j
= 0; j
<= 26; j
++) /* count how many items */
458 if ((i
= iven
[j
]) != 0)
479 for (i
= 22; i
< 84; i
++)
480 for (j
= 0; j
<= 26; j
++)
505 * function to show the things player can read only
510 int i
, j
, sigsav
, count
;
512 nosignal
= 1; /* don't allow ^c etc */
515 for (count
= 2, j
= 0; j
<= 26; j
++)
523 for (i
= 22; i
< 84; i
++)
524 for (j
= 0; j
<= 26; j
++)
537 * function to show the things player can eat only
542 int i
, j
, sigsav
, count
;
544 nosignal
= 1; /* don't allow ^c etc */
547 for (count
= 2, j
= 0; j
<= 26; j
++)
554 for (i
= 22; i
< 84; i
++)
555 for (j
= 0; j
<= 26; j
++)
567 function to show the things player can quaff only
572 int i
, j
, sigsav
, count
;
574 nosignal
= 1; /* don't allow ^c etc */
577 for (count
= 2, j
= 0; j
<= 26; j
++)
584 for (i
= 22; i
< 84; i
++)
585 for (j
= 0; j
<= 26; j
++)
597 show1(int idx
, const char *str2
[])
599 lprintf("\n%c) %s", idx
+ 'a', objectname
[iven
[idx
]]);
600 if (str2
!= 0 && str2
[ivenarg
[idx
]][0] != 0)
601 lprintf(" of%s", str2
[ivenarg
[idx
]]);
607 switch (iven
[indx
]) {
609 show1(indx
, potionname
);
612 show1(indx
, scrollname
);
630 lprintf("\n%c) %s", indx
+ 'a', objectname
[iven
[indx
]]);
631 if (ivenarg
[indx
] > 0)
632 lprintf(" + %ld", (long) ivenarg
[indx
]);
633 else if (ivenarg
[indx
] < 0)
634 lprintf(" %ld", (long) ivenarg
[indx
]);
637 if (c
[WIELD
] == indx
)
638 lprcat(" (weapon in hand)");
639 if ((c
[WEAR
] == indx
) || (c
[SHIELD
] == indx
))
640 lprcat(" (being worn)");
641 if (++srcount
>= 22) {
649 subroutine to randomly create monsters if needed
655 return; /* don't make monsters if time is stopped */
657 rmst
= 120 - (level
<< 2);
658 fillmonst(makemonst(level
));
667 get and execute a command
675 switch (k
) { /* get the token from the input and switch on
703 return; /* northeast */
706 return; /* northeast */
709 return; /* northwest */
712 return; /* northwest */
715 return; /* southeast */
718 return; /* southeast */
721 return; /* southwest */
724 return; /* southwest */
729 return; /* stay here */
734 return; /* wield a weapon */
739 return; /* wear armor */
745 lprcat("\nYou can't read anything when you're blind!");
746 } else if (c
[TIMESTOP
] == 0)
748 return; /* to read a scroll */
752 if (c
[TIMESTOP
] == 0)
754 return; /* quaff a potion */
758 if (c
[TIMESTOP
] == 0)
760 return; /* to drop an object */
765 return; /* cast a spell */
775 if (c
[TIMESTOP
] == 0)
777 return; /* to eat a fortune cookie */
783 return; /* list spells and scrolls */
789 return; /* give the help screen */
793 lprcat("Saving . . .");
795 savegame(savefilename
);
797 died(-257); /* save the game - doesn't return */
807 lprcat("\nAs yet, you don't have enough experience to use teleportation");
808 return; /* teleport yourself */
810 case '^': /* identify traps */
811 flag
= yrepcount
= 0;
814 for (j
= playery
- 1; j
< playery
+ 2; j
++) {
819 for (i
= playerx
- 1; i
< playerx
+ 2; i
++) {
824 switch (item
[i
][j
]) {
830 lprcat(objectname
[item
[i
][j
]]);
836 lprcat("\nNo traps are visible");
840 case '_': /* this is the fudge player password for
845 if (userid
!= wisid
) {
846 lprcat("Sorry, you are not empowered to be a wizard.\n");
847 scbr(); /* system("stty -echo cbreak"); */
851 if (getpassword() == 0) {
852 scbr(); /* system("stty -echo cbreak"); */
856 scbr(); /* system("stty -echo cbreak"); */
857 for (i
= 0; i
< 6; i
++)
859 iven
[0] = iven
[1] = 0;
864 c
[WEAR
] = c
[SHIELD
] = -1;
865 raiseexperience(6000000L);
866 c
[AWARENESS
] += 25000;
869 for (i
= 0; i
< MAXY
; i
++)
870 for (j
= 0; j
< MAXX
; j
++)
872 for (i
= 0; i
< SPNUM
; i
++)
874 for (i
= 0; i
< MAXSCROLL
; i
++)
875 scrollname
[i
] = scrollhide
[i
];
876 for (i
= 0; i
< MAXPOTION
; i
++)
877 potionname
[i
] = potionhide
[i
];
879 for (i
= 0; i
< MAXSCROLL
; i
++)
880 if (strlen(scrollname
[i
]) > 2) { /* no null items */
881 item
[i
][0] = OSCROLL
;
884 for (i
= MAXX
- 1; i
> MAXX
- 1 - MAXPOTION
; i
--)
885 if (strlen(potionname
[i
- MAXX
+ MAXPOTION
]) > 2) { /* no null items */
886 item
[i
][0] = OPOTION
;
887 iarg
[i
][0] = i
- MAXX
+ MAXPOTION
;
889 for (i
= 1; i
< MAXY
; i
++) {
893 for (i
= MAXY
; i
< MAXY
+ MAXX
; i
++) {
894 item
[i
- MAXY
][MAXY
- 1] = i
;
895 iarg
[i
- MAXY
][MAXY
- 1] = 0;
897 for (i
= MAXX
+ MAXY
; i
< MAXX
+ MAXY
+ MAXY
; i
++) {
898 item
[MAXX
- 1][i
- MAXX
- MAXY
] = i
;
899 iarg
[MAXX
- 1][i
- MAXX
- MAXY
] = 0;
909 if (c
[SHIELD
] != -1) {
911 lprcat("\nYour shield is off");
913 } else if (c
[WEAR
] != -1) {
915 lprcat("\nYour armor is off");
918 lprcat("\nYou aren't wearing anything");
923 lprintf("\nThe stuff you are carrying presently weighs %ld pounds", (long) packweight());
933 lprintf("\nCaverns of Larn, Version %ld.%ld, Diff=%ld",
934 (long) VERSION
, (long) SUBVERSION
,
964 } /* create diagnostic file */
970 if (outstanding_taxes
> 0)
971 lprintf("\nYou presently owe %ld gp in taxes.",
972 (long) outstanding_taxes
);
974 lprcat("\nYou do not owe any taxes.");
985 movemonst(); /* move the monsters */
1007 showcell(playerx
, playery
);
1012 function to wield a weapon
1019 if ((i
= whatitem("wield")) == '\33')
1024 else if (iven
[i
- 'a'] == 0) {
1027 } else if (iven
[i
- 'a'] == OPOTION
) {
1030 } else if (iven
[i
- 'a'] == OSCROLL
) {
1033 } else if ((c
[SHIELD
] != -1) && (iven
[i
- 'a'] == O2SWORD
)) {
1034 lprcat("\nBut one arm is busy with your shield!");
1038 if (iven
[i
- 'a'] == OLANCE
)
1050 common routine to say you don't have an item
1056 lprintf("\nYou don't have item %c!", x
);
1062 lprintf("\nYou can't wield item %c!", x
);
1066 function to wear armor
1073 if ((i
= whatitem("wear")) == '\33')
1079 switch (iven
[i
- 'a']) {
1091 if (c
[WEAR
] != -1) {
1092 lprcat("\nYou're already wearing some armor");
1099 if (c
[SHIELD
] != -1) {
1100 lprcat("\nYou are already wearing a shield");
1103 if (iven
[c
[WIELD
]] == O2SWORD
) {
1104 lprcat("\nYour hands are busy with the two handed sword!");
1107 c
[SHIELD
] = i
- 'a';
1111 lprcat("\nYou can't wear that!");
1118 function to drop an object
1126 p
= &item
[playerx
][playery
];
1128 if ((i
= whatitem("drop")) == '\33')
1133 if (i
== '.') { /* drop some gold */
1135 lprcat("\nThere's something here already!");
1140 lprcat("How much gold do you drop? ");
1141 if ((amt
= readnum((long) c
[GOLD
])) == 0)
1143 if (amt
> c
[GOLD
]) {
1144 lprcat("\nYou don't have that much!");
1150 } else if (amt
<= 327670L) {
1154 } else if (amt
<= 3276700L) {
1158 } else if (amt
<= 32767000L) {
1168 lprintf("You drop %ld gold pieces", (long)amt
);
1169 iarg
[playerx
][playery
] = i
;
1171 know
[playerx
][playery
] = 0;
1175 drop_object(i
- 'a');
1182 * readscr() Subroutine to read a scroll one is carrying
1189 if ((i
= whatitem("read")) == '\33')
1195 if (iven
[i
- 'a'] == OSCROLL
) {
1196 read_scroll(ivenarg
[i
- 'a']);
1200 if (iven
[i
- 'a'] == OBOOK
) {
1201 readbook(ivenarg
[i
- 'a']);
1205 if (iven
[i
- 'a'] == 0) {
1209 lprcat("\nThere's nothing on it to read");
1217 * subroutine to eat a cookie one is carrying
1226 if ((i
= whatitem("eat")) == '\33')
1232 if (iven
[i
- 'a'] == OCOOKIE
) {
1233 lprcat("\nThe cookie was delicious.");
1235 if (!c
[BLINDCOUNT
]) {
1236 if ((p
= fortune()) != NULL
) {
1237 lprcat(" Inside you find a scrap of paper that says:\n");
1243 if (iven
[i
- 'a'] == 0) {
1247 lprcat("\nYou can't eat that!");
1255 * subroutine to quaff a potion one is carrying
1262 if ((i
= whatitem("quaff")) == '\33')
1268 if (iven
[i
- 'a'] == OPOTION
) {
1269 quaffpotion(ivenarg
[i
- 'a']);
1273 if (iven
[i
- 'a'] == 0) {
1277 lprcat("\nYou wouldn't want to quaff that, would you? ");
1285 function to ask what player wants to do
1288 whatitem(const char *str
)
1292 lprintf("\nWhat do you want to %s [* for all] ? ", str
);
1294 while (i
> 'z' || (i
< 'a' && i
!= '*' && i
!= '\33' && i
!= '.'))
1302 subroutine to get a number from the player
1303 and allow * to mean return amt, else return the number entered
1309 unsigned long amt
= 0;
1311 if ((i
= ttgetch()) == '*')
1312 amt
= mx
; /* allow him to say * for all gold */
1320 if ((i
<= '9') && (i
>= '0') && (amt
< 99999999))
1321 amt
= amt
* 10 + i
- '0';
1330 * routine to zero every byte in a string
1339 #endif /* HIDEBYLINK */