1/* $NetBSD: events.c,v 1.10 2009/05/24 21:44:56 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 35static char sccsid[] = "@(#)events.c 8.1 (Berkeley) 5/31/93"; 36#else 37__RCSID("$NetBSD: events.c,v 1.10 2009/05/24 21:44:56 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 57int 58events(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