More magic-number hunting -- BASEMAX this time.
[super-star-trek.git] / setup.c
1 #include <time.h>
2 #include <sys/stat.h>
3 #include "sst.h"
4
5 #ifdef __linux__
6 static long filelength(int fd) {
7 struct stat buf;
8     fstat(fd, &buf);
9     return buf.st_size;
10 }
11 #endif
12
13 void prelim(void) {
14         skip(2);
15         prout("-SUPER- STAR TREK");
16         skip(1);
17 #ifdef __HISTORICAL__
18         prout("Latest update-21 Sept 78");
19         skip(1);
20 #endif /* __HISTORICAL__ */
21 }
22
23 void freeze(int boss) {
24         FILE *fp;
25         int key;
26         if (boss) {
27                 strcpy(citem, "emsave.trk");
28         }
29         else {
30                 if ((key = scan()) == IHEOL) {
31                         proutn("File name: ");
32                         key = scan();
33                 }
34                 if (key != IHALPHA) {
35                         huh();
36                         return;
37                 }
38                 chew();
39                 if (strchr(citem, '.') == NULL) {
40                         strcat(citem, ".trk");
41                 }
42         }
43         if ((fp = fopen(citem, "wb")) == NULL) {
44                 proutn("Can't freeze game as file ");
45                 proutn(citem);
46                 skip(1);
47                 return;
48         }
49         strcpy(game.magic, SSTMAGIC);
50         fwrite(&game, sizeof(game), 1, fp);
51
52         fclose(fp);
53
54         /* I hope that's enough! */
55 }
56
57
58 int thaw(void) {
59         FILE *fp;
60         int key;
61
62         game.passwd[0] = '\0';
63         if ((key = scan()) == IHEOL) {
64                 proutn("File name: ");
65                 key = scan();
66         }
67         if (key != IHALPHA) {
68                 huh();
69                 return 1;
70         }
71         chew();
72         if (strchr(citem, '.') == NULL) {
73                 strcat(citem, ".trk");
74         }
75         if ((fp = fopen(citem, "rb")) == NULL) {
76                 proutn("Can't find game file ");
77                 proutn(citem);
78                 skip(1);
79                 return 1;
80         }
81         fread(&game, sizeof(game), 1, fp);
82         if (feof(fp) || ftell(fp) != filelength(fileno(fp)) || strcmp(game.magic, SSTMAGIC)) {
83                 prout("Game file format is bad, should begin with " SSTMAGIC);
84                 skip(1);
85                 fclose(fp);
86                 return 1;
87         }
88
89         fclose(fp);
90
91         return 0;
92 }
93
94 void abandn(void) {
95         int nb, l;
96
97         chew();
98         if (condit==IHDOCKED) {
99                 if (ship!=IHE) {
100                         prout("You cannot abandon Ye Faerie Queene.");
101                         return;
102                 }
103         }
104         else {
105                 /* Must take shuttle craft to exit */
106                 if (game.damage[DSHUTTL]==-1) {
107                         prout("Ye Faerie Queene has no shuttle craft.");
108                         return;
109                 }
110                 if (game.damage[DSHUTTL]<0) {
111                         prout("Shuttle craft now serving Big Mac's.");
112                         return;
113                 }
114                 if (game.damage[DSHUTTL]>0) {
115                         prout("Shuttle craft damaged.");
116                         return;
117                 }
118                 if (landed==1) {
119                         prout("You must be aboard the Enterprise.");
120                         return;
121                 }
122                 if (iscraft!=1) {
123                         prout("Shuttle craft not currently available.");
124                         return;
125                 }
126                 /* Print abandon ship messages */
127                 skip(1);
128                 prouts("***ABANDON SHIP!  ABANDON SHIP!");
129                 skip(1);
130                 prouts("***ALL HANDS ABANDON SHIP!");
131                 skip(2);
132                 prout("Captain and crew escape in shuttle craft.");
133                 prout("Remainder of ship's complement beam down");
134                 prout("to nearest habitable planet.");
135                 if (game.state.rembase==0) {
136                         /* Ops! no place to go... */
137                         finish(FABANDN);
138                         return;
139                 }
140                 /* If at least one base left, give 'em the Faerie Queene */
141                 skip(1);
142                 icrystl = 0; /* crystals are lost */
143                 nprobes = 0; /* No probes */
144                 prout("You are captured by Klingons and released to");
145                 prout("the Federation in a prisoner-of-war exchange.");
146                 nb = Rand()*game.state.rembase+1;
147                 /* Set up quadrant and position FQ adjacient to base */
148                 if (quadx!=game.state.baseqx[nb] || quady!=game.state.baseqy[nb]) {
149                         quadx = game.state.baseqx[nb];
150                         quady = game.state.baseqy[nb];
151                         sectx = secty = 5;
152                         newqad(1);
153                 }
154                 for (;;) {
155                         /* position next to base by trial and error */
156                         game.quad[sectx][secty] = IHDOT;
157                         for (l = 1; l <= QUADSIZE; l++) {
158                                 sectx = 3.0*Rand() - 1.0 + basex;
159                                 secty = 3.0*Rand() - 1.0 + basey;
160                                 if (sectx >= 1 && sectx <= QUADSIZE &&
161                                         secty >= 1 && secty <= QUADSIZE &&
162                                         game.quad[sectx][secty] == IHDOT) break;
163                         }
164                         if (l < 11) break; /* found a spot */
165                         sectx=5;
166                         secty=5;
167                         newqad(1);
168                 }
169         }
170         /* Get new commission */
171         game.quad[sectx][secty] = ship = IHF;
172         prout("Starfleet puts you in command of another ship,");
173         prout("the Faerie Queene, which is antiquated but,");
174         prout("still useable.");
175         if (icrystl!=0) prout("The dilithium crystals have been moved.");
176         imine=0;
177         iscraft=0; /* Gallileo disappears */
178         /* Resupply ship */
179         condit=IHDOCKED;
180         for (l = 1; l <= NDEVICES; l++) game.damage[l] = 0.0;
181         game.damage[DSHUTTL] = -1;
182         energy = inenrg = 3000.0;
183         shield = inshld = 1250.0;
184         torps = intorps = 6;
185         lsupres=inlsr=3.0;
186         shldup=0;
187         warpfac=5.0;
188         wfacsq=25.0;
189         return;
190 }
191         
192 void setup(int needprompt) {
193         int i,j, krem, klumper;
194         int ix, iy;
195 #ifdef DEBUG
196         idebug = 0;
197 #endif
198         //  Decide how many of everything
199         if (choose(needprompt)) return; // frozen game
200         // Prepare the Enterprise
201         alldone = gamewon = 0;
202         ship = IHE;
203         energy = inenrg = 5000.0;
204         shield = inshld = 2500.0;
205         shldchg = shldup = 0;
206         inlsr = 4.0;
207         lsupres = 4.0;
208         iran8(&quadx, &quady);
209         iran10(&sectx, &secty);
210         torps = intorps = 10;
211         nprobes = (int)(3.0*Rand() + 2.0);      /* Give them 2-4 of these wonders */
212         warpfac = 5.0;
213         wfacsq = warpfac * warpfac;
214         for (i=0; i <= NDEVICES; i++) game.damage[i] = 0.0;
215         // Set up assorted game parameters
216         batx = baty = 0;
217         game.state.date = indate = 100.0*(int)(31.0*Rand()+20.0);
218         game.state.killk = game.state.killc = nkinks = nhelp = resting = casual = game.state.nromkl = 0;
219         isatb = iscate = imine = icrystl = icraft = game.state.nsckill = game.state.nplankl = 0;
220         game.state.starkl = game.state.basekl = 0;
221         iscraft = 1;
222         landed = -1;
223         alive = 1;
224         docfac = 0.25;
225         for (i = 1; i <= GALSIZE; i++)
226                 for (j = 1; j <= GALSIZE; j++) game.state.newstuf[i][j] = game.starch[i][j] = 0;
227         // Initialize times for extraneous events
228         game.future[FSNOVA] = game.state.date + expran(0.5 * intime);
229         game.future[FTBEAM] = game.state.date + expran(1.5 * (intime / game.state.remcom));
230         game.future[FSNAP] = game.state.date + 1.0 + Rand(); // Force an early snapshot
231         game.future[FBATTAK] = game.state.date + expran(0.3*intime);
232         game.future[FCDBAS] = 1e30;
233         game.future[FSCMOVE] = game.state.nscrem ? game.state.date+0.2777 : 1e30;
234         game.future[FSCDBAS] = 1e30;
235         game.future[FDSPROB] = 1e30;
236         // Starchart is functional
237         stdamtim = 1e30;
238         // Put stars in the galaxy
239         instar = 0;
240         for (i=1; i<=GALSIZE; i++)
241                 for (j=1; j<=GALSIZE; j++) {
242                         int k = Rand()*9.0 + 1.0;
243                         instar += k;
244                         game.state.galaxy[i][j] = k;
245                 }
246         // Locate star bases in galaxy
247         for (i = 1; i <= inbase; i++) {
248                 int contflag;
249                 do {
250                         do iran8(&ix, &iy);
251                         while (game.state.galaxy[ix][iy] >= 10);
252                         contflag = FALSE;
253                         for (j = i-1; j > 0; j--) {
254                                 /* Improved placement algorithm to spread out bases */
255                                 double distq = square(ix-game.state.baseqx[j]) + square(iy-game.state.baseqy[j]);
256                                 if (distq < 6.0*(BASEMAX-inbase) && Rand() < 0.75) {
257                                         contflag = TRUE;
258 #ifdef DEBUG
259                                         proutn("DEBUG: Abandoning base #%d at %d-%d\n", i, ix, iy);
260 #endif
261                                         break;
262                                 }
263 #ifdef DEBUG
264                                 else if (distq < 6.0 * (BASEMAX-inbase)) {
265                                         proutn("DEBUG: saving base #%d, close to #%d\n", i, j);
266                                 }
267 #endif
268                         }
269                 } while (contflag);
270                         
271                 game.state.baseqx[i] = ix;
272                 game.state.baseqy[i] = iy;
273                 game.starch[ix][iy] = -1;
274                 game.state.galaxy[ix][iy] += 10;
275         }
276         // Position ordinary Klingon Battle Cruisers
277         krem = inkling - incom - game.state.nscrem;
278         klumper = 0.25*skill*(9.0-length)+1.0;
279         if (klumper > 9) klumper = 9; // Can't have more than 9 in quadrant
280         do {
281                 double r = Rand();
282                 int klump = (1.0 - r*r)*klumper;
283                 if (klump > krem) klump = krem;
284                 krem -= klump;
285                 klump *= 100;
286                 do iran8(&ix, &iy);
287                 while (game.state.galaxy[ix][iy] + klump >= 1000);
288                 game.state.galaxy[ix][iy] += klump;
289         } while (krem > 0);
290         // Position Klingon Commander Ships
291 #ifdef DEBUG
292         klumper = 1;
293 #endif
294         for (i = 1; i <= incom; i++) {
295                 do {
296                         do { /* IF debugging, put commanders by bases, always! */
297 #ifdef DEBUG
298                                 if (idebug && klumper <= inbase) {
299                                         ix = game.state.baseqx[klumper];
300                                         iy = game.state.baseqy[klumper];
301                                         klumper++;
302                                 }
303                                 else
304 #endif
305                                         iran8(&ix, &iy);
306                         }
307                         while ((game.state.galaxy[ix][iy] < 99 && Rand() < 0.75)||
308                                    game.state.galaxy[ix][iy]>899);
309                         // check for duplicate
310                         for (j = 1; j < i; j++)
311                                 if (game.state.cx[j]==ix && game.state.cy[j]==iy) break;
312                 } while (j < i);
313                 game.state.galaxy[ix][iy] += 100;
314                 game.state.cx[i] = ix;
315                 game.state.cy[i] = iy;
316         }
317         // Locate planets in galaxy
318         for (i = 0; i < inplan; i++) {
319                 do iran8(&ix, &iy);
320                 while (game.state.newstuf[ix][iy] > 0);
321                 game.state.newstuf[ix][iy] = 1;
322                 game.state.plnets[i].x = ix;
323                 game.state.plnets[i].y = iy;
324                 game.state.plnets[i].pclass = Rand()*3.0; // Planet class M N or O
325                 game.state.plnets[i].crystals = 1.5*Rand();             // 1 in 3 chance of crystals
326                 game.state.plnets[i].known = unknown;
327         }
328         // Locate Romulans
329         for (i = 1; i <= game.state.nromrem; i++) {
330                 iran8(&ix, &iy);
331                 game.state.newstuf[ix][iy] += 10;
332         }
333         // Locate the Super Commander
334         if (game.state.nscrem > 0) {
335                 do iran8(&ix, &iy);
336                 while (game.state.galaxy[ix][iy] >= 900);
337                 game.state.isx = ix;
338                 game.state.isy = iy;
339                 game.state.galaxy[ix][iy] += 100;
340         }
341         // Place thing (in tournament game, thingx == -1, don't want one!)
342         if (thingx != -1) {
343                 iran8(&thingx, &thingy);
344         }
345         else {
346                 thingx = thingy = 0;
347         }
348
349 //      idate = date;
350         skip(2);
351         game.state.snap = 0;
352                 
353         if (skill == 1) {
354                 prout("It is stardate %d. The Federation is being attacked by",
355                            (int)game.state.date);
356                 prout("a deadly Klingon invasion force. As captain of the United");
357                 prout("Starship U.S.S. Enterprise, it is your mission to seek out");
358                 prout("and destroy this invasion force of %d battle cruisers.",
359                            inkling);
360                 prout("You have an initial allotment of %d stardates to complete", (int)intime);
361                 prout("your mission.  As you proceed you may be given more time.");
362                 prout("");
363                 prout("You will have %d supporting starbases.", inbase);
364                 proutn("Starbase locations-  ");
365         }
366         else {
367                 prout("Stardate %d.", (int)game.state.date);
368                 prout("");
369                 prout("%d Klingons.", inkling);
370                 prout("An unknown number of Romulans.");
371                 if (game.state.nscrem) prout("and one (GULP) Super-Commander.");
372                         prout("%d stardates.",(int)intime);
373                         proutn("%d starbases in ", inbase);
374         }
375         for (i = 1; i <= inbase; i++) {
376                 proutn(cramlc(0, game.state.baseqx[i], game.state.baseqy[i]));
377                 proutn("  ");
378         }
379         skip(2);
380         proutn("The Enterprise is currently in ");
381         proutn(cramlc(quadrant, quadx, quady));
382         proutn(" ");
383         proutn(cramlc(sector, sectx, secty));
384         skip(2);
385         prout("Good Luck!");
386         if (game.state.nscrem) prout("  YOU'LL NEED IT.");
387         waitfor();
388         newqad(0);
389         if (nenhere-iqhere-ithere) shldup=1.0;
390         if (neutz) attack(0);   // bad luck to start in a Romulan Neutral Zone
391 }
392
393 void randomize(void) {
394         srand((int)time(NULL));
395 }
396
397 int choose(int needprompt) {
398         while (TRUE) {
399         tourn = 0;
400         thawed = 0;
401         skill = 0;
402         length = 0;
403                 if (needprompt) /* Can start with command line options */
404                         proutn("Would you like a regular, tournament, or saved game? ");
405                 scan();
406                 if (strlen(citem)==0) continue; // Try again
407                 if (isit("tournament")) {
408                         while (scan() == IHEOL) {
409                                 proutn("Type in tournament number-");
410                         }
411                         if (aaitem == 0) {
412                                 chew();
413                                 continue; // We don't want a blank entry
414                         }
415                         tourn = (int)aaitem;
416                         thingx = -1;
417                         srand((unsigned int)(int)aaitem);
418                         break;
419                 }
420                 if (isit("saved") || isit("frozen")) {
421                         if (thaw()) continue;
422                         chew();
423                         if (*game.passwd==0) continue;
424                         if (!alldone) thawed = 1; // No plaque if not finished
425                         report();
426                         waitfor();
427                         return TRUE;
428                 }
429                 if (isit("regular")) break;
430                 proutn("What is \"");
431                 proutn(citem);
432                 prout("\"?");
433                 chew();
434         }
435         while (length==0 || skill==0) {
436                 if (scan() == IHALPHA) {
437                         if (isit("short")) length = 1;
438                         else if (isit("medium")) length = 2;
439                         else if (isit("long")) length = 4;
440                         else if (isit("novice")) skill = 1;
441                         else if (isit("fair")) skill = 2;
442                         else if (isit("good")) skill = 3;
443                         else if (isit("expert")) skill = 4;
444                         else if (isit("emeritus")) skill = 5;
445                         else {
446                                 proutn("What is \"");
447                                 proutn(citem);
448                                 prout("\"?");
449                         }
450                 }
451                 else {
452                         chew();
453                         if (length==0) proutn("Would you like a Short, Medium, or Long game? ");
454                         else if (skill == 0) proutn("Are you a Novice, Fair, Good, Expert, or Emeritus player? ");
455                 }
456         }
457         setpassword();
458 #ifdef DEBUG
459         if (strcmp(game.passwd, "debug")==0) idebug = 1;
460 #endif
461
462         // Use parameters to generate initial values of things
463         damfac = 0.5 * skill;
464         game.state.rembase = 3.0*Rand()+2.0;
465         inbase = game.state.rembase;
466         inplan = (PLNETMAX/2) + (PLNETMAX/2+1)*Rand();
467         game.state.nromrem = (2.0+Rand())*skill;
468         game.state.nscrem = (skill > 2? 1 : 0);
469         game.state.remtime = 7.0 * length;
470         intime = game.state.remtime;
471         game.state.remkl = 2.0*intime*((skill+1 - 2*Rand())*skill*0.1+.15);
472         inkling = game.state.remkl;
473         incom = skill + 0.0625*inkling*Rand();
474         game.state.remcom= min(10, incom);
475         incom = game.state.remcom;
476         game.state.remres = (inkling+4*incom)*intime;
477         inresor = game.state.remres;
478         if (inkling > 50) {
479                 inbase = (game.state.rembase += 1);
480         }
481         return FALSE;
482 }
483
484 void dropin(int iquad, int *ix, int *iy) {
485         do iran10(ix, iy);
486         while (game.quad[*ix][*iy] != IHDOT);
487         game.quad[*ix][*iy] = iquad;
488 }
489
490 void newcnd(void) {
491         condit = IHGREEN;
492         if (energy < 1000.0) condit = IHYELLOW;
493         if (game.state.galaxy[quadx][quady] > 99 || game.state.newstuf[quadx][quady] > 9)
494                 condit = IHRED;
495         if (!alive) condit=IHDEAD;
496 }
497
498
499 void newqad(int shutup) {
500         int quadnum = game.state.galaxy[quadx][quady];
501         int newnum = game.state.newstuf[quadx][quady];
502         int i, j, ix, iy, nplan;
503
504         iattak = 1;
505         justin = 1;
506         basex = basey = 0;
507         klhere = 0;
508         comhere = 0;
509         plnetx = plnety = 0;
510         ishere = 0;
511         irhere = 0;
512         iplnet = 0;
513         nenhere = 0;
514         neutz = 0;
515         inorbit = 0;
516         landed = -1;
517         ientesc = 0;
518         ithere = 0;
519         iqhere=0;
520         iqengry=0;
521         iseenit = 0;
522         if (iscate) {
523                 // Attempt to escape Super-commander, so tbeam back!
524                 iscate = 0;
525                 ientesc = 1;
526         }
527         // Clear quadrant
528         for (i=1; i <= QUADSIZE; i++)
529                 for (j=1; j <= QUADSIZE; j++) game.quad[i][j] = IHDOT;
530         // cope with supernova
531         if (quadnum > 999) {
532                 return;
533         }
534         klhere = quadnum/100;
535         irhere = newnum/10;
536         nplan = newnum%10;
537         nenhere = klhere + irhere;
538
539         // Position Starship
540         game.quad[sectx][secty] = ship;
541
542         if (quadnum >= 100) {
543                 // Position ordinary Klingons
544                 quadnum -= 100*klhere;
545                 for (i = 1; i <= klhere; i++) {
546                         dropin(IHK, &ix, &iy);
547                         game.kx[i] = ix;
548                         game.ky[i] = iy;
549                         game.kdist[i] = game.kavgd[i] = sqrt(square(sectx-ix) + square(secty-iy));
550                         game.kpower[i] = Rand()*150.0 +300.0 +25.0*skill;
551                 }
552                 // If we need a commander, promote a Klingon
553                 for (i = 1; i <= game.state.remcom ; i++) 
554                         if (game.state.cx[i]==quadx && game.state.cy[i]==quady) break;
555                         
556                 if (i <= game.state.remcom) {
557                         game.quad[ix][iy] = IHC;
558                         game.kpower[klhere] = 950.0+400.0*Rand()+50.0*skill;
559                         comhere = 1;
560                 }
561
562                 // If we need a super-commander, promote a Klingon
563                 if (quadx == game.state.isx && quady == game.state.isy) {
564                         game.quad[game.kx[1]][game.ky[1]] = IHS;
565                         game.kpower[1] = 1175.0 + 400.0*Rand() + 125.0*skill;
566                         iscate = game.state.remkl>1;
567                         ishere = 1;
568                 }
569         }
570         // Put in Romulans if needed
571         for (i = klhere+1; i <= nenhere; i++) {
572                 dropin(IHR, &ix, &iy);
573                 game.kx[i] = ix;
574                 game.ky[i] = iy;
575                 game.kdist[i] = game.kavgd[i] = sqrt(square(sectx-ix) + square(secty-iy));
576                 game.kpower[i] = Rand()*400.0 + 450.0 + 50.0*skill;
577         }
578         // If quadrant needs a starbase, put it in
579         if (quadnum >= 10) {
580                 quadnum -= 10;
581                 dropin(IHB, &basex, &basey);
582         }
583         
584         if (nplan) {
585                 // If quadrant needs a planet, put it in
586                 for (i=0; i < inplan; i++)
587                         if (game.state.plnets[i].x == quadx && game.state.plnets[i].y == quady) break;
588                 if (i < inplan) {
589                         iplnet = i;
590                         dropin(IHP, &plnetx, &plnety);
591                 }
592         }
593         // Check for condition
594         newcnd();
595         // And finally the stars
596         for (i = 1; i <= quadnum; i++) dropin(IHSTAR, &ix, &iy);
597
598         // Check for RNZ
599         if (irhere > 0 && klhere == 0) {
600                 neutz = 1;
601                 if (game.damage[DRADIO] <= 0.0) {
602                         skip(1);
603                         prout("LT. Uhura- \"Captain, an urgent message.");
604                         prout("  I'll put it on audio.\"  CLICK");
605                         skip(1);
606                         prout("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE.");
607                         prout("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!");
608                 }
609         }
610
611         if (shutup==0) {
612                 // Put in THING if needed
613                 if (thingx == quadx && thingy == quady) {
614                         dropin(IHQUEST, &ix, &iy);
615                         iran8(&thingx, &thingy);
616                         nenhere++;
617                         iqhere=1;
618                         game.kx[nenhere] = ix;
619                         game.ky[nenhere] = iy;
620                         game.kdist[nenhere] = game.kavgd[nenhere] =
621                             sqrt(square(sectx-ix) + square(secty-iy));
622                         game.kpower[nenhere] = Rand()*6000.0 +500.0 +250.0*skill;
623                         if (game.damage[DSRSENS] == 0.0) {
624                                 skip(1);
625                                 prout("MR. SPOCK- \"Captain, this is most unusual.");
626                                 prout("    Please examine your short-range scan.\"");
627                         }
628                 }
629         }
630
631         // Decide if quadrant needs a Tholian
632         if ((skill < 3 && Rand() <= 0.02) ||   /* Lighten up if skill is low */
633                 (skill == 3 && Rand() <= 0.05) ||
634                 (skill > 3 && Rand() <= 0.08)
635 #ifdef DEBUG
636                 || strcmp(passwd, "tholianx")==0
637 #endif
638                 ) {
639                 do {
640                         ithx = Rand() > 0.5 ? 10 : 1;
641                         ithy = Rand() > 0.5 ? 10 : 1;
642                 } while (game.quad[ithx][ithy] != IHDOT);
643                 game.quad[ithx][ithy] = IHT;
644                 ithere = 1;
645                 nenhere++;
646                 game.kx[nenhere] = ithx;
647                 game.ky[nenhere] = ithy;
648                 game.kdist[nenhere] = game.kavgd[nenhere] =
649                     sqrt(square(sectx-ithx) + square(secty-ithy));
650                 game.kpower[nenhere] = Rand()*400.0 +100.0 +25.0*skill;
651                 /* Reserve unocupied corners */
652                 if (game.quad[1][1]==IHDOT) game.quad[1][1] = 'X';
653                 if (game.quad[1][QUADSIZE]==IHDOT) game.quad[1][QUADSIZE] = 'X';
654                 if (game.quad[QUADSIZE][1]==IHDOT) game.quad[QUADSIZE][1] = 'X';
655                 if (game.quad[QUADSIZE][QUADSIZE]==IHDOT) game.quad[QUADSIZE][QUADSIZE] = 'X';
656         }
657         sortkl();
658
659         // Put in a few black holes
660         for (i = 1; i <= 3; i++)
661                 if (Rand() > 0.5) dropin(IHBLANK, &ix, &iy);
662
663         // Take out X's in corners if Tholian present
664         if (ithere) {
665                 if (game.quad[1][1]=='X') game.quad[1][1] = IHDOT;
666                 if (game.quad[1][QUADSIZE]=='X') game.quad[1][QUADSIZE] = IHDOT;
667                 if (game.quad[QUADSIZE][1]=='X') game.quad[QUADSIZE][1] = IHDOT;
668                 if (game.quad[QUADSIZE][QUADSIZE]=='X') game.quad[QUADSIZE][QUADSIZE] = IHDOT;
669         }               
670 }
671
672 void sortkl(void) {
673         double t;
674         int sw, j, k;
675
676         // The author liked bubble sort. So we will use it. :-(
677
678         if (nenhere-iqhere-ithere < 2) return;
679
680         do {
681                 sw = FALSE;
682                 for (j = 1; j < nenhere; j++)
683                         if (game.kdist[j] > game.kdist[j+1]) {
684                                 sw = TRUE;
685                                 t = game.kdist[j];
686                                 game.kdist[j] = game.kdist[j+1];
687                                 game.kdist[j+1] = t;
688                                 t = game.kavgd[j];
689                                 game.kavgd[j] = game.kavgd[j+1];
690                                 game.kavgd[j+1] = t;
691                                 k = game.kx[j];
692                                 game.kx[j] = game.kx[j+1];
693                                 game.kx[j+1] = k;
694                                 k = game.ky[j];
695                                 game.ky[j] = game.ky[j+1];
696                                 game.ky[j+1] = k;
697                                 t = game.kpower[j];
698                                 game.kpower[j] = game.kpower[j+1];
699                                 game.kpower[j+1] = t;
700                         }
701         } while (sw);
702 }