1 /* $OpenBSD: snake.c,v 1.2 1999/04/20 23:01:12 pjanzen Exp $ */ 2 /* $NetBSD: snake.c,v 1.8 1995/04/29 00:06:41 mycroft Exp $ */ 3 4 /* 5 * Copyright (c) 1980, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1980, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)snake.c 8.2 (Berkeley) 1/7/94"; 46 #else 47 static char rcsid[] = "$OpenBSD: snake.c,v 1.2 1999/04/20 23:01:12 pjanzen Exp $"; 48 #endif 49 #endif /* not lint */ 50 51 /* 52 * snake - crt hack game. 53 * 54 * You move around the screen with arrow keys trying to pick up money 55 * without getting eaten by the snake. hjkl work as in vi in place of 56 * arrow keys. You can leave at the exit any time. 57 * 58 * compile as follows: 59 * cc -O snake.c move.c -o snake -lm -ltermlib 60 */ 61 62 #include <sys/param.h> 63 64 #include <errno.h> 65 #include <fcntl.h> 66 #include <pwd.h> 67 #include <time.h> 68 #include <unistd.h> 69 70 #include "snake.h" 71 #include "pathnames.h" 72 73 struct point you; 74 struct point money; 75 struct point finish; 76 struct point snake[6]; 77 78 int loot, penalty; 79 int long tl, tm=0L; 80 int moves; 81 char stri[BSIZE]; 82 char *p; 83 char ch, savec; 84 char *kl, *kr, *ku, *kd; 85 int fast=1; 86 int repeat=1; 87 time_t tv; 88 char *tn; 89 90 int rawscores; 91 #ifdef LOGGING 92 FILE *logfile; 93 #endif 94 95 int 96 main(argc, argv) 97 int argc; 98 char **argv; 99 { 100 int ch, i; 101 char *p, **av; 102 103 /* don't create the score file if it doesn't exist. */ 104 rawscores = open(_PATH_RAWSCORES, O_RDWR, 0664); 105 #ifdef LOGGING 106 logfile = fopen(_PATH_LOGFILE, "a"); 107 #endif 108 109 /* revoke privs */ 110 setegid(getgid()); 111 setgid(getgid()); 112 113 (void)time(&tv); 114 srandom((int)tv); 115 116 /* check to see if we were called as snscore */ 117 av = argv; 118 p = strrchr(*av, '/'); 119 if (p++ == NULL) 120 p = *av; 121 if (strcmp(p,"snscore") == 0) { 122 snscore(rawscores, 0); 123 exit(0); 124 } 125 126 while ((ch = getopt(argc, argv, "hl:sw:")) != -1) 127 switch ((char)ch) { 128 #if 0 129 case 'd': 130 tv = atol(optarg); /* set seed */ 131 break; 132 #endif 133 case 'w': /* width */ 134 ccnt = atoi(optarg); 135 break; 136 case 'l': /* length */ 137 lcnt = atoi(optarg); 138 break; 139 case 's': /* score */ 140 snscore(rawscores, 0); 141 exit(0); 142 break; 143 case '?': 144 case 'h': 145 default: 146 fputs("usage: snake [-w width] [-l length] [-s]\n", 147 stderr); 148 exit(1); 149 } 150 151 penalty = loot = 0; 152 getcap(); 153 154 i = MIN(lcnt, ccnt); 155 if (i < 4) { 156 cook(); 157 errx(1, "screen too small for a fair game."); 158 } 159 /* 160 * chunk is the amount of money the user gets for each $. 161 * The formula below tries to be fair for various screen sizes. 162 * We only pay attention to the smaller of the 2 edges, since 163 * that seems to be the bottleneck. 164 * This formula is a hyperbola which includes the following points: 165 * (24, $25) (original scoring algorithm) 166 * (12, $40) (experimentally derived by the "feel") 167 * (48, $15) (a guess) 168 * This will give a 4x4 screen $99/shot. We don't allow anything 169 * smaller than 4x4 because there is a 3x3 game where you can win 170 * an infinite amount of money. 171 */ 172 if (i < 12) 173 i = 12; /* otherwise it isn't fair */ 174 /* 175 * Compensate for border. This really changes the game since 176 * the screen is two squares smaller but we want the default 177 * to be $25, and the high scores on small screens were a bit 178 * much anyway. 179 */ 180 i += 2; 181 chunk = (675.0 / (i + 6)) + 2.5; /* min screen edge */ 182 183 signal(SIGINT, stop); 184 putpad(TI); /* String to begin programs that use cm */ 185 putpad(KS); /* Put terminal in keypad transmit mode */ 186 187 snrand(&finish); 188 snrand(&you); 189 snrand(&money); 190 snrand(&snake[0]); 191 192 if (ospeed < 9600 || ((!CM) && (!TA))) 193 fast = 0; 194 for (i = 1; i < 6; i++) 195 chase(&snake[i], &snake[i - 1]); 196 setup(); 197 mainloop(); 198 /* NOT REACHED */ 199 return(0); 200 } 201 202 /* Main command loop */ 203 void 204 mainloop() 205 { 206 int j, k; 207 int c, match, lastc = 0; 208 struct point tmp; 209 210 for (;;) { 211 tmp.col = you.col + 1; 212 tmp.line = you.line + 1; /* Highlight you, not left & above */ 213 move(&tmp); 214 fflush(stdout); 215 if (((c = getchar() & 0177) <= '9') && (c >= '0')) { 216 ungetc(c, stdin); 217 j = scanf("%d", &repeat); 218 c = getchar() & 0177; 219 } else { 220 if (c != '.') 221 repeat = 1; 222 } 223 if (c == '.') 224 c = lastc; 225 if ((Klength > 0) && 226 (c == *KL || c == *KR || c == *KU || c == *KD)) { 227 savec = c; 228 match = 0; 229 kl = KL; 230 kr = KR; 231 ku = KU; 232 kd = KD; 233 for (j = Klength; j > 0; j--) { 234 if (match != 1) { 235 match = 0; 236 if (*kl++ == c) { 237 ch = 'h'; 238 match++; 239 } 240 if (*kr++ == c) { 241 ch = 'l'; 242 match++; 243 } 244 if (*ku++ == c) { 245 ch = 'k'; 246 match++; 247 } 248 if (*kd++ == c) { 249 ch = 'j'; 250 match++; 251 } 252 if (match == 0) { 253 ungetc(c, stdin); 254 ch = savec; 255 /* Oops! 256 * This works if we figure it out on second character. 257 */ 258 break; 259 } 260 } 261 savec = c; 262 if (j != 1) 263 c = getchar() & 0177; 264 } 265 c = ch; 266 } 267 if (!fast) 268 flushi(); 269 lastc = c; 270 switch (c) { 271 case CTRL('z'): 272 suspend(); 273 continue; 274 case EOT: 275 case 'x': 276 case 0177: /* del or end of file */ 277 ll(); 278 cook(); 279 length(moves); 280 #ifdef LOGGING 281 logit("quit"); 282 #endif 283 exit(0); 284 case CTRL('l'): 285 setup(); 286 winnings(cashvalue); 287 continue; 288 case 'p': 289 case 'd': 290 snap(); 291 continue; 292 case 'w': 293 spacewarp(0); 294 continue; 295 case 'A': 296 repeat = you.col; 297 c = 'h'; 298 break; 299 case 'H': 300 case 'S': 301 repeat = you.col - money.col; 302 c = 'h'; 303 break; 304 case 'T': 305 repeat = you.line; 306 c = 'k'; 307 break; 308 case 'K': 309 case 'E': 310 repeat = you.line - money.line; 311 c = 'k'; 312 break; 313 case 'P': 314 repeat = ccnt - 1 - you.col; 315 c = 'l'; 316 break; 317 case 'L': 318 case 'F': 319 repeat = money.col - you.col; 320 c = 'l'; 321 break; 322 case 'B': 323 repeat = lcnt - 1 - you.line; 324 c = 'j'; 325 break; 326 case 'J': 327 case 'C': 328 repeat = money.line - you.line; 329 c = 'j'; 330 break; 331 } 332 for(k = 1; k <= repeat; k++) { 333 moves++; 334 switch (c) { 335 case 's': 336 case 'h': 337 case '\b': 338 if (you.col >0) { 339 if ((fast) || (k == 1)) 340 pchar(&you,' '); 341 you.col--; 342 if ((fast) || (k == repeat) || (you.col == 0)) 343 pchar(&you,ME); 344 } 345 break; 346 case 'f': 347 case 'l': 348 case ' ': 349 if (you.col < ccnt-1) { 350 if ((fast) || (k == 1)) 351 pchar(&you, ' '); 352 you.col++; 353 if ((fast) || (k == repeat) || (you.col == ccnt-1)) 354 pchar(&you, ME); 355 } 356 break; 357 case CTRL('p'): 358 case 'e': 359 case 'k': 360 case 'i': 361 if (you.line > 0) { 362 if ((fast) || (k == 1)) 363 pchar(&you,' '); 364 you.line--; 365 if ((fast) || (k == repeat) || (you.line == 0)) 366 pchar(&you,ME); 367 } 368 break; 369 case CTRL('n'): 370 case 'c': 371 case 'j': 372 case LF: 373 case 'm': 374 if (you.line+1 < lcnt) { 375 if ((fast) || (k == 1)) 376 pchar(&you,' '); 377 you.line++; 378 if ((fast) || (k == repeat) || (you.line == lcnt-1)) 379 pchar(&you,ME); 380 } 381 break; 382 } 383 384 if (same(&you, &money)) { 385 loot += 25; 386 if (k < repeat) 387 pchar(&you, ' '); 388 do { 389 snrand(&money); 390 } while ((money.col == finish.col && money.line == finish.line) || 391 (money.col < 5 && money.line == 0) || 392 (money.col == you.col && money.line == you.line)); 393 pchar(&money, TREASURE); 394 winnings(cashvalue); 395 /* continue; Previously, snake missed a turn! */ 396 } 397 if (same(&you,&finish)) { 398 win(&finish); 399 ll(); 400 cook(); 401 printf("You have won with $%d.\n", cashvalue); 402 #ifdef LOGGING 403 logit("won"); 404 #endif 405 length(moves); 406 post(cashvalue, 1); 407 close(rawscores); 408 exit(0); 409 } 410 if (pushsnake()) 411 break; 412 } 413 fflush(stdout); 414 } 415 } 416 417 /* set up the board */ 418 void 419 setup() 420 { 421 int i; 422 423 clear(); 424 pchar(&you, ME); 425 pchar(&finish, GOAL); 426 pchar(&money, TREASURE); 427 for (i = 1; i < 6; i++) { 428 pchar(&snake[i], SNAKETAIL); 429 } 430 pchar(&snake[0], SNAKEHEAD); 431 drawbox(); 432 fflush(stdout); 433 } 434 435 void 436 drawbox() 437 { 438 int i; 439 struct point p; 440 441 p.line = -1; 442 for (i = 0; i < ccnt; i++) { 443 p.col = i; 444 pchar(&p, '-'); 445 } 446 p.col = ccnt; 447 for (i = -1; i <= lcnt; i++) { 448 p.line = i; 449 pchar(&p, '|'); 450 } 451 p.col = -1; 452 for (i = -1; i <= lcnt; i++) { 453 p.line = i; 454 pchar(&p, '|'); 455 } 456 p.line = lcnt; 457 for (i = 0; i < ccnt; i++) { 458 p.col = i; 459 pchar(&p, '-'); 460 } 461 } 462 463 void 464 snrand(sp) 465 struct point *sp; 466 { 467 struct point p; 468 int i; 469 470 for (;;) { 471 p.col = random() % ccnt; 472 p.line = random() % lcnt; 473 474 /* make sure it's not on top of something else */ 475 if (p.line == 0 && p.col < 5) 476 continue; 477 if (same(&p, &you)) 478 continue; 479 if (same(&p, &money)) 480 continue; 481 if (same(&p, &finish)) 482 continue; 483 for (i = 0; i < 6; i++) 484 if (same(&p, &snake[i])) 485 break; 486 if (i < 6) 487 continue; 488 break; 489 } 490 *sp = p; 491 } 492 493 int 494 post(iscore, flag) 495 int iscore, flag; 496 { 497 short score = iscore; 498 short oldbest=0; 499 uid_t uid; 500 501 /* I want to printf() the scores for terms that clear on cook(), 502 * but this routine also gets called with flag == 0 to see if 503 * the snake should wink. If (flag) then we're at game end and 504 * can printf. 505 */ 506 /* 507 * Neg uid cannot have scores recorded. 508 */ 509 if ((uid = getuid()) < 0) { 510 if (flag) 511 printf("\nNo saved scores for uid %d.\n", uid); 512 return(1); 513 } 514 if (rawscores == -1) { 515 if (flag) 516 printf("Can't open score file %s: %s.\n", 517 _PATH_RAWSCORES, strerror(errno)); 518 return(1); 519 } 520 /* Figure out what happened in the past */ 521 lseek(rawscores, uid * sizeof(short), SEEK_SET); 522 read(rawscores, &oldbest, sizeof(short)); 523 if (!flag) 524 return (score > oldbest ? 1 : 0); 525 526 /* Update this jokers best */ 527 if (score > oldbest) { 528 lseek(rawscores, uid * sizeof(short), SEEK_SET); 529 write(rawscores, &score, sizeof(short)); 530 printf("\nYou bettered your previous best of $%d\n", oldbest); 531 } else 532 printf("\nYour best to date is $%d\n", oldbest); 533 534 fsync(rawscores); 535 /* See if we have a new champ */ 536 snscore(rawscores, TOPN); 537 return(1); 538 } 539 540 /* 541 * Flush typeahead to keep from buffering a bunch of chars and then 542 * overshooting. This loses horribly at 9600 baud, but works nicely 543 * if the terminal gets behind. 544 */ 545 void 546 flushi() 547 { 548 tcflush(0, TCIFLUSH); 549 } 550 551 int mx [8] = { 0, 1, 1, 1, 0,-1,-1,-1}; 552 int my [8] = {-1,-1, 0, 1, 1, 1, 0,-1}; 553 float absv[8] = {1, 1.4, 1, 1.4, 1, 1.4, 1, 1.4}; 554 int oldw = 0; 555 556 void 557 chase (np, sp) 558 struct point *sp, *np; 559 { 560 /* this algorithm has bugs; otherwise the snake would get too good */ 561 struct point d; 562 int w, i, wt[8]; 563 double v1, v2, vp, max; 564 565 point(&d, you.col-sp->col, you.line-sp->line); 566 v1 = sqrt((double)(d.col * d.col + d.line * d.line) ); 567 w = 0; 568 max = 0; 569 for(i = 0; i < 8; i++) 570 { 571 vp = d.col * mx[i] + d.line * my[i]; 572 v2 = absv[i]; 573 if (v1 > 0) 574 vp = ((double)vp) / (v1 * v2); 575 else 576 vp = 1.0; 577 if (vp > max) { 578 max = vp; 579 w = i; 580 } 581 } 582 for (i = 0; i < 8; i++) { 583 point(&d, sp->col + mx[i], sp->line + my[i]); 584 wt[i] = 0; 585 if (d.col < 0 || d.col >= ccnt || d.line < 0 || d.line >= lcnt) 586 continue; 587 /* 588 * Change to allow snake to eat you if you're on the money; 589 * otherwise, you can just crouch there until the snake goes 590 * away. Not positive it's right. 591 * 592 * if (d.line == 0 && d.col < 5) continue; 593 */ 594 if (same(&d, &money) || same(&d,&finish)) 595 continue; 596 wt[i] = (i == w ? loot/10 : 1); 597 if (i == oldw) 598 wt[i] += loot/20; 599 } 600 for (w = i = 0; i < 8; i++) 601 w += wt[i]; 602 vp = ((rand() >> 6) & 01777) % w; 603 for (i = 0; i < 8; i++) 604 if (vp < wt[i]) 605 break; 606 else 607 vp -= wt[i]; 608 if (i == 8) { 609 pr("failure\n"); 610 i = 0; 611 while (wt[i] == 0) 612 i++; 613 } 614 oldw = w = i; 615 point(np, sp->col + mx[w], sp->line + my[w]); 616 } 617 618 void 619 spacewarp(w) 620 int w; 621 { 622 struct point p; 623 int j; 624 char *str; 625 626 snrand(&you); 627 point(&p, COLUMNS / 2 - 8, LINES / 2 - 1); 628 if (p.col < 0) 629 p.col = 0; 630 if (p.line < 0) 631 p.line = 0; 632 if (w) { 633 str = "BONUS!!!"; 634 loot = loot - penalty; 635 penalty = 0; 636 } else { 637 str = "SPACE WARP!!!"; 638 penalty += loot / PENALTY; 639 } 640 for (j = 0; j < 3; j++) { 641 clear(); 642 fflush(stdout); 643 delay(5); 644 apr(&p, str); 645 fflush(stdout); 646 delay(10); 647 } 648 setup(); 649 winnings(cashvalue); 650 } 651 652 void 653 snap() 654 { 655 struct point p; 656 657 /* I don't see the graphical purpose of the next block of code. 658 * It just makes no sense. 659 * 660 * if (you.line < 3) 661 * pchar(point(&p, you.col, 0), '-'); 662 * if (you.line > lcnt - 4) 663 * pchar(point(&p, you.col, lcnt - 1), '_'); 664 * if(you.col < 10) 665 * pchar(point(&p, 0, you.line), '('); 666 * if(you.col > ccnt-10) 667 * pchar(point(&p, ccnt-1, you.line), ')'); 668 */ 669 if (!stretch(&money)) 670 if (!stretch(&finish)) { 671 pchar(point(&p, you.col, you.line), '?'); 672 fflush(stdout); 673 delay(10); 674 pchar(point(&p, you.col, you.line), ME); 675 } 676 /* Again, I don't see the point of the following either. 677 * 678 * if (you.line < 3) { 679 * point(&p, you.col, 0); 680 * chk(&p); 681 * } 682 * if (you.line > lcnt - 4) { 683 * point(&p, you.col, lcnt - 1); 684 * chk(&p); 685 * } 686 * if (you.col < 10) { 687 * point(&p, 0, you.line); 688 * chk(&p); 689 * } 690 * if (you.col > ccnt-10) { 691 * point(&p, ccnt - 1, you.line); 692 * chk(&p); 693 * } 694 */ 695 fflush(stdout); 696 } 697 698 int 699 stretch(ps) 700 struct point *ps; 701 { 702 struct point p; 703 704 point(&p, you.col, you.line); 705 if ((abs(ps->col - you.col) < (ccnt / 12)) && (you.line != ps->line)) { 706 if (you.line < ps->line) { 707 for (p.line = you.line + 1; p.line <= ps->line; p.line++) 708 pchar(&p, 'v'); 709 fflush(stdout); 710 delay(10); 711 for (; p.line > you.line; p.line--) 712 chk(&p); 713 } else { 714 for (p.line = you.line - 1; p.line >= ps->line; p.line--) 715 pchar(&p, '^'); 716 fflush(stdout); 717 delay(10); 718 for (; p.line < you.line; p.line++) 719 chk(&p); 720 } 721 return(1); 722 } else if ((abs(ps->line - you.line) < (lcnt / 7)) && (you.col != ps->col)) { 723 p.line = you.line; 724 if (you.col < ps->col) { 725 for (p.col = you.col + 1; p.col <= ps->col; p.col++) 726 pchar(&p, '>'); 727 fflush(stdout); 728 delay(10); 729 for (; p.col > you.col; p.col--) 730 chk(&p); 731 } else { 732 for (p.col = you.col - 1; p.col >= ps->col; p.col--) 733 pchar(&p, '<'); 734 fflush(stdout); 735 delay(10); 736 for (; p.col < you.col; p.col++) 737 chk(&p); 738 } 739 return(1); 740 } 741 return(0); 742 } 743 744 void 745 surround(ps) 746 struct point *ps; 747 { 748 struct point x; 749 int j; 750 751 if (ps->col == 0) 752 ps->col++; 753 if (ps->line == 0) 754 ps->line++; 755 if (ps->line == LINES -1) 756 ps->line--; 757 if (ps->col == COLUMNS -1) 758 ps->col--; 759 apr(point(&x, ps->col-1, ps->line-1), "/*\\\r* *\r\\*/"); 760 for (j = 0; j < 20; j++) { 761 pchar(ps, '@'); 762 fflush(stdout); 763 delay(1); 764 pchar(ps,' '); 765 fflush(stdout); 766 delay(1); 767 } 768 if (post(cashvalue, 0)) { 769 apr(point(&x, ps->col - 1, ps->line - 1), " \ro.o\r\\_/"); 770 fflush(stdout); 771 delay(6); 772 apr(point(&x,ps->col - 1, ps->line - 1), " \ro.-\r\\_/"); 773 fflush(stdout); 774 delay(6); 775 } 776 apr(point(&x, ps->col - 1, ps->line - 1), " \ro.o\r\\_/"); 777 } 778 779 void 780 win(ps) 781 struct point *ps; 782 { 783 struct point x; 784 int j,k; 785 int boxsize; /* actually diameter of box, not radius */ 786 787 boxsize = (fast ? 10 : 4); 788 point(&x, ps->col, ps->line); 789 for (j = 1; j < boxsize; j++) { 790 for (k = 0; k < j; k++) { 791 pchar(&x, '#'); 792 x.line--; 793 } 794 for (k = 0; k < j; k++) { 795 pchar(&x, '#'); 796 x.col++; 797 } 798 j++; 799 for (k = 0; k < j; k++) { 800 pchar(&x, '#'); 801 x.line++; 802 } 803 for (k = 0; k < j; k++) { 804 pchar(&x, '#'); 805 x.col--; 806 } 807 fflush(stdout); 808 delay(1); 809 } 810 } 811 812 int 813 pushsnake() 814 { 815 int i, bonus; 816 int issame = 0; 817 struct point tmp; 818 819 /* 820 * My manual says times doesn't return a value. Furthermore, the 821 * snake should get his turn every time no matter if the user is 822 * on a fast terminal with typematic keys or not. 823 * So I have taken the call to times out. 824 */ 825 for (i = 4; i >=0; i--) 826 if (same(&snake[i], &snake[5])) 827 issame++; 828 if (!issame) 829 pchar(&snake[5], ' '); 830 /* Need the following to catch you if you step on the snake's tail */ 831 tmp.col = snake[5].col; tmp.line = snake[5].line; 832 for (i = 4; i >= 0; i--) 833 snake[i + 1] = snake[i]; 834 chase(&snake[0], &snake[1]); 835 pchar(&snake[1], SNAKETAIL); 836 pchar(&snake[0], SNAKEHEAD); 837 for (i = 0; i < 6; i++) { 838 if ((same(&snake[i], &you)) || (same(&tmp, &you))) { 839 surround(&you); 840 i = (cashvalue) % 10; 841 bonus = ((random() >> 8) & 0377) % 10; 842 ll(); 843 pr("%d\n", bonus); 844 fflush(stdout); 845 delay(30); 846 if (bonus == i) { 847 spacewarp(1); 848 #ifdef LOGGING 849 logit("bonus"); 850 #endif 851 flushi(); 852 return(1); 853 } 854 cook(); 855 if ( loot >= penalty ) { 856 printf("\nYou and your $%d have been eaten\n", cashvalue); 857 } else { 858 printf("\nThe snake ate you. You owe $%d.\n", -cashvalue); 859 } 860 #ifdef LOGGING 861 logit("eaten"); 862 #endif 863 length(moves); 864 snscore(rawscores, TOPN); 865 close(rawscores); 866 exit(0); 867 } 868 } 869 return(0); 870 } 871 872 int 873 chk(sp) 874 struct point *sp; 875 { 876 int j; 877 878 if (same(sp, &money)) { 879 pchar(sp, TREASURE); 880 return(2); 881 } 882 if (same(sp, &finish)) { 883 pchar(sp, GOAL); 884 return(3); 885 } 886 if (same(sp, &snake[0])) { 887 pchar(sp, SNAKEHEAD); 888 return(4); 889 } 890 for (j = 1; j < 6; j++) { 891 if (same(sp, &snake[j])) { 892 pchar(sp, SNAKETAIL); 893 return(4); 894 } 895 } 896 if ((sp->col < 4) && (sp->line == 0)) { 897 winnings(cashvalue); 898 if ((you.line == 0) && (you.col < 4)) 899 pchar(&you,ME); 900 return(5); 901 } 902 if (same(sp, &you)) { 903 pchar(sp, ME); 904 return(1); 905 } 906 pchar(sp, ' '); 907 return(0); 908 } 909 910 void 911 winnings(won) 912 int won; 913 { 914 struct point p; 915 916 p.line = p.col = 1; 917 if (won > 0) { 918 move(&p); 919 pr("$%d ", won); 920 } 921 } 922 923 void 924 stop(dummy) 925 int dummy; 926 { 927 signal(SIGINT, SIG_IGN); 928 ll(); 929 cook(); 930 length(moves); 931 exit(0); 932 } 933 934 void 935 suspend() 936 { 937 ll(); 938 cook(); 939 kill(getpid(), SIGTSTP); 940 raw(); 941 setup(); 942 winnings(cashvalue); 943 } 944 945 void 946 length(num) 947 int num; 948 { 949 printf("You made %d moves.\n",num); 950 } 951 952 #ifdef LOGGING 953 void 954 logit(msg) 955 char *msg; 956 { 957 time_t t; 958 959 if (logfile != NULL) { 960 time(&t); 961 fprintf(logfile, "%s $%d %dx%d %s %s", 962 getlogin(), cashvalue, lcnt, ccnt, msg, ctime(&t)); 963 fclose(logfile); 964 } 965 } 966 #endif 967