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