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