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