1 /* $NetBSD: main.c,v 1.27 2021/05/02 12:50:45 rillig Exp $ */ 2 3 /* main.c */ 4 #include <sys/cdefs.h> 5 #ifndef lint 6 __RCSID("$NetBSD: main.c,v 1.27 2021/05/02 12:50:45 rillig Exp $"); 7 #endif /* not lint */ 8 9 #include <sys/types.h> 10 #include <stdio.h> 11 #include <pwd.h> 12 #include <unistd.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include "header.h" 16 #include "extern.h" 17 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); 29 static void run(int); 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 *); 39 40 static char copyright[] = "\nLarn is copyrighted 1986 by Noah Morgan.\n"; 41 int srcount = 0; /* line counter for showstr() */ 42 int dropflag = 0; /* if 1 then don't lookforobject() next round */ 43 int rmst = 80; /* random monster creation counter */ 44 int userid; /* the players login user id number */ 45 gid_t gid, egid; /* used for security */ 46 u_char nowelcome = 0, nomove = 0; /* if (nomove) then don't 47 * count next iteration as a 48 * move */ 49 static char viewflag = 0; 50 /* 51 * if viewflag then we have done a 99 stay here and don't showcell in the 52 * main loop 53 */ 54 u_char restorflag = 0; /* 1 means restore has been done */ 55 static char cmdhelp[] = "\ 56 Cmd line format: larn [-slicnh] [-o<optsfile>] [-##] [++]\n\ 57 -s show the scoreboard\n\ 58 -l show the logfile (wizard id only)\n\ 59 -i show scoreboard with inventories of dead characters\n\ 60 -c create new scoreboard (wizard id only)\n\ 61 -n suppress welcome message on starting game\n\ 62 -## specify level of difficulty (example: -5)\n\ 63 -h print this help text\n\ 64 ++ restore game from checkpoint file\n\ 65 -o<optsfile> specify .larnopts filename to be used instead of \"~/.larnopts\"\n\ 66 "; 67 #ifdef VT100 68 static char *termtypes[] = {"vt100", "vt101", "vt102", "vt103", "vt125", 69 "vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340", 70 "vt341"}; 71 #endif /* VT100 */ 72 /* 73 ************ 74 MAIN PROGRAM 75 ************ 76 */ 77 int 78 main(int argc, char **argv) 79 { 80 int i; 81 int hard; 82 const char *ptr = 0; 83 struct passwd *pwe; 84 85 i = 0; 86 egid = getegid(); 87 gid = getgid(); 88 setegid(gid); /* give up "games" if we have it */ 89 /* 90 * first task is to identify the player 91 */ 92 #ifndef VT100 93 init_term(); /* setup the terminal (find out what type) 94 * for termcap */ 95 #endif /* VT100 */ 96 /* try to get login name */ 97 if (((ptr = getlogin()) == 0) || (*ptr == 0)) { 98 /* can we get it from /etc/passwd? */ 99 if ((pwe = getpwuid(getuid())) != NULL) 100 ptr = pwe->pw_name; 101 else if ((ptr = getenv("USER")) == 0) 102 if ((ptr = getenv("LOGNAME")) == 0) { 103 noone: write(2, "Can't find your logname. Who Are You?\n", 39); 104 exit(1); 105 } 106 } 107 if (ptr == 0) 108 goto noone; 109 if (strlen(ptr) == 0) 110 goto noone; 111 /* 112 * second task is to prepare the pathnames the player will need 113 */ 114 strcpy(loginname, ptr); /* save loginname of the user for logging 115 * purposes */ 116 strcpy(logname, ptr); /* this will be overwritten with the players 117 * name */ 118 if ((ptr = getenv("HOME")) == NULL) 119 ptr = "."; 120 strcpy(savefilename, ptr); 121 strcat(savefilename, "/Larn.sav"); /* save file name in home 122 * directory */ 123 snprintf(optsfile, sizeof(optsfile), "%s/.larnopts", ptr); 124 /* the .larnopts filename */ 125 126 /* 127 * now malloc the memory for the dungeon 128 */ 129 cell = (struct cel *) malloc(sizeof(struct cel) * (MAXLEVEL + MAXVLEVEL) * MAXX * MAXY); 130 if (cell == 0) 131 died(-285); /* malloc failure */ 132 lpbuf = malloc((5 * BUFBIG) >> 2); /* output buffer */ 133 inbuffer = malloc((5 * MAXIBUF) >> 2); /* output buffer */ 134 if ((lpbuf == 0) || (inbuffer == 0)) 135 died(-285); /* malloc() failure */ 136 137 lcreat((char *) 0); 138 newgame(); /* set the initial clock */ 139 hard = -1; 140 141 #ifdef VT100 142 /* 143 * check terminal type to avoid users who have not vt100 type terminals 144 */ 145 ttype = getenv("TERM"); 146 for (j = 1, i = 0; i < sizeof(termtypes) / sizeof(char *); i++) 147 if (strcmp(ttype, termtypes[i]) == 0) { 148 j = 0; 149 break; 150 } 151 if (j) { 152 lprcat("Sorry, Larn needs a VT100 family terminal for all its features.\n"); 153 lflush(); 154 exit(1); 155 } 156 #endif /* VT100 */ 157 158 /* 159 * now make scoreboard if it is not there (don't clear) 160 */ 161 if (access(scorefile, 0) == -1) /* not there */ 162 makeboard(); 163 164 /* 165 * now process the command line arguments 166 */ 167 for (i = 1; i < argc; i++) { 168 if (argv[i][0] == '-') 169 switch (argv[i][1]) { 170 case 's': 171 showscores(); 172 exit(0); /* show scoreboard */ 173 174 case 'l': /* show log file */ 175 diedlog(); 176 exit(0); 177 178 case 'i': 179 showallscores(); 180 exit(0); /* show all scoreboard */ 181 182 case 'c': /* anyone with password can create 183 * scoreboard */ 184 lprcat("Preparing to initialize the scoreboard.\n"); 185 if (getpassword() != 0) { /* make new scoreboard */ 186 makeboard(); 187 lprc('\n'); 188 showscores(); 189 } 190 exit(0); 191 192 case 'n': /* no welcome msg */ 193 nowelcome = 1; 194 argv[i][0] = 0; 195 break; 196 197 case '0': 198 case '1': 199 case '2': 200 case '3': 201 case '4': 202 case '5': 203 case '6': 204 case '7': 205 case '8': 206 case '9': /* for hardness */ 207 sscanf(&argv[i][1], "%d", &hard); 208 break; 209 210 case 'h': /* print out command line arguments */ 211 write(1, cmdhelp, sizeof(cmdhelp)); 212 exit(0); 213 214 case 'o': /* specify a .larnopts filename */ 215 strncpy(optsfile, argv[i] + 2, 127); 216 break; 217 218 default: 219 printf("Unknown option <%s>\n", argv[i]); 220 exit(1); 221 }; 222 223 if (argv[i][0] == '+') { 224 clear(); 225 restorflag = 1; 226 if (argv[i][1] == '+') { 227 hitflag = 1; 228 restoregame(ckpfile); /* restore checkpointed 229 * game */ 230 } 231 i = argc; 232 } 233 } 234 235 readopts(); /* read the options file if there is one */ 236 237 238 #ifdef UIDSCORE 239 userid = geteuid(); /* obtain the user's effective id number */ 240 #else /* UIDSCORE */ 241 userid = getplid(logname); /* obtain the players id number */ 242 #endif /* UIDSCORE */ 243 if (userid < 0) { 244 write(2, "Can't obtain playerid\n", 22); 245 exit(1); 246 } 247 #ifdef HIDEBYLINK 248 /* 249 * this section of code causes the program to look like something else to ps 250 */ 251 if (strcmp(psname, argv[0])) { /* if a different process name only */ 252 if ((i = access(psname, 1)) < 0) { /* link not there */ 253 if (link(argv[0], psname) >= 0) { 254 argv[0] = psname; 255 execv(psname, argv); 256 } 257 } else 258 unlink(psname); 259 } 260 for (i = 1; i < argc; i++) { 261 szero(argv[i]); /* zero the argument to avoid ps snooping */ 262 } 263 #endif /* HIDEBYLINK */ 264 265 if (access(savefilename, 0) == 0) { /* restore game if need to */ 266 clear(); 267 restorflag = 1; 268 hitflag = 1; 269 restoregame(savefilename); /* restore last game */ 270 } 271 sigsetup(); /* trap all needed signals */ 272 sethard(hard); /* set up the desired difficulty */ 273 setupvt100(); /* setup the terminal special mode */ 274 if (c[HP] == 0) { /* create new game */ 275 makeplayer(); /* make the character that will play */ 276 newcavelevel(0);/* make the dungeon */ 277 predostuff = 1; /* tell signals that we are in the welcome 278 * screen */ 279 if (nowelcome == 0) 280 welcome(); /* welcome the player to the game */ 281 } 282 drawscreen(); /* show the initial dungeon */ 283 predostuff = 2; /* tell the trap functions that they must do 284 * a showplayer() from here on */ 285 #if 0 286 nice(1); /* games should be run niced */ 287 #endif 288 yrepcount = hit2flag = 0; 289 while (1) { 290 if (dropflag == 0) 291 lookforobject(); /* see if there is an object 292 * here */ 293 else 294 dropflag = 0; /* don't show it just dropped an item */ 295 if (hitflag == 0) { 296 if (c[HASTEMONST]) 297 movemonst(); 298 movemonst(); 299 } /* move the monsters */ 300 if (viewflag == 0) 301 showcell(playerx, playery); 302 else 303 viewflag = 0; /* show stuff around player */ 304 if (hit3flag) 305 flushall(); 306 hitflag = hit3flag = 0; 307 nomove = 1; 308 bot_linex(); /* update bottom line */ 309 while (nomove) { 310 if (hit3flag) 311 flushall(); 312 nomove = 0; 313 parse(); 314 } /* get commands and make moves */ 315 regen(); /* regenerate hp and spells */ 316 if (c[TIMESTOP] == 0) 317 if (--rmst <= 0) { 318 rmst = 120 - (level << 2); 319 fillmonst(makemonst(level)); 320 } 321 } 322 } 323 324 325 /* 326 showstr() 327 328 show character's inventory 329 */ 330 static void 331 showstr(void) 332 { 333 int i, number; 334 for (number = 3, i = 0; i < 26; i++) 335 if (iven[i]) 336 number++; /* count items in inventory */ 337 t_setup(number); 338 qshowstr(); 339 t_endup(number); 340 } 341 342 void 343 qshowstr(void) 344 { 345 int i, j, k, sigsav; 346 srcount = 0; 347 sigsav = nosignal; 348 nosignal = 1; /* don't allow ^c etc */ 349 if (c[GOLD]) { 350 lprintf(".) %ld gold pieces", (long) c[GOLD]); 351 srcount++; 352 } 353 for (k = 26; k >= 0; k--) 354 if (iven[k]) { 355 for (i = 22; i < 84; i++) 356 for (j = 0; j <= k; j++) 357 if (i == iven[j]) 358 show3(j); 359 k = 0; 360 } 361 lprintf("\nElapsed time is %ld. You have %ld mobuls left", (long) ((gltime + 99) / 100 + 1), (long) ((TIMELIMIT - gltime) / 100)); 362 more(); 363 nosignal = sigsav; 364 } 365 366 /* 367 * subroutine to clear screen depending on # lines to display 368 */ 369 static void 370 t_setup(int count) 371 { 372 if (count < 20) { /* how do we clear the screen? */ 373 cl_up(79, count); 374 cursor(1, 1); 375 } else { 376 resetscroll(); 377 clear(); 378 } 379 } 380 381 /* 382 * subroutine to restore normal display screen depending on t_setup() 383 */ 384 static void 385 t_endup(int count) 386 { 387 if (count < 18) /* how did we clear the screen? */ 388 draws(0, MAXX, 0, (count > MAXY) ? MAXY : count); 389 else { 390 drawscreen(); 391 setscroll(); 392 } 393 } 394 395 /* 396 function to show the things player is wearing only 397 */ 398 static void 399 showwear(void) 400 { 401 int i, j, sigsav, count; 402 sigsav = nosignal; 403 nosignal = 1; /* don't allow ^c etc */ 404 srcount = 0; 405 406 for (count = 2, j = 0; j <= 26; j++) /* count number of items we 407 * will display */ 408 if ((i = iven[j]) != 0) 409 switch (i) { 410 case OLEATHER: 411 case OPLATE: 412 case OCHAIN: 413 case ORING: 414 case OSTUDLEATHER: 415 case OSPLINT: 416 case OPLATEARMOR: 417 case OSSPLATE: 418 case OSHIELD: 419 count++; 420 }; 421 422 t_setup(count); 423 424 for (i = 22; i < 84; i++) 425 for (j = 0; j <= 26; j++) 426 if (i == iven[j]) 427 switch (i) { 428 case OLEATHER: 429 case OPLATE: 430 case OCHAIN: 431 case ORING: 432 case OSTUDLEATHER: 433 case OSPLINT: 434 case OPLATEARMOR: 435 case OSSPLATE: 436 case OSHIELD: 437 show3(j); 438 }; 439 more(); 440 nosignal = sigsav; 441 t_endup(count); 442 } 443 444 /* 445 function to show the things player can wield only 446 */ 447 static void 448 showwield(void) 449 { 450 int i, j, sigsav, count; 451 sigsav = nosignal; 452 nosignal = 1; /* don't allow ^c etc */ 453 srcount = 0; 454 455 for (count = 2, j = 0; j <= 26; j++) /* count how many items */ 456 if ((i = iven[j]) != 0) 457 switch (i) { 458 case ODIAMOND: 459 case ORUBY: 460 case OEMERALD: 461 case OSAPPHIRE: 462 case OBOOK: 463 case OCHEST: 464 case OLARNEYE: 465 case ONOTHEFT: 466 case OSPIRITSCARAB: 467 case OCUBEofUNDEAD: 468 case OPOTION: 469 case OSCROLL: 470 break; 471 default: 472 count++; 473 }; 474 475 t_setup(count); 476 477 for (i = 22; i < 84; i++) 478 for (j = 0; j <= 26; j++) 479 if (i == iven[j]) 480 switch (i) { 481 case ODIAMOND: 482 case ORUBY: 483 case OEMERALD: 484 case OSAPPHIRE: 485 case OBOOK: 486 case OCHEST: 487 case OLARNEYE: 488 case ONOTHEFT: 489 case OSPIRITSCARAB: 490 case OCUBEofUNDEAD: 491 case OPOTION: 492 case OSCROLL: 493 break; 494 default: 495 show3(j); 496 }; 497 more(); 498 nosignal = sigsav; 499 t_endup(count); 500 } 501 502 /* 503 * function to show the things player can read only 504 */ 505 static void 506 showread(void) 507 { 508 int i, j, sigsav, count; 509 sigsav = nosignal; 510 nosignal = 1; /* don't allow ^c etc */ 511 srcount = 0; 512 513 for (count = 2, j = 0; j <= 26; j++) 514 switch (iven[j]) { 515 case OBOOK: 516 case OSCROLL: 517 count++; 518 }; 519 t_setup(count); 520 521 for (i = 22; i < 84; i++) 522 for (j = 0; j <= 26; j++) 523 if (i == iven[j]) 524 switch (i) { 525 case OBOOK: 526 case OSCROLL: 527 show3(j); 528 }; 529 more(); 530 nosignal = sigsav; 531 t_endup(count); 532 } 533 534 /* 535 * function to show the things player can eat only 536 */ 537 static void 538 showeat(void) 539 { 540 int i, j, sigsav, count; 541 sigsav = nosignal; 542 nosignal = 1; /* don't allow ^c etc */ 543 srcount = 0; 544 545 for (count = 2, j = 0; j <= 26; j++) 546 switch (iven[j]) { 547 case OCOOKIE: 548 count++; 549 }; 550 t_setup(count); 551 552 for (i = 22; i < 84; i++) 553 for (j = 0; j <= 26; j++) 554 if (i == iven[j]) 555 switch (i) { 556 case OCOOKIE: 557 show3(j); 558 }; 559 more(); 560 nosignal = sigsav; 561 t_endup(count); 562 } 563 564 /* 565 function to show the things player can quaff only 566 */ 567 static void 568 showquaff(void) 569 { 570 int i, j, sigsav, count; 571 sigsav = nosignal; 572 nosignal = 1; /* don't allow ^c etc */ 573 srcount = 0; 574 575 for (count = 2, j = 0; j <= 26; j++) 576 switch (iven[j]) { 577 case OPOTION: 578 count++; 579 }; 580 t_setup(count); 581 582 for (i = 22; i < 84; i++) 583 for (j = 0; j <= 26; j++) 584 if (i == iven[j]) 585 switch (i) { 586 case OPOTION: 587 show3(j); 588 }; 589 more(); 590 nosignal = sigsav; 591 t_endup(count); 592 } 593 594 static void 595 show1(int idx, const char *str2[]) 596 { 597 lprintf("\n%c) %s", idx + 'a', objectname[iven[idx]]); 598 if (str2 != 0 && str2[ivenarg[idx]][0] != 0) 599 lprintf(" of%s", str2[ivenarg[idx]]); 600 } 601 602 void 603 show3(int indx) 604 { 605 switch (iven[indx]) { 606 case OPOTION: 607 show1(indx, potionname); 608 break; 609 case OSCROLL: 610 show1(indx, scrollname); 611 break; 612 613 case OLARNEYE: 614 case OBOOK: 615 case OSPIRITSCARAB: 616 case ODIAMOND: 617 case ORUBY: 618 case OCUBEofUNDEAD: 619 case OEMERALD: 620 case OCHEST: 621 case OCOOKIE: 622 case OSAPPHIRE: 623 case ONOTHEFT: 624 show1(indx, NULL); 625 break; 626 627 default: 628 lprintf("\n%c) %s", indx + 'a', objectname[iven[indx]]); 629 if (ivenarg[indx] > 0) 630 lprintf(" + %ld", (long) ivenarg[indx]); 631 else if (ivenarg[indx] < 0) 632 lprintf(" %ld", (long) ivenarg[indx]); 633 break; 634 } 635 if (c[WIELD] == indx) 636 lprcat(" (weapon in hand)"); 637 if ((c[WEAR] == indx) || (c[SHIELD] == indx)) 638 lprcat(" (being worn)"); 639 if (++srcount >= 22) { 640 srcount = 0; 641 more(); 642 clear(); 643 } 644 } 645 646 /* 647 subroutine to randomly create monsters if needed 648 */ 649 static void 650 randmonst(void) 651 { 652 if (c[TIMESTOP]) 653 return; /* don't make monsters if time is stopped */ 654 if (--rmst <= 0) { 655 rmst = 120 - (level << 2); 656 fillmonst(makemonst(level)); 657 } 658 } 659 660 661 662 /* 663 parse() 664 665 get and execute a command 666 */ 667 static void 668 parse(void) 669 { 670 int i, j, k, flag; 671 while (1) { 672 k = yylex(); 673 switch (k) { /* get the token from the input and switch on 674 * it */ 675 case 'h': 676 moveplayer(4); 677 return; /* west */ 678 case 'H': 679 run(4); 680 return; /* west */ 681 case 'l': 682 moveplayer(2); 683 return; /* east */ 684 case 'L': 685 run(2); 686 return; /* east */ 687 case 'j': 688 moveplayer(1); 689 return; /* south */ 690 case 'J': 691 run(1); 692 return; /* south */ 693 case 'k': 694 moveplayer(3); 695 return; /* north */ 696 case 'K': 697 run(3); 698 return; /* north */ 699 case 'u': 700 moveplayer(5); 701 return; /* northeast */ 702 case 'U': 703 run(5); 704 return; /* northeast */ 705 case 'y': 706 moveplayer(6); 707 return; /* northwest */ 708 case 'Y': 709 run(6); 710 return; /* northwest */ 711 case 'n': 712 moveplayer(7); 713 return; /* southeast */ 714 case 'N': 715 run(7); 716 return; /* southeast */ 717 case 'b': 718 moveplayer(8); 719 return; /* southwest */ 720 case 'B': 721 run(8); 722 return; /* southwest */ 723 724 case '.': 725 if (yrepcount) 726 viewflag = 1; 727 return; /* stay here */ 728 729 case 'w': 730 yrepcount = 0; 731 wield(); 732 return; /* wield a weapon */ 733 734 case 'W': 735 yrepcount = 0; 736 wear(); 737 return; /* wear armor */ 738 739 case 'r': 740 yrepcount = 0; 741 if (c[BLINDCOUNT]) { 742 cursors(); 743 lprcat("\nYou can't read anything when you're blind!"); 744 } else if (c[TIMESTOP] == 0) 745 readscr(); 746 return; /* to read a scroll */ 747 748 case 'q': 749 yrepcount = 0; 750 if (c[TIMESTOP] == 0) 751 quaff(); 752 return; /* quaff a potion */ 753 754 case 'd': 755 yrepcount = 0; 756 if (c[TIMESTOP] == 0) 757 dropobj(); 758 return; /* to drop an object */ 759 760 case 'c': 761 yrepcount = 0; 762 cast(); 763 return; /* cast a spell */ 764 765 case 'i': 766 yrepcount = 0; 767 nomove = 1; 768 showstr(); 769 return; /* status */ 770 771 case 'e': 772 yrepcount = 0; 773 if (c[TIMESTOP] == 0) 774 eatcookie(); 775 return; /* to eat a fortune cookie */ 776 777 case 'D': 778 yrepcount = 0; 779 seemagic(0); 780 nomove = 1; 781 return; /* list spells and scrolls */ 782 783 case '?': 784 yrepcount = 0; 785 help(); 786 nomove = 1; 787 return; /* give the help screen */ 788 789 case 'S': 790 clear(); 791 lprcat("Saving . . ."); 792 lflush(); 793 savegame(savefilename); 794 wizard = 1; 795 died(-257); /* save the game - doesn't return */ 796 __unreachable(); 797 798 case 'Z': 799 yrepcount = 0; 800 if (c[LEVEL] > 9) { 801 oteleport(1); 802 return; 803 } 804 cursors(); 805 lprcat("\nAs yet, you don't have enough experience to use teleportation"); 806 return; /* teleport yourself */ 807 808 case '^': /* identify traps */ 809 flag = yrepcount = 0; 810 cursors(); 811 lprc('\n'); 812 for (j = playery - 1; j < playery + 2; j++) { 813 if (j < 0) 814 j = 0; 815 if (j >= MAXY) 816 break; 817 for (i = playerx - 1; i < playerx + 2; i++) { 818 if (i < 0) 819 i = 0; 820 if (i >= MAXX) 821 break; 822 switch (item[i][j]) { 823 case OTRAPDOOR: 824 case ODARTRAP: 825 case OTRAPARROW: 826 case OTELEPORTER: 827 lprcat("\nIt's "); 828 lprcat(objectname[item[i][j]]); 829 flag++; 830 }; 831 } 832 } 833 if (flag == 0) 834 lprcat("\nNo traps are visible"); 835 return; 836 837 #if WIZID 838 case '_': /* this is the fudge player password for 839 * wizard mode */ 840 yrepcount = 0; 841 cursors(); 842 nomove = 1; 843 if (userid != wisid) { 844 lprcat("Sorry, you are not empowered to be a wizard.\n"); 845 scbr(); /* system("stty -echo cbreak"); */ 846 lflush(); 847 return; 848 } 849 if (getpassword() == 0) { 850 scbr(); /* system("stty -echo cbreak"); */ 851 return; 852 } 853 wizard = 1; 854 scbr(); /* system("stty -echo cbreak"); */ 855 for (i = 0; i < 6; i++) 856 c[i] = 70; 857 iven[0] = iven[1] = 0; 858 take(OPROTRING, 50); 859 take(OLANCE, 25); 860 c[WIELD] = 1; 861 c[LANCEDEATH] = 1; 862 c[WEAR] = c[SHIELD] = -1; 863 raiseexperience(6000000L); 864 c[AWARENESS] += 25000; 865 { 866 int i, j; 867 for (i = 0; i < MAXY; i++) 868 for (j = 0; j < MAXX; j++) 869 know[j][i] = 1; 870 for (i = 0; i < SPNUM; i++) 871 spelknow[i] = 1; 872 for (i = 0; i < MAXSCROLL; i++) 873 scrollname[i] = scrollhide[i]; 874 for (i = 0; i < MAXPOTION; i++) 875 potionname[i] = potionhide[i]; 876 } 877 for (i = 0; i < MAXSCROLL; i++) 878 if (strlen(scrollname[i]) > 2) { /* no null items */ 879 item[i][0] = OSCROLL; 880 iarg[i][0] = i; 881 } 882 for (i = MAXX - 1; i > MAXX - 1 - MAXPOTION; i--) 883 if (strlen(potionname[i - MAXX + MAXPOTION]) > 2) { /* no null items */ 884 item[i][0] = OPOTION; 885 iarg[i][0] = i - MAXX + MAXPOTION; 886 } 887 for (i = 1; i < MAXY; i++) { 888 item[0][i] = i; 889 iarg[0][i] = 0; 890 } 891 for (i = MAXY; i < MAXY + MAXX; i++) { 892 item[i - MAXY][MAXY - 1] = i; 893 iarg[i - MAXY][MAXY - 1] = 0; 894 } 895 for (i = MAXX + MAXY; i < MAXX + MAXY + MAXY; i++) { 896 item[MAXX - 1][i - MAXX - MAXY] = i; 897 iarg[MAXX - 1][i - MAXX - MAXY] = 0; 898 } 899 c[GOLD] += 25000; 900 drawscreen(); 901 return; 902 #endif 903 904 case 'T': 905 yrepcount = 0; 906 cursors(); 907 if (c[SHIELD] != -1) { 908 c[SHIELD] = -1; 909 lprcat("\nYour shield is off"); 910 bottomline(); 911 } else if (c[WEAR] != -1) { 912 c[WEAR] = -1; 913 lprcat("\nYour armor is off"); 914 bottomline(); 915 } else 916 lprcat("\nYou aren't wearing anything"); 917 return; 918 919 case 'g': 920 cursors(); 921 lprintf("\nThe stuff you are carrying presently weighs %ld pounds", (long) packweight()); 922 /* FALLTHROUGH */ 923 case ' ': 924 yrepcount = 0; 925 nomove = 1; 926 return; 927 928 case 'v': 929 yrepcount = 0; 930 cursors(); 931 lprintf("\nCaverns of Larn, Version %ld.%ld, Diff=%ld", 932 (long) VERSION, (long) SUBVERSION, 933 (long) c[HARDGAME]); 934 if (wizard) 935 lprcat(" Wizard"); 936 nomove = 1; 937 if (cheat) 938 lprcat(" Cheater"); 939 lprcat(copyright); 940 return; 941 942 case 'Q': 943 yrepcount = 0; 944 quit(); 945 nomove = 1; 946 return; /* quit */ 947 948 case 'L' - 64: 949 yrepcount = 0; 950 drawscreen(); 951 nomove = 1; 952 return; /* look */ 953 954 #if WIZID 955 #ifdef EXTRA 956 case 'A': 957 yrepcount = 0; 958 nomove = 1; 959 if (wizard) { 960 diag(); 961 return; 962 } /* create diagnostic file */ 963 return; 964 #endif 965 #endif 966 case 'P': 967 cursors(); 968 if (outstanding_taxes > 0) 969 lprintf("\nYou presently owe %ld gp in taxes.", 970 (long) outstanding_taxes); 971 else 972 lprcat("\nYou do not owe any taxes."); 973 return; 974 }; 975 } 976 } 977 978 void 979 parse2(void) 980 { 981 if (c[HASTEMONST]) 982 movemonst(); 983 movemonst(); /* move the monsters */ 984 randmonst(); 985 regen(); 986 } 987 988 static void 989 run(int dir) 990 { 991 int i; 992 i = 1; 993 while (i) { 994 i = moveplayer(dir); 995 if (i > 0) { 996 if (c[HASTEMONST]) 997 movemonst(); 998 movemonst(); 999 randmonst(); 1000 regen(); 1001 } 1002 if (hitflag) 1003 i = 0; 1004 if (i != 0) 1005 showcell(playerx, playery); 1006 } 1007 } 1008 1009 /* 1010 function to wield a weapon 1011 */ 1012 static void 1013 wield(void) 1014 { 1015 int i; 1016 while (1) { 1017 if ((i = whatitem("wield")) == '\33') 1018 return; 1019 if (i != '.') { 1020 if (i == '*') 1021 showwield(); 1022 else if (iven[i - 'a'] == 0) { 1023 ydhi(i); 1024 return; 1025 } else if (iven[i - 'a'] == OPOTION) { 1026 ycwi(i); 1027 return; 1028 } else if (iven[i - 'a'] == OSCROLL) { 1029 ycwi(i); 1030 return; 1031 } else if ((c[SHIELD] != -1) && (iven[i - 'a'] == O2SWORD)) { 1032 lprcat("\nBut one arm is busy with your shield!"); 1033 return; 1034 } else { 1035 c[WIELD] = i - 'a'; 1036 if (iven[i - 'a'] == OLANCE) 1037 c[LANCEDEATH] = 1; 1038 else 1039 c[LANCEDEATH] = 0; 1040 bottomline(); 1041 return; 1042 } 1043 } 1044 } 1045 } 1046 1047 /* 1048 common routine to say you don't have an item 1049 */ 1050 static void 1051 ydhi(int x) 1052 { 1053 cursors(); 1054 lprintf("\nYou don't have item %c!", x); 1055 } 1056 static void 1057 ycwi(int x) 1058 { 1059 cursors(); 1060 lprintf("\nYou can't wield item %c!", x); 1061 } 1062 1063 /* 1064 function to wear armor 1065 */ 1066 static void 1067 wear(void) 1068 { 1069 int i; 1070 while (1) { 1071 if ((i = whatitem("wear")) == '\33') 1072 return; 1073 if (i != '.') { 1074 if (i == '*') 1075 showwear(); 1076 else 1077 switch (iven[i - 'a']) { 1078 case 0: 1079 ydhi(i); 1080 return; 1081 case OLEATHER: 1082 case OCHAIN: 1083 case OPLATE: 1084 case OSTUDLEATHER: 1085 case ORING: 1086 case OSPLINT: 1087 case OPLATEARMOR: 1088 case OSSPLATE: 1089 if (c[WEAR] != -1) { 1090 lprcat("\nYou're already wearing some armor"); 1091 return; 1092 } 1093 c[WEAR] = i - 'a'; 1094 bottomline(); 1095 return; 1096 case OSHIELD: 1097 if (c[SHIELD] != -1) { 1098 lprcat("\nYou are already wearing a shield"); 1099 return; 1100 } 1101 if (iven[c[WIELD]] == O2SWORD) { 1102 lprcat("\nYour hands are busy with the two handed sword!"); 1103 return; 1104 } 1105 c[SHIELD] = i - 'a'; 1106 bottomline(); 1107 return; 1108 default: 1109 lprcat("\nYou can't wear that!"); 1110 }; 1111 } 1112 } 1113 } 1114 1115 /* 1116 function to drop an object 1117 */ 1118 static void 1119 dropobj(void) 1120 { 1121 int i; 1122 unsigned char *p; 1123 long amt; 1124 p = &item[playerx][playery]; 1125 while (1) { 1126 if ((i = whatitem("drop")) == '\33') 1127 return; 1128 if (i == '*') 1129 showstr(); 1130 else { 1131 if (i == '.') { /* drop some gold */ 1132 if (*p) { 1133 lprcat("\nThere's something here already!"); 1134 return; 1135 } 1136 lprcat("\n\n"); 1137 cl_dn(1, 23); 1138 lprcat("How much gold do you drop? "); 1139 if ((amt = readnum((long) c[GOLD])) == 0) 1140 return; 1141 if (amt > c[GOLD]) { 1142 lprcat("\nYou don't have that much!"); 1143 return; 1144 } 1145 if (amt <= 32767) { 1146 *p = OGOLDPILE; 1147 i = amt; 1148 } else if (amt <= 327670L) { 1149 *p = ODGOLD; 1150 i = amt / 10; 1151 amt = 10 * i; 1152 } else if (amt <= 3276700L) { 1153 *p = OMAXGOLD; 1154 i = amt / 100; 1155 amt = 100 * i; 1156 } else if (amt <= 32767000L) { 1157 *p = OKGOLD; 1158 i = amt / 1000; 1159 amt = 1000 * i; 1160 } else { 1161 *p = OKGOLD; 1162 i = 32767; 1163 amt = 32767000L; 1164 } 1165 c[GOLD] -= amt; 1166 lprintf("You drop %ld gold pieces", (long)amt); 1167 iarg[playerx][playery] = i; 1168 bottomgold(); 1169 know[playerx][playery] = 0; 1170 dropflag = 1; 1171 return; 1172 } 1173 drop_object(i - 'a'); 1174 return; 1175 } 1176 } 1177 } 1178 1179 /* 1180 * readscr() Subroutine to read a scroll one is carrying 1181 */ 1182 static void 1183 readscr(void) 1184 { 1185 int i; 1186 while (1) { 1187 if ((i = whatitem("read")) == '\33') 1188 return; 1189 if (i != '.') { 1190 if (i == '*') 1191 showread(); 1192 else { 1193 if (iven[i - 'a'] == OSCROLL) { 1194 read_scroll(ivenarg[i - 'a']); 1195 iven[i - 'a'] = 0; 1196 return; 1197 } 1198 if (iven[i - 'a'] == OBOOK) { 1199 readbook(ivenarg[i - 'a']); 1200 iven[i - 'a'] = 0; 1201 return; 1202 } 1203 if (iven[i - 'a'] == 0) { 1204 ydhi(i); 1205 return; 1206 } 1207 lprcat("\nThere's nothing on it to read"); 1208 return; 1209 } 1210 } 1211 } 1212 } 1213 1214 /* 1215 * subroutine to eat a cookie one is carrying 1216 */ 1217 static void 1218 eatcookie(void) 1219 { 1220 const char *p; 1221 int i; 1222 1223 while (1) { 1224 if ((i = whatitem("eat")) == '\33') 1225 return; 1226 if (i != '.') { 1227 if (i == '*') 1228 showeat(); 1229 else { 1230 if (iven[i - 'a'] == OCOOKIE) { 1231 lprcat("\nThe cookie was delicious."); 1232 iven[i - 'a'] = 0; 1233 if (!c[BLINDCOUNT]) { 1234 if ((p = fortune()) != NULL) { 1235 lprcat(" Inside you find a scrap of paper that says:\n"); 1236 lprcat(p); 1237 } 1238 } 1239 return; 1240 } 1241 if (iven[i - 'a'] == 0) { 1242 ydhi(i); 1243 return; 1244 } 1245 lprcat("\nYou can't eat that!"); 1246 return; 1247 } 1248 } 1249 } 1250 } 1251 1252 /* 1253 * subroutine to quaff a potion one is carrying 1254 */ 1255 static void 1256 quaff(void) 1257 { 1258 int i; 1259 while (1) { 1260 if ((i = whatitem("quaff")) == '\33') 1261 return; 1262 if (i != '.') { 1263 if (i == '*') 1264 showquaff(); 1265 else { 1266 if (iven[i - 'a'] == OPOTION) { 1267 quaffpotion(ivenarg[i - 'a']); 1268 iven[i - 'a'] = 0; 1269 return; 1270 } 1271 if (iven[i - 'a'] == 0) { 1272 ydhi(i); 1273 return; 1274 } 1275 lprcat("\nYou wouldn't want to quaff that, would you? "); 1276 return; 1277 } 1278 } 1279 } 1280 } 1281 1282 /* 1283 function to ask what player wants to do 1284 */ 1285 static int 1286 whatitem(const char *str) 1287 { 1288 int i; 1289 cursors(); 1290 lprintf("\nWhat do you want to %s [* for all] ? ", str); 1291 i = 0; 1292 while (i > 'z' || (i < 'a' && i != '*' && i != '\33' && i != '.')) 1293 i = ttgetch(); 1294 if (i == '\33') 1295 lprcat(" aborted"); 1296 return (i); 1297 } 1298 1299 /* 1300 subroutine to get a number from the player 1301 and allow * to mean return amt, else return the number entered 1302 */ 1303 unsigned long 1304 readnum(long mx) 1305 { 1306 int i; 1307 unsigned long amt = 0; 1308 sncbr(); 1309 if ((i = ttgetch()) == '*') 1310 amt = mx; /* allow him to say * for all gold */ 1311 else 1312 while (i != '\n') { 1313 if (i == '\033') { 1314 scbr(); 1315 lprcat(" aborted"); 1316 return (0); 1317 } 1318 if ((i <= '9') && (i >= '0') && (amt < 99999999)) 1319 amt = amt * 10 + i - '0'; 1320 i = ttgetch(); 1321 } 1322 scbr(); 1323 return (amt); 1324 } 1325 1326 #ifdef HIDEBYLINK 1327 /* 1328 * routine to zero every byte in a string 1329 */ 1330 void 1331 szero(str) 1332 char *str; 1333 { 1334 while (*str) 1335 *str++ = 0; 1336 } 1337 #endif /* HIDEBYLINK */ 1338