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 NOEXIT(game.state.galaxy[iqx][iqy]))
11 return 0; /* no can do -- neg energy, supernovae, or >8 Klingons */
12 if (ienm == IHR) return 0; /* Romulans cannot escape! */
14 /* avoid intruding on another commander's territory */
16 for (l = 1; l <= game.state.remcom; l++)
17 if (game.state.cx[l]==iqx && game.state.cy[l]==iqy) return 0;
18 /* refuse to leave if currently attacking starbase */
19 if (batx==quadx && baty==quady) return 0;
21 /* don't leave if over 1000 units of energy */
22 if (game.kpower[loccom] > 1000.) return 0;
24 /* print escape message and move out of quadrant.
25 We know this if either short or long range sensors are working */
26 if (game.damage[DSRSENS] == 0.0 || game.damage[DLRSENS] == 0.0 ||
28 crmena(1, ienm, 2, game.kx[loccom], game.ky[loccom]);
29 prout(" escapes to %s (and regains strength).",
30 cramlc(quadrant, iqx, iqy));
32 /* handle local matters related to escape */
33 game.quad[game.kx[loccom]][game.ky[loccom]] = IHDOT;
34 game.kx[loccom] = game.kx[nenhere];
35 game.ky[loccom] = game.ky[nenhere];
36 game.kavgd[loccom] = game.kavgd[nenhere];
37 game.kpower[loccom] = game.kpower[nenhere];
38 game.kdist[loccom] = game.kdist[nenhere];
41 if (condit != IHDOCKED) newcnd();
42 /* Handle global matters related to escape */
43 game.state.galaxy[quadx][quady] -= KLINGON_PLACE;
44 game.state.galaxy[iqx][iqy] += KLINGON_PLACE;
50 game.future[FSCMOVE]=0.2777+game.state.date;
51 game.future[FSCDBAS]=1e30;
56 for (l=1; l<=game.state.remcom; l++) {
57 if (game.state.cx[l]==quadx && game.state.cy[l]==quady) {
65 return 1; /* success */
69 static void movebaddy(int comx, int comy, int loccom, int ienm)
71 int motion, mdist, nsteps, mx, my, nextx, nexty, lookx, looky, ll;
76 /* This should probably be just comhere + ishere */
77 int nbaddys = skill >= SKILL_EXPERT ?
78 (int)((comhere*2 + ishere*2+klhere*1.23+irhere*1.5)/2.0):
82 dist1 = game.kdist[loccom];
83 mdist = dist1 + 0.5; /* Nearest integer distance */
85 /* If SC, check with spy to see if should hi-tail it */
87 (game.kpower[loccom] <= 500.0 || (condit==IHDOCKED && game.damage[DPHOTON]==0))) {
92 /* decide whether to advance, retreat, or hold position */
94 * Enterprise has "force" based on condition of phaser and photon torpedoes.
95 If both are operating full strength, force is 1000. If both are damaged,
96 force is -1000. Having shields down subtracts an additional 1000.
98 * Enemy has forces equal to the energy of the attacker plus
99 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
100 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
102 Attacker Initial energy levels (nominal):
103 Klingon Romulan Commander Super-Commander
106 Good 450 800 1300 1750
107 Expert 475 850 1350 1875
108 Emeritus 500 900 1400 2000
109 VARIANCE 75 200 200 200
111 Enemy vessels only move prior to their attack. In Novice - Good games
112 only commanders move. In Expert games, all enemy vessels move if there
113 is a commander present. In Emeritus games all enemy vessels move.
115 * If Enterprise is not docked, an agressive action is taken if enemy
116 forces are 1000 greater than Enterprise.
118 Agressive action on average cuts the distance between the ship and
119 the enemy to 1/4 the original.
121 * At lower energy advantage, movement units are proportional to the
122 advantage with a 650 advantage being to hold ground, 800 to move forward
123 1, 950 for two, 150 for back 4, etc. Variance of 100.
125 If docked, is reduced by roughly 1.75*skill, generally forcing a
126 retreat, especially at high skill levels.
128 * Motion is limited to skill level, except for SC hi-tailing it out.
131 forces = game.kpower[loccom]+100.0*nenhere+400*(nbaddys-1);
132 if (shldup==0) forces += 1000; /* Good for enemy if shield is down! */
133 if (game.damage[DPHASER] == 0.0 || game.damage[DPHOTON] == 0.0) {
134 if (game.damage[DPHASER] != 0) /* phasers damaged */
137 forces -= 0.2*(energy - 2500.0);
138 if (game.damage[DPHOTON] != 0) /* photon torpedoes damaged */
141 forces -= 50.0*torps;
144 /* phasers and photon tubes both out! */
148 if (forces <= 1000.0 && condit != IHDOCKED) /* Typical situation */
149 motion = ((forces+200.0*Rand())/150.0) - 5.0;
151 if (forces > 1000.0) /* Very strong -- move in for kill */
152 motion = (1.0-square(Rand()))*dist1 + 1.0;
153 if (condit==IHDOCKED) /* protected by base -- back off ! */
154 motion -= skill*(2.0-square(Rand()));
158 proutn("MOTION = %1.2f", motion);
159 proutn(" FORCES = %1,2f", forces);
162 /* don't move if no motion */
163 if (motion==0) return;
164 /* Limit motion according to skill */
165 if (abs(motion) > skill) motion = (motion < 0) ? -skill : skill;
167 /* calcuate preferred number of steps */
168 nsteps = motion < 0 ? -motion : motion;
169 if (motion > 0 && nsteps > mdist) nsteps = mdist; /* don't overshoot */
170 if (nsteps > QUADSIZE) nsteps = QUADSIZE; /* This shouldn't be necessary */
171 if (nsteps < 1) nsteps = 1; /* This shouldn't be necessary */
174 prout("NSTEPS = %d", nsteps);
177 /* Compute preferred values of delta X and Y */
180 if (2.0 * abs(mx) < abs(my)) mx = 0;
181 if (2.0 * abs(my) < abs(sectx-comx)) my = 0;
182 if (mx != 0) mx = mx*motion < 0 ? -1 : 1;
183 if (my != 0) my = my*motion < 0 ? -1 : 1;
187 for (ll = 1; ll <= nsteps; ll++) {
193 /* Check if preferred position available */
196 krawlx = mx < 0 ? 1 : -1;
197 krawly = my < 0 ? 1 : -1;
199 attempts = 0; /* Settle mysterious hang problem */
200 while (attempts++ < 20 && !success) {
201 if (lookx < 1 || lookx > QUADSIZE) {
202 if (motion < 0 && tryexit(lookx, looky, ienm, loccom, irun))
204 if (krawlx == mx || my == 0) break;
205 lookx = nextx + krawlx;
208 else if (looky < 1 || looky > QUADSIZE) {
209 if (motion < 0 && tryexit(lookx, looky, ienm, loccom, irun))
211 if (krawly == my || mx == 0) break;
212 looky = nexty + krawly;
215 else if (game.quad[lookx][looky] != IHDOT) {
216 /* See if we should ram ship */
217 if (game.quad[lookx][looky] == ship &&
218 (ienm == IHC || ienm == IHS)) {
219 ram(1, ienm, comx, comy);
222 if (krawlx != mx && my != 0) {
223 lookx = nextx + krawlx;
226 else if (krawly != my && mx != 0) {
227 looky = nexty + krawly;
230 else break; /* we have failed */
239 prout(cramlc(neither, nextx, nexty));
243 else break; /* done early */
245 /* Put commander in place within same quadrant */
246 game.quad[comx][comy] = IHDOT;
247 game.quad[nextx][nexty] = ienm;
248 if (nextx != comx || nexty != comy) {
250 game.kx[loccom] = nextx;
251 game.ky[loccom] = nexty;
252 game.kdist[loccom] = game.kavgd[loccom] =
253 sqrt(square(sectx-nextx)+square(secty-nexty));
254 if (game.damage[DSRSENS] == 0 || condit == IHDOCKED) {
257 proutn(" from %s", cramlc(2, comx, comy));
258 if (game.kdist[loccom] < dist1) proutn(" advances to ");
259 else proutn(" retreats to ");
260 prout(cramlc(sector, nextx, nexty));
270 if (idebug) prout("MOVCOM");
273 /* Figure out which Klingon is the commander (or Supercommander)
275 if (comhere) for (i = 1; i <= nenhere; i++) {
278 if (game.quad[ix][iy] == IHC) {
279 movebaddy(ix, iy, i, IHC);
283 if (ishere) for (i = 1; i <= nenhere; i++) {
286 if (game.quad[ix][iy] == IHS) {
287 movebaddy(ix, iy, i, IHS);
291 /* if skill level is high, move other Klingons and Romulans too!
292 Move these last so they can base their actions on what the
294 if (skill >= SKILL_EXPERT) for (i = 1; i <= nenhere; i++) {
297 if (game.quad[ix][iy] == IHK || game.quad[ix][iy] == IHR)
298 movebaddy(ix, iy, i, game.quad[ix][iy]);
304 static int movescom(int iqx, int iqy, int flag, int *ipage)
308 if ((iqx==quadx && iqy==quady) ||
309 iqx < 1 || iqx > GALSIZE || iqy < 1 || iqy > GALSIZE ||
310 NOEXIT(game.state.galaxy[iqx][iqy])) return 1;
312 /* Avoid quadrants with bases if we want to avoid Enterprise */
313 for (i = 1; i <= game.state.rembase; i++)
314 if (game.state.baseqx[i]==iqx && game.state.baseqy[i]==iqy) return 1;
316 if (justin && !iscate) return 1;
318 game.state.galaxy[game.state.isx][game.state.isy] -= KLINGON_PLACE;
319 game.state.isx = iqx;
320 game.state.isy = iqy;
321 game.state.galaxy[game.state.isx][game.state.isy] += KLINGON_PLACE;
323 /* SC has scooted, Remove him from current quadrant */
328 game.future[FSCDBAS]=1e30;
329 for (i = 1; i <= nenhere; i++)
330 if (game.quad[game.kx[i]][game.ky[i]] == IHS) break;
331 game.quad[game.kx[i]][game.ky[i]] = IHDOT;
332 game.kx[i] = game.kx[nenhere];
333 game.ky[i] = game.ky[nenhere];
334 game.kdist[i] = game.kdist[nenhere];
335 game.kavgd[i] = game.kavgd[nenhere];
336 game.kpower[i] = game.kpower[nenhere];
339 if (condit!=IHDOCKED) newcnd();
342 /* check for a helpful planet */
343 for (i = 0; i < inplan; i++) {
344 if (game.state.plnets[i].x==game.state.isx && game.state.plnets[i].y==game.state.isy &&
345 game.state.plnets[i].crystals == 1) {
346 /* destroy the planet */
347 DESTROY(&game.state.plnets[i]);
348 game.state.newstuf[game.state.isx][game.state.isy] -= 1;
349 if (game.damage[DRADIO] == 0.0 || condit == IHDOCKED) {
350 if (*ipage==0) pause_game(1);
352 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
353 proutn(" a planet in ");
354 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
355 prout(" has been destroyed");
356 prout(" by the Super-commander.\"");
361 return 0; /* looks good! */
364 void scom(int *ipage)
366 int i, i2, j, ideltax, ideltay, ibqx, ibqy, sx, sy, ifindit, iwhichb;
368 int basetbl[BASEMAX];
369 double bdist[BASEMAX];
372 if (idebug) prout("SCOM");
375 /* Decide on being active or passive */
376 flag = ((game.state.killc+game.state.killk)/(game.state.date+0.01-indate) < 0.1*skill*(skill+1.0) ||
377 (game.state.date-indate) < 3.0);
378 if (iscate==0 && flag) {
379 /* compute move away from Enterprise */
380 ideltax = game.state.isx-quadx;
381 ideltay = game.state.isy-quady;
382 if (sqrt(ideltax*(double)ideltax+ideltay*(double)ideltay) > 2.0) {
383 /* circulate in space */
384 ideltax = game.state.isy-quady;
385 ideltay = quadx-game.state.isx;
389 /* compute distances to starbases */
390 if (game.state.rembase <= 0) {
391 /* nothing left to do */
392 game.future[FSCMOVE] = 1e30;
397 for (i = 1; i <= game.state.rembase; i++) {
399 ibqx = game.state.baseqx[i];
400 ibqy = game.state.baseqy[i];
401 bdist[i] = sqrt(square(ibqx-sx) + square(ibqy-sy));
403 if (game.state.rembase > 1) {
404 /* sort into nearest first order */
408 for (i=1; i < game.state.rembase-1; i++) {
409 if (bdist[i] > bdist[i+1]) {
412 bdist[i] = bdist[i+1];
414 basetbl[i] = basetbl[i+1];
421 /* look for nearest base without a commander, no Enterprise, and
422 without too many Klingons, and not already under attack. */
423 ifindit = iwhichb = 0;
425 for (i2 = 1; i2 <= game.state.rembase; i2++) {
426 i = basetbl[i2]; /* bug in original had it not finding nearest*/
427 ibqx = game.state.baseqx[i];
428 ibqy = game.state.baseqy[i];
429 if ((ibqx == quadx && ibqy == quady) ||
430 (ibqx == batx && ibqy == baty) ||
431 NOEXIT(game.state.galaxy[ibqx][ibqy])) continue;
432 /* if there is a commander, an no other base is appropriate,
433 we will take the one with the commander */
434 for (j = 1; j <= game.state.remcom; j++) {
435 if (ibqx==game.state.cx[j] && ibqy==game.state.cy[j] && ifindit!= 2) {
441 if (j > game.state.remcom) { /* no commander -- use this one */
447 if (ifindit==0) return; /* Nothing suitable -- wait until next time*/
448 ibqx = game.state.baseqx[iwhichb];
449 ibqy = game.state.baseqy[iwhichb];
450 /* decide how to move toward base */
451 ideltax = ibqx - game.state.isx;
452 ideltay = ibqy - game.state.isy;
454 /* Maximum movement is 1 quadrant in either or both axis */
455 if (ideltax > 1) ideltax = 1;
456 if (ideltax < -1) ideltax = -1;
457 if (ideltay > 1) ideltay = 1;
458 if (ideltay < -1) ideltay = -1;
460 /* try moving in both x and y directions */
461 iqx = game.state.isx + ideltax;
462 iqy = game.state.isy + ideltax;
463 if (movescom(iqx, iqy, flag, ipage)) {
464 /* failed -- try some other maneuvers */
465 if (ideltax==0 || ideltay==0) {
466 /* attempt angle move */
468 iqy = game.state.isy + 1;
469 if (movescom(iqx, iqy, flag, ipage)) {
470 iqy = game.state.isy - 1;
471 movescom(iqx, iqy, flag, ipage);
475 iqx = game.state.isx + 1;
476 if (movescom(iqx, iqy, flag, ipage)) {
477 iqx = game.state.isx - 1;
478 movescom(iqx, iqy, flag, ipage);
483 /* try moving just in x or y */
484 iqy = game.state.isy;
485 if (movescom(iqx, iqy, flag, ipage)) {
486 iqy = game.state.isy + ideltay;
487 iqx = game.state.isx;
488 movescom(iqx, iqy, flag, ipage);
492 /* check for a base */
493 if (game.state.rembase == 0) {
494 game.future[FSCMOVE] = 1e30;
496 else for (i=1; i<=game.state.rembase; i++) {
497 ibqx = game.state.baseqx[i];
498 ibqy = game.state.baseqy[i];
499 if (ibqx==game.state.isx && ibqy == game.state.isy && game.state.isx != batx && game.state.isy != baty) {
500 /* attack the base */
501 if (flag) return; /* no, don't attack base! */
504 game.future[FSCDBAS] = game.state.date + 1.0 +2.0*Rand();
505 if (game.future[FCDBAS] < 1e30) game.future[FSCDBAS] +=
506 game.future[FCDBAS]-game.state.date;
507 if (game.damage[DRADIO] > 0 && condit != IHDOCKED)
508 return; /* no warning */
510 if (*ipage == 0) pause_game(1);
512 proutn("Lt. Uhura- \"Captain, the starbase in ");
513 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
515 prout(" reports that it is under attack from the Klingon Super-commander.");
516 proutn(" It can survive until stardate %d.\"",
517 (int)game.future[FSCDBAS]);
518 if (resting==0) return;
519 prout("Mr. Spock- \"Captain, shall we cancel the rest period?\"");
522 Time = 0.0; /* actually finished */
526 /* Check for intelligence report */
532 (game.damage[DRADIO] > 0.0 && condit != IHDOCKED) ||
533 game.starch[game.state.isx][game.state.isy] > 0))
535 if (*ipage==0) pause_game(1);
537 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
538 proutn(" the Super-commander is in ");
539 proutn(cramlc(quadrant, game.state.isx, game.state. isy));
546 int idx, idy, im, i, dum, my;
547 /* Move the Tholian */
548 if (ithere==0 || justin == 1) return;
550 if (ithx == 1 && ithy == 1) {
551 idx = 1; idy = QUADSIZE;
553 else if (ithx == 1 && ithy == QUADSIZE) {
554 idx = QUADSIZE; idy = QUADSIZE;
556 else if (ithx == QUADSIZE && ithy == QUADSIZE) {
557 idx = QUADSIZE; idy = 1;
559 else if (ithx == QUADSIZE && ithy == 1) {
563 /* something is wrong! */
568 /* Do nothing if we are blocked */
569 if (game.quad[idx][idy]!= IHDOT && game.quad[idx][idy]!= IHWEB) return;
570 game.quad[ithx][ithy] = IHWEB;
574 im = fabs((double)idx - ithx)/((double)idx - ithx);
575 while (ithx != idx) {
577 if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;
580 else if (ithy != idy) {
582 im = fabs((double)idy - ithy)/((double)idy - ithy);
583 while (ithy != idy) {
585 if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;
588 game.quad[ithx][ithy] = IHT;
589 game.kx[nenhere]=ithx;
590 game.ky[nenhere]=ithy;
592 /* check to see if all holes plugged */
593 for (i = 1; i < QUADSIZE+1; i++) {
594 if (game.quad[1][i]!=IHWEB && game.quad[1][i]!=IHT) return;
595 if (game.quad[QUADSIZE][i]!=IHWEB && game.quad[QUADSIZE][i]!=IHT) return;
596 if (game.quad[i][1]!=IHWEB && game.quad[i][1]!=IHT) return;
597 if (game.quad[i][QUADSIZE]!=IHWEB && game.quad[i][QUADSIZE]!=IHT) return;
599 /* All plugged up -- Tholian splits */
600 game.quad[ithx][ithy]=IHWEB;
601 dropin(IHBLANK, &dum, &my);
602 crmena(1,IHT, 2, ithx, ithy);
603 prout(" completes web.");
604 ithere = ithx = ithy = 0;