Home | History | Annotate | Line # | Download | only in trek
events.c revision 1.1.1.1
      1 /*
      2  * Copyright (c) 1980 Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 static char sccsid[] = "@(#)events.c	5.4 (Berkeley) 6/1/90";
     36 #endif /* not lint */
     37 
     38 # include	"trek.h"
     39 
     40 /*
     41 **  CAUSE TIME TO ELAPSE
     42 **
     43 **	This routine does a hell of a lot.  It elapses time, eats up
     44 **	energy, regenerates energy, processes any events that occur,
     45 **	and so on.
     46 */
     47 
     48 
     49 events(warp)
     50 int	warp;		/* set if called in a time warp */
     51 {
     52 	register int		i;
     53 	int			j;
     54 	struct kling		*k;
     55 	double			rtime;
     56 	double			xdate;
     57 	double			idate;
     58 	struct event		*ev, *xsched(), *schedule();
     59 	int			ix, iy;
     60 	register struct quad	*q;
     61 	register struct event	*e;
     62 	int			evnum;
     63 	int			restcancel;
     64 
     65 	/* if nothing happened, just allow for any Klingons killed */
     66 	if (Move.time <= 0.0)
     67 	{
     68 		Now.time = Now.resource / Now.klings;
     69 		return (0);
     70 	}
     71 
     72 	/* indicate that the cloaking device is now working */
     73 	Ship.cloakgood = 1;
     74 
     75 	/* idate is the initial date */
     76 	idate = Now.date;
     77 
     78 	/* schedule attacks if resting too long */
     79 	if (Move.time > 0.5 && Move.resting)
     80 		schedule(E_ATTACK, 0.5, 0, 0, 0);
     81 
     82 	/* scan the event list */
     83 	while (1)
     84 	{
     85 		restcancel = 0;
     86 		evnum = -1;
     87 		/* xdate is the date of the current event */
     88 		xdate = idate + Move.time;
     89 
     90 		/* find the first event that has happened */
     91 		for (i = 0; i < MAXEVENTS; i++)
     92 		{
     93 			e = &Event[i];
     94 			if (e->evcode == 0 || (e->evcode & E_GHOST))
     95 				continue;
     96 			if (e->date < xdate)
     97 			{
     98 				xdate = e->date;
     99 				ev = e;
    100 				evnum = i;
    101 			}
    102 		}
    103 		e = ev;
    104 
    105 		/* find the time between events */
    106 		rtime = xdate - Now.date;
    107 
    108 		/* decrement the magic "Federation Resources" pseudo-variable */
    109 		Now.resource -= Now.klings * rtime;
    110 		/* and recompute the time left */
    111 		Now.time = Now.resource / Now.klings;
    112 
    113 		/* move us up to the next date */
    114 		Now.date = xdate;
    115 
    116 		/* check for out of time */
    117 		if (Now.time <= 0.0)
    118 			lose(L_NOTIME);
    119 #		ifdef xTRACE
    120 		if (evnum >= 0 && Trace)
    121 			printf("xdate = %.2f, evcode %d params %d %d %d\n",
    122 				xdate, e->evcode, e->x, e->y, e->systemname);
    123 #		endif
    124 
    125 		/* if evnum < 0, no events occurred  */
    126 		if (evnum < 0)
    127 			break;
    128 
    129 		/* otherwise one did.  Find out what it is */
    130 		switch (e->evcode & E_EVENT)
    131 		{
    132 
    133 		  case E_SNOVA:			/* supernova */
    134 			/* cause the supernova to happen */
    135 			snova(-1);
    136 			/* and schedule the next one */
    137 			xresched(e, E_SNOVA, 1);
    138 			break;
    139 
    140 		  case E_LRTB:			/* long range tractor beam */
    141 			/* schedule the next one */
    142 			xresched(e, E_LRTB, Now.klings);
    143 			/* LRTB cannot occur if we are docked */
    144 			if (Ship.cond != DOCKED)
    145 			{
    146 				/* pick a new quadrant */
    147 				i = ranf(Now.klings) + 1;
    148 				for (ix = 0; ix < NQUADS; ix++)
    149 				{
    150 					for (iy = 0; iy < NQUADS; iy++)
    151 					{
    152 						q = &Quad[ix][iy];
    153 						if (q->stars >= 0)
    154 							if ((i -= q->klings) <= 0)
    155 								break;
    156 					}
    157 					if (i <= 0)
    158 						break;
    159 				}
    160 
    161 				/* test for LRTB to same quadrant */
    162 				if (Ship.quadx == ix && Ship.quady == iy)
    163 					break;
    164 
    165 				/* nope, dump him in the new quadrant */
    166 				Ship.quadx = ix;
    167 				Ship.quady = iy;
    168 				printf("\n%s caught in long range tractor beam\n", Ship.shipname);
    169 				printf("*** Pulled to quadrant %d,%d\n", Ship.quadx, Ship.quady);
    170 				Ship.sectx = ranf(NSECTS);
    171 				Ship.secty = ranf(NSECTS);
    172 				initquad(0);
    173 				/* truncate the move time */
    174 				Move.time = xdate - idate;
    175 			}
    176 			break;
    177 
    178 		  case E_KATSB:			/* Klingon attacks starbase */
    179 			/* if out of bases, forget it */
    180 			if (Now.bases <= 0)
    181 			{
    182 				unschedule(e);
    183 				break;
    184 			}
    185 
    186 			/* check for starbase and Klingons in same quadrant */
    187 			for (i = 0; i < Now.bases; i++)
    188 			{
    189 				ix = Now.base[i].x;
    190 				iy = Now.base[i].y;
    191 				/* see if a Klingon exists in this quadrant */
    192 				q = &Quad[ix][iy];
    193 				if (q->klings <= 0)
    194 					continue;
    195 
    196 				/* see if already distressed */
    197 				for (j = 0; j < MAXEVENTS; j++)
    198 				{
    199 					e = &Event[j];
    200 					if ((e->evcode & E_EVENT) != E_KDESB)
    201 						continue;
    202 					if (e->x == ix && e->y == iy)
    203 						break;
    204 				}
    205 				if (j < MAXEVENTS)
    206 					continue;
    207 
    208 				/* got a potential attack */
    209 				break;
    210 			}
    211 			e = ev;
    212 			if (i >= Now.bases)
    213 			{
    214 				/* not now; wait a while and see if some Klingons move in */
    215 				reschedule(e, 0.5 + 3.0 * franf());
    216 				break;
    217 			}
    218 			/* schedule a new attack, and a destruction of the base */
    219 			xresched(e, E_KATSB, 1);
    220 			e = xsched(E_KDESB, 1, ix, iy, 0);
    221 
    222 			/* report it if we can */
    223 			if (!damaged(SSRADIO))
    224 			{
    225 				printf("\nUhura:  Captain, we have recieved a distress signal\n");
    226 				printf("  from the starbase in quadrant %d,%d.\n",
    227 					ix, iy);
    228 				restcancel++;
    229 			}
    230 			else
    231 				/* SSRADIO out, make it so we can't see the distress call */
    232 				/* but it's still there!!! */
    233 				e->evcode |= E_HIDDEN;
    234 			break;
    235 
    236 		  case E_KDESB:			/* Klingon destroys starbase */
    237 			unschedule(e);
    238 			q = &Quad[e->x][e->y];
    239 			/* if the base has mysteriously gone away, or if the Klingon
    240 			   got tired and went home, ignore this event */
    241 			if (q->bases <=0 || q->klings <= 0)
    242 				break;
    243 			/* are we in the same quadrant? */
    244 			if (e->x == Ship.quadx && e->y == Ship.quady)
    245 			{
    246 				/* yep, kill one in this quadrant */
    247 				printf("\nSpock: ");
    248 				killb(Ship.quadx, Ship.quady);
    249 			}
    250 			else
    251 				/* kill one in some other quadrant */
    252 				killb(e->x, e->y);
    253 			break;
    254 
    255 		  case E_ISSUE:		/* issue a distress call */
    256 			xresched(e, E_ISSUE, 1);
    257 			/* if we already have too many, throw this one away */
    258 			if (Ship.distressed >= MAXDISTR)
    259 				break;
    260 			/* try a whole bunch of times to find something suitable */
    261 			for (i = 0; i < 100; i++)
    262 			{
    263 				ix = ranf(NQUADS);
    264 				iy = ranf(NQUADS);
    265 				q = &Quad[ix][iy];
    266 				/* need a quadrant which is not the current one,
    267 				   which has some stars which are inhabited and
    268 				   not already under attack, which is not
    269 				   supernova'ed, and which has some Klingons in it */
    270 				if (!((ix == Ship.quadx && iy == Ship.quady) || q->stars < 0 ||
    271 				    (q->qsystemname & Q_DISTRESSED) ||
    272 				    (q->qsystemname & Q_SYSTEM) == 0 || q->klings <= 0))
    273 					break;
    274 			}
    275 			if (i >= 100)
    276 				/* can't seem to find one; ignore this call */
    277 				break;
    278 
    279 			/* got one!!  Schedule its enslavement */
    280 			Ship.distressed++;
    281 			e = xsched(E_ENSLV, 1, ix, iy, q->qsystemname);
    282 			q->qsystemname = (e - Event) | Q_DISTRESSED;
    283 
    284 			/* tell the captain about it if we can */
    285 			if (!damaged(SSRADIO))
    286 			{
    287 				printf("\nUhura: Captain, starsystem %s in quadrant %d,%d is under attack\n",
    288 					Systemname[e->systemname], ix, iy);
    289 				restcancel++;
    290 			}
    291 			else
    292 				/* if we can't tell him, make it invisible */
    293 				e->evcode |= E_HIDDEN;
    294 			break;
    295 
    296 		  case E_ENSLV:		/* starsystem is enslaved */
    297 			unschedule(e);
    298 			/* see if current distress call still active */
    299 			q = &Quad[e->x][e->y];
    300 			if (q->klings <= 0)
    301 			{
    302 				/* no Klingons, clean up */
    303 				/* restore the system name */
    304 				q->qsystemname = e->systemname;
    305 				break;
    306 			}
    307 
    308 			/* play stork and schedule the first baby */
    309 			e = schedule(E_REPRO, Param.eventdly[E_REPRO] * franf(), e->x, e->y, e->systemname);
    310 
    311 			/* report the disaster if we can */
    312 			if (!damaged(SSRADIO))
    313 			{
    314 				printf("\nUhura:  We've lost contact with starsystem %s\n",
    315 					Systemname[e->systemname]);
    316 				printf("  in quadrant %d,%d.\n",
    317 					e->x, e->y);
    318 			}
    319 			else
    320 				e->evcode |= E_HIDDEN;
    321 			break;
    322 
    323 		  case E_REPRO:		/* Klingon reproduces */
    324 			/* see if distress call is still active */
    325 			q = &Quad[e->x][e->y];
    326 			if (q->klings <= 0)
    327 			{
    328 				unschedule(e);
    329 				q->qsystemname = e->systemname;
    330 				break;
    331 			}
    332 			xresched(e, E_REPRO, 1);
    333 			/* reproduce one Klingon */
    334 			ix = e->x;
    335 			iy = e->y;
    336 			if (Now.klings == 127)
    337 				break;		/* full right now */
    338 			if (q->klings >= MAXKLQUAD)
    339 			{
    340 				/* this quadrant not ok, pick an adjacent one */
    341 				for (i = ix - 1; i <= ix + 1; i++)
    342 				{
    343 					if (i < 0 || i >= NQUADS)
    344 						continue;
    345 					for (j = iy - 1; j <= iy + 1; j++)
    346 					{
    347 						if (j < 0 || j >= NQUADS)
    348 							continue;
    349 						q = &Quad[i][j];
    350 						/* check for this quad ok (not full & no snova) */
    351 						if (q->klings >= MAXKLQUAD || q->stars < 0)
    352 							continue;
    353 						break;
    354 					}
    355 					if (j <= iy + 1)
    356 						break;
    357 				}
    358 				if (j > iy + 1)
    359 					/* cannot create another yet */
    360 					break;
    361 				ix = i;
    362 				iy = j;
    363 			}
    364 			/* deliver the child */
    365 			q->klings++;
    366 			Now.klings++;
    367 			if (ix == Ship.quadx && iy == Ship.quady)
    368 			{
    369 				/* we must position Klingon */
    370 				sector(&ix, &iy);
    371 				Sect[ix][iy] = KLINGON;
    372 				k = &Etc.klingon[Etc.nkling++];
    373 				k->x = ix;
    374 				k->y = iy;
    375 				k->power = Param.klingpwr;
    376 				k->srndreq = 0;
    377 				compkldist(Etc.klingon[0].dist == Etc.klingon[0].avgdist ? 0 : 1);
    378 			}
    379 
    380 			/* recompute time left */
    381 			Now.time = Now.resource / Now.klings;
    382 			break;
    383 
    384 		  case E_SNAP:		/* take a snapshot of the galaxy */
    385 			xresched(e, E_SNAP, 1);
    386 			i = (int) Etc.snapshot;
    387 			i = bmove(Quad, i, sizeof (Quad));
    388 			i = bmove(Event, i, sizeof (Event));
    389 			i = bmove(&Now, i, sizeof (Now));
    390 			Game.snap = 1;
    391 			break;
    392 
    393 		  case E_ATTACK:	/* Klingons attack during rest period */
    394 			if (!Move.resting)
    395 			{
    396 				unschedule(e);
    397 				break;
    398 			}
    399 			attack(1);
    400 			reschedule(e, 0.5);
    401 			break;
    402 
    403 		  case E_FIXDV:
    404 			i = e->systemname;
    405 			unschedule(e);
    406 
    407 			/* de-damage the device */
    408 			printf("%s reports repair work on the %s finished.\n",
    409 				Device[i].person, Device[i].name);
    410 
    411 			/* handle special processing upon fix */
    412 			switch (i)
    413 			{
    414 
    415 			  case LIFESUP:
    416 				Ship.reserves = Param.reserves;
    417 				break;
    418 
    419 			  case SINS:
    420 				if (Ship.cond == DOCKED)
    421 					break;
    422 				printf("Spock has tried to recalibrate your Space Internal Navigation System,\n");
    423 				printf("  but he has no standard base to calibrate to.  Suggest you get\n");
    424 				printf("  to a starbase immediately so that you can properly recalibrate.\n");
    425 				Ship.sinsbad = 1;
    426 				break;
    427 
    428 			  case SSRADIO:
    429 				restcancel = dumpssradio();
    430 				break;
    431 			}
    432 			break;
    433 
    434 		  default:
    435 			break;
    436 		}
    437 
    438 		if (restcancel && Move.resting && getynpar("Spock: Shall we cancel our rest period"))
    439 			Move.time = xdate - idate;
    440 
    441 	}
    442 
    443 	/* unschedule an attack during a rest period */
    444 	if (e = Now.eventptr[E_ATTACK])
    445 		unschedule(e);
    446 
    447 	if (!warp)
    448 	{
    449 		/* eat up energy if cloaked */
    450 		if (Ship.cloaked)
    451 			Ship.energy -= Param.cloakenergy * Move.time;
    452 
    453 		/* regenerate resources */
    454 		rtime = 1.0 - exp(-Param.regenfac * Move.time);
    455 		Ship.shield += (Param.shield - Ship.shield) * rtime;
    456 		Ship.energy += (Param.energy - Ship.energy) * rtime;
    457 
    458 		/* decrement life support reserves */
    459 		if (damaged(LIFESUP) && Ship.cond != DOCKED)
    460 			Ship.reserves -= Move.time;
    461 	}
    462 	return (0);
    463 }
    464