3 static int tryexit(int lookx, int looky, int ienm, int loccom, int irun) {
6 iqx = quadx+(lookx+(QUADSIZE-1))/QUADSIZE - 1;
7 iqy = quady+(looky+(QUADSIZE-1))/QUADSIZE - 1;
8 if (iqx < 1 || iqx > GALSIZE || iqy < 1 || iqy > GALSIZE ||
9 game.state.galaxy[iqx][iqy] > 899)
10 return 0; /* no can do -- neg energy, supernovae, or >8 Klingons */
11 if (ienm == IHR) return 0; /* Romulans cannot escape! */
13 /* avoid intruding on another commander's territory */
15 for (l = 1; l <= game.state.remcom; l++)
16 if (game.state.cx[l]==iqx && game.state.cy[l]==iqy) return 0;
17 /* refuse to leave if currently attacking starbase */
18 if (batx==quadx && baty==quady) return 0;
20 /* don't leave if over 1000 units of energy */
21 if (game.kpower[loccom] > 1000.) return 0;
23 /* print escape message and move out of quadrant.
24 We know this if either short or long range sensors are working */
25 if (game.damage[DSRSENS] == 0.0 || game.damage[DLRSENS] == 0.0 ||
27 crmena(1, ienm, 2, game.kx[loccom], game.ky[loccom]);
28 prout(" escapes to %s (and regains strength).",
29 cramlc(quadrant, iqx, iqy));
31 /* handle local matters related to escape */
32 game.quad[game.kx[loccom]][game.ky[loccom]] = IHDOT;
33 game.kx[loccom] = game.kx[nenhere];
34 game.ky[loccom] = game.ky[nenhere];
35 game.kavgd[loccom] = game.kavgd[nenhere];
36 game.kpower[loccom] = game.kpower[nenhere];
37 game.kdist[loccom] = game.kdist[nenhere];
40 if (condit != IHDOCKED) newcnd();
41 /* Handle global matters related to escape */
42 game.state.galaxy[quadx][quady] -= 100;
43 game.state.galaxy[iqx][iqy] += 100;
49 game.future[FSCMOVE]=0.2777+game.state.date;
50 game.future[FSCDBAS]=1e30;
55 for (l=1; l<=game.state.remcom; l++) {
56 if (game.state.cx[l]==quadx && game.state.cy[l]==quady) {
64 return 1; /* success */
68 static void movebaddy(int comx, int comy, int loccom, int ienm) {
69 int motion, mdist, nsteps, mx, my, nextx, nexty, lookx, looky, ll;
74 /* This should probably be just comhere + ishere */
75 int nbaddys = skill > 3 ?
76 (int)((comhere*2 + ishere*2+klhere*1.23+irhere*1.5)/2.0):
80 dist1 = game.kdist[loccom];
81 mdist = dist1 + 0.5; /* Nearest integer distance */
83 /* If SC, check with spy to see if should hi-tail it */
85 (game.kpower[loccom] <= 500.0 || (condit==IHDOCKED && game.damage[DPHOTON]==0))) {
90 /* decide whether to advance, retreat, or hold position */
92 * Enterprise has "force" based on condition of phaser and photon torpedoes.
93 If both are operating full strength, force is 1000. If both are damaged,
94 force is -1000. Having shields down subtracts an additional 1000.
96 * Enemy has forces equal to the energy of the attacker plus
97 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
98 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
100 Attacker Initial energy levels (nominal):
101 Klingon Romulan Commander Super-Commander
104 Good 450 800 1300 1750
105 Expert 475 850 1350 1875
106 Emeritus 500 900 1400 2000
107 VARIANCE 75 200 200 200
109 Enemy vessels only move prior to their attack. In Novice - Good games
110 only commanders move. In Expert games, all enemy vessels move if there
111 is a commander present. In Emeritus games all enemy vessels move.
113 * If Enterprise is not docked, an agressive action is taken if enemy
114 forces are 1000 greater than Enterprise.
116 Agressive action on average cuts the distance between the ship and
117 the enemy to 1/4 the original.
119 * At lower energy advantage, movement units are proportional to the
120 advantage with a 650 advantage being to hold ground, 800 to move forward
121 1, 950 for two, 150 for back 4, etc. Variance of 100.
123 If docked, is reduced by roughly 1.75*skill, generally forcing a
124 retreat, especially at high skill levels.
126 * Motion is limited to skill level, except for SC hi-tailing it out.
129 forces = game.kpower[loccom]+100.0*nenhere+400*(nbaddys-1);
130 if (shldup==0) forces += 1000; /* Good for enemy if shield is down! */
131 if (game.damage[DPHASER] == 0.0 || game.damage[DPHOTON] == 0.0) {
132 if (game.damage[DPHASER] != 0) /* phasers damaged */
135 forces -= 0.2*(energy - 2500.0);
136 if (game.damage[DPHOTON] != 0) /* photon torpedoes damaged */
139 forces -= 50.0*torps;
142 /* phasers and photon tubes both out! */
146 if (forces <= 1000.0 && condit != IHDOCKED) /* Typical situation */
147 motion = ((forces+200.0*Rand())/150.0) - 5.0;
149 if (forces > 1000.0) /* Very strong -- move in for kill */
150 motion = (1.0-square(Rand()))*dist1 + 1.0;
151 if (condit==IHDOCKED) /* protected by base -- back off ! */
152 motion -= skill*(2.0-square(Rand()));
156 proutn("MOTION = %1.2f", motion);
157 proutn(" FORCES = %1,2f", forces);
160 /* don't move if no motion */
161 if (motion==0) return;
162 /* Limit motion according to skill */
163 if (abs(motion) > skill) motion = (motion < 0) ? -skill : skill;
165 /* calcuate preferred number of steps */
166 nsteps = motion < 0 ? -motion : motion;
167 if (motion > 0 && nsteps > mdist) nsteps = mdist; /* don't overshoot */
168 if (nsteps > QUADSIZE) nsteps = QUADSIZE; /* This shouldn't be necessary */
169 if (nsteps < 1) nsteps = 1; /* This shouldn't be necessary */
172 prout("NSTEPS = %d", nsteps);
175 /* Compute preferred values of delta X and Y */
178 if (2.0 * abs(mx) < abs(my)) mx = 0;
179 if (2.0 * abs(my) < abs(sectx-comx)) my = 0;
180 if (mx != 0) mx = mx*motion < 0 ? -1 : 1;
181 if (my != 0) my = my*motion < 0 ? -1 : 1;
185 for (ll = 1; ll <= nsteps; ll++) {
191 /* Check if preferred position available */
194 krawlx = mx < 0 ? 1 : -1;
195 krawly = my < 0 ? 1 : -1;
197 attempts = 0; /* Settle mysterious hang problem */
198 while (attempts++ < 20 && !success) {
199 if (lookx < 1 || lookx > QUADSIZE) {
200 if (motion < 0 && tryexit(lookx, looky, ienm, loccom, irun))
202 if (krawlx == mx || my == 0) break;
203 lookx = nextx + krawlx;
206 else if (looky < 1 || looky > QUADSIZE) {
207 if (motion < 0 && tryexit(lookx, looky, ienm, loccom, irun))
209 if (krawly == my || mx == 0) break;
210 looky = nexty + krawly;
213 else if (game.quad[lookx][looky] != IHDOT) {
214 /* See if we should ram ship */
215 if (game.quad[lookx][looky] == ship &&
216 (ienm == IHC || ienm == IHS)) {
217 ram(1, ienm, comx, comy);
220 if (krawlx != mx && my != 0) {
221 lookx = nextx + krawlx;
224 else if (krawly != my && mx != 0) {
225 looky = nexty + krawly;
228 else break; /* we have failed */
237 prout(cramlc(neither, nextx, nexty));
241 else break; /* done early */
243 /* Put commander in place within same quadrant */
244 game.quad[comx][comy] = IHDOT;
245 game.quad[nextx][nexty] = ienm;
246 if (nextx != comx || nexty != comy) {
248 game.kx[loccom] = nextx;
249 game.ky[loccom] = nexty;
250 game.kdist[loccom] = game.kavgd[loccom] =
251 sqrt(square(sectx-nextx)+square(secty-nexty));
252 if (game.damage[DSRSENS] == 0 || condit == IHDOCKED) {
255 proutn(" from %s", cramlc(2, comx, comy));
256 if (game.kdist[loccom] < dist1) proutn(" advances to ");
257 else proutn(" retreats to ");
258 prout(cramlc(sector, nextx, nexty));
267 if (idebug) prout("MOVCOM");
270 /* Figure out which Klingon is the commander (or Supercommander)
272 if (comhere) for (i = 1; i <= nenhere; i++) {
275 if (game.quad[ix][iy] == IHC) {
276 movebaddy(ix, iy, i, IHC);
280 if (ishere) for (i = 1; i <= nenhere; i++) {
283 if (game.quad[ix][iy] == IHS) {
284 movebaddy(ix, iy, i, IHS);
288 /* if skill level is high, move other Klingons and Romulans too!
289 Move these last so they can base their actions on what the
291 if (skill > 3) for (i = 1; i <= nenhere; i++) {
294 if (game.quad[ix][iy] == IHK || game.quad[ix][iy] == IHR)
295 movebaddy(ix, iy, i, game.quad[ix][iy]);
301 static int movescom(int iqx, int iqy, int flag, int *ipage) {
304 if ((iqx==quadx && iqy==quady) ||
305 iqx < 1 || iqx > GALSIZE || iqy < 1 || iqy > GALSIZE ||
306 game.state.galaxy[iqx][iqy] > 899) return 1;
308 /* Avoid quadrants with bases if we want to avoid Enterprise */
309 for (i = 1; i <= game.state.rembase; i++)
310 if (game.state.baseqx[i]==iqx && game.state.baseqy[i]==iqy) return 1;
312 if (justin && !iscate) return 1;
314 game.state.galaxy[game.state.isx][game.state.isy] -= 100;
315 game.state.isx = iqx;
316 game.state.isy = iqy;
317 game.state.galaxy[game.state.isx][game.state.isy] += 100;
319 /* SC has scooted, Remove him from current quadrant */
324 game.future[FSCDBAS]=1e30;
325 for (i = 1; i <= nenhere; i++)
326 if (game.quad[game.kx[i]][game.ky[i]] == IHS) break;
327 game.quad[game.kx[i]][game.ky[i]] = IHDOT;
328 game.kx[i] = game.kx[nenhere];
329 game.ky[i] = game.ky[nenhere];
330 game.kdist[i] = game.kdist[nenhere];
331 game.kavgd[i] = game.kavgd[nenhere];
332 game.kpower[i] = game.kpower[nenhere];
335 if (condit!=IHDOCKED) newcnd();
338 /* check for a helpful planet */
339 for (i = 0; i < inplan; i++) {
340 if (game.state.plnets[i].x==game.state.isx && game.state.plnets[i].y==game.state.isy &&
341 game.state.plnets[i].crystals == 1) {
342 /* destroy the planet */
343 DESTROY(&game.state.plnets[i]);
344 game.state.newstuf[game.state.isx][game.state.isy] -= 1;
345 if (game.damage[DRADIO] == 0.0 || condit == IHDOCKED) {
346 if (*ipage==0) pause_game(1);
348 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
349 proutn(" a planet in ");
350 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
351 prout(" has been destroyed");
352 prout(" by the Super-commander.\"");
357 return 0; /* looks good! */
364 void scom(int *ipage) {
365 int i, i2, j, ideltax, ideltay, ibqx, ibqy, sx, sy, ifindit, iwhichb;
371 if (idebug) prout("SCOM");
374 /* Decide on being active or passive */
375 flag = ((game.state.killc+game.state.killk)/(game.state.date+0.01-indate) < 0.1*skill*(skill+1.0) ||
376 (game.state.date-indate) < 3.0);
377 if (iscate==0 && flag) {
378 /* compute move away from Enterprise */
379 ideltax = game.state.isx-quadx;
380 ideltay = game.state.isy-quady;
381 if (sqrt(ideltax*(double)ideltax+ideltay*(double)ideltay) > 2.0) {
382 /* circulate in space */
383 ideltax = game.state.isy-quady;
384 ideltay = quadx-game.state.isx;
388 /* compute distances to starbases */
389 if (game.state.rembase <= 0) {
390 /* nothing left to do */
391 game.future[FSCMOVE] = 1e30;
396 for (i = 1; i <= game.state.rembase; i++) {
398 ibqx = game.state.baseqx[i];
399 ibqy = game.state.baseqy[i];
400 bdist[i] = sqrt(square(ibqx-sx) + square(ibqy-sy));
402 if (game.state.rembase > 1) {
403 /* sort into nearest first order */
407 for (i=1; i < game.state.rembase-1; i++) {
408 if (bdist[i] > bdist[i+1]) {
411 bdist[i] = bdist[i+1];
413 basetbl[i] = basetbl[i+1];
420 /* look for nearest base without a commander, no Enterprise, and
421 without too many Klingons, and not already under attack. */
422 ifindit = iwhichb = 0;
424 for (i2 = 1; i2 <= game.state.rembase; i2++) {
425 i = basetbl[i2]; /* bug in original had it not finding nearest*/
426 ibqx = game.state.baseqx[i];
427 ibqy = game.state.baseqy[i];
428 if ((ibqx == quadx && ibqy == quady) ||
429 (ibqx == batx && ibqy == baty) ||
430 game.state.galaxy[ibqx][ibqy] > 899) continue;
431 /* if there is a commander, an no other base is appropriate,
432 we will take the one with the commander */
433 for (j = 1; j <= game.state.remcom; j++) {
434 if (ibqx==game.state.cx[j] && ibqy==game.state.cy[j] && ifindit!= 2) {
440 if (j > game.state.remcom) { /* no commander -- use this one */
446 if (ifindit==0) return; /* Nothing suitable -- wait until next time*/
447 ibqx = game.state.baseqx[iwhichb];
448 ibqy = game.state.baseqy[iwhichb];
449 /* decide how to move toward base */
450 ideltax = ibqx - game.state.isx;
451 ideltay = ibqy - game.state.isy;
453 /* Maximum movement is 1 quadrant in either or both axis */
454 if (ideltax > 1) ideltax = 1;
455 if (ideltax < -1) ideltax = -1;
456 if (ideltay > 1) ideltay = 1;
457 if (ideltay < -1) ideltay = -1;
459 /* try moving in both x and y directions */
460 iqx = game.state.isx + ideltax;
461 iqy = game.state.isy + ideltax;
462 if (movescom(iqx, iqy, flag, ipage)) {
463 /* failed -- try some other maneuvers */
464 if (ideltax==0 || ideltay==0) {
465 /* attempt angle move */
467 iqy = game.state.isy + 1;
468 if (movescom(iqx, iqy, flag, ipage)) {
469 iqy = game.state.isy - 1;
470 movescom(iqx, iqy, flag, ipage);
474 iqx = game.state.isx + 1;
475 if (movescom(iqx, iqy, flag, ipage)) {
476 iqx = game.state.isx - 1;
477 movescom(iqx, iqy, flag, ipage);
482 /* try moving just in x or y */
483 iqy = game.state.isy;
484 if (movescom(iqx, iqy, flag, ipage)) {
485 iqy = game.state.isy + ideltay;
486 iqx = game.state.isx;
487 movescom(iqx, iqy, flag, ipage);
491 /* check for a base */
492 if (game.state.rembase == 0) {
493 game.future[FSCMOVE] = 1e30;
495 else for (i=1; i<=game.state.rembase; i++) {
496 ibqx = game.state.baseqx[i];
497 ibqy = game.state.baseqy[i];
498 if (ibqx==game.state.isx && ibqy == game.state.isy && game.state.isx != batx && game.state.isy != baty) {
499 /* attack the base */
500 if (flag) return; /* no, don't attack base! */
503 game.future[FSCDBAS] = game.state.date + 1.0 +2.0*Rand();
504 if (game.future[FCDBAS] < 1e30) game.future[FSCDBAS] +=
505 game.future[FCDBAS]-game.state.date;
506 if (game.damage[DRADIO] > 0 && condit != IHDOCKED)
507 return; /* no warning */
509 if (*ipage == 0) pause_game(1);
511 proutn("Lt. Uhura- \"Captain, the starbase in ");
512 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
514 prout(" reports that it is under attack from the Klingon Super-commander.");
515 proutn(" It can survive until stardate %d.\"",
516 (int)game.future[FSCDBAS]);
517 if (resting==0) return;
518 prout("Mr. Spock- \"Captain, shall we cancel the rest period?\"");
521 Time = 0.0; /* actually finished */
525 /* Check for intelligence report */
531 (game.damage[DRADIO] > 0.0 && condit != IHDOCKED) ||
532 game.starch[game.state.isx][game.state.isy] > 0))
534 if (*ipage==0) pause_game(1);
536 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
537 proutn(" the Super-commander is in ");
538 proutn(cramlc(quadrant, game.state.isx, game.state. isy));
544 int idx, idy, im, i, dum, my;
545 /* Move the Tholian */
546 if (ithere==0 || justin == 1) return;
548 if (ithx == 1 && ithy == 1) {
549 idx = 1; idy = QUADSIZE;
551 else if (ithx == 1 && ithy == QUADSIZE) {
552 idx = QUADSIZE; idy = QUADSIZE;
554 else if (ithx == QUADSIZE && ithy == QUADSIZE) {
555 idx = QUADSIZE; idy = 1;
557 else if (ithx == QUADSIZE && ithy == 1) {
561 /* something is wrong! */
566 /* Do nothing if we are blocked */
567 if (game.quad[idx][idy]!= IHDOT && game.quad[idx][idy]!= IHWEB) return;
568 game.quad[ithx][ithy] = IHWEB;
572 im = fabs((double)idx - ithx)/((double)idx - ithx);
573 while (ithx != idx) {
575 if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;
578 else if (ithy != idy) {
580 im = fabs((double)idy - ithy)/((double)idy - ithy);
581 while (ithy != idy) {
583 if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;
586 game.quad[ithx][ithy] = IHT;
587 game.kx[nenhere]=ithx;
588 game.ky[nenhere]=ithy;
590 /* check to see if all holes plugged */
591 for (i = 1; i < 11; i++) {
592 if (game.quad[1][i]!=IHWEB && game.quad[1][i]!=IHT) return;
593 if (game.quad[QUADSIZE][i]!=IHWEB && game.quad[QUADSIZE][i]!=IHT) return;
594 if (game.quad[i][1]!=IHWEB && game.quad[i][1]!=IHT) return;
595 if (game.quad[i][QUADSIZE]!=IHWEB && game.quad[i][QUADSIZE]!=IHT) return;
597 /* All plugged up -- Tholian splits */
598 game.quad[ithx][ithy]=IHWEB;
599 dropin(IHBLANK, &dum, &my);
600 crmena(1,IHT, 2, ithx, ithy);
601 prout(" completes web.");
602 ithere = ithx = ithy = 0;