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