3 static int tryexit(int lookx, int looky, int ienm, int loccom, int irun)
7 iqx = game.quadx+(lookx+(QUADSIZE-1))/QUADSIZE - 1;
8 iqy = game.quady+(looky+(QUADSIZE-1))/QUADSIZE - 1;
9 if (!VALID_QUADRANT(iqx,iqy) ||
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 */
18 if (game.state.cx[l]==iqx && game.state.cy[l]==iqy) return 0;
19 /* refuse to leave if currently attacking starbase */
20 if (game.batx==game.quadx && game.baty==game.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 ||
28 game.condit == IHDOCKED) {
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[game.nenhere];
36 game.ky[loccom] = game.ky[game.nenhere];
37 game.kavgd[loccom] = game.kavgd[game.nenhere];
38 game.kpower[loccom] = game.kpower[game.nenhere];
39 game.kdist[loccom] = game.kdist[game.nenhere];
42 if (game.condit != IHDOCKED) newcnd();
43 /* Handle global matters related to escape */
44 game.state.galaxy[game.quadx][game.quady].klingons--;
45 game.state.galaxy[iqx][iqy].klingons++;
51 game.future[FSCMOVE]=0.2777+game.state.date;
52 game.future[FSCDBAS]=FOREVER;
58 if (game.state.cx[l]==game.quadx && game.state.cy[l]==game.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 game.comhere + game.ishere */
78 int nbaddys = game.skill >= SKILL_EXPERT ?
79 (int)((game.comhere*2 + game.ishere*2+game.klhere*1.23+game.irhere*1.5)/2.0):
80 (game.comhere + game.ishere);
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 || (game.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*game.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*game.nenhere+400*(nbaddys-1);
133 if (game.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*(game.energy - 2500.0);
139 if (game.damage[DPHOTON] != 0) /* photon torpedoes damaged */
142 forces -= 50.0*game.torps;
145 /* phasers and photon tubes both out! */
149 if (forces <= 1000.0 && game.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 (game.condit==IHDOCKED && (game.options & OPTION_BASE)) /* protected by base -- back off ! */
155 motion -= game.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) > game.skill) motion = (motion < 0) ? -game.skill : game.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 */
179 mx = game.sectx - comx;
180 my = game.secty - comy;
181 if (2.0 * abs(mx) < abs(my)) mx = 0;
182 if (2.0 * abs(my) < abs(game.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 = 0; 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.options & OPTION_RAMMING) && game.quad[lookx][looky] != IHDOT) {
217 /* See if we should ram ship */
218 if (game.quad[lookx][looky] == game.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(game.sectx-nextx)+square(game.secty-nexty));
255 if (game.damage[DSRSENS] == 0 || game.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 (game.idebug) prout("MOVCOM");
274 /* Figure out which Klingon is the commander (or Supercommander)
277 for_local_enemies(i) {
280 if (game.quad[ix][iy] == IHC) {
281 movebaddy(ix, iy, i, IHC);
286 for_local_enemies(i) {
289 if (game.quad[ix][iy] == IHS) {
290 movebaddy(ix, iy, i, IHS);
294 /* if skill level is high, move other Klingons and Romulans too!
295 Move these last so they can base their actions on what the
297 if (game.skill >= SKILL_EXPERT && (game.options & OPTION_MVBADDY))
298 for_local_enemies(i) {
301 if (game.quad[ix][iy] == IHK || game.quad[ix][iy] == IHR)
302 movebaddy(ix, iy, i, game.quad[ix][iy]);
308 static int movescom(int iqx, int iqy, int flag, int *ipage)
312 if ((iqx==game.quadx && iqy==game.quady) ||
313 !VALID_QUADRANT(iqx, iqy) ||
314 game.state.galaxy[iqx][iqy].supernova ||
315 game.state.galaxy[iqx][iqy].klingons > 8)
318 /* Avoid quadrants with bases if we want to avoid Enterprise */
320 if (game.state.baseqx[i]==iqx && game.state.baseqy[i]==iqy) return 1;
322 if (game.justin && !game.iscate) return 1;
324 game.state.galaxy[game.state.isx][game.state.isy].klingons--;
325 game.state.isx = iqx;
326 game.state.isy = iqy;
327 game.state.galaxy[game.state.isx][game.state.isy].klingons++;
329 /* SC has scooted, Remove him from current quadrant */
334 game.future[FSCDBAS]=FOREVER;
336 if (game.quad[game.kx[i]][game.ky[i]] == IHS) break;
337 game.quad[game.kx[i]][game.ky[i]] = IHDOT;
338 game.kx[i] = game.kx[game.nenhere];
339 game.ky[i] = game.ky[game.nenhere];
340 game.kdist[i] = game.kdist[game.nenhere];
341 game.kavgd[i] = game.kavgd[game.nenhere];
342 game.kpower[i] = game.kpower[game.nenhere];
345 if (game.condit!=IHDOCKED) newcnd();
348 /* check for a helpful planet */
349 for (i = 0; i < game.inplan; i++) {
350 if (game.state.plnets[i].x==game.state.isx && game.state.plnets[i].y==game.state.isy &&
351 game.state.plnets[i].crystals == 1) {
352 /* destroy the planet */
353 DESTROY(&game.state.plnets[i]);
354 game.state.galaxy[game.state.isx][game.state.isy].planets -= 1;
355 if (game.damage[DRADIO] == 0.0 || game.condit == IHDOCKED) {
356 if (*ipage==0) pause_game(1);
358 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
359 proutn(" a planet in ");
360 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
361 prout(" has been destroyed");
362 prout(" by the Super-commander.\"");
367 return 0; /* looks good! */
370 void scom(int *ipage)
372 int i, i2, j, ideltax, ideltay, ibqx, ibqy, sx, sy, ifindit, iwhichb;
374 int basetbl[BASEMAX+1];
375 double bdist[BASEMAX+1];
378 if (game.idebug) prout("SCOM");
381 /* Decide on being active or passive */
382 flag = ((NKILLC+NKILLK)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) ||
383 (game.state.date-game.indate) < 3.0);
384 if (game.iscate==0 && flag) {
385 /* compute move away from Enterprise */
386 ideltax = game.state.isx-game.quadx;
387 ideltay = game.state.isy-game.quady;
388 if (sqrt(ideltax*(double)ideltax+ideltay*(double)ideltay) > 2.0) {
389 /* circulate in space */
390 ideltax = game.state.isy-game.quady;
391 ideltay = game.quadx-game.state.isx;
395 /* compute distances to starbases */
396 if (game.state.rembase <= 0) {
397 /* nothing left to do */
398 game.future[FSCMOVE] = FOREVER;
405 ibqx = game.state.baseqx[i];
406 ibqy = game.state.baseqy[i];
407 bdist[i] = sqrt(square(ibqx-sx) + square(ibqy-sy));
409 if (game.state.rembase > 1) {
410 /* sort into nearest first order */
414 for (i=1; i < game.state.rembase-1; i++) {
415 if (bdist[i] > bdist[i+1]) {
418 bdist[i] = bdist[i+1];
420 basetbl[i] = basetbl[i+1];
427 /* look for nearest base without a commander, no Enterprise, and
428 without too many Klingons, and not already under attack. */
429 ifindit = iwhichb = 0;
432 i = basetbl[i2]; /* bug in original had it not finding nearest*/
433 ibqx = game.state.baseqx[i];
434 ibqy = game.state.baseqy[i];
435 if ((ibqx == game.quadx && ibqy == game.quady) ||
436 (ibqx == game.batx && ibqy == game.baty) ||
437 game.state.galaxy[ibqx][ibqy].supernova ||
438 game.state.galaxy[ibqx][ibqy].klingons > 8)
440 /* if there is a commander, an no other base is appropriate,
441 we will take the one with the commander */
443 if (ibqx==game.state.cx[j] && ibqy==game.state.cy[j] && ifindit!= 2) {
449 if (j > game.state.remcom) { /* no commander -- use this one */
455 if (ifindit==0) return; /* Nothing suitable -- wait until next time*/
456 ibqx = game.state.baseqx[iwhichb];
457 ibqy = game.state.baseqy[iwhichb];
458 /* decide how to move toward base */
459 ideltax = ibqx - game.state.isx;
460 ideltay = ibqy - game.state.isy;
462 /* Maximum movement is 1 quadrant in either or both axis */
463 if (ideltax > 1) ideltax = 1;
464 if (ideltax < -1) ideltax = -1;
465 if (ideltay > 1) ideltay = 1;
466 if (ideltay < -1) ideltay = -1;
468 /* try moving in both x and y directions */
469 iqx = game.state.isx + ideltax;
470 iqy = game.state.isy + ideltax;
471 if (movescom(iqx, iqy, flag, ipage)) {
472 /* failed -- try some other maneuvers */
473 if (ideltax==0 || ideltay==0) {
474 /* attempt angle move */
476 iqy = game.state.isy + 1;
477 if (movescom(iqx, iqy, flag, ipage)) {
478 iqy = game.state.isy - 1;
479 movescom(iqx, iqy, flag, ipage);
483 iqx = game.state.isx + 1;
484 if (movescom(iqx, iqy, flag, ipage)) {
485 iqx = game.state.isx - 1;
486 movescom(iqx, iqy, flag, ipage);
491 /* try moving just in x or y */
492 iqy = game.state.isy;
493 if (movescom(iqx, iqy, flag, ipage)) {
494 iqy = game.state.isy + ideltay;
495 iqx = game.state.isx;
496 movescom(iqx, iqy, flag, ipage);
500 /* check for a base */
501 if (game.state.rembase == 0) {
502 game.future[FSCMOVE] = FOREVER;
504 else for_starbases(i) {
505 ibqx = game.state.baseqx[i];
506 ibqy = game.state.baseqy[i];
507 if (ibqx==game.state.isx && ibqy == game.state.isy && game.state.isx != game.batx && game.state.isy != game.baty) {
508 /* attack the base */
509 if (flag) return; /* no, don't attack base! */
512 game.future[FSCDBAS] = game.state.date + 1.0 +2.0*Rand();
513 if (game.future[FCDBAS] < FOREVER) game.future[FSCDBAS] +=
514 game.future[FCDBAS]-game.state.date;
515 if (game.damage[DRADIO] > 0 && game.condit != IHDOCKED)
516 return; /* no warning */
518 if (*ipage == 0) pause_game(1);
520 proutn("Lt. Uhura- \"Captain, the starbase in ");
521 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
523 prout(" reports that it is under attack from the Klingon Super-commander.");
524 proutn(" It can survive until stardate %d.\"",
525 (int)game.future[FSCDBAS]);
526 if (game.resting==0) return;
527 prout("Mr. Spock- \"Captain, shall we cancel the rest period?\"");
530 game.optime = 0.0; /* actually finished */
534 /* Check for intelligence report */
540 (game.damage[DRADIO] > 0.0 && game.condit != IHDOCKED) ||
541 !game.state.galaxy[game.state.isx][game.state.isy].charted))
543 if (*ipage==0) pause_game(1);
545 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
546 proutn(" the Super-commander is in ");
547 proutn(cramlc(quadrant, game.state.isx, game.state. isy));
554 int idx, idy, im, i, dum, my;
555 /* Move the Tholian */
556 if (game.ithere==0 || game.justin == 1) return;
558 if (game.ithx == 1 && game.ithy == 1) {
559 idx = 1; idy = QUADSIZE;
561 else if (game.ithx == 1 && game.ithy == QUADSIZE) {
562 idx = QUADSIZE; idy = QUADSIZE;
564 else if (game.ithx == QUADSIZE && game.ithy == QUADSIZE) {
565 idx = QUADSIZE; idy = 1;
567 else if (game.ithx == QUADSIZE && game.ithy == 1) {
571 /* something is wrong! */
576 /* Do nothing if we are blocked */
577 if (game.quad[idx][idy]!= IHDOT && game.quad[idx][idy]!= IHWEB) return;
578 game.quad[game.ithx][game.ithy] = IHWEB;
580 if (game.ithx != idx) {
582 im = fabs((double)idx - game.ithx)/((double)idx - game.ithx);
583 while (game.ithx != idx) {
585 if (game.quad[game.ithx][game.ithy]==IHDOT) game.quad[game.ithx][game.ithy] = IHWEB;
588 else if (game.ithy != idy) {
590 im = fabs((double)idy - game.ithy)/((double)idy - game.ithy);
591 while (game.ithy != idy) {
593 if (game.quad[game.ithx][game.ithy]==IHDOT) game.quad[game.ithx][game.ithy] = IHWEB;
596 game.quad[game.ithx][game.ithy] = IHT;
597 game.kx[game.nenhere]=game.ithx;
598 game.ky[game.nenhere]=game.ithy;
600 /* check to see if all holes plugged */
602 if (game.quad[1][i]!=IHWEB && game.quad[1][i]!=IHT) return;
603 if (game.quad[QUADSIZE][i]!=IHWEB && game.quad[QUADSIZE][i]!=IHT) return;
604 if (game.quad[i][1]!=IHWEB && game.quad[i][1]!=IHT) return;
605 if (game.quad[i][QUADSIZE]!=IHWEB && game.quad[i][QUADSIZE]!=IHT) return;
607 /* All plugged up -- Tholian splits */
608 game.quad[game.ithx][game.ithy]=IHWEB;
609 dropin(IHBLANK, &dum, &my);
610 crmena(1,IHT, 2, game.ithx, game.ithy);
611 prout(" completes web.");
612 game.ithere = game.ithx = game.ithy = 0;