121278Sdist /*
2*60857Sbostic * Copyright (c) 1980, 1993
3*60857Sbostic * The Regents of the University of California. All rights reserved.
434205Sbostic *
542605Sbostic * %sccs.include.redist.c%
621278Sdist */
721278Sdist
811672Smckusick #ifndef lint
9*60857Sbostic static char sccsid[] = "@(#)events.c 8.1 (Berkeley) 05/31/93";
1034205Sbostic #endif /* not lint */
1111672Smckusick
1211672Smckusick # include "trek.h"
1311672Smckusick
1411672Smckusick /*
1511672Smckusick ** CAUSE TIME TO ELAPSE
1611672Smckusick **
1711672Smckusick ** This routine does a hell of a lot. It elapses time, eats up
1811672Smckusick ** energy, regenerates energy, processes any events that occur,
1911672Smckusick ** and so on.
2011672Smckusick */
2111672Smckusick
2211672Smckusick
events(warp)2311672Smckusick events(warp)
2411672Smckusick int warp; /* set if called in a time warp */
2511672Smckusick {
2611672Smckusick register int i;
2711672Smckusick int j;
2811672Smckusick struct kling *k;
2911672Smckusick double rtime;
3011672Smckusick double xdate;
3111672Smckusick double idate;
3212737Slayer struct event *ev, *xsched(), *schedule();
3311672Smckusick int ix, iy;
3411672Smckusick register struct quad *q;
3511672Smckusick register struct event *e;
3611672Smckusick int evnum;
3711672Smckusick int restcancel;
3811672Smckusick
3911672Smckusick /* if nothing happened, just allow for any Klingons killed */
4011672Smckusick if (Move.time <= 0.0)
4111672Smckusick {
4211672Smckusick Now.time = Now.resource / Now.klings;
4311672Smckusick return (0);
4411672Smckusick }
4511672Smckusick
4611672Smckusick /* indicate that the cloaking device is now working */
4711672Smckusick Ship.cloakgood = 1;
4811672Smckusick
4911672Smckusick /* idate is the initial date */
5011672Smckusick idate = Now.date;
5111672Smckusick
5211672Smckusick /* schedule attacks if resting too long */
5311672Smckusick if (Move.time > 0.5 && Move.resting)
5411672Smckusick schedule(E_ATTACK, 0.5, 0, 0, 0);
5511672Smckusick
5611672Smckusick /* scan the event list */
5711672Smckusick while (1)
5811672Smckusick {
5911672Smckusick restcancel = 0;
6011672Smckusick evnum = -1;
6111672Smckusick /* xdate is the date of the current event */
6211672Smckusick xdate = idate + Move.time;
6311672Smckusick
6411672Smckusick /* find the first event that has happened */
6511672Smckusick for (i = 0; i < MAXEVENTS; i++)
6611672Smckusick {
6711672Smckusick e = &Event[i];
6811672Smckusick if (e->evcode == 0 || (e->evcode & E_GHOST))
6911672Smckusick continue;
7011672Smckusick if (e->date < xdate)
7111672Smckusick {
7211672Smckusick xdate = e->date;
7311672Smckusick ev = e;
7411672Smckusick evnum = i;
7511672Smckusick }
7611672Smckusick }
7711672Smckusick e = ev;
7811672Smckusick
7911672Smckusick /* find the time between events */
8011672Smckusick rtime = xdate - Now.date;
8111672Smckusick
8211672Smckusick /* decrement the magic "Federation Resources" pseudo-variable */
8312737Slayer Now.resource -= Now.klings * rtime;
8411672Smckusick /* and recompute the time left */
8511672Smckusick Now.time = Now.resource / Now.klings;
8611672Smckusick
8711672Smckusick /* move us up to the next date */
8811672Smckusick Now.date = xdate;
8911672Smckusick
9011672Smckusick /* check for out of time */
9111672Smckusick if (Now.time <= 0.0)
9211672Smckusick lose(L_NOTIME);
9311672Smckusick # ifdef xTRACE
9411672Smckusick if (evnum >= 0 && Trace)
9511672Smckusick printf("xdate = %.2f, evcode %d params %d %d %d\n",
9611672Smckusick xdate, e->evcode, e->x, e->y, e->systemname);
9711672Smckusick # endif
9811672Smckusick
9911672Smckusick /* if evnum < 0, no events occurred */
10011672Smckusick if (evnum < 0)
10111672Smckusick break;
10211672Smckusick
10311672Smckusick /* otherwise one did. Find out what it is */
10411672Smckusick switch (e->evcode & E_EVENT)
10511672Smckusick {
10611672Smckusick
10711672Smckusick case E_SNOVA: /* supernova */
10811672Smckusick /* cause the supernova to happen */
10911672Smckusick snova(-1);
11011672Smckusick /* and schedule the next one */
11111672Smckusick xresched(e, E_SNOVA, 1);
11211672Smckusick break;
11311672Smckusick
11411672Smckusick case E_LRTB: /* long range tractor beam */
11511672Smckusick /* schedule the next one */
11611672Smckusick xresched(e, E_LRTB, Now.klings);
11711672Smckusick /* LRTB cannot occur if we are docked */
11811672Smckusick if (Ship.cond != DOCKED)
11911672Smckusick {
12011672Smckusick /* pick a new quadrant */
12111672Smckusick i = ranf(Now.klings) + 1;
12211672Smckusick for (ix = 0; ix < NQUADS; ix++)
12311672Smckusick {
12411672Smckusick for (iy = 0; iy < NQUADS; iy++)
12511672Smckusick {
12611672Smckusick q = &Quad[ix][iy];
12711672Smckusick if (q->stars >= 0)
12812737Slayer if ((i -= q->klings) <= 0)
12911672Smckusick break;
13011672Smckusick }
13111672Smckusick if (i <= 0)
13211672Smckusick break;
13311672Smckusick }
13411672Smckusick
13511672Smckusick /* test for LRTB to same quadrant */
13611672Smckusick if (Ship.quadx == ix && Ship.quady == iy)
13711672Smckusick break;
13811672Smckusick
13911672Smckusick /* nope, dump him in the new quadrant */
14011672Smckusick Ship.quadx = ix;
14111672Smckusick Ship.quady = iy;
14211672Smckusick printf("\n%s caught in long range tractor beam\n", Ship.shipname);
14311672Smckusick printf("*** Pulled to quadrant %d,%d\n", Ship.quadx, Ship.quady);
14411672Smckusick Ship.sectx = ranf(NSECTS);
14511672Smckusick Ship.secty = ranf(NSECTS);
14611672Smckusick initquad(0);
14711672Smckusick /* truncate the move time */
14811672Smckusick Move.time = xdate - idate;
14911672Smckusick }
15011672Smckusick break;
15111672Smckusick
15211672Smckusick case E_KATSB: /* Klingon attacks starbase */
15311672Smckusick /* if out of bases, forget it */
15411672Smckusick if (Now.bases <= 0)
15511672Smckusick {
15611672Smckusick unschedule(e);
15711672Smckusick break;
15811672Smckusick }
15911672Smckusick
16011672Smckusick /* check for starbase and Klingons in same quadrant */
16111672Smckusick for (i = 0; i < Now.bases; i++)
16211672Smckusick {
16311672Smckusick ix = Now.base[i].x;
16411672Smckusick iy = Now.base[i].y;
16511672Smckusick /* see if a Klingon exists in this quadrant */
16611672Smckusick q = &Quad[ix][iy];
16711672Smckusick if (q->klings <= 0)
16811672Smckusick continue;
16911672Smckusick
17011672Smckusick /* see if already distressed */
17111672Smckusick for (j = 0; j < MAXEVENTS; j++)
17211672Smckusick {
17311672Smckusick e = &Event[j];
17411672Smckusick if ((e->evcode & E_EVENT) != E_KDESB)
17511672Smckusick continue;
17611672Smckusick if (e->x == ix && e->y == iy)
17711672Smckusick break;
17811672Smckusick }
17911672Smckusick if (j < MAXEVENTS)
18011672Smckusick continue;
18111672Smckusick
18211672Smckusick /* got a potential attack */
18311672Smckusick break;
18411672Smckusick }
18511672Smckusick e = ev;
18611672Smckusick if (i >= Now.bases)
18711672Smckusick {
18811672Smckusick /* not now; wait a while and see if some Klingons move in */
18911672Smckusick reschedule(e, 0.5 + 3.0 * franf());
19011672Smckusick break;
19111672Smckusick }
19211672Smckusick /* schedule a new attack, and a destruction of the base */
19311672Smckusick xresched(e, E_KATSB, 1);
19411672Smckusick e = xsched(E_KDESB, 1, ix, iy, 0);
19511672Smckusick
19611672Smckusick /* report it if we can */
19711672Smckusick if (!damaged(SSRADIO))
19811672Smckusick {
19911672Smckusick printf("\nUhura: Captain, we have recieved a distress signal\n");
20011672Smckusick printf(" from the starbase in quadrant %d,%d.\n",
20111672Smckusick ix, iy);
20211672Smckusick restcancel++;
20311672Smckusick }
20411672Smckusick else
20511672Smckusick /* SSRADIO out, make it so we can't see the distress call */
20611672Smckusick /* but it's still there!!! */
20712737Slayer e->evcode |= E_HIDDEN;
20811672Smckusick break;
20911672Smckusick
21011672Smckusick case E_KDESB: /* Klingon destroys starbase */
21111672Smckusick unschedule(e);
21211672Smckusick q = &Quad[e->x][e->y];
21311672Smckusick /* if the base has mysteriously gone away, or if the Klingon
21411672Smckusick got tired and went home, ignore this event */
21511672Smckusick if (q->bases <=0 || q->klings <= 0)
21611672Smckusick break;
21711672Smckusick /* are we in the same quadrant? */
21811672Smckusick if (e->x == Ship.quadx && e->y == Ship.quady)
21911672Smckusick {
22011672Smckusick /* yep, kill one in this quadrant */
22111672Smckusick printf("\nSpock: ");
22211672Smckusick killb(Ship.quadx, Ship.quady);
22311672Smckusick }
22411672Smckusick else
22511672Smckusick /* kill one in some other quadrant */
22611672Smckusick killb(e->x, e->y);
22711672Smckusick break;
22811672Smckusick
22911672Smckusick case E_ISSUE: /* issue a distress call */
23011672Smckusick xresched(e, E_ISSUE, 1);
23111672Smckusick /* if we already have too many, throw this one away */
23211672Smckusick if (Ship.distressed >= MAXDISTR)
23311672Smckusick break;
23411672Smckusick /* try a whole bunch of times to find something suitable */
23511672Smckusick for (i = 0; i < 100; i++)
23611672Smckusick {
23711672Smckusick ix = ranf(NQUADS);
23811672Smckusick iy = ranf(NQUADS);
23911672Smckusick q = &Quad[ix][iy];
24011672Smckusick /* need a quadrant which is not the current one,
24111672Smckusick which has some stars which are inhabited and
24211672Smckusick not already under attack, which is not
24311672Smckusick supernova'ed, and which has some Klingons in it */
24411672Smckusick if (!((ix == Ship.quadx && iy == Ship.quady) || q->stars < 0 ||
24512737Slayer (q->qsystemname & Q_DISTRESSED) ||
24612737Slayer (q->qsystemname & Q_SYSTEM) == 0 || q->klings <= 0))
24711672Smckusick break;
24811672Smckusick }
24911672Smckusick if (i >= 100)
25011672Smckusick /* can't seem to find one; ignore this call */
25111672Smckusick break;
25211672Smckusick
25311672Smckusick /* got one!! Schedule its enslavement */
25412737Slayer Ship.distressed++;
25512737Slayer e = xsched(E_ENSLV, 1, ix, iy, q->qsystemname);
25612737Slayer q->qsystemname = (e - Event) | Q_DISTRESSED;
25711672Smckusick
25811672Smckusick /* tell the captain about it if we can */
25911672Smckusick if (!damaged(SSRADIO))
26011672Smckusick {
26111672Smckusick printf("\nUhura: Captain, starsystem %s in quadrant %d,%d is under attack\n",
26211672Smckusick Systemname[e->systemname], ix, iy);
26311672Smckusick restcancel++;
26411672Smckusick }
26511672Smckusick else
26611672Smckusick /* if we can't tell him, make it invisible */
26712737Slayer e->evcode |= E_HIDDEN;
26811672Smckusick break;
26911672Smckusick
27011672Smckusick case E_ENSLV: /* starsystem is enslaved */
27111672Smckusick unschedule(e);
27211672Smckusick /* see if current distress call still active */
27311672Smckusick q = &Quad[e->x][e->y];
27411672Smckusick if (q->klings <= 0)
27511672Smckusick {
27611672Smckusick /* no Klingons, clean up */
27711672Smckusick /* restore the system name */
27812737Slayer q->qsystemname = e->systemname;
27911672Smckusick break;
28011672Smckusick }
28111672Smckusick
28211672Smckusick /* play stork and schedule the first baby */
28311672Smckusick e = schedule(E_REPRO, Param.eventdly[E_REPRO] * franf(), e->x, e->y, e->systemname);
28411672Smckusick
28511672Smckusick /* report the disaster if we can */
28611672Smckusick if (!damaged(SSRADIO))
28711672Smckusick {
28811672Smckusick printf("\nUhura: We've lost contact with starsystem %s\n",
28911672Smckusick Systemname[e->systemname]);
29011672Smckusick printf(" in quadrant %d,%d.\n",
29111672Smckusick e->x, e->y);
29211672Smckusick }
29311672Smckusick else
29412737Slayer e->evcode |= E_HIDDEN;
29511672Smckusick break;
29611672Smckusick
29711672Smckusick case E_REPRO: /* Klingon reproduces */
29811672Smckusick /* see if distress call is still active */
29911672Smckusick q = &Quad[e->x][e->y];
30011672Smckusick if (q->klings <= 0)
30111672Smckusick {
30211672Smckusick unschedule(e);
30312737Slayer q->qsystemname = e->systemname;
30411672Smckusick break;
30511672Smckusick }
30611672Smckusick xresched(e, E_REPRO, 1);
30711672Smckusick /* reproduce one Klingon */
30811672Smckusick ix = e->x;
30911672Smckusick iy = e->y;
31011672Smckusick if (Now.klings == 127)
31111672Smckusick break; /* full right now */
31211672Smckusick if (q->klings >= MAXKLQUAD)
31311672Smckusick {
31411672Smckusick /* this quadrant not ok, pick an adjacent one */
31511672Smckusick for (i = ix - 1; i <= ix + 1; i++)
31611672Smckusick {
31711672Smckusick if (i < 0 || i >= NQUADS)
31811672Smckusick continue;
31911672Smckusick for (j = iy - 1; j <= iy + 1; j++)
32011672Smckusick {
32111672Smckusick if (j < 0 || j >= NQUADS)
32211672Smckusick continue;
32311672Smckusick q = &Quad[i][j];
32411672Smckusick /* check for this quad ok (not full & no snova) */
32511672Smckusick if (q->klings >= MAXKLQUAD || q->stars < 0)
32611672Smckusick continue;
32711672Smckusick break;
32811672Smckusick }
32911672Smckusick if (j <= iy + 1)
33011672Smckusick break;
33111672Smckusick }
33211672Smckusick if (j > iy + 1)
33311672Smckusick /* cannot create another yet */
33411672Smckusick break;
33511672Smckusick ix = i;
33611672Smckusick iy = j;
33711672Smckusick }
33811672Smckusick /* deliver the child */
33912737Slayer q->klings++;
34012737Slayer Now.klings++;
34111672Smckusick if (ix == Ship.quadx && iy == Ship.quady)
34211672Smckusick {
34311672Smckusick /* we must position Klingon */
34411672Smckusick sector(&ix, &iy);
34511672Smckusick Sect[ix][iy] = KLINGON;
34611672Smckusick k = &Etc.klingon[Etc.nkling++];
34711672Smckusick k->x = ix;
34811672Smckusick k->y = iy;
34911672Smckusick k->power = Param.klingpwr;
35011672Smckusick k->srndreq = 0;
35111672Smckusick compkldist(Etc.klingon[0].dist == Etc.klingon[0].avgdist ? 0 : 1);
35211672Smckusick }
35311672Smckusick
35411672Smckusick /* recompute time left */
35511672Smckusick Now.time = Now.resource / Now.klings;
35611672Smckusick break;
35711672Smckusick
35811672Smckusick case E_SNAP: /* take a snapshot of the galaxy */
35911672Smckusick xresched(e, E_SNAP, 1);
36012737Slayer i = (int) Etc.snapshot;
36112737Slayer i = bmove(Quad, i, sizeof (Quad));
36212737Slayer i = bmove(Event, i, sizeof (Event));
36316249Smckusick i = bmove(&Now, i, sizeof (Now));
36411672Smckusick Game.snap = 1;
36511672Smckusick break;
36611672Smckusick
36711672Smckusick case E_ATTACK: /* Klingons attack during rest period */
36811672Smckusick if (!Move.resting)
36911672Smckusick {
37011672Smckusick unschedule(e);
37111672Smckusick break;
37211672Smckusick }
37311672Smckusick attack(1);
37411672Smckusick reschedule(e, 0.5);
37511672Smckusick break;
37611672Smckusick
37711672Smckusick case E_FIXDV:
37811672Smckusick i = e->systemname;
37911672Smckusick unschedule(e);
38011672Smckusick
38111672Smckusick /* de-damage the device */
38211672Smckusick printf("%s reports repair work on the %s finished.\n",
38311672Smckusick Device[i].person, Device[i].name);
38411672Smckusick
38511672Smckusick /* handle special processing upon fix */
38611672Smckusick switch (i)
38711672Smckusick {
38811672Smckusick
38911672Smckusick case LIFESUP:
39011672Smckusick Ship.reserves = Param.reserves;
39111672Smckusick break;
39211672Smckusick
39311672Smckusick case SINS:
39411672Smckusick if (Ship.cond == DOCKED)
39511672Smckusick break;
39611672Smckusick printf("Spock has tried to recalibrate your Space Internal Navigation System,\n");
39711672Smckusick printf(" but he has no standard base to calibrate to. Suggest you get\n");
39811672Smckusick printf(" to a starbase immediately so that you can properly recalibrate.\n");
39911672Smckusick Ship.sinsbad = 1;
40011672Smckusick break;
40111672Smckusick
40211672Smckusick case SSRADIO:
40311672Smckusick restcancel = dumpssradio();
40411672Smckusick break;
40511672Smckusick }
40611672Smckusick break;
40711672Smckusick
40811672Smckusick default:
40911672Smckusick break;
41011672Smckusick }
41111672Smckusick
41211672Smckusick if (restcancel && Move.resting && getynpar("Spock: Shall we cancel our rest period"))
41311672Smckusick Move.time = xdate - idate;
41411672Smckusick
41511672Smckusick }
41611672Smckusick
41711672Smckusick /* unschedule an attack during a rest period */
41811672Smckusick if (e = Now.eventptr[E_ATTACK])
41911672Smckusick unschedule(e);
42011672Smckusick
42111672Smckusick if (!warp)
42211672Smckusick {
42311672Smckusick /* eat up energy if cloaked */
42411672Smckusick if (Ship.cloaked)
42512737Slayer Ship.energy -= Param.cloakenergy * Move.time;
42611672Smckusick
42711672Smckusick /* regenerate resources */
42811672Smckusick rtime = 1.0 - exp(-Param.regenfac * Move.time);
42912737Slayer Ship.shield += (Param.shield - Ship.shield) * rtime;
43012737Slayer Ship.energy += (Param.energy - Ship.energy) * rtime;
43111672Smckusick
43211672Smckusick /* decrement life support reserves */
43311672Smckusick if (damaged(LIFESUP) && Ship.cond != DOCKED)
43412737Slayer Ship.reserves -= Move.time;
43511672Smckusick }
43611672Smckusick return (0);
43711672Smckusick }
438