1: /* 2: * snake - crt hack game. 3: * 4: * You move around the screen with arrow keys trying to pick up money 5: * without getting eaten by the snake. hjkl work as in vi in place of 6: * arrow keys. You can leave at the exit any time. 7: * 8: * compile as follows: 9: * cc -O snake.c move.c -o snake -lm -ltermlib 10: */ 11: 12: #include "snake.h" 13: #include <pwd.h> 14: 15: /* 16: * If CHECKBUSY is defined, the file BUSY must be executable 17: * and must return a value which is used to determine the priority 18: * a which snake runs. A zero value means no nice. 19: * If BUSY does not exist, snake won't play. 20: */ 21: #ifndef BUSY 22: #define BUSY "/usr/games/lib/busy" 23: #endif 24: 25: /* 26: * This is the data file for scorekeeping. 27: */ 28: #ifndef SNAKERAWSCORES 29: #define SNAKERAWSCORES "/usr/games/lib/snakerawscores" 30: #endif 31: 32: /* 33: * If it exists, a log is kept here. Otherwise it isn't. 34: */ 35: #ifndef LOGFILE 36: #define LOGFILE "/usr/games/lib/snake.log" 37: #endif 38: 39: #define PENALTY 10 /* % penalty for invoking spacewarp */ 40: 41: #define EOT '\004' 42: #define LF '\n' 43: #define DEL '\177' 44: 45: #define ME 'I' 46: #define SNAKEHEAD 'S' 47: #define SNAKETAIL 's' 48: #define TREASURE '$' 49: #define GOAL '#' 50: 51: #define BSIZE 80 52: 53: struct point you; 54: struct point money; 55: struct point finish; 56: struct point snake[6]; 57: 58: int loot, penalty; 59: int long tl, tm=0L; 60: int argcount; 61: char **argval; 62: int moves; 63: char str[BSIZE]; 64: char stri[BSIZE]; 65: char *p; 66: char ch, savec; 67: char *kl, *kr, *ku, *kd; 68: int fast=1; 69: int repeat=1; 70: long tv; 71: char *tn; 72: 73: main(argc,argv) 74: int argc; 75: char **argv; 76: { 77: int i,k; 78: int j; 79: long time(); 80: int stop(); 81: extern char _sobuf[]; 82: 83: argcount = argc; 84: argval = argv; 85: penalty = loot = 0; 86: getcap(); 87: ccnt -= 2; lcnt -= 2; /* compensate for border */ 88: busy(); 89: time(&tv); 90: 91: for (i=1; i<argc; i++) { 92: switch(argv[i][1]) { 93: case 'd': 94: sscanf(argv[1], "-d%ld", &tv); 95: break; 96: case 'w': /* width */ 97: case 'c': /* columns */ 98: ccnt = atoi(argv[i]+2); 99: break; 100: case 'l': /* length */ 101: case 'h': /* height */ 102: case 'r': /* rows */ 103: lcnt = atoi(argv[i]+2); 104: break; 105: default: 106: printf("bad option %s\n", argv[1]); 107: } 108: } 109: 110: srand((int)tv); 111: setbuf(stdout,_sobuf); 112: i = ((lcnt < ccnt) ? lcnt : ccnt); /* min screen edge */ 113: if (i < 4) { 114: printf("Screen too small for a fair game\n"); 115: done(); 116: } 117: /* 118: * chunk is the amount of money the user gets for each $. 119: * The formula below tries to be fair for various screen sizes. 120: * We only pay attention to the smaller of the 2 edges, since 121: * that seems to be the bottleneck. 122: * This formula is a hyperbola which includes the following points: 123: * (24, $25) (original scoring algorithm) 124: * (12, $40) (experimentally derived by the "feel") 125: * (48, $15) (a guess) 126: * This will give a 4x4 screen $99/shot. We don't allow anything 127: * smaller than 4x4 because there is a 3x3 game where you can win 128: * an infinite amount of money. 129: */ 130: if (i < 12) i = 12; /* otherwise it isn't fair */ 131: /* 132: * Compensate for border. This really changes the game since 133: * the screen is two squares smaller but we want the default 134: * to be $25, and the high scores on small screens were a bit 135: * much anyway. 136: */ 137: i += 2; 138: chunk = (675.0 / (i+6)) + 2.5; /* min screen edge */ 139: 140: signal (SIGINT, stop); 141: putpad(TI); /* String to begin programs that use cm */ 142: putpad(KS); /* Put terminal in keypad transmit mode */ 143: 144: random(&finish); 145: random(&you); 146: random(&money); 147: random(&snake[0]); 148: 149: if ((orig.sg_ospeed < B9600) || 150: ((! CM) && (! TA))) fast=0; 151: for(i=1;i<6;i++) 152: chase (&snake[i], &snake[i-1]); 153: setup(); 154: mainloop(); 155: } 156: 157: /* Main command loop */ 158: mainloop() 159: { 160: int j, k; 161: 162: for (;;) { 163: int c,lastc,match; 164: 165: move(&you); 166: fflush(stdout); 167: if (((c = getchar() & 0177) <= '9') && (c >= '0')) { 168: ungetc(c,stdin); 169: j = scanf("%d",&repeat); 170: c = getchar() & 0177; 171: } else { 172: if (c != '.') repeat = 1; 173: } 174: if (c == '.') { 175: c = lastc; 176: } 177: if ((Klength > 0) && 178: (c == *KL || c == *KR || c == *KU || c == *KD)) { 179: savec = c; 180: match = 0; 181: kl = KL; 182: kr = KR; 183: ku = KU; 184: kd = KD; 185: for (j=Klength;j>0;j--){ 186: if (match != 1) { 187: match = 0; 188: if (*kl++ == c) { 189: ch = 'h'; 190: match++; 191: } 192: if (*kr++ == c) { 193: ch = 'l'; 194: match++; 195: } 196: if (*ku++ == c) { 197: ch = 'k'; 198: match++; 199: } 200: if (*kd++ == c) { 201: ch = 'j'; 202: match++; 203: } 204: if (match == 0) { 205: ungetc(c,stdin); 206: ch = savec; 207: /* Oops! 208: * This works if we figure it out on second character. 209: */ 210: break; 211: } 212: } 213: savec = c; 214: if(j != 1) c = getchar() & 0177; 215: } 216: c = ch; 217: } 218: if (!fast) flushi(); 219: lastc = c; 220: switch (c){ 221: case CTRL(z): 222: case CTRL(c): 223: suspend(); 224: continue; 225: case EOT: 226: case 'x': 227: case 0177: /* del or end of file */ 228: ll(); 229: length(moves); 230: logit("quit"); 231: done(); 232: case '!': 233: cook(); 234: putchar('\n'); 235: putchar(c); 236: fflush(stdout); 237: j = read(0,stri,BSIZE); 238: stri[j] = 0; 239: system(stri); 240: printf("READY?\n"); 241: fflush(stdout); 242: raw(); 243: c = getchar(); 244: ungetc(c,stdin); 245: putpad(KS); 246: putpad(TI); 247: point(&cursor,0,lcnt-1); 248: case CTRL(l): 249: setup(); 250: winnings(cashvalue); 251: continue; 252: case 'p': 253: case 'd': 254: snap(); 255: continue; 256: case 'w': 257: spacewarp(0); 258: continue; 259: case 'A': 260: repeat = you.col; 261: c = 'h'; 262: break; 263: case 'H': 264: case 'S': 265: repeat = you.col - money.col; 266: c = 'h'; 267: break; 268: case 'T': 269: repeat = you.line; 270: c = 'k'; 271: break; 272: case 'K': 273: case 'E': 274: repeat = you.line - money.line; 275: c = 'k'; 276: break; 277: case 'P': 278: repeat = ccnt - 1 - you.col; 279: c = 'l'; 280: break; 281: case 'L': 282: case 'F': 283: repeat = money.col - you.col; 284: c = 'l'; 285: break; 286: case 'B': 287: repeat = lcnt - 1 - you.line; 288: c = 'j'; 289: break; 290: case 'J': 291: case 'C': 292: repeat = money.line - you.line; 293: c = 'j'; 294: break; 295: } 296: for(k=1;k<=repeat;k++){ 297: moves++; 298: switch(c) { 299: case 's': 300: case 'h': 301: case '\b': 302: if (you.col >0) { 303: if((fast)||(k == 1)) 304: pchar(&you,' '); 305: you.col--; 306: if((fast) || (k == repeat) || 307: (you.col == 0)) 308: pchar(&you,ME); 309: } 310: break; 311: case 'f': 312: case 'l': 313: case ' ': 314: if (you.col < ccnt-1) { 315: if((fast)||(k == 1)) 316: pchar(&you,' '); 317: you.col++; 318: if((fast) || (k == repeat) || 319: (you.col == ccnt-1)) 320: pchar(&you,ME); 321: } 322: break; 323: case CTRL(p): 324: case 'e': 325: case 'k': 326: case 'i': 327: if (you.line > 0) { 328: if((fast)||(k == 1)) 329: pchar(&you,' '); 330: you.line--; 331: if((fast) || (k == repeat) || 332: (you.line == 0)) 333: pchar(&you,ME); 334: } 335: break; 336: case CTRL(n): 337: case 'c': 338: case 'j': 339: case LF: 340: case 'm': 341: if (you.line+1 < lcnt) { 342: if((fast)||(k == 1)) 343: pchar(&you,' '); 344: you.line++; 345: if((fast) || (k == repeat) || 346: (you.line == lcnt-1)) 347: pchar(&you,ME); 348: } 349: break; 350: } 351: 352: if (same(&you,&money)) 353: { 354: char xp[20]; 355: struct point z; 356: loot += 25; 357: if(k < repeat) 358: pchar(&you,' '); 359: do { 360: random(&money); 361: } while (money.col == finish.col && money.line == finish.line || 362: money.col < 5 && money.line == 0 || 363: money.col == you.col && money.line == you.line); 364: pchar(&money,TREASURE); 365: winnings(cashvalue); 366: continue; 367: } 368: if (same(&you,&finish)) 369: { 370: win(&finish); 371: ll(); 372: cook(); 373: printf("You have won with $%d.\n",cashvalue); 374: fflush(stdout); 375: logit("won"); 376: post(cashvalue,0); 377: length(moves); 378: done(0); 379: } 380: if (pushsnake())break; 381: } 382: fflush(stdout); 383: } 384: } 385: 386: setup(){ /* 387: * setup the board 388: */ 389: int i; 390: 391: clear(); 392: pchar(&you,ME); 393: pchar(&finish,GOAL); 394: pchar(&money,TREASURE); 395: for(i=1; i<6; i++) { 396: pchar(&snake[i],SNAKETAIL); 397: } 398: pchar(&snake[0], SNAKEHEAD); 399: drawbox(); 400: fflush(stdout); 401: } 402: 403: drawbox() 404: { 405: register int i; 406: struct point p; 407: 408: p.line = -1; 409: for (i= 0; i<ccnt; i++) { 410: p.col = i; 411: pchar(&p, '-'); 412: } 413: p.col = ccnt; 414: for (i= -1; i<=lcnt; i++) { 415: p.line = i; 416: pchar(&p, '|'); 417: } 418: p.col = -1; 419: for (i= -1; i<=lcnt; i++) { 420: p.line = i; 421: pchar(&p, '|'); 422: } 423: p.line = lcnt; 424: for (i= 0; i<ccnt; i++) { 425: p.col = i; 426: pchar(&p, '-'); 427: } 428: } 429: 430: 431: random(sp) 432: struct point *sp; 433: { 434: register int issame; 435: struct point p; 436: register int i; 437: 438: sp->col = sp->line = -1; /* impossible */ 439: do { 440: issame = 0; 441: p.col = ((rand()>>8) & 0377)% ccnt; 442: p.line = ((rand()>>8) & 0377)% lcnt; 443: 444: /* make sure it's not on top of something else */ 445: if (p.line == 0 && p.col <5) issame++; 446: if(same(&p, &you)) issame++; 447: if(same(&p, &money)) issame++; 448: if(same(&p, &finish)) issame++; 449: for (i=0; i<5; i++) 450: if(same(&p, &snake[i])) issame++; 451: 452: } while (issame); 453: *sp = p; 454: } 455: 456: busy() 457: { 458: FILE *pip, *popen(); 459: char c; 460: int b,r; 461: float a; 462: 463: #ifdef CHECKBUSY 464: if (! strcmp (argval[0], "test")) return; 465: if ((access(BUSY,1) != 0) || (pip = popen(BUSY,"r")) == NULL){ 466: printf("Sorry, no snake just now.\n"); 467: done(); 468: } 469: fscanf(pip,"%d",&b); 470: pclose(pip); 471: if (b > 20) { 472: printf("Sorry, the system is too heavily loaded right now.\n"); 473: done(); 474: } 475: nice(b); 476: #endif 477: } 478: 479: post(score, flag) 480: int score, flag; 481: { 482: int rawscores; 483: short uid = getuid(); 484: short oldbest=0; 485: short allbwho=0, allbscore=0; 486: struct passwd *p, *getpwuid(); 487: 488: /* 489: * Neg uid, 0, and 1 cannot have scores recorded. 490: */ 491: if ((uid=getuid()) > 1 && (rawscores=open(SNAKERAWSCORES,2))>=0) { 492: /* Figure out what happened in the past */ 493: read(rawscores, &allbscore, sizeof(short)); 494: read(rawscores, &allbwho, sizeof(short)); 495: lseek(rawscores, ((long)uid)*sizeof(short), 0); 496: read(rawscores, &oldbest, sizeof(short)); 497: if (flag) return (score > oldbest ? 1 : 0); 498: 499: /* Update this jokers best */ 500: if (score > oldbest) { 501: lseek(rawscores, ((long)uid)*sizeof(short), 0); 502: write(rawscores, &score, sizeof(short)); 503: printf("You bettered your previous best of $%d\n", oldbest); 504: } else 505: printf("Your best to date is $%d\n", oldbest); 506: 507: /* See if we have a new champ */ 508: p = getpwuid(allbwho); 509: if (p == NULL || score > allbscore) { 510: lseek(rawscores, (long)0, 0); 511: write(rawscores, &score, sizeof(short)); 512: write(rawscores, &uid, sizeof(short)); 513: if (p != NULL) 514: printf("You beat %s's old record of $%d!\n", p->pw_name, allbscore); 515: else 516: printf("You set a new record!\n"); 517: } else 518: printf("The highest is %s with $%d\n", p->pw_name, allbscore); 519: close(rawscores); 520: } else 521: if (!flag) 522: printf("Unable to post score.\n"); 523: return (1); 524: } 525: 526: /* 527: * Flush typeahead to keep from buffering a bunch of chars and then 528: * overshooting. This loses horribly at 9600 baud, but works nicely 529: * if the terminal gets behind. 530: */ 531: flushi() 532: { 533: stty(0, &new); 534: } 535: int mx [8] = { 536: 0, 1, 1, 1, 0,-1,-1,-1}; 537: int my [8] = { 538: -1,-1, 0, 1, 1, 1, 0,-1}; 539: float absv[8]= { 540: 1, 1.4, 1, 1.4, 1, 1.4, 1, 1.4 541: }; 542: int oldw=0; 543: chase (np, sp) 544: struct point *sp, *np; 545: { 546: /* this algorithm has bugs; otherwise the 547: snake would get too good */ 548: struct point d; 549: int w, i, wt[8]; 550: double sqrt(), v1, v2, vp, max; 551: point(&d,you.col-sp->col,you.line-sp->line); 552: v1 = sqrt( (double) (d.col*d.col + d.line*d.line) ); 553: w=0; 554: max=0; 555: for(i=0; i<8; i++) 556: { 557: vp = d.col*mx[i] + d.line*my[i]; 558: v2 = absv[i]; 559: if (v1>0) 560: vp = ((double)vp)/(v1*v2); 561: else vp=1.0; 562: if (vp>max) 563: { 564: max=vp; 565: w=i; 566: } 567: } 568: for(i=0; i<8; i++) 569: { 570: point(&d,sp->col+mx[i],sp->line+my[i]); 571: wt[i]=0; 572: if (d.col<0 || d.col>=ccnt || d.line<0 || d.line>=lcnt) 573: continue; 574: if (d.line == 0 && d.col < 5) continue; 575: if (same(&d,&money)) continue; 576: if (same(&d,&finish)) continue; 577: wt[i]= i==w ? loot/10 : 1; 578: if (i==oldw) wt [i] += loot/20; 579: } 580: for(w=i=0; i<8; i++) 581: w+= wt[i]; 582: vp = (( rand() >> 6 ) & 01777) %w; 583: for(i=0; i<8; i++) 584: if (vp <wt[i]) 585: break; 586: else 587: vp -= wt[i]; 588: if (i==8) { 589: printf("failure\n"); 590: i=0; 591: while (wt[i]==0) i++; 592: } 593: oldw=w=i; 594: point(np,sp->col+mx[w],sp->line+my[w]); 595: } 596: 597: spacewarp(w) 598: int w;{ 599: struct point p; 600: int j; 601: 602: random(&you); 603: point(&p,COLUMNS/2 - 8,LINES/2 - 1); 604: if (p.col < 0) 605: p.col = 0; 606: if (p.line < 0) 607: p.line = 0; 608: if (w) { 609: sprintf(str,"BONUS!!!"); 610: loot = loot - penalty; 611: penalty = 0; 612: } else { 613: sprintf(str,"SPACE WARP!!!"); 614: penalty += loot/PENALTY; 615: } 616: for(j=0;j<3;j++){ 617: clear(); 618: delay(5); 619: aprintf(&p,str); 620: delay(10); 621: } 622: setup(); 623: winnings(cashvalue); 624: } 625: snap() 626: { 627: struct point p; 628: int i; 629: 630: if(you.line < 3){ 631: pchar(point(&p,you.col,0),'-'); 632: } 633: if(you.line > lcnt-4){ 634: pchar(point(&p,you.col,lcnt-1),'_'); 635: } 636: if(you.col < 10){ 637: pchar(point(&p,0,you.line),'('); 638: } 639: if(you.col > ccnt-10){ 640: pchar(point(&p,ccnt-1,you.line),')'); 641: } 642: if (! stretch(&money)) if (! stretch(&finish)) delay(10); 643: if(you.line < 3){ 644: point(&p,you.col,0); 645: remove(&p); 646: } 647: if(you.line > lcnt-4){ 648: point(&p,you.col,lcnt-1); 649: remove(&p); 650: } 651: if(you.col < 10){ 652: point(&p,0,you.line); 653: remove(&p); 654: } 655: if(you.col > ccnt-10){ 656: point(&p,ccnt-1,you.line); 657: remove(&p); 658: } 659: fflush(stdout); 660: } 661: stretch(ps) 662: struct point *ps;{ 663: struct point p; 664: 665: point(&p,you.col,you.line); 666: if(abs(ps->col-you.col) < 6){ 667: if(you.line < ps->line){ 668: for (p.line = you.line+1;p.line <= ps->line;p.line++) 669: pchar(&p,'v'); 670: delay(10); 671: for (;p.line > you.line;p.line--) 672: remove(&p); 673: } else { 674: for (p.line = you.line-1;p.line >= ps->line;p.line--) 675: pchar(&p,'^'); 676: delay(10); 677: for (;p.line < you.line;p.line++) 678: remove(&p); 679: } 680: return(1); 681: } else if(abs(ps->line-you.line) < 3){ 682: p.line = you.line; 683: if(you.col < ps->col){ 684: for (p.col = you.col+1;p.col <= ps->col;p.col++) 685: pchar(&p,'>'); 686: delay(10); 687: for (;p.col > you.col;p.col--) 688: remove(&p); 689: } else { 690: for (p.col = you.col-1;p.col >= ps->col;p.col--) 691: pchar(&p,'<'); 692: delay(10); 693: for (;p.col < you.col;p.col++) 694: remove(&p); 695: } 696: return(1); 697: } 698: return(0); 699: } 700: 701: surround(ps) 702: struct point *ps;{ 703: struct point x; 704: int i,j; 705: 706: if(ps->col == 0)ps->col++; 707: if(ps->line == 0)ps->line++; 708: if(ps->line == LINES -1)ps->line--; 709: if(ps->col == COLUMNS -1)ps->col--; 710: aprintf(point(&x,ps->col-1,ps->line-1),"/*\\\r* *\r\\*/"); 711: for (j=0;j<20;j++){ 712: pchar(ps,'@'); 713: delay(1); 714: pchar(ps,' '); 715: delay(1); 716: } 717: if (post(cashvalue,1)) { 718: aprintf(point(&x,ps->col-1,ps->line-1)," \ro.o\r\\_/"); 719: delay(6); 720: aprintf(point(&x,ps->col-1,ps->line-1)," \ro.-\r\\_/"); 721: delay(6); 722: } 723: aprintf(point(&x,ps->col-1,ps->line-1)," \ro.o\r\\_/"); 724: } 725: win(ps) 726: struct point *ps; 727: { 728: struct point x; 729: int j,k; 730: int boxsize; /* actually diameter of box, not radius */ 731: 732: boxsize = fast ? 10 : 4; 733: point(&x,ps->col,ps->line); 734: for(j=1;j<boxsize;j++){ 735: for(k=0;k<j;k++){ 736: pchar(&x,'#'); 737: x.line--; 738: } 739: for(k=0;k<j;k++){ 740: pchar(&x,'#'); 741: x.col++; 742: } 743: j++; 744: for(k=0;k<j;k++){ 745: pchar(&x,'#'); 746: x.line++; 747: } 748: for(k=0;k<j;k++){ 749: pchar(&x,'#'); 750: x.col--; 751: } 752: } 753: fflush(stdout); 754: } 755: 756: pushsnake() 757: { 758: int i, bonus; 759: int issame = 0; 760: 761: /* 762: * My manual says times doesn't return a value. Furthermore, the 763: * snake should get his turn every time no matter if the user is 764: * on a fast terminal with typematic keys or not. 765: * So I have taken the call to times out. 766: */ 767: for(i=4; i>=0; i--) 768: if (same(&snake[i], &snake[5])) 769: issame++; 770: if (!issame) 771: pchar(&snake[5],' '); 772: for(i=4; i>=0; i--) 773: snake[i+1]= snake[i]; 774: chase(&snake[0], &snake[1]); 775: pchar(&snake[1],SNAKETAIL); 776: pchar(&snake[0],SNAKEHEAD); 777: for(i=0; i<6; i++) 778: { 779: if (same(&snake[i],&you)) 780: { 781: surround(&you); 782: i = (cashvalue) % 10; 783: bonus = ((rand()>>8) & 0377)% 10; 784: ll(); 785: printf("%d\n", bonus); 786: delay(30); 787: if (bonus == i) { 788: spacewarp(1); 789: logit("bonus"); 790: flushi(); 791: return(1); 792: } 793: if ( loot >= penalty ){ 794: printf("You and your $%d have been eaten\n",cashvalue); 795: } else { 796: printf("The snake ate you. You owe $%d.\n",-cashvalue); 797: } 798: logit("eaten"); 799: length(moves); 800: done(); 801: } 802: } 803: return(0); 804: } 805: 806: remove(sp) 807: struct point *sp; 808: { 809: int j; 810: 811: if (same(sp,&money)) { 812: pchar(sp,TREASURE); 813: return(2); 814: } 815: if (same(sp,&finish)) { 816: pchar(sp,GOAL); 817: return(3); 818: } 819: if (same(sp,&snake[0])) { 820: pchar(sp,SNAKEHEAD); 821: return(4); 822: } 823: for(j=1;j<6;j++){ 824: if(same(sp,&snake[j])){ 825: pchar(sp,SNAKETAIL); 826: return(4); 827: } 828: } 829: if ((sp->col < 4) && (sp->line == 0)){ 830: winnings(cashvalue); 831: if((you.line == 0) && (you.col < 4)) pchar(&you,ME); 832: return(5); 833: } 834: if (same(sp,&you)) { 835: pchar(sp,ME); 836: return(1); 837: } 838: pchar(sp,' '); 839: return(0); 840: } 841: winnings(won) 842: int won; 843: { 844: struct point p; 845: 846: p.line = p.col = 1; 847: if(won>0){ 848: move(&p); 849: printf("$%d",won); 850: } 851: } 852: 853: stop(){ 854: signal(SIGINT,1); 855: ll(); 856: length(moves); 857: done(); 858: } 859: 860: suspend() 861: { 862: char *sh; 863: 864: cook(); 865: #ifdef SIGTSTP 866: kill(getpid(), SIGTSTP); 867: #else 868: sh = getenv("SHELL"); 869: if (sh == NULL) 870: sh = "/bin/sh"; 871: system(sh); 872: #endif 873: raw(); 874: setup(); 875: winnings(cashvalue); 876: } 877: 878: length(num) 879: int num; 880: { 881: printf("You made %d moves.\n",num); 882: } 883: 884: logit(msg) 885: char *msg; 886: { 887: FILE *logfile; 888: long t; 889: 890: if ((logfile=fopen(LOGFILE, "a")) != NULL) { 891: time(&t); 892: fprintf(logfile, "%s $%d %dx%d %s %s", getlogin(), cashvalue, lcnt, ccnt, msg, ctime(&t)); 893: fclose(logfile); 894: } 895: }