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