3 static int tryexit(int lookx, int looky, int ienm, int loccom, int irun)
7 iqx = quadx+(lookx+(QUADSIZE-1))/QUADSIZE - 1;
8 iqy = quady+(looky+(QUADSIZE-1))/QUADSIZE - 1;
9 if (iqx < 1 || iqx > GALSIZE || iqy < 1 || iqy > GALSIZE ||
10 game.state.galaxy[iqx][iqy].supernova ||
11 game.state.galaxy[iqx][iqy].klingons > 8)
12 return 0; /* no can do -- neg energy, supernovae, or >8 Klingons */
13 if (ienm == IHR) return 0; /* Romulans cannot escape! */
15 /* avoid intruding on another commander's territory */
17 for (l = 1; l <= game.state.remcom; l++)
18 if (game.state.cx[l]==iqx && game.state.cy[l]==iqy) return 0;
19 /* refuse to leave if currently attacking starbase */
20 if (batx==quadx && baty==quady) return 0;
22 /* don't leave if over 1000 units of energy */
23 if (game.kpower[loccom] > 1000.) return 0;
25 /* print escape message and move out of quadrant.
26 We know this if either short or long range sensors are working */
27 if (game.damage[DSRSENS] == 0.0 || game.damage[DLRSENS] == 0.0 ||
29 crmena(1, ienm, 2, game.kx[loccom], game.ky[loccom]);
30 prout(" escapes to %s (and regains strength).",
31 cramlc(quadrant, iqx, iqy));
33 /* handle local matters related to escape */
34 game.quad[game.kx[loccom]][game.ky[loccom]] = IHDOT;
35 game.kx[loccom] = game.kx[nenhere];
36 game.ky[loccom] = game.ky[nenhere];
37 game.kavgd[loccom] = game.kavgd[nenhere];
38 game.kpower[loccom] = game.kpower[nenhere];
39 game.kdist[loccom] = game.kdist[nenhere];
42 if (condit != IHDOCKED) newcnd();
43 /* Handle global matters related to escape */
44 game.state.galaxy[quadx][quady].klingons--;
45 game.state.galaxy[iqx][iqy].klingons++;
51 game.future[FSCMOVE]=0.2777+game.state.date;
52 game.future[FSCDBAS]=1e30;
57 for (l=1; l<=game.state.remcom; l++) {
58 if (game.state.cx[l]==quadx && game.state.cy[l]==quady) {
66 return 1; /* success */
70 static void movebaddy(int comx, int comy, int loccom, int ienm)
72 int motion, mdist, nsteps, mx, my, nextx, nexty, lookx, looky, ll;
77 /* This should probably be just comhere + ishere */
78 int nbaddys = skill >= SKILL_EXPERT ?
79 (int)((comhere*2 + ishere*2+klhere*1.23+irhere*1.5)/2.0):
83 dist1 = game.kdist[loccom];
84 mdist = dist1 + 0.5; /* Nearest integer distance */
86 /* If SC, check with spy to see if should hi-tail it */
88 (game.kpower[loccom] <= 500.0 || (condit==IHDOCKED && game.damage[DPHOTON]==0))) {
93 /* decide whether to advance, retreat, or hold position */
95 * Enterprise has "force" based on condition of phaser and photon torpedoes.
96 If both are operating full strength, force is 1000. If both are damaged,
97 force is -1000. Having shields down subtracts an additional 1000.
99 * Enemy has forces equal to the energy of the attacker plus
100 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
101 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
103 Attacker Initial energy levels (nominal):
104 Klingon Romulan Commander Super-Commander
107 Good 450 800 1300 1750
108 Expert 475 850 1350 1875
109 Emeritus 500 900 1400 2000
110 VARIANCE 75 200 200 200
112 Enemy vessels only move prior to their attack. In Novice - Good games
113 only commanders move. In Expert games, all enemy vessels move if there
114 is a commander present. In Emeritus games all enemy vessels move.
116 * If Enterprise is not docked, an agressive action is taken if enemy
117 forces are 1000 greater than Enterprise.
119 Agressive action on average cuts the distance between the ship and
120 the enemy to 1/4 the original.
122 * At lower energy advantage, movement units are proportional to the
123 advantage with a 650 advantage being to hold ground, 800 to move forward
124 1, 950 for two, 150 for back 4, etc. Variance of 100.
126 If docked, is reduced by roughly 1.75*skill, generally forcing a
127 retreat, especially at high skill levels.
129 * Motion is limited to skill level, except for SC hi-tailing it out.
132 forces = game.kpower[loccom]+100.0*nenhere+400*(nbaddys-1);
133 if (shldup==0) forces += 1000; /* Good for enemy if shield is down! */
134 if (game.damage[DPHASER] == 0.0 || game.damage[DPHOTON] == 0.0) {
135 if (game.damage[DPHASER] != 0) /* phasers damaged */
138 forces -= 0.2*(energy - 2500.0);
139 if (game.damage[DPHOTON] != 0) /* photon torpedoes damaged */
142 forces -= 50.0*torps;
145 /* phasers and photon tubes both out! */
149 if (forces <= 1000.0 && condit != IHDOCKED) /* Typical situation */
150 motion = ((forces+200.0*Rand())/150.0) - 5.0;
152 if (forces > 1000.0) /* Very strong -- move in for kill */
153 motion = (1.0-square(Rand()))*dist1 + 1.0;
154 if (condit==IHDOCKED) /* protected by base -- back off ! */
155 motion -= skill*(2.0-square(Rand()));
159 proutn("MOTION = %1.2f", motion);
160 proutn(" FORCES = %1,2f", forces);
163 /* don't move if no motion */
164 if (motion==0) return;
165 /* Limit motion according to skill */
166 if (abs(motion) > skill) motion = (motion < 0) ? -skill : skill;
168 /* calculate preferred number of steps */
169 nsteps = motion < 0 ? -motion : motion;
170 if (motion > 0 && nsteps > mdist) nsteps = mdist; /* don't overshoot */
171 if (nsteps > QUADSIZE) nsteps = QUADSIZE; /* This shouldn't be necessary */
172 if (nsteps < 1) nsteps = 1; /* This shouldn't be necessary */
175 prout("NSTEPS = %d", nsteps);
178 /* Compute preferred values of delta X and Y */
181 if (2.0 * abs(mx) < abs(my)) mx = 0;
182 if (2.0 * abs(my) < abs(sectx-comx)) my = 0;
183 if (mx != 0) mx = mx*motion < 0 ? -1 : 1;
184 if (my != 0) my = my*motion < 0 ? -1 : 1;
188 for (ll = 1; ll <= nsteps; ll++) {
194 /* Check if preferred position available */
197 krawlx = mx < 0 ? 1 : -1;
198 krawly = my < 0 ? 1 : -1;
200 attempts = 0; /* Settle mysterious hang problem */
201 while (attempts++ < 20 && !success) {
202 if (lookx < 1 || lookx > QUADSIZE) {
203 if (motion < 0 && tryexit(lookx, looky, ienm, loccom, irun))
205 if (krawlx == mx || my == 0) break;
206 lookx = nextx + krawlx;
209 else if (looky < 1 || looky > QUADSIZE) {
210 if (motion < 0 && tryexit(lookx, looky, ienm, loccom, irun))
212 if (krawly == my || mx == 0) break;
213 looky = nexty + krawly;
216 else if (game.quad[lookx][looky] != IHDOT) {
217 /* See if we should ram ship */
218 if (game.quad[lookx][looky] == ship &&
219 (ienm == IHC || ienm == IHS)) {
220 ram(1, ienm, comx, comy);
223 if (krawlx != mx && my != 0) {
224 lookx = nextx + krawlx;
227 else if (krawly != my && mx != 0) {
228 looky = nexty + krawly;
231 else break; /* we have failed */
240 prout(cramlc(neither, nextx, nexty));
244 else break; /* done early */
246 /* Put commander in place within same quadrant */
247 game.quad[comx][comy] = IHDOT;
248 game.quad[nextx][nexty] = ienm;
249 if (nextx != comx || nexty != comy) {
251 game.kx[loccom] = nextx;
252 game.ky[loccom] = nexty;
253 game.kdist[loccom] = game.kavgd[loccom] =
254 sqrt(square(sectx-nextx)+square(secty-nexty));
255 if (game.damage[DSRSENS] == 0 || condit == IHDOCKED) {
258 proutn(" from %s", cramlc(2, comx, comy));
259 if (game.kdist[loccom] < dist1) proutn(" advances to ");
260 else proutn(" retreats to ");
261 prout(cramlc(sector, nextx, nexty));
271 if (idebug) prout("MOVCOM");
274 /* Figure out which Klingon is the commander (or Supercommander)
276 if (comhere) for (i = 1; i <= nenhere; i++) {
279 if (game.quad[ix][iy] == IHC) {
280 movebaddy(ix, iy, i, IHC);
284 if (ishere) for (i = 1; i <= nenhere; i++) {
287 if (game.quad[ix][iy] == IHS) {
288 movebaddy(ix, iy, i, IHS);
292 /* if skill level is high, move other Klingons and Romulans too!
293 Move these last so they can base their actions on what the
295 if (skill >= SKILL_EXPERT) for (i = 1; i <= nenhere; i++) {
298 if (game.quad[ix][iy] == IHK || game.quad[ix][iy] == IHR)
299 movebaddy(ix, iy, i, game.quad[ix][iy]);
305 static int movescom(int iqx, int iqy, int flag, int *ipage)
309 if ((iqx==quadx && iqy==quady) ||
310 iqx < 1 || iqx > GALSIZE || iqy < 1 || iqy > GALSIZE ||
311 game.state.galaxy[iqx][iqy].supernova ||
312 game.state.galaxy[iqx][iqy].klingons > 8)
315 /* Avoid quadrants with bases if we want to avoid Enterprise */
316 for (i = 1; i <= game.state.rembase; i++)
317 if (game.state.baseqx[i]==iqx && game.state.baseqy[i]==iqy) return 1;
319 if (justin && !iscate) return 1;
321 game.state.galaxy[game.state.isx][game.state.isy].klingons--;
322 game.state.isx = iqx;
323 game.state.isy = iqy;
324 game.state.galaxy[game.state.isx][game.state.isy].klingons++;
326 /* SC has scooted, Remove him from current quadrant */
331 game.future[FSCDBAS]=1e30;
332 for (i = 1; i <= nenhere; i++)
333 if (game.quad[game.kx[i]][game.ky[i]] == IHS) break;
334 game.quad[game.kx[i]][game.ky[i]] = IHDOT;
335 game.kx[i] = game.kx[nenhere];
336 game.ky[i] = game.ky[nenhere];
337 game.kdist[i] = game.kdist[nenhere];
338 game.kavgd[i] = game.kavgd[nenhere];
339 game.kpower[i] = game.kpower[nenhere];
342 if (condit!=IHDOCKED) newcnd();
345 /* check for a helpful planet */
346 for (i = 0; i < inplan; i++) {
347 if (game.state.plnets[i].x==game.state.isx && game.state.plnets[i].y==game.state.isy &&
348 game.state.plnets[i].crystals == 1) {
349 /* destroy the planet */
350 DESTROY(&game.state.plnets[i]);
351 game.state.galaxy[game.state.isx][game.state.isy].planets -= 1;
352 if (game.damage[DRADIO] == 0.0 || condit == IHDOCKED) {
353 if (*ipage==0) pause_game(1);
355 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
356 proutn(" a planet in ");
357 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
358 prout(" has been destroyed");
359 prout(" by the Super-commander.\"");
364 return 0; /* looks good! */
367 void scom(int *ipage)
369 int i, i2, j, ideltax, ideltay, ibqx, ibqy, sx, sy, ifindit, iwhichb;
371 int basetbl[BASEMAX];
372 double bdist[BASEMAX];
375 if (idebug) prout("SCOM");
378 /* Decide on being active or passive */
379 flag = ((game.state.killc+game.state.killk)/(game.state.date+0.01-indate) < 0.1*skill*(skill+1.0) ||
380 (game.state.date-indate) < 3.0);
381 if (iscate==0 && flag) {
382 /* compute move away from Enterprise */
383 ideltax = game.state.isx-quadx;
384 ideltay = game.state.isy-quady;
385 if (sqrt(ideltax*(double)ideltax+ideltay*(double)ideltay) > 2.0) {
386 /* circulate in space */
387 ideltax = game.state.isy-quady;
388 ideltay = quadx-game.state.isx;
392 /* compute distances to starbases */
393 if (game.state.rembase <= 0) {
394 /* nothing left to do */
395 game.future[FSCMOVE] = 1e30;
400 for (i = 1; i <= game.state.rembase; i++) {
402 ibqx = game.state.baseqx[i];
403 ibqy = game.state.baseqy[i];
404 bdist[i] = sqrt(square(ibqx-sx) + square(ibqy-sy));
406 if (game.state.rembase > 1) {
407 /* sort into nearest first order */
411 for (i=1; i < game.state.rembase-1; i++) {
412 if (bdist[i] > bdist[i+1]) {
415 bdist[i] = bdist[i+1];
417 basetbl[i] = basetbl[i+1];
424 /* look for nearest base without a commander, no Enterprise, and
425 without too many Klingons, and not already under attack. */
426 ifindit = iwhichb = 0;
428 for (i2 = 1; i2 <= game.state.rembase; i2++) {
429 i = basetbl[i2]; /* bug in original had it not finding nearest*/
430 ibqx = game.state.baseqx[i];
431 ibqy = game.state.baseqy[i];
432 if ((ibqx == quadx && ibqy == quady) ||
433 (ibqx == batx && ibqy == baty) ||
434 game.state.galaxy[ibqx][ibqy].supernova ||
435 game.state.galaxy[ibqx][ibqy].klingons > 8)
437 /* if there is a commander, an no other base is appropriate,
438 we will take the one with the commander */
439 for (j = 1; j <= game.state.remcom; j++) {
440 if (ibqx==game.state.cx[j] && ibqy==game.state.cy[j] && ifindit!= 2) {
446 if (j > game.state.remcom) { /* no commander -- use this one */
452 if (ifindit==0) return; /* Nothing suitable -- wait until next time*/
453 ibqx = game.state.baseqx[iwhichb];
454 ibqy = game.state.baseqy[iwhichb];
455 /* decide how to move toward base */
456 ideltax = ibqx - game.state.isx;
457 ideltay = ibqy - game.state.isy;
459 /* Maximum movement is 1 quadrant in either or both axis */
460 if (ideltax > 1) ideltax = 1;
461 if (ideltax < -1) ideltax = -1;
462 if (ideltay > 1) ideltay = 1;
463 if (ideltay < -1) ideltay = -1;
465 /* try moving in both x and y directions */
466 iqx = game.state.isx + ideltax;
467 iqy = game.state.isy + ideltax;
468 if (movescom(iqx, iqy, flag, ipage)) {
469 /* failed -- try some other maneuvers */
470 if (ideltax==0 || ideltay==0) {
471 /* attempt angle move */
473 iqy = game.state.isy + 1;
474 if (movescom(iqx, iqy, flag, ipage)) {
475 iqy = game.state.isy - 1;
476 movescom(iqx, iqy, flag, ipage);
480 iqx = game.state.isx + 1;
481 if (movescom(iqx, iqy, flag, ipage)) {
482 iqx = game.state.isx - 1;
483 movescom(iqx, iqy, flag, ipage);
488 /* try moving just in x or y */
489 iqy = game.state.isy;
490 if (movescom(iqx, iqy, flag, ipage)) {
491 iqy = game.state.isy + ideltay;
492 iqx = game.state.isx;
493 movescom(iqx, iqy, flag, ipage);
497 /* check for a base */
498 if (game.state.rembase == 0) {
499 game.future[FSCMOVE] = 1e30;
501 else for (i=1; i<=game.state.rembase; i++) {
502 ibqx = game.state.baseqx[i];
503 ibqy = game.state.baseqy[i];
504 if (ibqx==game.state.isx && ibqy == game.state.isy && game.state.isx != batx && game.state.isy != baty) {
505 /* attack the base */
506 if (flag) return; /* no, don't attack base! */
509 game.future[FSCDBAS] = game.state.date + 1.0 +2.0*Rand();
510 if (game.future[FCDBAS] < 1e30) game.future[FSCDBAS] +=
511 game.future[FCDBAS]-game.state.date;
512 if (game.damage[DRADIO] > 0 && condit != IHDOCKED)
513 return; /* no warning */
515 if (*ipage == 0) pause_game(1);
517 proutn("Lt. Uhura- \"Captain, the starbase in ");
518 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
520 prout(" reports that it is under attack from the Klingon Super-commander.");
521 proutn(" It can survive until stardate %d.\"",
522 (int)game.future[FSCDBAS]);
523 if (resting==0) return;
524 prout("Mr. Spock- \"Captain, shall we cancel the rest period?\"");
527 Time = 0.0; /* actually finished */
531 /* Check for intelligence report */
537 (game.damage[DRADIO] > 0.0 && condit != IHDOCKED) ||
538 !game.state.galaxy[game.state.isx][game.state.isy].charted))
540 if (*ipage==0) pause_game(1);
542 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
543 proutn(" the Super-commander is in ");
544 proutn(cramlc(quadrant, game.state.isx, game.state. isy));
551 int idx, idy, im, i, dum, my;
552 /* Move the Tholian */
553 if (ithere==0 || justin == 1) return;
555 if (ithx == 1 && ithy == 1) {
556 idx = 1; idy = QUADSIZE;
558 else if (ithx == 1 && ithy == QUADSIZE) {
559 idx = QUADSIZE; idy = QUADSIZE;
561 else if (ithx == QUADSIZE && ithy == QUADSIZE) {
562 idx = QUADSIZE; idy = 1;
564 else if (ithx == QUADSIZE && ithy == 1) {
568 /* something is wrong! */
573 /* Do nothing if we are blocked */
574 if (game.quad[idx][idy]!= IHDOT && game.quad[idx][idy]!= IHWEB) return;
575 game.quad[ithx][ithy] = IHWEB;
579 im = fabs((double)idx - ithx)/((double)idx - ithx);
580 while (ithx != idx) {
582 if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;
585 else if (ithy != idy) {
587 im = fabs((double)idy - ithy)/((double)idy - ithy);
588 while (ithy != idy) {
590 if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;
593 game.quad[ithx][ithy] = IHT;
594 game.kx[nenhere]=ithx;
595 game.ky[nenhere]=ithy;
597 /* check to see if all holes plugged */
598 for (i = 1; i < QUADSIZE+1; i++) {
599 if (game.quad[1][i]!=IHWEB && game.quad[1][i]!=IHT) return;
600 if (game.quad[QUADSIZE][i]!=IHWEB && game.quad[QUADSIZE][i]!=IHT) return;
601 if (game.quad[i][1]!=IHWEB && game.quad[i][1]!=IHT) return;
602 if (game.quad[i][QUADSIZE]!=IHWEB && game.quad[i][QUADSIZE]!=IHT) return;
604 /* All plugged up -- Tholian splits */
605 game.quad[ithx][ithy]=IHWEB;
606 dropin(IHBLANK, &dum, &my);
607 crmena(1,IHT, 2, ithx, ithy);
608 prout(" completes web.");
609 ithere = ithx = ithy = 0;