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