X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=src%2Fai.c;h=31d19ad13bdcf06293ab473679a9abfc09a817a5;hp=66b50d7165ded56ef8d606e8f368760c8f96b21b;hb=2c5438d3c22fe863ad8054d214f2afdd061ad43a;hpb=9aef5f5aae5fde0ed2b462945750c7aee59b3c1e diff --git a/src/ai.c b/src/ai.c index 66b50d7..31d19ad 100644 --- a/src/ai.c +++ b/src/ai.c @@ -12,11 +12,12 @@ static bool tryexit(coord look, int ienm, int loccom, bool irun) game.state.galaxy[iq.x][iq.y].supernova || game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1) return false; /* no can do -- neg energy, supernovae, or >MAXKLQUAD-1 Klingons */ - if (ienm == IHR) return false; /* Romulans cannot escape! */ + if (ienm == IHR) + return false; /* Romulans cannot escape! */ if (!irun) { /* avoid intruding on another commander's territory */ if (ienm == IHC) { - for_commanders(n) + for (n = 1; n <= game.state.remcom; n++) if (same(game.state.kcmdr[n],iq)) return false; /* refuse to leave if currently attacking starbase */ @@ -27,8 +28,8 @@ static bool tryexit(coord look, int ienm, int loccom, bool irun) if (game.kpower[loccom] > 1000.0) return false; } - /* print escape message and move out of quadrant. - We know this if either short or long range sensors are working */ + // print escape message and move out of quadrant. + // We know this if either short or long range sensors are working if (!damaged(DSRSENS) || !damaged(DLRSENS) || game.condition == docked) { crmena(true, ienm, sector, game.ks[loccom]); @@ -58,7 +59,7 @@ static bool tryexit(coord look, int ienm, int loccom, bool irun) game.state.kscmdr=iq; } else { - for_commanders(n) { + for (n = 1; n <= game.state.remcom; n++) { if (same(game.state.kcmdr[n], game.quadrant)) { game.state.kcmdr[n]=iq; break; @@ -69,6 +70,45 @@ static bool tryexit(coord look, int ienm, int loccom, bool irun) return true; /* success */ } +/************************************************************************* +The bad-guy movement algorithm: + +1. Enterprise has "force" based on condition of phaser and photon torpedoes. +If both are operating full strength, force is 1000. If both are damaged, +force is -1000. Having shields down subtracts an additional 1000. + +2. Enemy has forces equal to the energy of the attacker plus +100*(K+R) + 500*(C+S) - 400 for novice through good levels OR +346*K + 400*R + 500*(C+S) - 400 for expert and emeritus. + +Attacker Initial energy levels (nominal): +Klingon Romulan Commander Super-Commander +Novice 400 700 1200 +Fair 425 750 1250 +Good 450 800 1300 1750 +Expert 475 850 1350 1875 +Emeritus 500 900 1400 2000 +VARIANCE 75 200 200 200 + +Enemy vessels only move prior to their attack. In Novice - Good games +only commanders move. In Expert games, all enemy vessels move if there +is a commander present. In Emeritus games all enemy vessels move. + +3. If Enterprise is not docked, an agressive action is taken if enemy +forces are 1000 greater than Enterprise. + +Agressive action on average cuts the distance between the ship and +the enemy to 1/4 the original. + +4. At lower energy advantage, movement units are proportional to the +advantage with a 650 advantage being to hold ground, 800 to move forward +1, 950 for two, 150 for back 4, etc. Variance of 100. + +If docked, is reduced by roughly 1.75*game.skill, generally forcing a +retreat, especially at high skill levels. + +5. Motion is limited to skill level, except for SC hi-tailing it out. +**************************************************************************/ static void movebaddy(coord com, int loccom, feature ienm) /* tactical movement for the bad guys */ @@ -95,46 +135,9 @@ static void movebaddy(coord com, int loccom, feature ienm) } else { /* decide whether to advance, retreat, or hold position */ -/* Algorithm: - * Enterprise has "force" based on condition of phaser and photon torpedoes. - If both are operating full strength, force is 1000. If both are damaged, - force is -1000. Having shields down subtracts an additional 1000. - - * Enemy has forces equal to the energy of the attacker plus - 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR - 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus. - - Attacker Initial energy levels (nominal): - Klingon Romulan Commander Super-Commander - Novice 400 700 1200 - Fair 425 750 1250 - Good 450 800 1300 1750 - Expert 475 850 1350 1875 - Emeritus 500 900 1400 2000 - VARIANCE 75 200 200 200 - - Enemy vessels only move prior to their attack. In Novice - Good games - only commanders move. In Expert games, all enemy vessels move if there - is a commander present. In Emeritus games all enemy vessels move. - - * If Enterprise is not docked, an agressive action is taken if enemy - forces are 1000 greater than Enterprise. - - Agressive action on average cuts the distance between the ship and - the enemy to 1/4 the original. - - * At lower energy advantage, movement units are proportional to the - advantage with a 650 advantage being to hold ground, 800 to move forward - 1, 950 for two, 150 for back 4, etc. Variance of 100. - - If docked, is reduced by roughly 1.75*game.skill, generally forcing a - retreat, especially at high skill levels. - - * Motion is limited to skill level, except for SC hi-tailing it out. - */ - forces = game.kpower[loccom]+100.0*game.nenhere+400*(nbaddys-1); - if (!game.shldup) forces += 1000; /* Good for enemy if shield is down! */ + if (!game.shldup) + forces += 1000; /* Good for enemy if shield is down! */ if (!damaged(DPHASER) || !damaged(DPHOTON)) { if (damaged(DPHASER)) /* phasers damaged */ forces += 300.0; @@ -169,9 +172,12 @@ static void movebaddy(coord com, int loccom, feature ienm) } /* calculate preferred number of steps */ nsteps = motion < 0 ? -motion : motion; - if (motion > 0 && nsteps > mdist) nsteps = mdist; /* don't overshoot */ - if (nsteps > QUADSIZE) nsteps = QUADSIZE; /* This shouldn't be necessary */ - if (nsteps < 1) nsteps = 1; /* This shouldn't be necessary */ + if (motion > 0 && nsteps > mdist) + nsteps = mdist; /* don't overshoot */ + if (nsteps > QUADSIZE) + nsteps = QUADSIZE; /* This shouldn't be necessary */ + if (nsteps < 1) + nsteps = 1; /* This shouldn't be necessary */ if (idebug) { proutn("NSTEPS = %d:", nsteps); } @@ -268,7 +274,7 @@ static void movebaddy(coord com, int loccom, feature ienm) } void moveklings(void) -/* move a commander */ +/* Klingon tactical movement */ { coord w; int i; @@ -276,10 +282,10 @@ void moveklings(void) if (idebug) prout("== MOVCOM"); - /* Figure out which Klingon is the commander (or Supercommander) - and do move */ + // Figure out which Klingon is the commander (or Supercommander) + // and do move if (game.comhere) - for_local_enemies(i) { + for (i = 1; i <= game.nenhere; i++) { w = game.ks[i]; if (game.quad[w.x][w.y] == IHC) { movebaddy(w, i, IHC); @@ -287,27 +293,27 @@ void moveklings(void) } } if (game.ishere) - for_local_enemies(i) { + for (i = 1; i <= game.nenhere; i++) { w = game.ks[i]; if (game.quad[w.x][w.y] == IHS) { movebaddy(w, i, IHS); break; } } - /* if skill level is high, move other Klingons and Romulans too! - Move these last so they can base their actions on what the - commander(s) do. */ + // if skill level is high, move other Klingons and Romulans too! + // Move these last so they can base their actions on what the + // commander(s) do. if (game.skill >= SKILL_EXPERT && (game.options & OPTION_MVBADDY)) - for_local_enemies(i) { + for (i = 1; i <= game.nenhere; i++) { w = game.ks[i]; if (game.quad[w.x][w.y] == IHK || game.quad[w.x][w.y] == IHR) movebaddy(w, i, game.quad[w.x][w.y]); } - sortkl(); + sortklings(); } -static bool movescom(coord iq, bool flag) +static bool movescom(coord iq, bool avoid) /* commander movement helper */ { int i; @@ -316,9 +322,9 @@ static bool movescom(coord iq, bool flag) game.state.galaxy[iq.x][iq.y].supernova || game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1) return 1; - if (flag) { + if (avoid) { /* Avoid quadrants with bases if we want to avoid Enterprise */ - for_starbases(i) + for (i = 1; i <= game.state.rembase; i++) if (same(game.state.baseq[i], iq)) return true; } @@ -335,7 +341,7 @@ static bool movescom(coord iq, bool flag) game.ishere = false; game.ientesc = false; unschedule(FSCDBAS); - for_local_enemies(i) + for (i = 1; i <= game.nenhere; i++) if (game.quad[game.ks[i].x][game.ks[i].y] == IHS) break; game.quad[game.ks[i].x][game.ks[i].y] = IHDOT; @@ -347,14 +353,14 @@ static bool movescom(coord iq, bool flag) game.nenhere--; if (game.condition!=docked) newcnd(); - sortkl(); + sortklings(); } /* check for a helpful planet */ for (i = 0; i < game.inplan; i++) { if (same(game.state.planets[i].w, game.state.kscmdr) && game.state.planets[i].crystals == present) { /* destroy the planet */ - DESTROY(&game.state.planets[i]); + game.state.planets[i].pclass = destroyed; game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].planet = NOPLANET; if (!damaged(DRADIO) || game.condition == docked) { pause_game(true); @@ -370,22 +376,22 @@ static bool movescom(coord iq, bool flag) return false; /* looks good! */ } -void scom(void) +void supercommander(void) /* move the Super Commander */ { int i, i2, j, ideltax, ideltay, ifindit, iwhichb; coord iq, sc, ibq; int basetbl[BASEMAX+1]; double bdist[BASEMAX+1]; - bool flag; + bool avoid; if (idebug) - prout("== SCOM"); + prout("== SUPERCOMMANDER"); /* Decide on being active or passive */ - flag = ((NKILLC+NKILLK)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) || + avoid = ((NKILLC+NKILLK)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) || (game.state.date-game.indate) < 3.0); - if (!game.iscate && flag) { + if (!game.iscate && avoid) { /* compute move away from Enterprise */ ideltax = game.state.kscmdr.x-game.quadrant.x; ideltay = game.state.kscmdr.y-game.quadrant.y; @@ -403,7 +409,7 @@ void scom(void) return; } sc = game.state.kscmdr; - for_starbases(i) { + for (i = 1; i <= game.state.rembase; i++) { basetbl[i] = i; bdist[i] = distance(game.state.baseq[i], sc); } @@ -429,16 +435,16 @@ void scom(void) without too many Klingons, and not already under attack. */ ifindit = iwhichb = 0; - for_starbases(i2) { + for (i2 = 1; i2 <= game.state.rembase; i2++) { i = basetbl[i2]; /* bug in original had it not finding nearest*/ ibq = game.state.baseq[i]; if (same(ibq, game.quadrant) || same(ibq, game.battle) || game.state.galaxy[ibq.x][ibq.y].supernova || game.state.galaxy[ibq.x][ibq.y].klingons > MAXKLQUAD-1) continue; - /* if there is a commander, an no other base is appropriate, - we will take the one with the commander */ - for_commanders (j) { + // if there is a commander, and no other base is appropriate, + // we will take the one with the commander + for (j = 1; j <= game.state.remcom; j++) { if (same(ibq, game.state.kcmdr[j]) && ifindit!= 2) { ifindit = 2; iwhichb = i; @@ -451,7 +457,8 @@ void scom(void) break; } } - if (ifindit==0) return; /* Nothing suitable -- wait until next time*/ + if (ifindit==0) + return; /* Nothing suitable -- wait until next time*/ ibq = game.state.baseq[iwhichb]; /* decide how to move toward base */ ideltax = ibq.x - game.state.kscmdr.x; @@ -470,32 +477,32 @@ void scom(void) /* try moving in both x and y directions */ iq.x = game.state.kscmdr.x + ideltax; iq.y = game.state.kscmdr.y + ideltax; - if (movescom(iq, flag)) { + if (movescom(iq, avoid)) { /* failed -- try some other maneuvers */ if (ideltax==0 || ideltay==0) { /* attempt angle move */ if (ideltax != 0) { iq.y = game.state.kscmdr.y + 1; - if (movescom(iq, flag)) { + if (movescom(iq, avoid)) { iq.y = game.state.kscmdr.y - 1; - movescom(iq, flag); + movescom(iq, avoid); } } else { iq.x = game.state.kscmdr.x + 1; - if (movescom(iq, flag)) { + if (movescom(iq, avoid)) { iq.x = game.state.kscmdr.x - 1; - movescom(iq, flag); + movescom(iq, avoid); } } } else { /* try moving just in x or y */ iq.y = game.state.kscmdr.y; - if (movescom(iq, flag)) { + if (movescom(iq, avoid)) { iq.y = game.state.kscmdr.y + ideltay; iq.x = game.state.kscmdr.x; - movescom(iq, flag); + movescom(iq, avoid); } } } @@ -503,34 +510,37 @@ void scom(void) if (game.state.rembase == 0) { unschedule(FSCMOVE); } - else for_starbases(i) { - ibq = game.state.baseq[i]; - if (same(ibq, game.state.kscmdr) && same(game.state.kscmdr, game.battle)) { - /* attack the base */ - if (flag) return; /* no, don't attack base! */ - game.iseenit = false; - game.isatb = 1; - schedule(FSCDBAS, 1.0 +2.0*Rand()); - if (is_scheduled(FCDBAS)) - postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date); - if (damaged(DRADIO) && game.condition != docked) - return; /* no warning */ - game.iseenit = true; - pause_game(true); - proutn(_("Lt. Uhura- \"Captain, the starbase in ")); - proutn(cramlc(quadrant, game.state.kscmdr)); - skip(1); - prout(_(" reports that it is under attack from the Klingon Super-commander.")); - proutn(_(" It can survive until stardate %d.\""), - (int)scheduled(FSCDBAS)); - if (!game.resting) - return; - prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")); - if (ja() == false) + else { + for (i = 1; i <= game.state.rembase; i++) { + ibq = game.state.baseq[i]; + if (same(ibq, game.state.kscmdr) && same(game.state.kscmdr, game.battle)) { + /* attack the base */ + if (avoid) + return; /* no, don't attack base! */ + game.iseenit = false; + game.isatb = 1; + schedule(FSCDBAS, 1.0 +2.0*Rand()); + if (is_scheduled(FCDBAS)) + postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date); + if (damaged(DRADIO) && game.condition != docked) + return; /* no warning */ + game.iseenit = true; + pause_game(true); + proutn(_("Lt. Uhura- \"Captain, the starbase in ")); + proutn(cramlc(quadrant, game.state.kscmdr)); + skip(1); + prout(_(" reports that it is under attack from the Klingon Super-commander.")); + proutn(_(" It can survive until stardate %d.\""), + (int)scheduled(FSCDBAS)); + if (!game.resting) + return; + prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")); + if (ja() == false) + return; + game.resting = false; + game.optime = 0.0; /* actually finished */ return; - game.resting = false; - game.optime = 0.0; /* actually finished */ - return; + } } } /* Check for intelligence report */ @@ -548,11 +558,10 @@ void scom(void) return; } -void movetho(void) +void movetholian(void) /* move the Tholian */ { int idx, idy, im, i; - /* Move the Tholian */ if (!game.ithere || game.justin) return; @@ -574,7 +583,7 @@ void movetho(void) return; } - /* Do nothing if we are blocked */ + /* do nothing if we are blocked */ if (game.quad[idx][idy]!= IHDOT && game.quad[idx][idy]!= IHWEB) return; game.quad[game.tholian.x][game.tholian.y] = IHWEB; @@ -601,7 +610,7 @@ void movetho(void) game.ks[game.nenhere] = game.tholian; /* check to see if all holes plugged */ - for_sectors(i) { + for (i = 1; i <= QUADSIZE; i++) { if (game.quad[1][i]!=IHWEB && game.quad[1][i]!=IHT) return; if (game.quad[QUADSIZE][i]!=IHWEB && game.quad[QUADSIZE][i]!=IHT)