X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=src%2Fevents.c;h=b82aff7caa9b65addeaf47cdb725b20cf5c64722;hp=589a83821ad22a3489a01dc0fb10334be4a3dbca;hb=9aef5f5aae5fde0ed2b462945750c7aee59b3c1e;hpb=e535e2ef833a03ec84d0f002d684c07ddde893f1 diff --git a/src/events.c b/src/events.c index 589a838..b82aff7 100644 --- a/src/events.c +++ b/src/events.c @@ -1,27 +1,113 @@ +/* + * events.c -- event-queue handling + * + * This isn't a real event queue a la BSD Trek yet -- you can only have one + * event of each type active at any given time. Mostly these means we can + * only have one FDISTR/FENSLV/FREPRO sequence going at any given time; + * BSD Trek, from which we swiped the idea, can have up to 5. + */ #include "sst.h" #include +event *unschedule(int evtype) +/* remove an event from the schedule */ +{ + game.future[evtype].date = FOREVER; + return &game.future[evtype]; +} + +int is_scheduled(int evtype) +/* is an event of specified type scheduled */ +{ + return game.future[evtype].date != FOREVER; +} + +extern double scheduled(int evtype) +/* when will this event happen? */ +{ + return game.future[evtype].date; +} + +event *schedule(int evtype, double offset) +/* schedule an event of specified type */ +{ + game.future[evtype].date = game.state.date + offset; + return &game.future[evtype]; +} + +void postpone(int evtype, double offset) +/* poistpone a scheduled event */ +{ + game.future[evtype].date += offset; +} + +static bool cancelrest(void) +/* rest period is interrupted by event */ +{ + if (game.resting) { + skip(1); + proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")); + if (ja() == true) { + game.resting = false; + game.optime = 0.0; + return true; + } + } + + return false; +} + void events(void) +/* run through the event queue looking for things to do */ { - int ictbeam=0, ipage=0, istract=0, line, i=0, j, k, l, ixhold=0, iyhold=0; - double fintim = game.state.date + Time, datemin, xtime, repair, yank=0; - int radio_was_broken; + int evcode, i=0, j, k, l; + double fintim = game.state.date + game.optime, datemin, xtime, repair, yank=0; + bool radio_was_broken, ictbeam = false, istract = false; + struct quadrant *pdest, *q; + coord w, hold; + event *ev, *ev2; + + pause_reset(); -#ifdef DEBUG - if (idebug) prout("EVENTS"); -#endif + if (idebug) { + prout("=== EVENTS from %.2f to %.2f:", game.state.date, fintim); + for (i = 1; i < NEVENTS; i++) { + switch (i) { + case FSNOVA: proutn("=== Supernova "); break; + case FTBEAM: proutn("=== T Beam "); break; + case FSNAP: proutn("=== Snapshot "); break; + case FBATTAK: proutn("=== Base Attack "); break; + case FCDBAS: proutn("=== Base Destroy "); break; + case FSCMOVE: proutn("=== SC Move "); break; + case FSCDBAS: proutn("=== SC Base Destroy "); break; + case FDSPROB: proutn("=== Probe Move "); break; + case FDISTR: proutn("=== Distress Call "); break; + case FENSLV: proutn("=== Enlavement "); break; + case FREPRO: proutn("=== Klingon Build "); break; + } + if (is_scheduled(i)) + prout("%.2f", scheduled(i)); + else + prout("never"); - radio_was_broken = (game.damage[DRADIO] != 0.0); + } + } + radio_was_broken = damaged(DRADIO); + + hold.x = hold.y = 0; for (;;) { - /* Select earliest extraneous event, line==0 if no events */ - line = FSPY; - if (alldone) return; + /* Select earliest extraneous event, evcode==0 if no events */ + evcode = FSPY; + if (game.alldone) + return; datemin = fintim; for (l = 1; l < NEVENTS; l++) - if (game.future[l] < datemin) { - line = l; - datemin = game.future[l]; + if (game.future[l].date < datemin) { + evcode = l; + if (idebug) + prout("== Event %d fires", evcode); + datemin = game.future[l].date; } xtime = datemin-game.state.date; game.state.date = datemin; @@ -32,336 +118,451 @@ void events(void) finish(FDEPLETE); return; } + /* Any crew left alive? */ + if (game.state.crew <=0) { + finish(FCREW); + return; + } /* Is life support adequate? */ - if (game.damage[DLIFSUP] && condit != IHDOCKED) { - if (lsupres < xtime && game.damage[DLIFSUP] > lsupres) { + if (damaged(DLIFSUP) && game.condition != docked) { + if (game.lsupres < xtime && game.damage[DLIFSUP] > game.lsupres) { finish(FLIFESUP); return; } - lsupres -= xtime; - if (game.damage[DLIFSUP] <= xtime) lsupres = inlsr; + game.lsupres -= xtime; + if (game.damage[DLIFSUP] <= xtime) + game.lsupres = game.inlsr; } /* Fix devices */ repair = xtime; - if (condit == IHDOCKED) repair /= docfac; + if (game.condition == docked) + repair /= game.docfac; /* Don't fix Deathray here */ for (l=0; l 0.0 && l != DDRAY) game.damage[l] -= (game.damage[l]-repair > 0.0 ? repair : game.damage[l]); /* If radio repaired, update star chart and attack reports */ - if (radio_was_broken && game.damage[DRADIO] == 0.0) { - prout("Lt. Uhura- \"Captain, the sub-space radio is working and"); - prout(" surveillance reports are coming in."); + if (radio_was_broken && !damaged(DRADIO)) { + prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and")); + prout(_(" surveillance reports are coming in.")); skip(1); - if (iseenit==0) { - attakreport(0); - iseenit = 1; + if (!game.iseenit) { + attakreport(false); + game.iseenit = true; } rechart(); - prout(" The star chart is now up to date.\""); + prout(_(" The star chart is now up to date.\"")); skip(1); } - /* Cause extraneous event LINE to occur */ - Time -= xtime; - switch (line) { + /* Cause extraneous event EVCODE to occur */ + game.optime -= xtime; + switch (evcode) { case FSNOVA: /* Supernova */ - if (ipage==0) pause_game(1); - ipage=1; - snova(0,0); - game.future[FSNOVA] = game.state.date + expran(0.5*intime); - if (game.state.galaxy[quadx][quady].supernova) return; + pause_game(true); + snova(false, NULL); + schedule(FSNOVA, expran(0.5*game.intime)); + if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) + return; break; case FSPY: /* Check with spy to see if S.C. should tractor beam */ if (game.state.nscrem == 0 || - ictbeam+istract > 0 || - condit==IHDOCKED || isatb==1 || iscate==1) return; - if (ientesc || - (energy < 2000 && torps < 4 && shield < 1250) || - (game.damage[DPHASER]>0 && (game.damage[DPHOTON]>0 || torps < 4)) || - (game.damage[DSHIELD] > 0 && - (energy < 2500 || game.damage[DPHASER] > 0) && - (torps < 5 || game.damage[DPHOTON] > 0))) { + ictbeam || istract || + game.condition==docked || game.isatb==1 || game.iscate) return; + if (game.ientesc || + (game.energy < 2000 && game.torps < 4 && game.shield < 1250) || + (damaged(DPHASER) && (damaged(DPHOTON) || game.torps < 4)) || + (damaged(DSHIELD) && + (game.energy < 2500 || damaged(DPHASER)) && + (game.torps < 5 || damaged(DPHOTON)))) { /* Tractor-beam her! */ - istract=1; - yank = square(game.state.isx-quadx) + square(game.state.isy-quady); + istract = true; + yank = distance(game.state.kscmdr, game.quadrant); /********* fall through to FTBEAM code ***********/ } - else return; + else + return; case FTBEAM: /* Tractor beam */ - if (line==FTBEAM) { + if (evcode==FTBEAM) { if (game.state.remcom == 0) { - game.future[FTBEAM] = FOREVER; + unschedule(FTBEAM); break; } i = Rand()*game.state.remcom+1.0; - yank = square(game.state.cx[i]-quadx) + square(game.state.cy[i]-quady); - if (istract || condit == IHDOCKED || yank == 0) { + yank = square(game.state.kcmdr[i].x-game.quadrant.x) + square(game.state.kcmdr[i].y-game.quadrant.y); + if (istract || game.condition == docked || yank == 0) { /* Drats! Have to reschedule */ - game.future[FTBEAM] = game.state.date + Time + - expran(1.5*intime/game.state.remcom); + schedule(FTBEAM, + game.optime + expran(1.5*game.intime/game.state.remcom)); break; } } /* tractor beaming cases merge here */ yank = sqrt(yank); - if (ipage==0) pause_game(1); - ipage=1; - Time = (10.0/(7.5*7.5))*yank; /* 7.5 is yank rate (warp 7.5) */ - ictbeam = 1; + pause_game(true); + game.optime = (10.0/(7.5*7.5))*yank; /* 7.5 is yank rate (warp 7.5) */ + ictbeam = true; skip(1); proutn("***"); crmshp(); - prout(" caught in long range tractor beam--"); + prout(_(" caught in long range tractor beam--")); /* If Kirk & Co. screwing around on planet, handle */ - atover(1); /* atover(1) is Grab */ - if (alldone) return; - if (icraft == 1) { /* Caught in Galileo? */ + atover(true); /* atover(true) is Grab */ + if (game.alldone) + return; + if (game.icraft) { /* Caught in Galileo? */ finish(FSTRACTOR); return; } /* Check to see if shuttle is aboard */ - if (iscraft==0) { + if (game.iscraft == offship) { skip(1); if (Rand() > 0.5) { - prout("Galileo, left on the planet surface, is captured"); - prout("by aliens and made into a flying McDonald's."); + prout(_("Galileo, left on the planet surface, is captured")); + prout(_("by aliens and made into a flying McDonald's.")); game.damage[DSHUTTL] = -10; - iscraft = -1; + game.iscraft = removed; } else { - prout("Galileo, left on the planet surface, is well hidden."); + prout(_("Galileo, left on the planet surface, is well hidden.")); } } - if (line==0) { - quadx = game.state.isx; - quady = game.state.isy; - } - else { - quadx = game.state.cx[i]; - quady = game.state.cy[i]; - } - iran(QUADSIZE, §x, §y); + if (evcode==0) + game.quadrant = game.state.kscmdr; + else + game.quadrant = game.state.kcmdr[i]; + game.sector = randplace(QUADSIZE); crmshp(); - proutn(" is pulled to "); - proutn(cramlc(quadrant, quadx, quady)); + proutn(_(" is pulled to ")); + proutn(cramlc(quadrant, game.quadrant)); proutn(", "); - prout(cramlc(sector, sectx, secty)); - if (resting) { - prout("(Remainder of rest/repair period cancelled.)"); - resting = 0; - } - if (shldup==0) { - if (game.damage[DSHIELD]==0 && shield > 0) { - doshield(2); /* Shldsup */ - shldchg=0; + prout(cramlc(sector, game.sector)); + if (game.resting) { + prout(_("(Remainder of rest/repair period cancelled.)")); + game.resting = false; + } + if (!game.shldup) { + if (!damaged(DSHIELD) && game.shield > 0) { + doshield(true); /* raise shields */ + game.shldchg=false; } - else prout("(Shields not currently useable.)"); + else + prout(_("(Shields not currently useable.)")); } - newqad(0); + newqad(false); /* Adjust finish time to time of tractor beaming */ - fintim = game.state.date+Time; - attack(0); - if (game.state.remcom <= 0) game.future[FTBEAM] = FOREVER; - else game.future[FTBEAM] = game.state.date+Time+expran(1.5*intime/game.state.remcom); + fintim = game.state.date+game.optime; + attack(false); + if (game.state.remcom <= 0) + unschedule(FTBEAM); + else + schedule(FTBEAM, game.optime+expran(1.5*game.intime/game.state.remcom)); break; case FSNAP: /* Snapshot of the universe (for time warp) */ game.snapsht = game.state; - game.state.snap = 1; - game.future[FSNAP] = game.state.date + expran(0.5 * intime); + game.state.snap = true; + schedule(FSNAP, expran(0.5 * game.intime)); break; case FBATTAK: /* Commander attacks starbase */ if (game.state.remcom==0 || game.state.rembase==0) { /* no can do */ - game.future[FBATTAK] = game.future[FCDBAS] = FOREVER; + unschedule(FBATTAK); + unschedule(FCDBAS); break; } i = 0; for_starbases(j) { for_commanders(k) - if (game.state.baseqx[j]==game.state.cx[k] && game.state.baseqy[j]==game.state.cy[k] && - (game.state.baseqx[j]!=quadx || game.state.baseqy[j]!=quady) && - (game.state.baseqx[j]!=game.state.isx || game.state.baseqy[j]!=game.state.isy)) { + if (same(game.state.baseq[j], game.state.kcmdr[k]) && + !same(game.state.baseq[j], game.quadrant) && + !same(game.state.baseq[j], game.state.kscmdr)) { i = 1; break; } - if (i == 1) break; + if (i == 1) + break; } if (j>game.state.rembase) { /* no match found -- try later */ - game.future[FBATTAK] = game.state.date + expran(0.3*intime); - game.future[FCDBAS] = FOREVER; + schedule(FBATTAK, expran(0.3*game.intime)); + unschedule(FCDBAS); break; } /* commander + starbase combination found -- launch attack */ - batx = game.state.baseqx[j]; - baty = game.state.baseqy[j]; - game.future[FCDBAS] = game.state.date+1.0+3.0*Rand(); - if (isatb) /* extra time if SC already attacking */ - game.future[FCDBAS] += game.future[FSCDBAS]-game.state.date; - game.future[FBATTAK] = game.future[FCDBAS] +expran(0.3*intime); - iseenit = 0; - if (game.damage[DRADIO] != 0.0 && - condit != IHDOCKED) break; /* No warning :-( */ - iseenit = 1; - if (ipage==0) pause_game(1); - ipage = 1; + game.battle = game.state.baseq[j]; + schedule(FCDBAS, 1.0+3.0*Rand()); + if (game.isatb) /* extra time if SC already attacking */ + postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date); + game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime); + game.iseenit = false; + if (!damaged(DRADIO) && game.condition != docked) + break; /* No warning :-( */ + game.iseenit = true; + pause_game(true); skip(1); - proutn("Lt. Uhura- \"Captain, the starbase in "); - prout(cramlc(quadrant, batx, baty)); - prout(" reports that it is under attack and that it can"); - proutn(" hold out only until stardate %d", - (int)game.future[FCDBAS]); + proutn(_("Lt. Uhura- \"Captain, the starbase in ")); + prout(cramlc(quadrant, game.battle)); + prout(_(" reports that it is under attack and that it can")); + proutn(_(" hold out only until stardate %d"), + (int)scheduled(FCDBAS)); prout(".\""); - if (resting) { - skip(1); - proutn("Mr. Spock- \"Captain, shall we cancel the rest period?\" "); - if (ja()) { - resting = 0; - Time = 0.0; - return; - } - } + if (cancelrest()) + return; break; case FSCDBAS: /* Supercommander destroys base */ - game.future[FSCDBAS] = FOREVER; - isatb = 2; - if (!game.state.galaxy[game.state.isx][game.state.isy].starbase) + unschedule(FSCDBAS); + game.isatb = 2; + if (!game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].starbase) break; /* WAS RETURN! */ - ixhold = batx; - iyhold = baty; - batx = game.state.isx; - baty = game.state.isy; + hold = game.battle; + game.battle = game.state.kscmdr; + /* FALL THROUGH */ case FCDBAS: /* Commander succeeds in destroying base */ - if (line==FCDBAS) { - game.future[FCDBAS] = FOREVER; + if (evcode==FCDBAS) { + unschedule(FCDBAS); /* find the lucky pair */ for_commanders(i) - if (game.state.cx[i]==batx && game.state.cy[i]==baty) + if (same(game.state.kcmdr[i], game.battle)) break; if (i > game.state.remcom || game.state.rembase == 0 || - !game.state.galaxy[batx][baty].starbase) { + !game.state.galaxy[game.battle.x][game.battle.y].starbase) { /* No action to take after all */ - batx = baty = 0; + invalidate(game.battle); break; } } /* Code merges here for any commander destroying base */ /* Not perfect, but will have to do */ /* Handle case where base is in same quadrant as starship */ - if (batx==quadx && baty==quady) { - game.state.chart[batx][baty].starbase = FALSE; - game.quad[basex][basey]= IHDOT; - basex=basey=0; + if (same(game.battle, game.quadrant)) { + game.state.chart[game.battle.x][game.battle.y].starbase = false; + game.quad[game.base.x][game.base.y] = IHDOT; + game.base.x=game.base.y=0; newcnd(); skip(1); - prout("Spock- \"Captain, I believe the starbase has been destroyegame.state.\""); + prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\"")); } else if (game.state.rembase != 1 && - (game.damage[DRADIO] <= 0.0 || condit == IHDOCKED)) { + (!damaged(DRADIO) || game.condition == docked)) { /* Get word via subspace radio */ - if (ipage==0) pause_game(1); - ipage = 1; + pause_game(true); skip(1); - prout("Lt. Uhura- \"Captain, Starfleet Command reports that"); - proutn(" the starbase in "); - proutn(cramlc(quadrant, batx, baty)); - prout(" has been destroyed by"); - if (isatb==2) prout("the Klingon Super-Commander"); - else prout("a Klingon Commander"); - game.state.chart[batx][baty].starbase = FALSE; + prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that")); + proutn(_(" the starbase in ")); + proutn(cramlc(quadrant, game.battle)); + prout(_(" has been destroyed by")); + if (game.isatb == 2) + prout(_("the Klingon Super-Commander")); + else + prout(_("a Klingon Commander")); + game.state.chart[game.battle.x][game.battle.y].starbase = false; } /* Remove Starbase from galaxy */ - game.state.galaxy[batx][baty].starbase = FALSE; + game.state.galaxy[game.battle.x][game.battle.y].starbase = false; for_starbases(i) - if (game.state.baseqx[i]==batx && game.state.baseqy[i]==baty) { - game.state.baseqx[i]=game.state.baseqx[game.state.rembase]; - game.state.baseqy[i]=game.state.baseqy[game.state.rembase]; - } + if (same(game.state.baseq[i], game.battle)) + game.state.baseq[i] = game.state.baseq[game.state.rembase]; game.state.rembase--; - if (isatb == 2) { + if (game.isatb == 2) { /* reinstate a commander's base attack */ - batx = ixhold; - baty = iyhold; - isatb = 0; - } - else { - batx = baty = 0; + game.battle = hold; + game.isatb = 0; } + else + invalidate(game.battle); break; case FSCMOVE: /* Supercommander moves */ - game.future[FSCMOVE] = game.state.date+0.2777; - if (ientesc+istract==0 && - isatb!=1 && - (iscate!=1 || justin==1)) scom(&ipage); + schedule(FSCMOVE, 0.2777); + if (!game.ientesc && !istract && game.isatb != 1 && + (!game.iscate || !game.justin)) + scom(); break; case FDSPROB: /* Move deep space probe */ - game.future[FDSPROB] = game.state.date + 0.01; - probex += probeinx; - probey += probeiny; - i = (int)(probex/QUADSIZE +0.05); - j = (int)(probey/QUADSIZE + 0.05); - if (probecx != i || probecy != j) { - probecx = i; - probecy = j; + schedule(FDSPROB, 0.01); + game.probex += game.probeinx; + game.probey += game.probeiny; + i = (int)(game.probex/QUADSIZE +0.05); + j = (int)(game.probey/QUADSIZE + 0.05); + if (game.probec.x != i || game.probec.y != j) { + game.probec.x = i; + game.probec.y = j; if (!VALID_QUADRANT(i, j) || - game.state.galaxy[probecx][probecy].supernova) { + game.state.galaxy[game.probec.x][game.probec.y].supernova) { // Left galaxy or ran into supernova - if (game.damage[DRADIO]==0.0 || condit == IHDOCKED) { - if (ipage==0) pause_game(1); - ipage = 1; + if (!damaged(DRADIO) || game.condition == docked) { + pause_game(true); skip(1); - proutn("Lt. Uhura- \"The deep space probe "); + proutn(_("Lt. Uhura- \"The deep space probe ")); if (!VALID_QUADRANT(j, i)) - proutn("has left the galaxy"); + proutn(_("has left the galaxy")); else - proutn("is no longer transmitting"); + proutn(_("is no longer transmitting")); prout(".\""); } - game.future[FDSPROB] = FOREVER; + unschedule(FDSPROB); break; } - if (game.damage[DRADIO]==0.0 || condit == IHDOCKED) { - if (ipage==0) pause_game(1); - ipage = 1; + if (!damaged(DRADIO) || game.condition == docked) { + pause_game(true); skip(1); - proutn("Lt. Uhura- \"The deep space probe is now in "); - proutn(cramlc(quadrant, probecx, probecy)); + proutn(_("Lt. Uhura- \"The deep space probe is now in ")); + proutn(cramlc(quadrant, game.probec)); prout(".\""); } } + pdest = &game.state.galaxy[game.probec.x][game.probec.y]; /* Update star chart if Radio is working or have access to radio. */ - if (game.damage[DRADIO] == 0.0 || condit == IHDOCKED) { - game.state.chart[probecx][probecy].klingons = game.state.galaxy[probecx][probecy].klingons; - game.state.chart[probecx][probecy].starbase = game.state.galaxy[probecx][probecy].starbase; - game.state.chart[probecx][probecy].stars = game.state.galaxy[probecx][probecy].stars; - game.state.galaxy[probecx][probecy].charted = TRUE; - } - proben--; // One less to travel - if (proben == 0 && isarmed && - game.state.galaxy[probecx][probecy].stars) { + if (!damaged(DRADIO) || game.condition == docked) { + struct page *chp = &game.state.chart[game.probec.x][game.probec.y]; + + chp->klingons = pdest->klingons; + chp->starbase = pdest->starbase; + chp->stars = pdest->stars; + pdest->charted = true; + } + game.proben--; // One less to travel + if (game.proben == 0 && game.isarmed && pdest->stars) { /* lets blow the sucker! */ - snova(1,0); - game.future[FDSPROB] = FOREVER; - if (game.state.galaxy[quadx][quady].supernova) + snova(true, &game.probec); + unschedule(FDSPROB); + if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) + return; + } + break; + case FDISTR: /* inhabited system issues distress call */ + unschedule(FDISTR); + /* try a whole bunch of times to find something suitable */ + i = 100; + do { + /* need a quadrant which is not the current one, + which has some stars which are inhabited and + not already under attack, which is not + supernova'ed, and which has some Klingons in it */ + w = randplace(GALSIZE); + q = &game.state.galaxy[w.x][w.y]; + } while (--i && + (same(game.quadrant, w) || q->planet == NOPLANET || + q->supernova || q->status!=secure || q->klingons<=0)); + if (i == 0) { + /* can't seem to find one; ignore this call */ + if (idebug) + prout("=== Couldn't find location for distress event."); + break; + } + + /* got one!! Schedule its enslavement */ + ev = schedule(FENSLV, expran(game.intime)); + ev->quadrant = w; + q->status = distressed; + + /* tell the captain about it if we can */ + if (!damaged(DRADIO) || game.condition == docked) + { + prout("Uhura- Captain, %s in %s reports it is under attack", + systnames[q->planet], cramlc(quadrant, w)); + prout("by a Klingon invasion fleet."); + if (cancelrest()) return; } break; + case FENSLV: /* starsystem is enslaved */ + ev = unschedule(FENSLV); + /* see if current distress call still active */ + q = &game.state.galaxy[ev->quadrant.x][ev->quadrant.y]; + if (q->klingons <= 0) { + q->status = secure; + break; + } + q->status = enslaved; + + /* play stork and schedule the first baby */ + ev2 = schedule(FREPRO, expran(2.0 * game.intime)); + ev2->quadrant = ev->quadrant; + + /* report the disaster if we can */ + if (!damaged(DRADIO) || game.condition == docked) + { + prout("Uhura- We've lost contact with starsystem %s", + systnames[q->planet]); + prout("in %s.\n", cramlc(quadrant, ev->quadrant)); + } + break; + case FREPRO: /* Klingon reproduces */ + /* + * If we ever switch to a real event queue, we'll need to + * explicitly retrieve and restore the x and y. + */ + ev = schedule(FREPRO, expran(1.0 * game.intime)); + /* see if current distress call still active */ + q = &game.state.galaxy[ev->quadrant.x][ev->quadrant.y]; + if (q->klingons <= 0) { + q->status = secure; + break; + } + if (game.state.remkl >=MAXKLGAME) + break; /* full right now */ + /* reproduce one Klingon */ + w = ev->quadrant; + if (game.klhere >= MAXKLQUAD) { + /* this quadrant not ok, pick an adjacent one */ + for (i = w.x - 1; i <= w.x + 1; i++) + { + for (j = w.y - 1; j <= w.y + 1; j++) + { + if (!VALID_QUADRANT(i, j)) + continue; + q = &game.state.galaxy[w.x][w.y]; + /* check for this quad ok (not full & no snova) */ + if (q->klingons >= MAXKLQUAD || q->supernova) + continue; + goto foundit; + } + } + break; /* search for eligible quadrant failed */ + foundit: + w.x = i; + w.y = j; + } + + /* deliver the child */ + game.state.remkl++; + q->klingons++; + if (same(game.quadrant, w)) + newkling(++game.klhere); + + /* recompute time left */ + game.state.remtime = game.state.remres/(game.state.remkl+4*game.state.remcom); + /* report the disaster if we can */ + if (!damaged(DRADIO) || game.condition == docked) + { + if (same(game.quadrant, w)) { + prout("Spock- sensors indicate the Klingons have"); + prout("launched a warship from %s.", systnames[q->planet]); + } else { + prout("Uhura- Starfleet reports increased Klingon activity"); + if (q->planet != NOPLANET) + proutn("near %s", systnames[q->planet]); + prout("in %s.\n", cramlc(quadrant, w)); + } + } + break; } } } void wait(void) +/* wait on events */ { int key; double temp, delay, origTime; - ididit = 0; + game.ididit = false; for (;;) { key = scan(); - if (key != IHEOL) break; - proutn("How long? "); + if (key != IHEOL) + break; + proutn(_("How long? ")); } chew(); if (key != IHREAL) { @@ -369,79 +570,99 @@ void wait(void) return; } origTime = delay = aaitem; - if (delay <= 0.0) return; - if (delay >= game.state.remtime || nenhere != 0) { - proutn("Are you sure? "); - if (ja() == 0) return; + if (delay <= 0.0) + return; + if (delay >= game.state.remtime || game.nenhere != 0) { + proutn(_("Are you sure? ")); + if (ja() == false) + return; } /* Alternate resting periods (events) with attacks */ - resting = 1; + game.resting = true; do { - if (delay <= 0) resting = 0; - if (resting == 0) { - prout("%d stardates left.", (int)game.state.remtime); + if (delay <= 0) + game.resting = false; + if (!game.resting) { + prout(_("%d stardates left."), (int)game.state.remtime); return; } - temp = Time = delay; + temp = game.optime = delay; - if (nenhere) { + if (game.nenhere) { double rtime = 1.0 + Rand(); - if (rtime < temp) temp = rtime; - Time = temp; + if (rtime < temp) + temp = rtime; + game.optime = temp; } - if (Time < delay) attack(0); - if (alldone) return; + if (game.optime < delay) + attack(false); + if (game.alldone) + return; events(); - ididit = 1; - if (alldone) return; + game.ididit = true; + if (game.alldone) + return; delay -= temp; /* Repair Deathray if long rest at starbase */ - if (origTime-delay >= 9.99 && condit == IHDOCKED) + if (origTime-delay >= 9.99 && game.condition == docked) game.damage[DDRAY] = 0.0; } while // leave if quadrant supernovas - (!game.state.galaxy[quadx][quady].supernova); + (!game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova); - resting = 0; - Time = 0; + game.resting = false; + game.optime = 0; } -void nova(int ix, int iy) +/* + * A nova occurs. It is the result of having a star hit with a + * photon torpedo, or possibly of a probe warhead going off. + * Stars that go nova cause stars which surround them to undergo + * the same probabilistic process. Klingons next to them are + * destroyed. And if the starship is next to it, it gets zapped. + * If the zap is too much, it gets destroyed. + */ +void nova(coord nov) +/* star goes nova */ { static double course[] = {0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5}; int bot, top, top2, hits[QUADSIZE+1][3], kount, icx, icy, mm, nn, j; - int iquad, iquad1, i, ll, newcx, newcy, ii, jj; + int iquad, iquad1, i, ll; + coord newc, scratch; + if (Rand() < 0.05) { /* Wow! We've supernova'ed */ - snova(ix, iy); + snova(false, &nov); return; } /* handle initial nova */ - game.quad[ix][iy] = IHDOT; - crmena(1, IHSTAR, 2, ix, iy); - prout(" novas."); - game.state.galaxy[quadx][quady].stars--; + game.quad[nov.x][nov.y] = IHDOT; + crmena(false, IHSTAR, sector, nov); + prout(_(" novas.")); + game.state.galaxy[game.quadrant.x][game.quadrant.y].stars--; game.state.starkl++; /* Set up stack to recursively trigger adjacent stars */ bot = top = top2 = 1; kount = 0; icx = icy = 0; - hits[1][1] = ix; - hits[1][2] = iy; + hits[1][1] = nov.x; + hits[1][2] = nov.y; while (1) { for (mm = bot; mm <= top; mm++) for (nn = 1; nn <= 3; nn++) /* nn,j represents coordinates around current */ for (j = 1; j <= 3; j++) { - if (j==2 && nn== 2) continue; - ii = hits[mm][1]+nn-2; - jj = hits[mm][2]+j-2; - if (!VALID_SECTOR(jj, ii)) continue; - iquad = game.quad[ii][jj]; + if (j==2 && nn== 2) + continue; + scratch.x = hits[mm][1]+nn-2; + scratch.y = hits[mm][2]+j-2; + if (!VALID_SECTOR(scratch.y, scratch.x)) + continue; + iquad = game.quad[scratch.x][scratch.y]; switch (iquad) { // case IHDOT: /* Empty space ends reaction // case IHQUEST: @@ -453,98 +674,101 @@ void nova(int ix, int iy) case IHSTAR: /* Affect another star */ if (Rand() < 0.05) { /* This star supernovas */ - snova(ii,jj); + snova(false, &scratch); return; } top2++; - hits[top2][1]=ii; - hits[top2][2]=jj; - game.state.galaxy[quadx][quady].stars -= 1; + hits[top2][1]=scratch.x; + hits[top2][2]=scratch.y; + game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1; game.state.starkl++; - crmena(1, IHSTAR, 2, ii, jj); - prout(" novas."); - game.quad[ii][jj] = IHDOT; + crmena(true, IHSTAR, sector, scratch); + prout(_(" novas.")); + game.quad[scratch.x][scratch.y] = IHDOT; break; case IHP: /* Destroy planet */ - game.state.galaxy[quadx][quady].planets -= 1; + game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET; game.state.nplankl++; - crmena(1, IHP, 2, ii, jj); - prout(" destroyed."); - DESTROY(&game.state.plnets[iplnet]); - iplnet = plnetx = plnety = 0; - if (landed == 1) { + crmena(true, IHP, sector, scratch); + prout(_(" destroyed.")); + DESTROY(&game.state.planets[game.iplnet]); + game.iplnet = 0; + invalidate(game.plnet); + if (game.landed) { finish(FPNOVA); return; } - game.quad[ii][jj] = IHDOT; + game.quad[scratch.x][scratch.y] = IHDOT; break; case IHB: /* Destroy base */ - game.state.galaxy[quadx][quady].starbase = FALSE; + game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase = false; for_starbases(i) - if (game.state.baseqx[i]==quadx && game.state.baseqy[i]==quady) + if (same(game.state.baseq[i], game.quadrant)) break; - game.state.baseqx[i] = game.state.baseqx[game.state.rembase]; - game.state.baseqy[i] = game.state.baseqy[game.state.rembase]; + game.state.baseq[i] = game.state.baseq[game.state.rembase]; game.state.rembase--; - basex = basey = 0; + invalidate(game.base); game.state.basekl++; newcnd(); - crmena(1, IHB, 2, ii, jj); - prout(" destroyed."); - game.quad[ii][jj] = IHDOT; + crmena(true, IHB, sector, scratch); + prout(_(" destroyed.")); + game.quad[scratch.x][scratch.y] = IHDOT; break; case IHE: /* Buffet ship */ case IHF: - prout("***Starship buffeted by nova."); - if (shldup) { - if (shield >= 2000.0) shield -= 2000.0; + prout(_("***Starship buffeted by nova.")); + if (game.shldup) { + if (game.shield >= 2000.0) + game.shield -= 2000.0; else { - double diff = 2000.0 - shield; - energy -= diff; - shield = 0.0; - shldup = 0; - prout("***Shields knocked out."); - game.damage[DSHIELD] += 0.005*damfac*Rand()*diff; + double diff = 2000.0 - game.shield; + game.energy -= diff; + game.shield = 0.0; + game.shldup = false; + prout(_("***Shields knocked out.")); + game.damage[DSHIELD] += 0.005*game.damfac*Rand()*diff; } } - else energy -= 2000.0; - if (energy <= 0) { + else + game.energy -= 2000.0; + if (game.energy <= 0) { finish(FNOVA); return; } /* add in course nova contributes to kicking starship*/ - icx += sectx-hits[mm][1]; - icy += secty-hits[mm][2]; + icx += game.sector.x-hits[mm][1]; + icy += game.sector.y-hits[mm][2]; kount++; break; case IHK: /* kill klingon */ - deadkl(ii,jj,iquad, ii, jj); + deadkl(scratch,iquad, scratch); break; case IHC: /* Damage/destroy big enemies */ case IHS: case IHR: for_local_enemies(ll) - if (game.kx[ll]==ii && game.ky[ll]==jj) break; + if (same(game.ks[ll], scratch)) + break; game.kpower[ll] -= 800.0; /* If firepower is lost, die */ if (game.kpower[ll] <= 0.0) { - deadkl(ii, jj, iquad, ii, jj); + deadkl(scratch, iquad, scratch); break; } - newcx = ii + ii - hits[mm][1]; - newcy = jj + jj - hits[mm][2]; - crmena(1, iquad, 2, ii, jj); - proutn(" damaged"); - if (!VALID_SECTOR(newcx, newcy)) { + newc.x = scratch.x + scratch.x - hits[mm][1]; + newc.y = scratch.y + scratch.y - hits[mm][2]; + crmena(true, iquad, sector, scratch); + proutn(_(" damaged")); + if (!VALID_SECTOR(newc.x, newc.y)) { /* can't leave quadrant */ skip(1); break; } - iquad1 = game.quad[newcx][newcy]; + iquad1 = game.quad[newc.x][newc.y]; if (iquad1 == IHBLANK) { - proutn(", blasted into "); - crmena(0, IHBLANK, 2, newcx, newcy); + proutn(_(", blasted into ")); + crmena(false, IHBLANK, sector, newc); skip(1); - deadkl(ii, jj, iquad, newcx, newcy); + deadkl(scratch, iquad, newc); break; } if (iquad1 != IHDOT) { @@ -552,14 +776,12 @@ void nova(int ix, int iy) skip(1); break; } - proutn(", buffeted to "); - proutn(cramlc(sector, newcx, newcy)); - game.quad[ii][jj] = IHDOT; - game.quad[newcx][newcy] = iquad; - game.kx[ll] = newcx; - game.ky[ll] = newcy; - game.kavgd[ll] = sqrt(square(sectx-newcx)+square(secty-newcy)); - game.kdist[ll] = game.kavgd[ll]; + proutn(_(", buffeted to ")); + proutn(cramlc(sector, newc)); + game.quad[scratch.x][scratch.y] = IHDOT; + game.quad[newc.x][newc.y] = iquad; + game.ks[ll] = newc; + game.kdist[ll] = game.kavgd[ll] = distance(game.sector, newc); skip(1); break; } @@ -573,183 +795,168 @@ void nova(int ix, int iy) return; /* Starship affected by nova -- kick it away. */ - dist = kount*0.1; - if (icx) icx = (icx < 0 ? -1 : 1); - if (icy) icy = (icy < 0 ? -1 : 1); - direc = course[3*(icx+1)+icy+2]; - if (direc == 0.0) dist = 0.0; - if (dist == 0.0) return; - Time = 10.0*dist/16.0; + game.dist = kount*0.1; + if (icx) + icx = (icx < 0 ? -1 : 1); + if (icy) + icy = (icy < 0 ? -1 : 1); + game.direc = course[3*(icx+1)+icy+2]; + if (game.direc == 0.0) + game.dist = 0.0; + if (game.dist == 0.0) + return; + game.optime = 10.0*game.dist/16.0; skip(1); - prout("Force of nova displaces starship."); - iattak=2; /* Eliminates recursion problem */ - imove(); - Time = 10.0*dist/16.0; + prout(_("Force of nova displaces starship.")); + imove(true); + game.optime = 10.0*game.dist/16.0; return; } -void snova(int insx, int insy) +void snova(bool induced, coord *w) +/* star goes supernova */ { - int comdead, nqx=0, nqy=0, nsx, nsy, num=0, kldead, iscdead; - int nrmdead, npdead; - int incipient=0; - - nsx = insy; - nsy = insy; - - if (insy== 0) { - if (insx == 1) { - /* NOVAMAX being used */ - nqx = probecx; - nqy = probecy; - } - else { - int stars = 0; - /* Scheduled supernova -- select star */ - /* logic changed here so that we won't favor quadrants in top - left of universe */ - for_quadrants(nqx) { - for_quadrants(nqy) { - stars += game.state.galaxy[nqx][nqy].stars; - } + int num = 0, nrmdead, npdead, kldead; + coord nq; + + if (w != NULL) + nq = *w; + else { + int stars = 0; + /* Scheduled supernova -- select star */ + /* logic changed here so that we won't favor quadrants in top + left of universe */ + for_quadrants(nq.x) { + for_quadrants(nq.y) { + stars += game.state.galaxy[nq.x][nq.y].stars; } - if (stars == 0) return; /* nothing to supernova exists */ - num = Rand()*stars + 1; - for_quadrants(nqx) { - for_quadrants(nqy) { - num -= game.state.galaxy[nqx][nqy].stars; - if (num <= 0) break; - } - if (num <=0) break; - } -#ifdef DEBUG - if (idebug) { - proutn("Super nova here?"); - if (ja()==1) { - nqx = quadx; - nqy = quady; - } + } + if (stars == 0) return; /* nothing to supernova exists */ + num = Rand()*stars + 1; + for_quadrants(nq.x) { + for_quadrants(nq.y) { + num -= game.state.galaxy[nq.x][nq.y].stars; + if (num <= 0) + break; } -#endif + if (num <=0) + break; } + if (idebug) { + proutn("=== Super nova here?"); + if (ja() == true) + nq = game.quadrant; + } + } - if (nqx != quady || nqy != quady || justin != 0) { - /* it isn't here, or we just entered (treat as inroute) */ - if (game.damage[DRADIO] == 0.0 || condit == IHDOCKED) { - skip(1); - prout("Message from Starfleet Command Stardate %.2f", game.state.date); - prout(" Supernova in %s; caution advised.", - cramlc(quadrant, nqx, nqy)); - } + if (!same(nq, game.quadrant) || game.justin) { + /* it isn't here, or we just entered (treat as enroute) */ + if (!damaged(DRADIO) || game.condition == docked) { + skip(1); + prout(_("Message from Starfleet Command Stardate %.2f"), game.state.date); + prout(_(" Supernova in %s; caution advised."), + cramlc(quadrant, nq)); } - else { - /* we are in the quadrant! */ - incipient = 1; - num = Rand()* game.state.galaxy[nqx][nqy].stars + 1; - for_sectors(nsx) { - for_sectors(nsy) { - if (game.quad[nsx][nsy]==IHSTAR) { - num--; - if (num==0) break; - } + } + else { + coord ns; + /* we are in the quadrant! */ + num = Rand()* game.state.galaxy[nq.x][nq.y].stars + 1; + for_sectors(ns.x) { + for_sectors(ns.y) { + if (game.quad[ns.x][ns.y]==IHSTAR) { + num--; + if (num==0) + break; } - if (num==0) break; } + if (num==0) + break; } - } - else { - incipient = 1; - } - if (incipient) { skip(1); - prouts("***RED ALERT! RED ALERT!"); + prouts(_("***RED ALERT! RED ALERT!")); skip(1); - prout("***Incipient supernova detected at ", cramlc(sector, nsx, nsy)); - nqx = quadx; - nqy = quady; - if (square(nsx-sectx) + square(nsy-secty) <= 2.1) { - proutn("Emergency override attempts t"); + prout(_("***Incipient supernova detected at %s"), cramlc(sector, ns)); + if (square(ns.x-game.sector.x) + square(ns.y-game.sector.y) <= 2.1) { + proutn(_("Emergency override attempts t")); prouts("***************"); skip(1); stars(); - alldone=1; + game.alldone = true; } } + /* destroy any Klingons in supernovaed quadrant */ - kldead = game.state.galaxy[nqx][nqy].klingons; - game.state.galaxy[nqx][nqy].klingons = 0; - comdead = iscdead = 0; - if (nqx==game.state.isx && nqy == game.state.isy) { + kldead = game.state.galaxy[nq.x][nq.y].klingons; + game.state.galaxy[nq.x][nq.y].klingons = 0; + if (same(nq, game.state.kscmdr)) { /* did in the Supercommander! */ - game.state.nscrem = game.state.isx = game.state.isy = isatb = iscate = 0; - iscdead = 1; - game.future[FSCMOVE] = game.future[FSCDBAS] = FOREVER; + game.state.nscrem = game.state.kscmdr.x = game.state.kscmdr.y = game.isatb = 0; + game.iscate = false; + unschedule(FSCMOVE); + unschedule(FSCDBAS); } if (game.state.remcom) { int maxloop = game.state.remcom, l; for (l = 1; l <= maxloop; l++) { - if (game.state.cx[l] == nqx && game.state.cy[l] == nqy) { - game.state.cx[l] = game.state.cx[game.state.remcom]; - game.state.cy[l] = game.state.cy[game.state.remcom]; - game.state.cx[game.state.remcom] = game.state.cy[game.state.remcom] = 0; + if (same(game.state.kcmdr[l], nq)) { + game.state.kcmdr[l] = game.state.kcmdr[game.state.remcom]; + invalidate(game.state.kcmdr[game.state.remcom]); game.state.remcom--; kldead--; - comdead++; - if (game.state.remcom==0) game.future[FTBEAM] = FOREVER; + if (game.state.remcom==0) + unschedule(FTBEAM); break; } } } game.state.remkl -= kldead; /* destroy Romulans and planets in supernovaed quadrant */ - nrmdead = game.state.galaxy[nqx][nqy].romulans; - game.state.galaxy[nqx][nqy].romulans = 0; + nrmdead = game.state.galaxy[nq.x][nq.y].romulans; + game.state.galaxy[nq.x][nq.y].romulans = 0; game.state.nromrem -= nrmdead; npdead = num - nrmdead*10; if (npdead) { - int l; - for (l = 0; l < inplan; l++) - if (game.state.plnets[l].x == nqx && game.state.plnets[l].y == nqy) { - DESTROY(&game.state.plnets[l]); + int loop; + for (loop = 0; loop < game.inplan; loop++) + if (same(game.state.planets[loop].w, nq)) { + DESTROY(&game.state.planets[loop]); } } /* Destroy any base in supernovaed quadrant */ if (game.state.rembase) { - int maxloop = game.state.rembase, l; - for (l = 1; l <= maxloop; l++) - if (game.state.baseqx[l]==nqx && game.state.baseqy[l]==nqy) { - game.state.baseqx[l] = game.state.baseqx[game.state.rembase]; - game.state.baseqy[l] = game.state.baseqy[game.state.rembase]; - game.state.baseqx[game.state.rembase] = game.state.baseqy[game.state.rembase] = 0; + int maxloop = game.state.rembase, loop; + for (loop = 1; loop <= maxloop; loop++) + if (same(game.state.baseq[loop], nq)) { + game.state.baseq[loop] = game.state.baseq[game.state.rembase]; + invalidate(game.state.baseq[game.state.rembase]); game.state.rembase--; break; } } /* If starship caused supernova, tally up destruction */ - if (insx) { - game.state.starkl += game.state.galaxy[nqx][nqy].stars; - game.state.basekl += game.state.galaxy[nqx][nqy].starbase; + if (induced) { + game.state.starkl += game.state.galaxy[nq.x][nq.y].stars; + game.state.basekl += game.state.galaxy[nq.x][nq.y].starbase; game.state.nplankl += npdead; } /* mark supernova in galaxy and in star chart */ - if ((quadx == nqx && quady == nqy) || - game.damage[DRADIO] == 0 || - condit == IHDOCKED) - game.state.galaxy[nqx][nqy].supernova = TRUE; - /* If supernova destroys last klingons give special message */ - if (KLINGREM==0 && (nqx != quadx || nqy != quady)) { + if (same(game.quadrant, nq) || !damaged(DRADIO) || game.condition == docked) + game.state.galaxy[nq.x][nq.y].supernova = true; + /* If supernova destroys last Klingons give special message */ + if (KLINGREM==0 && !same(nq, game.quadrant)) { skip(2); - if (insx == 0) prout("Lucky you!"); - proutn("A supernova in %s has just destroyed the last Klingons.", - cramlc(quadrant, nqx, nqy)); + if (!induced) + prout(_("Lucky you!")); + proutn(_("A supernova in %s has just destroyed the last Klingons."), + cramlc(quadrant, nq)); finish(FWON); return; } /* if some Klingons remain, continue or die in supernova */ - if (alldone) finish(FSNOVAED); + if (game.alldone) + finish(FSNOVAED); return; } - -