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