X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=src%2Fevents.c;h=079fea41ef72529ff8d1f6022b4cd187ce2717ec;hp=55de8a5040dba6dcabff12602849fd685be7e1e4;hb=2cae1cd3feb922843b40af851f43f9e08bb18f0d;hpb=459d6afcbe13be588b29c8bd1fbffb39b13fdee1 diff --git a/src/events.c b/src/events.c index 55de8a5..079fea4 100644 --- a/src/events.c +++ b/src/events.c @@ -1,56 +1,107 @@ +/* + * 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 -void unschedule(int evtype) +event *unschedule(int evtype) /* remove an event from the schedule */ { - game.future[evtype] = FOREVER; + 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] != FOREVER; + return game.future[evtype].date != FOREVER; } extern double scheduled(int evtype) /* when will this event happen? */ { - return game.future[evtype]; + return game.future[evtype].date; } -void schedule(int evtype, double offset) +event *schedule(int evtype, double offset) /* schedule an event of specified type */ { - game.future[evtype] = game.state.date + offset; + 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] += offset; + game.future[evtype].date += offset; +} + +static bool cancelrest(void) +{ + if (game.resting) { + skip(1); + proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")); + if (ja()) { + game.resting = false; + game.optime = 0.0; + return true; + } + } + + return false; } void events(void) { - int ictbeam=0, ipage=0, istract=0, line, i=0, j, k, l, ixhold=0, iyhold=0; + int istract=0, evcode, i=0, j, k, l; double fintim = game.state.date + game.optime, datemin, xtime, repair, yank=0; - int radio_was_broken; - struct quadrant *pdest; + bool radio_was_broken, ictbeam = false, ipage = false; + struct quadrant *pdest, *q; + coord w, hold; + event *ev, *ev2; + + 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"); - if (idebug) prout("=== EVENTS"); + } + } - radio_was_broken = (game.damage[DRADIO] != 0.0); + radio_was_broken = damaged(DRADIO); for (;;) { - /* Select earliest extraneous event, line==0 if no events */ - line = FSPY; + /* 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; @@ -62,7 +113,7 @@ void events(void) return; } /* Is life support adequate? */ - if (game.damage[DLIFSUP] && game.condit != IHDOCKED) { + if (damaged(DLIFSUP) && game.condit != IHDOCKED) { if (game.lsupres < xtime && game.damage[DLIFSUP] > game.lsupres) { finish(FLIFESUP); return; @@ -78,7 +129,7 @@ void events(void) if (game.damage[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) { + 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); @@ -90,12 +141,12 @@ void events(void) prout(_(" The star chart is now up to date.\"")); skip(1); } - /* Cause extraneous event LINE to occur */ + /* Cause extraneous event EVCODE to occur */ game.optime -= xtime; - switch (line) { + switch (evcode) { case FSNOVA: /* Supernova */ - if (ipage==0) pause_game(1); - ipage=1; + if (!ipage) pause_game(1); + ipage=true; snova(0,0); schedule(FSNOVA, expran(0.5*game.intime)); if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) return; @@ -106,10 +157,10 @@ void events(void) game.condit==IHDOCKED || game.isatb==1 || game.iscate==1) return; if (game.ientesc || (game.energy < 2000 && game.torps < 4 && game.shield < 1250) || - (game.damage[DPHASER]>0 && (game.damage[DPHOTON]>0 || game.torps < 4)) || - (game.damage[DSHIELD] > 0 && - (game.energy < 2500 || game.damage[DPHASER] > 0) && - (game.torps < 5 || game.damage[DPHOTON] > 0))) { + (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.kscmdr.x-game.quadrant.x) + square(game.state.kscmdr.y-game.quadrant.y); @@ -117,7 +168,7 @@ void events(void) } else return; case FTBEAM: /* Tractor beam */ - if (line==FTBEAM) { + if (evcode==FTBEAM) { if (game.state.remcom == 0) { unschedule(FTBEAM); break; @@ -133,8 +184,8 @@ void events(void) } /* tractor beaming cases merge here */ yank = sqrt(yank); - if (ipage==0) pause_game(1); - ipage=1; + if (!ipage) pause_game(1); + ipage=true; game.optime = (10.0/(7.5*7.5))*yank; /* 7.5 is yank rate (warp 7.5) */ ictbeam = 1; skip(1); @@ -161,14 +212,10 @@ void events(void) prout(_("Galileo, left on the planet surface, is well hidden.")); } } - if (line==0) { - game.quadrant.x = game.state.kscmdr.x; - game.quadrant.y = game.state.kscmdr.y; - } - else { - game.quadrant.x = game.state.kcmdr[i].x; - game.quadrant.y = game.state.kcmdr[i].y; - } + if (evcode==0) + game.quadrant = game.state.kscmdr; + else + game.quadrant = game.state.kcmdr[i]; iran(QUADSIZE, &game.sector.x, &game.sector.y); crmshp(); proutn(_(" is pulled to ")); @@ -177,10 +224,10 @@ void events(void) prout(cramlc(sector, game.sector)); if (game.resting) { prout(_("(Remainder of rest/repair period cancelled.)")); - game.resting = 0; + game.resting = false; } - if (game.shldup==0) { - if (game.damage[DSHIELD]==0 && game.shield > 0) { + if (!game.shldup) { + if (!damaged(DSHIELD) && game.shield > 0) { doshield(2); /* Shldsup */ game.shldchg=0; } @@ -208,9 +255,9 @@ void events(void) i = 0; for_starbases(j) { for_commanders(k) - if (game.state.baseq[j].x==game.state.kcmdr[k].x && game.state.baseq[j].y==game.state.kcmdr[k].y && - (game.state.baseq[j].x!=game.quadrant.x || game.state.baseq[j].y!=game.quadrant.y) && - (game.state.baseq[j].x!=game.state.kscmdr.x || game.state.baseq[j].y!=game.state.kscmdr.y)) { + 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; } @@ -223,18 +270,17 @@ void events(void) break; } /* commander + starbase combination found -- launch attack */ - game.battle.x = game.state.baseq[j].x; - game.battle.y = game.state.baseq[j].y; + 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] = game.future[FCDBAS] +expran(0.3*game.intime); + game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime); game.iseenit = 0; - if (game.damage[DRADIO] != 0.0 && - game.condit != IHDOCKED) break; /* No warning :-( */ + if (!damaged(DRADIO) && game.condit != IHDOCKED) + break; /* No warning :-( */ game.iseenit = 1; - if (ipage==0) pause_game(1); - ipage = 1; + if (!ipage) pause_game(1); + ipage = true; skip(1); proutn(_("Lt. Uhura- \"Captain, the starbase in ")); prout(cramlc(quadrant, game.battle)); @@ -242,31 +288,23 @@ void events(void) proutn(_(" hold out only until stardate %d"), (int)scheduled(FCDBAS)); prout(".\""); - if (game.resting) { - skip(1); - proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\"")); - if (ja()) { - game.resting = 0; - game.optime = 0.0; - return; - } - } + if (cancelrest()) + return; break; case FSCDBAS: /* Supercommander destroys base */ unschedule(FSCDBAS); game.isatb = 2; if (!game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].starbase) break; /* WAS RETURN! */ - ixhold = game.battle.x; - iyhold = game.battle.y; - game.battle.x = game.state.kscmdr.x; - game.battle.y = game.state.kscmdr.y; + hold = game.battle; + game.battle = game.state.kscmdr; + /* FALL THROUGH */ case FCDBAS: /* Commander succeeds in destroying base */ - if (line==FCDBAS) { + if (evcode==FCDBAS) { unschedule(FCDBAS); /* find the lucky pair */ for_commanders(i) - if (game.state.kcmdr[i].x==game.battle.x && game.state.kcmdr[i].y==game.battle.y) + if (same(game.state.kcmdr[i], game.battle)) break; if (i > game.state.remcom || game.state.rembase == 0 || !game.state.galaxy[game.battle.x][game.battle.y].starbase) { @@ -278,7 +316,7 @@ void events(void) /* 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 (game.battle.x==game.quadrant.x && game.battle.y==game.quadrant.y) { + 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; @@ -287,10 +325,10 @@ void events(void) prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\"")); } else if (game.state.rembase != 1 && - (game.damage[DRADIO] <= 0.0 || game.condit == IHDOCKED)) { + (!damaged(DRADIO) || game.condit == IHDOCKED)) { /* Get word via subspace radio */ - if (ipage==0) pause_game(1); - ipage = 1; + if (!ipage) pause_game(1); + ipage = true; skip(1); prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that")); proutn(_(" the starbase in ")); @@ -304,15 +342,12 @@ void events(void) /* Remove Starbase from galaxy */ game.state.galaxy[game.battle.x][game.battle.y].starbase = false; for_starbases(i) - if (game.state.baseq[i].x==game.battle.x && game.state.baseq[i].y==game.battle.y) { - game.state.baseq[i].x=game.state.baseq[game.state.rembase].x; - game.state.baseq[i].y=game.state.baseq[game.state.rembase].y; - } + if (same(game.state.baseq[i], game.battle)) + game.state.baseq[i] = game.state.baseq[game.state.rembase]; game.state.rembase--; if (game.isatb == 2) { /* reinstate a commander's base attack */ - game.battle.x = ixhold; - game.battle.y = iyhold; + game.battle = hold; game.isatb = 0; } else { @@ -337,7 +372,7 @@ void events(void) if (!VALID_QUADRANT(i, j) || game.state.galaxy[game.probec.x][game.probec.y].supernova) { // Left galaxy or ran into supernova - if (game.damage[DRADIO]==0.0 || game.condit == IHDOCKED) { + if (!damaged(DRADIO) || game.condit == IHDOCKED) { if (ipage==0) pause_game(1); ipage = 1; skip(1); @@ -351,7 +386,7 @@ void events(void) unschedule(FDSPROB); break; } - if (game.damage[DRADIO]==0.0 || game.condit == IHDOCKED) { + if (!damaged(DRADIO) || game.condit == IHDOCKED) { if (ipage==0) pause_game(1); ipage = 1; skip(1); @@ -363,7 +398,7 @@ void events(void) 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 || game.condit == IHDOCKED) { + if (!damaged(DRADIO) || game.condit == IHDOCKED) { struct page *chp = &game.state.chart[game.probec.x][game.probec.y]; chp->klingons = pdest->klingons; @@ -380,122 +415,123 @@ void events(void) return; } break; -#ifdef EXPERIMENTAL case FDISTR: /* inhabited system issues distress call */ - /* in BSD Trek this is a straight 1 stardate ahead */ - schedule(FDISTR, 1.0 + Rand()); - /* if we already have too many, throw this one away */ - if (game.ndistr >= MAXDISTR) - break; + unschedule(FDISTR); /* try a whole bunch of times to find something suitable */ - for (i = 0; i < 100; i++) { - struct quadrant *q; - iran(GALSIZE, &ix, &iy); - q = &game.state.galaxy[game.quadrant.x][game.quadrant.y]; + 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 */ - if (!((ix == game.quadrant.x && iy == game.quadrant.y) || q->stars<=0 || - (q->qsystemname & Q_DISTRESSED) || - (q->qsystemname & Q_SYSTEM) == 0 || q->klings <= 0)) - break; - } - if (i >= 100) + iran(GALSIZE, &w.x, &w.y); + 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 */ - game.ndistr++; - e = xsched(E_ENSLV, 1, ix, iy, q->qsystemname); - q->qsystemname = (e - Event) | Q_DISTRESSED; + ev = schedule(FENSLV, expran(game.intime)); + ev->quadrant = w; + q->status = distressed; /* tell the captain about it if we can */ - if (game.damage[DRADIO] == 0.0) + if (!damaged(DRADIO) || game.condit == IHDOCKED) { - printf("\nUhura: Captain, starsystem %s in quadrant %d,%d is under attack\n", - Systemname[e->systemname], ix, iy); - restcancel++; + prout("Uhura- Captain, %s in %s reports it is under attack", + systemname(q->planet), cramlc(quadrant, w)); + prout("by a Klingon invasion fleet."); + if (cancelrest()) + return; } - else - /* if we can't tell him, make it invisible */ - e->evcode |= E_HIDDEN; break; - case FENSLV: /* starsystem is enslaved */ - unschedule(e); + case FENSLV: /* starsystem is enslaved */ + ev = unschedule(FENSLV); /* see if current distress call still active */ - q = &Quad[e->x][e->y]; - if (q->klings <= 0) - { - /* no Klingons, clean up */ - /* restore the system name */ - q->qsystemname = e->systemname; + 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 */ - e = schedule(E_REPRO, Param.eventdly[E_REPRO] * franf(), e->x, e->y, e->systemname); + ev2 = schedule(FREPRO, expran(2.0 * game.intime)); + ev2->quadrant = ev->quadrant; /* report the disaster if we can */ - if (game.damage[DRADIO] == 0.0) + if (!damaged(DRADIO) || game.condit == IHDOCKED) { - printf("\nUhura: We've lost contact with starsystem %s\n", - Systemname[e->systemname]); - printf(" in quadrant %d,%d.\n", e->x, e->y); + prout("Uhura- We've lost contact with starsystem %s", + systemname(q->planet)); + prout("in %s.\n", cramlc(quadrant, ev->quadrant)); } - else - e->evcode |= E_HIDDEN; break; - case FREPRO: /* Klingon reproduces */ - /* see if distress call is still active */ - q = &Quad[e->x][e->y]; - if (q->klings <= 0) - { - unschedule(e); - q->qsystemname = e->systemname; + 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; } - xresched(e, E_REPRO, 1); - /* reproduce one Klingon */ - ix = e->x; - iy = e->y; - if (Now.klings == 127) + if (game.state.remkl >=MAXKLGAME) break; /* full right now */ - if (q->klings >= MAXKLQUAD) - { + /* reproduce one Klingon */ + w = ev->quadrant; + if (game.klhere >= MAXKLQUAD) { /* this quadrant not ok, pick an adjacent one */ - for (i = ix - 1; i <= ix + 1; i++) + for (i = w.x - 1; i <= w.x + 1; i++) { - if (!VALID_QUADRANT(i)) - continue; - for (j = iy - 1; j <= iy + 1; j++) + for (j = w.y - 1; j <= w.y + 1; j++) { - if (!VALID_QUADRANT(j)) + if (!VALID_QUADRANT(i, j)) continue; - q = &Quad[i][j]; + q = &game.state.galaxy[w.x][w.y]; /* check for this quad ok (not full & no snova) */ - if (q->klings >= MAXKLQUAD || q->stars < 0) + if (q->klingons >= MAXKLQUAD || q->supernova) continue; - break; + goto foundit; } - if (j <= iy + 1) - break; } - if (j > iy + 1) - /* cannot create another yet */ - break; - ix = i; - iy = j; + break; /* search for eligible quadrant failed */ + foundit: + w.x = i; + w.y = j; } + /* deliver the child */ - game.remkl++; - if (ix == game.quadrant.x && iy == game.quadrant.y) - newkling(++game.klhere, &ixhold, &iyhold); + game.state.remkl++; + q->klingons++; + if (same(game.quadrant, w)) + newkling(++game.klhere, &hold); /* 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.condit == IHDOCKED) + { + if (same(game.quadrant, w)) { + prout("Spock- sensors indicate the Klingons have"); + prout("launched a warship from %s.",systemname(q->planet)); + } else { + prout("Uhura- Starfleet reports increased Klingon activity"); + if (q->planet != NOPLANET) + proutn("near %s", systemname(q->planet)); + prout("in %s.\n", cramlc(quadrant, w)); + } + } break; -#endif /* EXPERIMENTAL */ } } } @@ -526,10 +562,10 @@ void wait(void) /* Alternate resting periods (events) with attacks */ - game.resting = 1; + game.resting = true; do { - if (delay <= 0) game.resting = 0; - if (game.resting == 0) { + if (delay <= 0) game.resting = false; + if (!game.resting) { prout(_("%d stardates left."), (int)game.state.remtime); return; } @@ -553,7 +589,7 @@ void wait(void) // leave if quadrant supernovas (!game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova); - game.resting = 0; + game.resting = false; game.optime = 0; } @@ -618,7 +654,7 @@ void nova(int ix, int iy) game.quad[scratch.x][scratch.y] = IHDOT; break; case IHP: /* Destroy planet */ - game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NULL; + game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET; game.state.nplankl++; crmena(1, IHP, 2, scratch); prout(_(" destroyed.")); @@ -653,7 +689,7 @@ void nova(int ix, int iy) double diff = 2000.0 - game.shield; game.energy -= diff; game.shield = 0.0; - game.shldup = 0; + game.shldup = false; prout(_("***Shields knocked out.")); game.damage[DSHIELD] += 0.005*game.damfac*Rand()*diff; } @@ -785,7 +821,7 @@ void snova(int insx, int insy) if (nq.x != game.quadrant.y || nq.y != game.quadrant.y || game.justin != 0) { /* it isn't here, or we just entered (treat as inroute) */ - if (game.damage[DRADIO] == 0.0 || game.condit == IHDOCKED) { + if (!damaged(DRADIO) || game.condit == IHDOCKED) { skip(1); prout(_("Message from Starfleet Command Stardate %.2f"), game.state.date); prout(_(" Supernova in %s; caution advised."), @@ -883,11 +919,9 @@ void snova(int insx, int insy) game.state.nplankl += npdead; } /* mark supernova in galaxy and in star chart */ - if ((game.quadrant.x == nq.x && game.quadrant.y == nq.y) || - game.damage[DRADIO] == 0 || - game.condit == IHDOCKED) + if (same(game.quadrant, nq) || !damaged(DRADIO) || game.condit == IHDOCKED) game.state.galaxy[nq.x][nq.y].supernova = true; - /* If supernova destroys last klingons give special message */ + /* If supernova destroys last Klingons give special message */ if (KLINGREM==0 && (nq.x != game.quadrant.x || nq.y != game.quadrant.y)) { skip(2); if (insx == 0) prout(_("Lucky you!"));