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