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 (!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 (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;
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)
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 (skill >= SKILL_EXPERT) for_local_enemies(i) {
300 if (game.quad[ix][iy] == IHK || game.quad[ix][iy] == IHR)
301 movebaddy(ix, iy, i, game.quad[ix][iy]);
307 static int movescom(int iqx, int iqy, int flag, int *ipage)
311 if ((iqx==quadx && iqy==quady) ||
312 !VALID_QUADRANT(iqx, iqy) ||
313 game.state.galaxy[iqx][iqy].supernova ||
314 game.state.galaxy[iqx][iqy].klingons > 8)
317 /* Avoid quadrants with bases if we want to avoid Enterprise */
319 if (game.state.baseqx[i]==iqx && game.state.baseqy[i]==iqy) return 1;
321 if (justin && !iscate) return 1;
323 game.state.galaxy[game.state.isx][game.state.isy].klingons--;
324 game.state.isx = iqx;
325 game.state.isy = iqy;
326 game.state.galaxy[game.state.isx][game.state.isy].klingons++;
328 /* SC has scooted, Remove him from current quadrant */
333 game.future[FSCDBAS]=1e30;
335 if (game.quad[game.kx[i]][game.ky[i]] == IHS) break;
336 game.quad[game.kx[i]][game.ky[i]] = IHDOT;
337 game.kx[i] = game.kx[nenhere];
338 game.ky[i] = game.ky[nenhere];
339 game.kdist[i] = game.kdist[nenhere];
340 game.kavgd[i] = game.kavgd[nenhere];
341 game.kpower[i] = game.kpower[nenhere];
344 if (condit!=IHDOCKED) newcnd();
347 /* check for a helpful planet */
348 for (i = 0; i < inplan; i++) {
349 if (game.state.plnets[i].x==game.state.isx && game.state.plnets[i].y==game.state.isy &&
350 game.state.plnets[i].crystals == 1) {
351 /* destroy the planet */
352 DESTROY(&game.state.plnets[i]);
353 game.state.galaxy[game.state.isx][game.state.isy].planets -= 1;
354 if (game.damage[DRADIO] == 0.0 || condit == IHDOCKED) {
355 if (*ipage==0) pause_game(1);
357 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
358 proutn(" a planet in ");
359 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
360 prout(" has been destroyed");
361 prout(" by the Super-commander.\"");
366 return 0; /* looks good! */
369 void scom(int *ipage)
371 int i, i2, j, ideltax, ideltay, ibqx, ibqy, sx, sy, ifindit, iwhichb;
373 int basetbl[BASEMAX];
374 double bdist[BASEMAX];
377 if (idebug) prout("SCOM");
380 /* Decide on being active or passive */
381 flag = ((game.state.killc+game.state.killk)/(game.state.date+0.01-indate) < 0.1*skill*(skill+1.0) ||
382 (game.state.date-indate) < 3.0);
383 if (iscate==0 && flag) {
384 /* compute move away from Enterprise */
385 ideltax = game.state.isx-quadx;
386 ideltay = game.state.isy-quady;
387 if (sqrt(ideltax*(double)ideltax+ideltay*(double)ideltay) > 2.0) {
388 /* circulate in space */
389 ideltax = game.state.isy-quady;
390 ideltay = quadx-game.state.isx;
394 /* compute distances to starbases */
395 if (game.state.rembase <= 0) {
396 /* nothing left to do */
397 game.future[FSCMOVE] = 1e30;
404 ibqx = game.state.baseqx[i];
405 ibqy = game.state.baseqy[i];
406 bdist[i] = sqrt(square(ibqx-sx) + square(ibqy-sy));
408 if (game.state.rembase > 1) {
409 /* sort into nearest first order */
413 for (i=1; i < game.state.rembase-1; i++) {
414 if (bdist[i] > bdist[i+1]) {
417 bdist[i] = bdist[i+1];
419 basetbl[i] = basetbl[i+1];
426 /* look for nearest base without a commander, no Enterprise, and
427 without too many Klingons, and not already under attack. */
428 ifindit = iwhichb = 0;
431 i = basetbl[i2]; /* bug in original had it not finding nearest*/
432 ibqx = game.state.baseqx[i];
433 ibqy = game.state.baseqy[i];
434 if ((ibqx == quadx && ibqy == quady) ||
435 (ibqx == batx && ibqy == baty) ||
436 game.state.galaxy[ibqx][ibqy].supernova ||
437 game.state.galaxy[ibqx][ibqy].klingons > 8)
439 /* if there is a commander, an no other base is appropriate,
440 we will take the one with the commander */
442 if (ibqx==game.state.cx[j] && ibqy==game.state.cy[j] && ifindit!= 2) {
448 if (j > game.state.remcom) { /* no commander -- use this one */
454 if (ifindit==0) return; /* Nothing suitable -- wait until next time*/
455 ibqx = game.state.baseqx[iwhichb];
456 ibqy = game.state.baseqy[iwhichb];
457 /* decide how to move toward base */
458 ideltax = ibqx - game.state.isx;
459 ideltay = ibqy - game.state.isy;
461 /* Maximum movement is 1 quadrant in either or both axis */
462 if (ideltax > 1) ideltax = 1;
463 if (ideltax < -1) ideltax = -1;
464 if (ideltay > 1) ideltay = 1;
465 if (ideltay < -1) ideltay = -1;
467 /* try moving in both x and y directions */
468 iqx = game.state.isx + ideltax;
469 iqy = game.state.isy + ideltax;
470 if (movescom(iqx, iqy, flag, ipage)) {
471 /* failed -- try some other maneuvers */
472 if (ideltax==0 || ideltay==0) {
473 /* attempt angle move */
475 iqy = game.state.isy + 1;
476 if (movescom(iqx, iqy, flag, ipage)) {
477 iqy = game.state.isy - 1;
478 movescom(iqx, iqy, flag, ipage);
482 iqx = game.state.isx + 1;
483 if (movescom(iqx, iqy, flag, ipage)) {
484 iqx = game.state.isx - 1;
485 movescom(iqx, iqy, flag, ipage);
490 /* try moving just in x or y */
491 iqy = game.state.isy;
492 if (movescom(iqx, iqy, flag, ipage)) {
493 iqy = game.state.isy + ideltay;
494 iqx = game.state.isx;
495 movescom(iqx, iqy, flag, ipage);
499 /* check for a base */
500 if (game.state.rembase == 0) {
501 game.future[FSCMOVE] = 1e30;
503 else for_starbases(i) {
504 ibqx = game.state.baseqx[i];
505 ibqy = game.state.baseqy[i];
506 if (ibqx==game.state.isx && ibqy == game.state.isy && game.state.isx != batx && game.state.isy != baty) {
507 /* attack the base */
508 if (flag) return; /* no, don't attack base! */
511 game.future[FSCDBAS] = game.state.date + 1.0 +2.0*Rand();
512 if (game.future[FCDBAS] < 1e30) game.future[FSCDBAS] +=
513 game.future[FCDBAS]-game.state.date;
514 if (game.damage[DRADIO] > 0 && condit != IHDOCKED)
515 return; /* no warning */
517 if (*ipage == 0) pause_game(1);
519 proutn("Lt. Uhura- \"Captain, the starbase in ");
520 proutn(cramlc(quadrant, game.state.isx, game.state.isy));
522 prout(" reports that it is under attack from the Klingon Super-commander.");
523 proutn(" It can survive until stardate %d.\"",
524 (int)game.future[FSCDBAS]);
525 if (resting==0) return;
526 prout("Mr. Spock- \"Captain, shall we cancel the rest period?\"");
529 Time = 0.0; /* actually finished */
533 /* Check for intelligence report */
539 (game.damage[DRADIO] > 0.0 && condit != IHDOCKED) ||
540 !game.state.galaxy[game.state.isx][game.state.isy].charted))
542 if (*ipage==0) pause_game(1);
544 prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports");
545 proutn(" the Super-commander is in ");
546 proutn(cramlc(quadrant, game.state.isx, game.state. isy));
553 int idx, idy, im, i, dum, my;
554 /* Move the Tholian */
555 if (ithere==0 || justin == 1) return;
557 if (ithx == 1 && ithy == 1) {
558 idx = 1; idy = QUADSIZE;
560 else if (ithx == 1 && ithy == QUADSIZE) {
561 idx = QUADSIZE; idy = QUADSIZE;
563 else if (ithx == QUADSIZE && ithy == QUADSIZE) {
564 idx = QUADSIZE; idy = 1;
566 else if (ithx == QUADSIZE && ithy == 1) {
570 /* something is wrong! */
575 /* Do nothing if we are blocked */
576 if (game.quad[idx][idy]!= IHDOT && game.quad[idx][idy]!= IHWEB) return;
577 game.quad[ithx][ithy] = IHWEB;
581 im = fabs((double)idx - ithx)/((double)idx - ithx);
582 while (ithx != idx) {
584 if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;
587 else if (ithy != idy) {
589 im = fabs((double)idy - ithy)/((double)idy - ithy);
590 while (ithy != idy) {
592 if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;
595 game.quad[ithx][ithy] = IHT;
596 game.kx[nenhere]=ithx;
597 game.ky[nenhere]=ithy;
599 /* check to see if all holes plugged */
601 if (game.quad[1][i]!=IHWEB && game.quad[1][i]!=IHT) return;
602 if (game.quad[QUADSIZE][i]!=IHWEB && game.quad[QUADSIZE][i]!=IHT) return;
603 if (game.quad[i][1]!=IHWEB && game.quad[i][1]!=IHT) return;
604 if (game.quad[i][QUADSIZE]!=IHWEB && game.quad[i][QUADSIZE]!=IHT) return;
606 /* All plugged up -- Tholian splits */
607 game.quad[ithx][ithy]=IHWEB;
608 dropin(IHBLANK, &dum, &my);
609 crmena(1,IHT, 2, ithx, ithy);
610 prout(" completes web.");
611 ithere = ithx = ithy = 0;