Abstract all references to the future array (outside of events.c) away.
[super-star-trek.git] / src / events.c
index dc81f56e86dfb70638c872571475c8285555d2b4..7b915f22e28f45b3119f74d3c6c0013da5b74ed6 100644 (file)
@@ -1,6 +1,36 @@
 #include "sst.h"
 #include <math.h>
 
+void unschedule(int evtype)
+/* remove an event from the schedule */
+{
+    game.future[evtype] = FOREVER;
+}
+
+int is_scheduled(int evtype)
+/* is an event of specified type scheduled */
+{
+    return game.future[evtype] != FOREVER;
+}
+
+extern double scheduled(int evtype)
+/* when will this event happen? */
+{
+    return game.future[evtype];
+}
+
+void schedule(int evtype, double offset)
+/* schedule an event of specified type */
+{
+    game.future[evtype] = game.state.date + offset;
+}
+
+void postpone(int evtype, double offset)
+/* poistpone a scheduled event */
+{
+    game.future[evtype] += offset;
+}
+
 void events(void) 
 {
     int ictbeam=0, ipage=0, istract=0, line, i=0, j, k, l, ixhold=0, iyhold=0;
@@ -68,7 +98,7 @@ void events(void)
            if (ipage==0) pause_game(1);
            ipage=1;
            snova(0,0);
-           game.future[FSNOVA] = game.state.date + expran(0.5*game.intime);
+           schedule(FSNOVA, expran(0.5*game.intime));
            if (game.state.galaxy[game.quadx][game.quady].supernova) return;
            break;
        case FSPY: /* Check with spy to see if S.C. should tractor beam */
@@ -90,15 +120,15 @@ void events(void)
        case FTBEAM: /* Tractor beam */
            if (line==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]-game.quadx) + square(game.state.cy[i]-game.quady);
                if (istract || game.condit == IHDOCKED || yank == 0) {
                    /* Drats! Have to reschedule */
-                   game.future[FTBEAM] = game.state.date + game.optime +
-                       expran(1.5*game.intime/game.state.remcom);
+                   schedule(FTBEAM, 
+                            game.optime + expran(1.5*game.intime/game.state.remcom));
                    break;
                }
            }
@@ -161,18 +191,19 @@ void events(void)
            /* Adjust finish time to time of tractor beaming */
            fintim = game.state.date+game.optime;
            attack(0);
-           if (game.state.remcom <= 0) game.future[FTBEAM] = FOREVER;
-           else game.future[FTBEAM] = game.state.date+game.optime+expran(1.5*game.intime/game.state.remcom);
+           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 * game.intime);
+           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;
@@ -188,16 +219,16 @@ void events(void)
            }
            if (j>game.state.rembase) {
                /* no match found -- try later */
-               game.future[FBATTAK] = game.state.date + expran(0.3*game.intime);
-               game.future[FCDBAS] = FOREVER;
+               schedule(FBATTAK, expran(0.3*game.intime));
+               unschedule(FCDBAS);
                break;
            }
            /* commander + starbase combination found -- launch attack */
            game.batx = game.state.baseqx[j];
            game.baty = game.state.baseqy[j];
-           game.future[FCDBAS] = game.state.date+1.0+3.0*Rand();
+           schedule(FCDBAS, 1.0+3.0*Rand());
            if (game.isatb) /* extra time if SC already attacking */
-               game.future[FCDBAS] += game.future[FSCDBAS]-game.state.date;
+               postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date);
            game.future[FBATTAK] = game.future[FCDBAS] +expran(0.3*game.intime);
            game.iseenit = 0;
            if (game.damage[DRADIO] != 0.0 &&
@@ -210,7 +241,7 @@ void events(void)
            prout(cramlc(quadrant, game.batx, game.baty));
            prout(_("   reports that it is under attack and that it can"));
            proutn(_("   hold out only until stardate %d"),
-                  (int)game.future[FCDBAS]);
+                  (int)scheduled(FCDBAS));
            prout(".\"");
            if (game.resting) {
                skip(1);
@@ -223,7 +254,7 @@ void events(void)
            }
            break;
        case FSCDBAS: /* Supercommander destroys base */
-           game.future[FSCDBAS] = FOREVER;
+           unschedule(FSCDBAS);
            game.isatb = 2;
            if (!game.state.galaxy[game.state.isx][game.state.isy].starbase) 
                break; /* WAS RETURN! */
@@ -233,7 +264,7 @@ void events(void)
            game.baty = game.state.isy;
        case FCDBAS: /* Commander succeeds in destroying base */
            if (line==FCDBAS) {
-               game.future[FCDBAS] = FOREVER;
+               unschedule(FCDBAS);
                /* find the lucky pair */
                for_commanders(i)
                    if (game.state.cx[i]==game.batx && game.state.cy[i]==game.baty) 
@@ -289,13 +320,13 @@ void events(void)
            }
            break;
        case FSCMOVE: /* Supercommander moves */
