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