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