-           game.future[FSCMOVE] = game.state.date+0.2777;
+           schedule(FSCMOVE, 0.2777);
            if (game.ientesc+istract==0 &&
                game.isatb!=1 &&
                (game.iscate!=1 || game.justin==1)) scom(&ipage);
            break;
        case FDSPROB: /* Move deep space probe */
-           game.future[FDSPROB] = game.state.date + 0.01;
+           schedule(FDSPROB, 0.01);
            game.probex += game.probeinx;
            game.probey += game.probeiny;
            i = (int)(game.probex/QUADSIZE +0.05);
@@ -317,7 +348,7 @@ void events(void)
                            proutn(_("is no longer transmitting"));
                        prout(".\"");
                    }
-                   game.future[FDSPROB] = FOREVER;
+                   unschedule(FDSPROB);
                    break;
                }
                if (game.damage[DRADIO]==0.0   || game.condit == IHDOCKED) {
@@ -342,11 +373,127 @@ void events(void)
                game.state.galaxy[game.probecx][game.probecy].stars) {
                /* lets blow the sucker! */
                snova(1,0);
-               game.future[FDSPROB] = FOREVER;
+               unschedule(FDSPROB);
                if (game.state.galaxy[game.quadx][game.quady].supernova) 
                    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;
+           /* 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.quadx][game.quady];
+               /* 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.quadx && iy == game.quady) || q->stars<=0 ||
+                     (q->qsystemname & Q_DISTRESSED) ||
+                     (q->qsystemname & Q_SYSTEM) == 0 || q->klings <= 0))
+                   break;
+           }
+           if (i >= 100)
+               /* can't seem to find one; ignore this call */
+               break;
+
+           /* got one!!  Schedule its enslavement */
+           game.ndistr++;
+           e = xsched(E_ENSLV, 1, ix, iy, q->qsystemname);
+           q->qsystemname = (e - Event) | Q_DISTRESSED;
+
+           /* tell the captain about it if we can */
+           if (game.damage[DRADIO] == 0.0)
+           {
+               printf("\nUhura: Captain, starsystem %s in quadrant %d,%d is under attack\n",
+                      Systemname[e->systemname], ix, iy);
+               restcancel++;
+           }
+           else
+               /* if we can't tell him, make it invisible */
+               e->evcode |= E_HIDDEN;
+           break;
+      case FENSLV:             /* starsystem is enslaved */
+           unschedule(e);
+           /* 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;
+               break;
+           }
+
+           /* play stork and schedule the first baby */
+           e = schedule(E_REPRO, Param.eventdly[E_REPRO] * franf(), e->x, e->y, e->systemname);
+
+           /* report the disaster if we can */
+           if (game.damage[DRADIO] == 0.0)
+           {
+               printf("\nUhura:  We've lost contact with starsystem %s\n",
+                      Systemname[e->systemname]);
+               printf("  in quadrant %d,%d.\n", e->x, e->y);
+           }
+           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;
+               break;
+           }
+           xresched(e, E_REPRO, 1);
+           /* reproduce one Klingon */
+           ix = e->x;
+           iy = e->y;
+           if (Now.klings == 127)
+               break;          /* full right now */
+           if (q->klings >= MAXKLQUAD)
+           {
+               /* this quadrant not ok, pick an adjacent one */
+               for (i = ix - 1; i <= ix + 1; i++)
+               {
+                   if (!VALID_QUADRANT(i))
+                       continue;
+                   for (j = iy - 1; j <= iy + 1; j++)
+                   {
+                       if (!VALID_QUADRANT(j))
+                           continue;
+                       q = &Quad[i][j];
+                       /* check for this quad ok (not full & no snova) */
+                       if (q->klings >= MAXKLQUAD || q->stars < 0)
+                           continue;
+                       break;
+                   }
+                   if (j <= iy + 1)
+                       break;
+               }
+               if (j > iy + 1)
+                   /* cannot create another yet */
+                   break;
+               ix = i;
+               iy = j;
+           }
+           /* deliver the child */
+           game.remkl++;
+           if (ix == game.quadx && iy == game.quady)
+               newkling(++game.klhere, &ixhold, &iyhold);
+
+           /* recompute time left */
+           game.state.remtime = game.state.remres/(game.state.remkl+4*game.state.remcom);
+           break;
+#endif /* EXPERIMENTAL */
        }
     }
 }
@@ -685,7 +832,8 @@ void snova(int insx, int insy)
        /* did in the Supercommander! */
        game.state.nscrem = game.state.isx = game.state.isy = game.isatb = game.iscate = 0;
        iscdead = 1;
-       game.future[FSCMOVE] = game.future[FSCDBAS] = FOREVER;
+       unschedule(FSCMOVE);
+       unschedule(FSCDBAS);
     }
     if (game.state.remcom) {
        int maxloop = game.state.remcom, l;
@@ -697,7 +845,7 @@ void snova(int insx, int insy)
                game.state.remcom--;
                kldead--;
                comdead++;
-               if (game.state.remcom==0) game.future[FTBEAM] = FOREVER;
+               if (game.state.remcom==0) unschedule(FTBEAM);
                break;
            }
        }