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