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