Home | History | Annotate | Line # | Download | only in warp
score.c revision 1.2
      1 /* Header: /usr/src/games/warp/RCS/score.c,v 1.1 87/07/03 02:13:26 games Exp */
      2 
      3 /* Log:	score.c,v
      4  * Revision 7.0.1.2a  87/07/03  02:13:26  games
      5  * Fixed numerous long vs. int bugs in printfs, etc.
      6  *
      7  * Revision 7.0.1.2  86/10/20  12:06:56  lwall
      8  * Made all exits reset tty.
      9  *
     10  * Revision 7.0.1.1  86/10/16  10:52:47  lwall
     11  * Added Damage.  Fixed random bugs.
     12  *
     13  * Revision 7.0  86/10/08  15:13:14  lwall
     14  * Split into separate files.  Added amoebas and pirates.
     15  *
     16  */
     17 
     18 #include "EXTERN.h"
     19 #include "warp.h"
     20 #include "intrp.h"
     21 #include "object.h"
     22 #include "play.h"
     23 #include "sig.h"
     24 #include "term.h"
     25 #include "us.h"
     26 #include "util.h"
     27 #include "weapon.h"
     28 #include "INTERN.h"
     29 #include "score.h"
     30 
     31 void
     32 score_init()
     33 {
     34     Reg1 char *s;
     35     Reg2 int i;
     36     FILE *savfil;
     37 
     38     if (stat(SAVEDIR,&filestat)) {
     39 	printf("Cannot access %s\r\n",SAVEDIR);
     40 	finalize(1);
     41     }
     42     if (filestat.st_uid != geteuid()) {
     43 	printf("Warp will not run right without being setuid.\r\n");
     44 	finalize(1);
     45     }
     46     if ((filestat.st_mode & 0605) != 0605) {
     47 	printf("%s is not protected correctly (must be u+rw o+rx).\r\n",SAVEDIR);
     48 	finalize(1);
     49     }
     50 
     51 #ifdef SCOREFULL
     52     interp(longlognam, sizeof longlognam, "%N");
     53     for (i=strlen(longlognam); i<24; i++)
     54 	longlognam[i] = ' ';	/* make sure it is 24 long for strncmp */
     55     longlognam[24] = '\0';
     56 #else
     57     interp(longlognam, sizeof longlognam, "%L");
     58     for (i=strlen(longlognam); i<8; i++)
     59 	longlognam[i] = ' ';	/* make sure it is 8 long for strncmp */
     60     longlognam[8] = '\0';
     61 #endif
     62 
     63     if (scorespec)
     64 	wscore();
     65 
     66     Sprintf(savefilename, "save.%s", logname);
     67 
     68     savfil = experimenting ? NULL : fopen(savefilename,"r");
     69     if (savfil != NULL && fgets(spbuf,100,savfil) != NULL) {
     70 	char tmpbuf[80];
     71 
     72 	spbuf[strlen(spbuf)-1] = '\0';
     73 	if (fgets(tmpbuf,80,savfil) != NULL) {
     74 	    int processnum;
     75 
     76 	    tmpbuf[strlen(tmpbuf)-1] = '\0';
     77 	    printf("You seem to have left a game %s.\r\n",tmpbuf+9);
     78 	    s = index(tmpbuf+9, ',');
     79 	    *s = '\0';
     80 	    processnum = atoi(s+11);
     81 	    if (kill(processnum, SIGINT)) {
     82 					/* does process not exist? */
     83 					/* (warp ignores SIGINT) */
     84 		printf("\r\n\
     85 That process does not seem to exist anymore, so you'll have to start the\r\n");
     86 		printf(
     87 "last wave over.\r\n\n");
     88 		printf(
     89 "                      [type anything to continue]");
     90 		Fflush(stdout);
     91 		eat_typeahead();
     92 		getcmd(tmpbuf);
     93 		if (*tmpbuf == INTRCH)
     94 		    finalize(0);
     95 		printf("\r\n");
     96 	    }
     97 	    else {
     98 		if (strcmp(term+8,tmpbuf+23)) {
     99 		    printf(
    100 "That is not your current terminal--you are on %s.\r\n", term+5);
    101 		    printf("\r\nYour options:\r\n");
    102 		    printf("   1) Exit and find the terminal it's running on\r\n");
    103 		}
    104 		else {
    105 		    printf("\r\nYour options:\r\n");
    106 		    printf("   1) Exit and try to foreground it\r\n");
    107 		}
    108 		printf("   2) Let me terminate the other game\r\n\n");
    109 		printf("What do you want to do? ");
    110 		Fflush(stdout);
    111 		eat_typeahead();
    112 		getcmd(tmpbuf);
    113 		printf("\r\n");
    114 		if (*tmpbuf == INTRCH)
    115 		    finalize(0);
    116 		if (*tmpbuf == '1') {
    117 		    printf(
    118 "If you don't succeed, come back and do option 2 instead.  Good luck.\r\n");
    119 		    finalize(0);
    120 		}
    121 		printf(
    122 "Ok, hang on a few moments \r\n");
    123 		Fclose(savfil);
    124 		if (kill(processnum, SIGQUIT)) {
    125 		    printf("Unable to kill process #%d!\r\n",processnum);
    126 		    roundsleep(2);
    127 		}
    128 		else {
    129 #ifdef SIGCONT
    130 		    kill(processnum, SIGCONT);
    131 #endif
    132 		    for (i=15; i; --i) {
    133 			sleep(1);
    134 			if (kill(processnum,SIGINT))
    135 					/* does process not exist? */
    136 					/* (warp ignores SIGINT) */
    137 			    break;
    138 		    }
    139 		    didkill++;
    140 		}
    141 		savfil = fopen(savefilename,"r");
    142 		if (savfil != NULL) {
    143 		    Fgets(spbuf,100,savfil);
    144 		}
    145 	    }
    146 	}
    147     }
    148     else
    149 	savfil = NULL;
    150     if (savfil == NULL) {
    151 	totalscore = smarts = cumsmarts = wave = 0;
    152 	numents = 5;
    153 	numbases = 3;
    154     }
    155     else {
    156 	totalscore = atol(spbuf+9);
    157 	smarts = atoi(spbuf+20);
    158 	cumsmarts = atoi(spbuf+24);
    159 	numents = atoi(spbuf+30);
    160 	numbases = atoi(spbuf+33);
    161 	wave = atoi(spbuf+36);
    162 	apolspec = (spbuf[40] == 'a');
    163 	beginner   = (spbuf[41] == 'b');
    164 	crushspec  = (spbuf[42] == 'c');
    165 	gornspec   = (spbuf[43] == 'g');
    166 	massacre   = (spbuf[44] == 'm');
    167 	romspec    = (spbuf[45] == 'r');
    168 	tholspec   = (spbuf[46] == 't');
    169 	lowspeed   = (spbuf[47] == 'l') || lowspeed;
    170 	amoebaspec = (spbuf[48] == '&');
    171 	Fclose(savfil);
    172     }
    173 
    174     if (!ismarts) {
    175 	ismarts = 1;
    176 	clear();
    177 	page(NEWSFILE,FALSE);
    178 	if (smarts) {
    179 	    printf("\r\nSaved game: SCORE DIFF CUMDIFF ENTERPRISES BASES WAVE");
    180 	    printf("\r\n          %7ld  %2d   %4d        %1d        %1d   %3d",
    181 		totalscore,smarts,cumsmarts,numents,numbases,wave);
    182 	}
    183 	printf("\r\nWould you like instructions? ");
    184 	Fflush(stdout);
    185 	eat_typeahead();
    186 	getcmd(buf);
    187 	printf("\r\n");
    188 	if (*buf == INTRCH)
    189 	    finalize(0);
    190 	if (*buf == 'Y' || *buf == 'y') {
    191 	    page(HELPFILE,FALSE);
    192 	    printf("\r\nWould you like to play easy games for a while? ");
    193 	    Fflush(stdout);
    194 	    eat_typeahead();
    195 	    getcmd(buf);
    196 	    printf("\r\n");
    197 	    if (*buf == 'Y' || *buf == 'y') {
    198 		beginner = TRUE;
    199 		lowspeed = TRUE;
    200 	    }
    201 	}
    202     }
    203     if (!smarts)
    204 	smarts = ismarts;
    205 }
    206 
    207 void
    208 wscore()
    209 {
    210     clear();
    211     printf("                             TOP WARPISTS\r\n\n");
    212     printf("RANK  WHO                     AKA        SCORE DIFF  CUMDIFF  WHEN\r\n");
    213     page(SCOREBOARD,TRUE);
    214     printf("                     [Type anything to continue]");
    215     Fflush(stdout);
    216     getcmd(spbuf);
    217     if (*spbuf == INTRCH)
    218 	finalize(0);
    219     clear();
    220     printf("                        TOP LOW-SPEED WARPISTS\r\n\n");
    221     printf("RANK  WHO                     AKA        SCORE DIFF  CUMDIFF  WHEN\r\n");
    222     page(LSCOREBOARD,TRUE);
    223     printf("                     [Type anything to continue]");
    224     Fflush(stdout);
    225     getcmd(spbuf);
    226     if (*spbuf == INTRCH)
    227 	finalize(0);
    228     clear();
    229     printf("                          TOP FUNNY WARPISTS\r\n\n");
    230     printf("RANK  WHO                     AKA        SCORE DIFF  CUMDIFF  WHEN\r\n");
    231     page(FSCOREBOARD,TRUE);
    232     printf("                     [Type anything to continue]");
    233     Fflush(stdout);
    234     getcmd(spbuf);
    235     if (*spbuf == INTRCH)
    236 	finalize(0);
    237     clear();
    238     printf("          GAMES SAVED OR IN PROGRESS\r\n\n");
    239     printf("WHO           SCORE  DF   CDF  E  B  WV  FLAGS\r\n");
    240     resetty();
    241     Sprintf(spbuf,"/bin/cat %ssave.*",SAVEDIR);
    242 #ifndef lint
    243     execl("/bin/sh", "sh", "-c", spbuf, 0);
    244 #endif
    245     finalize(1);
    246 }
    247 
    248 
    249 void
    250 display_status()
    251 {
    252     Reg1 int tmp;
    253     static char *status_names[] = {"Impl", "Warp", "Base", "****" };
    254 
    255     if (oldstatus != status) {
    256 	Sprintf(spbuf,"%-4s",status_names[status]);
    257 	mvaddstr(0,0, spbuf);
    258 	oldstatus = status;
    259     }
    260     if (ent) {
    261 	if (ent->energy != oldeenergy) {
    262 	    oldeenergy = ent->energy;
    263 	    Sprintf(spbuf,"%4ld",oldeenergy);
    264 	    mvaddstr(0,8, spbuf);
    265 	}
    266 	if (etorp != oldetorp) {
    267 	    Sprintf(spbuf,"%2d",etorp);
    268 	    mvaddstr(0,13, spbuf);
    269 	    oldetorp = etorp;
    270 	}
    271     }
    272     else {
    273 	if (etorp >= 0) {
    274 	    etorp = -1;
    275 	    mvaddstr(0,8,"*******");
    276 	    damage = 0;
    277 	}
    278     }
    279     if (base) {
    280 	if (base->energy != oldbenergy) {
    281 	    oldbenergy = base->energy;
    282 	    Sprintf(spbuf,"%5ld",oldbenergy);
    283 	    mvaddstr(0,19, spbuf);
    284 	}
    285 	if (btorp != oldbtorp) {
    286 	    Sprintf(spbuf,"%3d",btorp);
    287 	    mvaddstr(0,25, spbuf);
    288 	    oldbtorp = btorp;
    289 	}
    290     }
    291     else {
    292 	if (btorp >= 0) {
    293 	    btorp = -1;
    294 	    mvaddstr(0,19,"*********");
    295 	}
    296     }
    297     if (damage) {
    298 	if (!olddamage)
    299 	    mvaddstr(0,42,"*** ");
    300 	if (damage > 1 || !damflag[dam]) {
    301 	    do {
    302 		if (++dam == MAXDAMAGE)
    303 		    dam = 0;
    304 	    } while (!damflag[dam]);
    305 	}
    306 	if (!--damflag[dam]) {
    307 	    olddamage = damage;
    308 	    damage--;
    309 	    Sprintf(spbuf,"%s OK ***       ",dammess[dam]);
    310 	    spbuf[15] = '\0';
    311 	    mvaddstr(0,46,spbuf);
    312 	}
    313 	else if (dam == NOSHIELDS) {
    314 	    olddamage = damage;
    315 	    tmp = (34 - damflag[dam]) * 3 - rand_mod(3);
    316 	    if (tmp < 0)
    317 		tmp = 0;
    318 	    Sprintf(spbuf,"%d%% %s ***       ",tmp,dammess[dam]);
    319 	    spbuf[15] = '\0';
    320 	    mvaddstr(0,46,spbuf);
    321 	}
    322 	else if (dam != lastdam || !olddamage) {
    323 	    olddamage = damage;
    324 	    Sprintf(spbuf,"NO %s ***       ",dammess[dam]);
    325 	    spbuf[15] = '\0';
    326 	    mvaddstr(0,46,spbuf);
    327 	}
    328 	if (status < 2) {
    329 	    if (dam == NOIMPULSE && !entmode)
    330 		status = entmode = 1;
    331 	    if (dam == NOWARP && entmode)
    332 		status = entmode = 0;
    333 	}
    334 	tmp = damflag[dam] * damage;
    335 	Sprintf(spbuf,"%3d.%1d ETR",tmp/10,tmp%10);
    336 	mvaddstr(0,69,spbuf);
    337 	lastdam = dam;
    338     }
    339     else {
    340 	if (olddamage) {
    341 	    Sprintf(spbuf,"Stars: %-3d Stardate",numstars);
    342 	    mvaddstr(0,42,spbuf);
    343 	    lastdam = -1;
    344 	    olddamage = 0;
    345 	    oldcurscore = -1;
    346 	}
    347 	else if (numstars != oldstrs) {
    348 	    Sprintf(spbuf,"%-3d",numstars);
    349 	    mvaddstr(0,49, spbuf);
    350 	}
    351 	oldstrs = numstars;
    352     }
    353     if (numenemies != oldenemies) {
    354 	Sprintf(spbuf,"%-3d",numenemies);
    355 	mvaddstr(0,38, spbuf);
    356 	oldenemies = numenemies;
    357     }
    358     if (tmp = timer%10) {
    359 	Sprintf(spbuf,"%1d",tmp);
    360 	mvaddstr(0,67, spbuf);
    361     }
    362     else {
    363 	Sprintf(spbuf,"%5d.%1d",timer/10+smarts*100,tmp);
    364 	mvaddstr(0,61, spbuf);
    365     }
    366     if ((!damage || !damflag[dam]) && curscore != oldcurscore) {
    367 	Sprintf(spbuf,"%9ld",curscore);
    368 	mvaddstr(0,69, spbuf);
    369 	oldcurscore = curscore;
    370     }
    371 }
    372 
    373 void
    374 wavescore()
    375 {
    376     double power, effectscore, starscore, pi_over_2;
    377     long bonuses;
    378     long tmp;
    379     FILE *mapfp;
    380     int row;
    381     double pow();
    382 #ifndef lint
    383     double atan2();
    384 #endif
    385 
    386     clear();
    387     if (curscore > possiblescore)
    388 	curscore = possiblescore;
    389     pi_over_2 = 3.14159265 / 2.0;
    390     power = pow((double)inumenemies+     /* total number of enemies */
    391 			inumroms*2+      /* count roms 3 times */
    392 			inumgorns+       /* count gorns 2 times */
    393 			inumthols+       /* count thols 2 times */
    394 			inumapollos*4+   /* count apollo 5 times */
    395 			inumcrushes*3+   /* count crushers 4 times */
    396 			inumamoebas*5	 /* count amoebas 6 times */
    397 	    , 0.50) *                    /* skew it a little */
    398 	    (double)smarts;              /* average energy and intelligence */
    399     if (inumstars < 350 && inumenemies > 5)
    400 	    power += (350.0 - (double)inumstars) * ((double)inumenemies - 5.0);
    401     if (inumstars > 850 && inumenemies > 2)
    402 	    power += ((double)inumstars - 850.0) * ((double)inumenemies - 2.0);
    403 #ifndef lint
    404     effectscore = ((double)curscore / possiblescore) *
    405 	atan2(power, (double) timer + 1.0) / pi_over_2;
    406 #else
    407     effectscore = pi_over_2;
    408 #endif
    409     if (inumstars)
    410 	starscore = (double) numstars / (double) inumstars;
    411     else
    412 	starscore = 1.0;
    413     wave++;
    414     Sprintf(spbuf,"Wave = %d, Difficulty = %d, cumulative difficulty = %d",
    415 	 wave, smarts, cumsmarts);
    416     mvaddstr(1, 13+(smarts<10), spbuf);
    417     mvaddstr( 4, 68, " BONUS");
    418     Sprintf(spbuf,"Efficiency rating:       %1.8f (diff=%0.2f,time=%d)",
    419 	 effectscore, power, timer + 1);
    420     mvaddstr( 5,5, spbuf);
    421     if (effectscore < 0.8)
    422 	bonuses = tmp = 0;
    423     else
    424 	bonuses = tmp = (long) ((effectscore-0.8) * smarts * 1000);
    425     Sprintf(spbuf, "%6ld", tmp);
    426     mvaddstr( 5, 68, spbuf);
    427     Sprintf(spbuf,"Star save ratio:         %1.8f (%d/%d)",
    428 	starscore, numstars, inumstars);
    429     mvaddstr( 6,5, spbuf);
    430 #ifndef lint
    431     bonuses += tmp = (long) (((double)curscore / possiblescore) *
    432 	(starscore*starscore) * smarts * 20);
    433 #endif
    434     Sprintf(spbuf, "%6ld", tmp);
    435     mvaddstr( 6, 68, spbuf);
    436     row = 7;
    437     if (inuminhab != numinhab) {
    438 	Sprintf(spbuf, "Inhabited stars depopulated:  %5d", inuminhab-numinhab);
    439 	mvaddstr(row,5, spbuf);
    440 	bonuses += tmp = (long) (inuminhab-numinhab) * -500;
    441 	Sprintf(spbuf, "%6ld", tmp);
    442 	mvaddstr(row, 68, spbuf);
    443 	row++;
    444     }
    445     if (inumfriends != numfriends) {
    446 	Sprintf(spbuf, "Friendly craft destroyed:     %5d",
    447 	    inumfriends-numfriends);
    448 	mvaddstr(row,5, spbuf);
    449 	bonuses += tmp = (long) (inumfriends-numfriends) * -250;
    450 	Sprintf(spbuf, "%6ld", tmp);
    451 	mvaddstr(row, 68, spbuf);
    452 	row++;
    453     }
    454     if (deadmudds) {
    455 	mvaddstr(row,5,"For destroying Harry Mudd:");
    456 	bonuses += tmp = (long) rand_mod(deadmudds * 20 + 1) - deadmudds*10;
    457 	Sprintf(spbuf, "%6ld", tmp);
    458 	mvaddstr(row, 68, spbuf);
    459 	row++;
    460     }
    461     if (bombed_out) {
    462 	mvaddstr(row,5, "For running away from reality:");
    463 	bonuses += tmp = (long) -possiblescore/2;
    464 	Sprintf(spbuf, "%6ld", tmp);
    465 	mvaddstr(row, 68,  spbuf);
    466 	row++;
    467     }
    468     if (row < 9)
    469 	row++;
    470     Sprintf(spbuf, "Enterprise: %-9s%5d remaining",
    471 	!ient?"":ent?"saved":"destroyed", numents);
    472     mvaddstr(row,5, spbuf);
    473     bonuses += tmp = ent && !bombed_out ? (smarts+1)*15 : 0;
    474     Sprintf(spbuf, "%6ld", tmp);
    475     mvaddstr(row, 68, spbuf);
    476     row++;
    477     Sprintf(spbuf, "Base: %-9s      %5d remaining",
    478 	!ibase?"":base?"saved":"destroyed", numbases);
    479     mvaddstr(row,5, spbuf);
    480     bonuses += tmp = base && !bombed_out ? (smarts+1)*10 : 0;
    481     Sprintf(spbuf, "%6ld", tmp);
    482     mvaddstr(row, 68,  spbuf);
    483     if (beginner) {
    484 	mvaddstr(13+(row>11),19, "(Special games count only a tenth as much)");
    485 	curscore /= 10;
    486 	bonuses /= 10;
    487     }
    488     Sprintf(spbuf, "Previous point total:%10ld",lastscore);
    489     mvaddstr(15,24, spbuf);
    490     Sprintf(spbuf, "Points this round:   %10ld",curscore);
    491     mvaddstr(16,24, spbuf);
    492     Sprintf(spbuf, "Bonuses:             %10ld",bonuses);
    493     mvaddstr(17,24, spbuf);
    494     totalscore = lastscore + curscore + bonuses;
    495     Sprintf(spbuf, "New point total:     %10ld",totalscore);
    496     mvaddstr(18,24, spbuf);
    497     if (lastscore / ENTBOUNDARY < totalscore / ENTBOUNDARY) {
    498 	mvaddstr(row-1,42,"+ 1 new");
    499 	numents++;
    500     }
    501     else if (numents>0 &&
    502 	lastscore / ENTBOUNDARY > totalscore / ENTBOUNDARY) {
    503 	mvaddstr(row-1,42,"- 1 obsolete");
    504 	numents--;
    505     }
    506     if (lastscore / BASEBOUNDARY < totalscore / BASEBOUNDARY) {
    507 	mvaddstr(row,42,"+ 1 new");
    508 	numbases++;
    509     }
    510     else if (numbases>0 &&
    511 	lastscore / BASEBOUNDARY > totalscore / BASEBOUNDARY) {
    512 	mvaddstr(row,42,"- 1 obsolete");
    513 	numbases--;
    514     }
    515     if (starscore < 0.8 && inumstars > 200 && numstars > 50) {
    516 	Sprintf(spbuf, "smap.%d",rand_mod(MAPS-PERMMAPS)+PERMMAPS);
    517 	if ((mapfp = fopen(spbuf,"w")) != NULL) {
    518 	    Reg1 OBJECT *obj;
    519 
    520 	    fprintf(mapfp,"%d\n",numstars);
    521 	    for (obj = root.next; obj != &root; obj = obj->next) {
    522 		if (obj->type == Star) {
    523 		    fprintf(mapfp,"%d %d\n",obj->posy,obj->posx);
    524 		}
    525 	    }
    526 	    Fclose(mapfp);
    527 	}
    528     }
    529 }
    530 
    531 void
    532 score()
    533 {
    534     char tmp, *retval, cdate[30];
    535     Reg1 FILE *logfd;
    536     Reg2 FILE *outfd;
    537     Reg3 int i;
    538     long nowtime, time();
    539     char *scoreboard;
    540 
    541     for (i=0; link(LOGFILE, LOCKFILE) == -1 && i<10; i++)
    542 	sleep(1);
    543     nowtime = time((long *)0);
    544     strcpy(cdate,ctime(&nowtime));
    545     if ((logfd = fopen(LOGFILE,"a")) != NULL) {
    546 	fprintf(logfd,
    547 	    "%-24s%-9s%7ld%c%2d %4d %s",
    548 	    realname, logname, totalscore, c,smarts, cumsmarts, cdate);
    549 	Fclose(logfd);
    550     }
    551     strcpy(cdate+11,cdate+20);
    552     if (beginner)
    553 	scoreboard = FSCOREBOARD;
    554     else if (lowspeed)
    555 	scoreboard = LSCOREBOARD;
    556     else
    557 	scoreboard = SCOREBOARD;
    558     if (eaccess(scoreboard,0)) {
    559 	if ((logfd = fopen(scoreboard,"w")) != NULL)
    560 	    Fclose(logfd);
    561     }
    562     if ((logfd = fopen(scoreboard,"r")) != NULL &&
    563 	(outfd = fopen(TMPSCOREBOARD,"w")) != NULL) {
    564 	for (i=0; i<20; i++) {
    565 	    if ((retval = fgets(buf, 100, logfd)) == NULL)
    566 		break;
    567 	    if (atol(buf+32) < totalscore)
    568 		break;
    569 	    if (strnEQ(buf+COMPOFF,COMPNAME,COMPLEN)) {
    570 		i = 100;
    571 		break;
    572 	    }
    573 	    fprintf(outfd, "%s", buf);
    574 	}
    575 	if (i == 100) {
    576 	    mvaddstr(20,21, "You did not better your previous score");
    577 	    Fclose(outfd);
    578 	    unlink(TMPSCOREBOARD);
    579 	}
    580 	else if (i < 20) {
    581 	    fprintf(outfd, "%-24s%-8s%8ld%c %2d    %4d    %s",
    582 		realname, logname, totalscore, c,smarts, cumsmarts, cdate);
    583 	    i++;
    584 	    Sprintf(spbuf, "    Congratulations--you've placed %d%s",
    585 	      i, i==1?"st":(i==2?"nd":(i==3?"rd":"th")));
    586 	    if (retval != NULL) {
    587 		if (strnNE(buf+COMPOFF,COMPNAME,COMPLEN)) {
    588 		    fprintf(outfd, "%s", buf);
    589 		    i++;
    590 		}
    591 		else
    592 		    strcpy(spbuf,"Congratulations--you've bettered your score");
    593 		while (i<20) {
    594 		    if (fgets(buf, 100, logfd) == NULL)
    595 			break;
    596 		    if (strnNE(buf+COMPOFF,COMPNAME,COMPLEN)) {
    597 			fprintf(outfd, "%s", buf);
    598 			i++;
    599 		    }
    600 		}
    601 	    }
    602 	    mvaddstr(20,19, spbuf);
    603 	    Fclose(logfd);
    604 	    Fclose(outfd);
    605 	    while (unlink(scoreboard) == 0)
    606 		;
    607 	    link(TMPSCOREBOARD,scoreboard);
    608 	    unlink(TMPSCOREBOARD);
    609 	    logfd = fopen(scoreboard,"r");
    610 	}
    611 	else {
    612 	    mvaddstr(20,22,"You did not place within the top 20");
    613 	    Fclose(outfd);
    614 	}
    615     }
    616     else {
    617 	Sprintf(spbuf,"(Cannot access %s file, error %d)",
    618 	    (logfd==NULL?"log":"tmp"),errno);
    619 	mvaddstr(20,22,spbuf);
    620     }
    621     move(23,0,0);
    622     erase_eol();
    623     mvaddstr(23,11,
    624 	"[Hit space for scoreboard, 'r' for new game, 'q' to quit]");
    625     unlink(LOCKFILE);
    626     Fflush(stdout);
    627     eat_typeahead();
    628     do {
    629 	getcmd(&tmp);
    630     } while (tmp != INTRCH && tmp != BREAKCH && !index(" rqQ",tmp));
    631     if (index("qQr",tmp)) {
    632 	justonemoretime = (tmp == 'r');
    633 	if (logfd != NULL)
    634 	    Fclose(logfd);
    635     }
    636     else {
    637 	clear();
    638 	if (logfd != NULL) {
    639 	    fseek(logfd, 0L, 0);
    640 	    if (beginner)
    641 		mvaddstr(0,31,"TOP FUNNY WARPISTS");
    642 	    else if (lowspeed)
    643 		mvaddstr(0,29,"TOP LOW-SPEED WARPISTS");
    644 	    else
    645 		mvaddstr(0,33,"TOP WARPISTS");
    646 	    mvaddstr(2,0,"RANK  WHO                     AKA        SCORE DIFF  CUMDIFF  WHEN");
    647 	    for (i=1; i<=20; i++) {
    648 		if (fgets(buf, 100, logfd) == NULL)
    649 		    break;
    650 		buf[strlen(buf)-1] = '\0';
    651 		Sprintf(spbuf, " %2d   %s", i, buf);
    652 		mvaddstr(i+2,0, spbuf);
    653 	    }
    654 	    Fclose(logfd);
    655 	}
    656 	roundsleep(1);
    657 	mvaddstr(23,25,"Would you like to play again?");
    658 	eat_typeahead();
    659 	do {
    660 	    getcmd(&tmp);
    661 	} while (tmp != INTRCH && tmp != BREAKCH && !index("nNyY \n\r",tmp));
    662 	if (tmp == 'n' || tmp == 'N' || tmp == INTRCH || tmp == BREAKCH)
    663 	    justonemoretime = FALSE;
    664     }
    665 
    666     smarts = ismarts;
    667     totalscore = cumsmarts = wave = 0;
    668     numents = 5;
    669     numbases = 3;
    670     apolspec = FALSE;
    671     beginner   = FALSE;
    672     crushspec  = FALSE;
    673     gornspec   = FALSE;
    674     massacre   = (ismarts >= 40);
    675     romspec    = FALSE;
    676     tholspec   = FALSE;
    677 }
    678 
    679 void
    680 save_game()
    681 {
    682     FILE *savfil;
    683 
    684     if (experimenting)
    685 	return;
    686     if ((savfil = fopen(savefilename,"w")) == NULL) {
    687 	resetty();
    688 	printf("Cannot save game\r\n");
    689 	finalize(1);
    690     }
    691     fprintf(savfil, "%-8s %10ld, %2d,%5d,%2d,%2d,%3d %c%c%c%c%c%c%c%c\n",
    692 	logname, totalscore, smarts, cumsmarts, numents, numbases, wave,
    693 	apolspec ? 'a' : ' ',
    694 	beginner   ? 'b' : ' ',
    695 	crushspec  ? 'c' : ' ',
    696 	gornspec   ? 'g' : ' ',
    697 	massacre   ? 'm' : ' ',
    698 	romspec    ? 'r' : ' ',
    699 	tholspec   ? 't' : ' ',
    700 	lowspeed   ? 'l' : ' ',
    701 	amoebaspec ? '&' : ' '
    702     );
    703     Fclose(savfil);
    704     resetty();
    705     if (panic)
    706 	finalize(0);
    707     clear();
    708     finalize(0);
    709 }
    710