|
|
1.1 ! root 1: // g_misc.c ! 2: ! 3: #include "g_local.h" ! 4: ! 5: ! 6: /*QUAKED func_group (0 0 0) ? ! 7: Used to group brushes together just for editor convenience. ! 8: */ ! 9: ! 10: //===================================================== ! 11: ! 12: void Use_Areaportal (edict_t *ent, edict_t *other, edict_t *activator) ! 13: { ! 14: ent->count ^= 1; // toggle state ! 15: // gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count); ! 16: gi.SetAreaPortalState (ent->style, ent->count); ! 17: } ! 18: ! 19: /*QUAKED func_areaportal (0 0 0) ? ! 20: ! 21: This is a non-visible object that divides the world into ! 22: areas that are seperated when this portal is not activated. ! 23: Usually enclosed in the middle of a door. ! 24: */ ! 25: void SP_func_areaportal (edict_t *ent) ! 26: { ! 27: ent->use = Use_Areaportal; ! 28: ent->count = 0; // always start closed; ! 29: } ! 30: ! 31: //===================================================== ! 32: ! 33: ! 34: /* ! 35: ================= ! 36: Misc functions ! 37: ================= ! 38: */ ! 39: void VelocityForDamage (int damage, vec3_t v) ! 40: { ! 41: v[0] = 100.0 * crandom(); ! 42: v[1] = 100.0 * crandom(); ! 43: v[2] = 200.0 + 100.0 * random(); ! 44: ! 45: if (damage < 50) ! 46: VectorScale (v, 0.7, v); ! 47: else ! 48: VectorScale (v, 1.2, v); ! 49: } ! 50: ! 51: void ClipGibVelocity (edict_t *ent) ! 52: { ! 53: if (ent->velocity[0] < -300) ! 54: ent->velocity[0] = -300; ! 55: else if (ent->velocity[0] > 300) ! 56: ent->velocity[0] = 300; ! 57: if (ent->velocity[1] < -300) ! 58: ent->velocity[1] = -300; ! 59: else if (ent->velocity[1] > 300) ! 60: ent->velocity[1] = 300; ! 61: if (ent->velocity[2] < 200) ! 62: ent->velocity[2] = 200; // always some upwards ! 63: else if (ent->velocity[2] > 500) ! 64: ent->velocity[2] = 500; ! 65: } ! 66: ! 67: ! 68: /* ! 69: ================= ! 70: gibs ! 71: ================= ! 72: */ ! 73: void gib_think (edict_t *self) ! 74: { ! 75: self->s.frame++; ! 76: self->nextthink = level.time + FRAMETIME; ! 77: ! 78: if (self->s.frame == 10) ! 79: { ! 80: self->think = G_FreeEdict; ! 81: self->nextthink = level.time + 8 + random()*10; ! 82: } ! 83: } ! 84: ! 85: void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 86: { ! 87: vec3_t normal_angles, right; ! 88: ! 89: if (!self->groundentity) ! 90: return; ! 91: ! 92: self->touch = NULL; ! 93: ! 94: if (plane) ! 95: { ! 96: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0); ! 97: ! 98: vectoangles (plane->normal, normal_angles); ! 99: AngleVectors (normal_angles, NULL, right, NULL); ! 100: vectoangles (right, self->s.angles); ! 101: ! 102: if (self->s.modelindex == sm_meat_index) ! 103: { ! 104: self->s.frame++; ! 105: self->think = gib_think; ! 106: self->nextthink = level.time + FRAMETIME; ! 107: } ! 108: } ! 109: } ! 110: ! 111: // RAFAEL 24-APR-98 ! 112: // removed acid damage ! 113: #if 0 ! 114: // RAFAEL ! 115: void gib_touchacid (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 116: { ! 117: vec3_t normal_angles, right; ! 118: ! 119: if (other->takedamage) ! 120: { ! 121: T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH); ! 122: G_FreeEdict (self); ! 123: } ! 124: ! 125: if (!self->groundentity) ! 126: return; ! 127: ! 128: if (plane) ! 129: { ! 130: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0); ! 131: ! 132: vectoangles (plane->normal, normal_angles); ! 133: AngleVectors (normal_angles, NULL, right, NULL); ! 134: vectoangles (right, self->s.angles); ! 135: ! 136: if (self->s.modelindex == sm_meat_index) ! 137: { ! 138: self->s.frame++; ! 139: self->think = gib_think; ! 140: self->nextthink = level.time + FRAMETIME; ! 141: } ! 142: } ! 143: } ! 144: #endif ! 145: ! 146: void gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) ! 147: { ! 148: G_FreeEdict (self); ! 149: } ! 150: ! 151: void ThrowGib (edict_t *self, char *gibname, int damage, int type) ! 152: { ! 153: edict_t *gib; ! 154: vec3_t vd; ! 155: vec3_t origin; ! 156: vec3_t size; ! 157: float vscale; ! 158: ! 159: gib = G_Spawn(); ! 160: ! 161: VectorScale (self->size, 0.5, size); ! 162: VectorAdd (self->absmin, size, origin); ! 163: gib->s.origin[0] = origin[0] + crandom() * size[0]; ! 164: gib->s.origin[1] = origin[1] + crandom() * size[1]; ! 165: gib->s.origin[2] = origin[2] + crandom() * size[2]; ! 166: ! 167: gi.setmodel (gib, gibname); ! 168: gib->solid = SOLID_NOT; ! 169: gib->s.effects |= EF_GIB; ! 170: gib->flags |= FL_NO_KNOCKBACK; ! 171: gib->takedamage = DAMAGE_YES; ! 172: gib->die = gib_die; ! 173: ! 174: if (type == GIB_ORGANIC) ! 175: { ! 176: gib->movetype = MOVETYPE_TOSS; ! 177: gib->touch = gib_touch; ! 178: vscale = 0.5; ! 179: } ! 180: else ! 181: { ! 182: gib->movetype = MOVETYPE_BOUNCE; ! 183: vscale = 1.0; ! 184: } ! 185: ! 186: VelocityForDamage (damage, vd); ! 187: VectorMA (self->velocity, vscale, vd, gib->velocity); ! 188: ClipGibVelocity (gib); ! 189: gib->avelocity[0] = random()*600; ! 190: gib->avelocity[1] = random()*600; ! 191: gib->avelocity[2] = random()*600; ! 192: ! 193: gib->think = G_FreeEdict; ! 194: gib->nextthink = level.time + 10 + random()*10; ! 195: ! 196: gi.linkentity (gib); ! 197: } ! 198: ! 199: ! 200: ! 201: void ThrowHead (edict_t *self, char *gibname, int damage, int type) ! 202: { ! 203: vec3_t vd; ! 204: float vscale; ! 205: ! 206: self->s.skinnum = 0; ! 207: self->s.frame = 0; ! 208: VectorClear (self->mins); ! 209: VectorClear (self->maxs); ! 210: ! 211: self->s.modelindex2 = 0; ! 212: gi.setmodel (self, gibname); ! 213: self->solid = SOLID_NOT; ! 214: self->s.effects |= EF_GIB; ! 215: self->s.effects &= ~EF_FLIES; ! 216: self->s.sound = 0; ! 217: self->flags |= FL_NO_KNOCKBACK; ! 218: self->svflags &= ~SVF_MONSTER; ! 219: self->takedamage = DAMAGE_YES; ! 220: self->die = gib_die; ! 221: ! 222: if (type == GIB_ORGANIC) ! 223: { ! 224: self->movetype = MOVETYPE_TOSS; ! 225: self->touch = gib_touch; ! 226: vscale = 0.5; ! 227: } ! 228: else ! 229: { ! 230: self->movetype = MOVETYPE_BOUNCE; ! 231: vscale = 1.0; ! 232: } ! 233: ! 234: VelocityForDamage (damage, vd); ! 235: VectorMA (self->velocity, vscale, vd, self->velocity); ! 236: ClipGibVelocity (self); ! 237: ! 238: self->avelocity[YAW] = crandom()*600; ! 239: ! 240: self->think = G_FreeEdict; ! 241: self->nextthink = level.time + 10 + random()*10; ! 242: ! 243: gi.linkentity (self); ! 244: } ! 245: ! 246: ! 247: // RAFAEL ! 248: void ThrowGibACID (edict_t *self, char *gibname, int damage, int type) ! 249: { ! 250: edict_t *gib; ! 251: vec3_t vd; ! 252: vec3_t origin; ! 253: vec3_t size; ! 254: float vscale; ! 255: ! 256: gib = G_Spawn(); ! 257: ! 258: VectorScale (self->size, 0.5, size); ! 259: VectorAdd (self->absmin, size, origin); ! 260: gib->s.origin[0] = origin[0] + crandom() * size[0]; ! 261: gib->s.origin[1] = origin[1] + crandom() * size[1]; ! 262: gib->s.origin[2] = origin[2] + crandom() * size[2]; ! 263: ! 264: // gi.setmodel (gib, gibname); ! 265: gib->s.modelindex = gi.modelindex (gibname); ! 266: ! 267: gib->clipmask = MASK_SHOT; ! 268: gib->solid = SOLID_BBOX; ! 269: ! 270: gib->s.effects |= EF_GREENGIB; ! 271: // note to self check this ! 272: gib->s.renderfx |= RF_FULLBRIGHT; ! 273: gib->flags |= FL_NO_KNOCKBACK; ! 274: gib->takedamage = DAMAGE_YES; ! 275: gib->die = gib_die; ! 276: gib->dmg = 2; ! 277: ! 278: if (type == GIB_ORGANIC) ! 279: { ! 280: gib->movetype = MOVETYPE_TOSS; ! 281: // RAFAEL 24-APR-98 ! 282: // removed acid damage ! 283: //gib->touch = gib_touchacid; ! 284: vscale = 3.0; ! 285: } ! 286: else ! 287: { ! 288: gib->movetype = MOVETYPE_BOUNCE; ! 289: vscale = 1.0; ! 290: } ! 291: ! 292: VelocityForDamage (damage, vd); ! 293: VectorMA (self->velocity, vscale, vd, gib->velocity); ! 294: ClipGibVelocity (gib); ! 295: gib->avelocity[0] = random()*600; ! 296: gib->avelocity[1] = random()*600; ! 297: gib->avelocity[2] = random()*600; ! 298: ! 299: gib->think = G_FreeEdict; ! 300: gib->nextthink = level.time + 10 + random()*10; ! 301: ! 302: gi.linkentity (gib); ! 303: } ! 304: ! 305: // RAFAEL ! 306: void ThrowHeadACID (edict_t *self, char *gibname, int damage, int type) ! 307: { ! 308: vec3_t vd; ! 309: float vscale; ! 310: ! 311: self->s.skinnum = 0; ! 312: self->s.frame = 0; ! 313: VectorClear (self->mins); ! 314: VectorClear (self->maxs); ! 315: ! 316: self->s.modelindex2 = 0; ! 317: gi.setmodel (self, gibname); ! 318: ! 319: self->clipmask = MASK_SHOT; ! 320: self->solid = SOLID_BBOX; ! 321: ! 322: self->s.effects |= EF_GREENGIB; ! 323: self->s.effects &= ~EF_FLIES; ! 324: self->s.effects |= RF_FULLBRIGHT; ! 325: self->s.sound = 0; ! 326: self->flags |= FL_NO_KNOCKBACK; ! 327: self->svflags &= ~SVF_MONSTER; ! 328: self->takedamage = DAMAGE_YES; ! 329: self->die = gib_die; ! 330: self->dmg = 2; ! 331: ! 332: if (type == GIB_ORGANIC) ! 333: { ! 334: self->movetype = MOVETYPE_TOSS; ! 335: // RAFAEL 24-APR-98 ! 336: // removed acid damage ! 337: // self->touch = gib_touchacid; ! 338: vscale = 0.5; ! 339: } ! 340: else ! 341: { ! 342: self->movetype = MOVETYPE_BOUNCE; ! 343: vscale = 1.0; ! 344: } ! 345: ! 346: VelocityForDamage (damage, vd); ! 347: VectorMA (self->velocity, vscale, vd, self->velocity); ! 348: ClipGibVelocity (self); ! 349: ! 350: self->avelocity[YAW] = crandom()*600; ! 351: ! 352: self->think = G_FreeEdict; ! 353: self->nextthink = level.time + 10 + random()*10; ! 354: ! 355: gi.linkentity (self); ! 356: } ! 357: ! 358: ! 359: void ThrowClientHead (edict_t *self, int damage) ! 360: { ! 361: vec3_t vd; ! 362: char *gibname; ! 363: ! 364: if (rand()&1) ! 365: { ! 366: gibname = "models/objects/gibs/head2/tris.md2"; ! 367: self->s.skinnum = 1; // second skin is player ! 368: } ! 369: else ! 370: { ! 371: gibname = "models/objects/gibs/skull/tris.md2"; ! 372: self->s.skinnum = 0; ! 373: } ! 374: ! 375: self->s.origin[2] += 32; ! 376: self->s.frame = 0; ! 377: gi.setmodel (self, gibname); ! 378: VectorSet (self->mins, -16, -16, 0); ! 379: VectorSet (self->maxs, 16, 16, 16); ! 380: ! 381: self->takedamage = DAMAGE_NO; ! 382: self->solid = SOLID_NOT; ! 383: self->s.effects = EF_GIB; ! 384: self->s.sound = 0; ! 385: self->flags |= FL_NO_KNOCKBACK; ! 386: ! 387: self->movetype = MOVETYPE_BOUNCE; ! 388: VelocityForDamage (damage, vd); ! 389: VectorAdd (self->velocity, vd, self->velocity); ! 390: ! 391: if (self->client) // bodies in the queue don't have a client anymore ! 392: { ! 393: self->client->anim_priority = ANIM_DEATH; ! 394: self->client->anim_end = self->s.frame; ! 395: } ! 396: else ! 397: { ! 398: self->think = NULL; ! 399: self->nextthink = 0; ! 400: } ! 401: ! 402: gi.linkentity (self); ! 403: } ! 404: ! 405: ! 406: /* ! 407: ================= ! 408: debris ! 409: ================= ! 410: */ ! 411: void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) ! 412: { ! 413: G_FreeEdict (self); ! 414: } ! 415: ! 416: void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin) ! 417: { ! 418: edict_t *chunk; ! 419: vec3_t v; ! 420: ! 421: chunk = G_Spawn(); ! 422: VectorCopy (origin, chunk->s.origin); ! 423: gi.setmodel (chunk, modelname); ! 424: v[0] = 100 * crandom(); ! 425: v[1] = 100 * crandom(); ! 426: v[2] = 100 + 100 * crandom(); ! 427: VectorMA (self->velocity, speed, v, chunk->velocity); ! 428: chunk->movetype = MOVETYPE_BOUNCE; ! 429: chunk->solid = SOLID_NOT; ! 430: chunk->avelocity[0] = random()*600; ! 431: chunk->avelocity[1] = random()*600; ! 432: chunk->avelocity[2] = random()*600; ! 433: chunk->think = G_FreeEdict; ! 434: chunk->nextthink = level.time + 5 + random()*5; ! 435: chunk->s.frame = 0; ! 436: chunk->flags = 0; ! 437: chunk->classname = "debris"; ! 438: chunk->takedamage = DAMAGE_YES; ! 439: chunk->die = debris_die; ! 440: gi.linkentity (chunk); ! 441: } ! 442: ! 443: ! 444: void BecomeExplosion1 (edict_t *self) ! 445: { ! 446: gi.WriteByte (svc_temp_entity); ! 447: gi.WriteByte (TE_EXPLOSION1); ! 448: gi.WritePosition (self->s.origin); ! 449: gi.multicast (self->s.origin, MULTICAST_PVS); ! 450: ! 451: G_FreeEdict (self); ! 452: } ! 453: ! 454: ! 455: void BecomeExplosion2 (edict_t *self) ! 456: { ! 457: gi.WriteByte (svc_temp_entity); ! 458: gi.WriteByte (TE_EXPLOSION2); ! 459: gi.WritePosition (self->s.origin); ! 460: gi.multicast (self->s.origin, MULTICAST_PVS); ! 461: ! 462: G_FreeEdict (self); ! 463: } ! 464: ! 465: ! 466: /*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT ! 467: Target: next path corner ! 468: Pathtarget: gets used when an entity that has ! 469: this path_corner targeted touches it ! 470: */ ! 471: ! 472: void path_corner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 473: { ! 474: vec3_t v; ! 475: edict_t *next; ! 476: ! 477: if (other->movetarget != self) ! 478: return; ! 479: ! 480: if (other->enemy) ! 481: return; ! 482: ! 483: if (self->pathtarget) ! 484: { ! 485: char *savetarget; ! 486: ! 487: savetarget = self->target; ! 488: self->target = self->pathtarget; ! 489: G_UseTargets (self, other); ! 490: self->target = savetarget; ! 491: } ! 492: ! 493: if (self->target) ! 494: next = G_PickTarget(self->target); ! 495: else ! 496: next = NULL; ! 497: ! 498: if ((next) && (next->spawnflags & 1)) ! 499: { ! 500: VectorCopy (next->s.origin, v); ! 501: v[2] += next->mins[2]; ! 502: v[2] -= other->mins[2]; ! 503: VectorCopy (v, other->s.origin); ! 504: next = G_PickTarget(next->target); ! 505: other->s.event = EV_OTHER_TELEPORT; ! 506: } ! 507: ! 508: other->goalentity = other->movetarget = next; ! 509: ! 510: if (self->wait) ! 511: { ! 512: other->monsterinfo.pausetime = level.time + self->wait; ! 513: other->monsterinfo.stand (other); ! 514: return; ! 515: } ! 516: ! 517: if (!other->movetarget) ! 518: { ! 519: other->monsterinfo.pausetime = level.time + 100000000; ! 520: other->monsterinfo.stand (other); ! 521: } ! 522: else ! 523: { ! 524: VectorSubtract (other->goalentity->s.origin, other->s.origin, v); ! 525: other->ideal_yaw = vectoyaw (v); ! 526: } ! 527: } ! 528: ! 529: void SP_path_corner (edict_t *self) ! 530: { ! 531: if (!self->targetname) ! 532: { ! 533: gi.dprintf ("path_corner with no targetname at %s\n", vtos(self->s.origin)); ! 534: G_FreeEdict (self); ! 535: return; ! 536: } ! 537: ! 538: self->solid = SOLID_TRIGGER; ! 539: self->touch = path_corner_touch; ! 540: VectorSet (self->mins, -8, -8, -8); ! 541: VectorSet (self->maxs, 8, 8, 8); ! 542: self->svflags |= SVF_NOCLIENT; ! 543: gi.linkentity (self); ! 544: } ! 545: ! 546: ! 547: /*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold ! 548: Makes this the target of a monster and it will head here ! 549: when first activated before going after the activator. If ! 550: hold is selected, it will stay here. ! 551: */ ! 552: void point_combat_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 553: { ! 554: edict_t *activator; ! 555: ! 556: if (other->movetarget != self) ! 557: return; ! 558: ! 559: if (self->target) ! 560: { ! 561: other->target = self->target; ! 562: other->goalentity = other->movetarget = G_PickTarget(other->target); ! 563: if (!other->goalentity) ! 564: { ! 565: gi.dprintf("%s at %s target %s does not exist\n", self->classname, vtos(self->s.origin), self->target); ! 566: other->movetarget = self; ! 567: } ! 568: self->target = NULL; ! 569: } ! 570: else if ((self->spawnflags & 1) && !(other->flags & (FL_SWIM|FL_FLY))) ! 571: { ! 572: other->monsterinfo.pausetime = level.time + 100000000; ! 573: other->monsterinfo.aiflags |= AI_STAND_GROUND; ! 574: other->monsterinfo.stand (other); ! 575: } ! 576: ! 577: if (other->movetarget == self) ! 578: { ! 579: other->target = NULL; ! 580: other->movetarget = NULL; ! 581: other->goalentity = other->enemy; ! 582: other->monsterinfo.aiflags &= ~AI_COMBAT_POINT; ! 583: } ! 584: ! 585: if (self->pathtarget) ! 586: { ! 587: char *savetarget; ! 588: ! 589: savetarget = self->target; ! 590: self->target = self->pathtarget; ! 591: if (other->enemy && other->enemy->client) ! 592: activator = other->enemy; ! 593: else if (other->oldenemy && other->oldenemy->client) ! 594: activator = other->oldenemy; ! 595: else if (other->activator && other->activator->client) ! 596: activator = other->activator; ! 597: else ! 598: activator = other; ! 599: G_UseTargets (self, activator); ! 600: self->target = savetarget; ! 601: } ! 602: } ! 603: ! 604: void SP_point_combat (edict_t *self) ! 605: { ! 606: if (deathmatch->value) ! 607: { ! 608: G_FreeEdict (self); ! 609: return; ! 610: } ! 611: self->solid = SOLID_TRIGGER; ! 612: self->touch = point_combat_touch; ! 613: VectorSet (self->mins, -8, -8, -16); ! 614: VectorSet (self->maxs, 8, 8, 16); ! 615: self->svflags = SVF_NOCLIENT; ! 616: gi.linkentity (self); ! 617: }; ! 618: ! 619: ! 620: /*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8) ! 621: Just for the debugging level. Don't use ! 622: */ ! 623: void TH_viewthing(edict_t *ent) ! 624: { ! 625: ent->s.frame = (ent->s.frame + 1) % 7; ! 626: ent->nextthink = level.time + FRAMETIME; ! 627: } ! 628: ! 629: void SP_viewthing(edict_t *ent) ! 630: { ! 631: gi.dprintf ("viewthing spawned\n"); ! 632: ! 633: ent->movetype = MOVETYPE_NONE; ! 634: ent->solid = SOLID_BBOX; ! 635: ent->s.renderfx = RF_FRAMELERP; ! 636: VectorSet (ent->mins, -16, -16, -24); ! 637: VectorSet (ent->maxs, 16, 16, 32); ! 638: ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2"); ! 639: gi.linkentity (ent); ! 640: ent->nextthink = level.time + 0.5; ! 641: ent->think = TH_viewthing; ! 642: return; ! 643: } ! 644: ! 645: ! 646: /*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) ! 647: Used as a positional target for spotlights, etc. ! 648: */ ! 649: void SP_info_null (edict_t *self) ! 650: { ! 651: G_FreeEdict (self); ! 652: }; ! 653: ! 654: ! 655: /*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4) ! 656: Used as a positional target for lightning. ! 657: */ ! 658: void SP_info_notnull (edict_t *self) ! 659: { ! 660: VectorCopy (self->s.origin, self->absmin); ! 661: VectorCopy (self->s.origin, self->absmax); ! 662: }; ! 663: ! 664: ! 665: /*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF ! 666: Non-displayed light. ! 667: Default light value is 300. ! 668: Default style is 0. ! 669: If targeted, will toggle between on and off. ! 670: Default _cone value is 10 (used to set size of light for spotlights) ! 671: */ ! 672: ! 673: #define START_OFF 1 ! 674: ! 675: static void light_use (edict_t *self, edict_t *other, edict_t *activator) ! 676: { ! 677: if (self->spawnflags & START_OFF) ! 678: { ! 679: gi.configstring (CS_LIGHTS+self->style, "m"); ! 680: self->spawnflags &= ~START_OFF; ! 681: } ! 682: else ! 683: { ! 684: gi.configstring (CS_LIGHTS+self->style, "a"); ! 685: self->spawnflags |= START_OFF; ! 686: } ! 687: } ! 688: ! 689: void SP_light (edict_t *self) ! 690: { ! 691: // no targeted lights in deathmatch, because they cause global messages ! 692: if (!self->targetname || deathmatch->value) ! 693: { ! 694: G_FreeEdict (self); ! 695: return; ! 696: } ! 697: ! 698: if (self->style >= 32) ! 699: { ! 700: self->use = light_use; ! 701: if (self->spawnflags & START_OFF) ! 702: gi.configstring (CS_LIGHTS+self->style, "a"); ! 703: else ! 704: gi.configstring (CS_LIGHTS+self->style, "m"); ! 705: } ! 706: } ! 707: ! 708: ! 709: /*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST ! 710: This is just a solid wall if not inhibited ! 711: ! 712: TRIGGER_SPAWN the wall will not be present until triggered ! 713: it will then blink in to existance; it will ! 714: kill anything that was in it's way ! 715: ! 716: TOGGLE only valid for TRIGGER_SPAWN walls ! 717: this allows the wall to be turned on and off ! 718: ! 719: START_ON only valid for TRIGGER_SPAWN walls ! 720: the wall will initially be present ! 721: */ ! 722: ! 723: void func_wall_use (edict_t *self, edict_t *other, edict_t *activator) ! 724: { ! 725: if (self->solid == SOLID_NOT) ! 726: { ! 727: self->solid = SOLID_BSP; ! 728: self->svflags &= ~SVF_NOCLIENT; ! 729: KillBox (self); ! 730: } ! 731: else ! 732: { ! 733: self->solid = SOLID_NOT; ! 734: self->svflags |= SVF_NOCLIENT; ! 735: } ! 736: gi.linkentity (self); ! 737: ! 738: if (!(self->spawnflags & 2)) ! 739: self->use = NULL; ! 740: } ! 741: ! 742: void SP_func_wall (edict_t *self) ! 743: { ! 744: self->movetype = MOVETYPE_PUSH; ! 745: gi.setmodel (self, self->model); ! 746: ! 747: if (self->spawnflags & 8) ! 748: self->s.effects |= EF_ANIM_ALL; ! 749: if (self->spawnflags & 16) ! 750: self->s.effects |= EF_ANIM_ALLFAST; ! 751: ! 752: // just a wall ! 753: if ((self->spawnflags & 7) == 0) ! 754: { ! 755: self->solid = SOLID_BSP; ! 756: gi.linkentity (self); ! 757: return; ! 758: } ! 759: ! 760: // it must be TRIGGER_SPAWN ! 761: if (!(self->spawnflags & 1)) ! 762: { ! 763: // gi.dprintf("func_wall missing TRIGGER_SPAWN\n"); ! 764: self->spawnflags |= 1; ! 765: } ! 766: ! 767: // yell if the spawnflags are odd ! 768: if (self->spawnflags & 4) ! 769: { ! 770: if (!(self->spawnflags & 2)) ! 771: { ! 772: gi.dprintf("func_wall START_ON without TOGGLE\n"); ! 773: self->spawnflags |= 2; ! 774: } ! 775: } ! 776: ! 777: self->use = func_wall_use; ! 778: if (self->spawnflags & 4) ! 779: { ! 780: self->solid = SOLID_BSP; ! 781: } ! 782: else ! 783: { ! 784: self->solid = SOLID_NOT; ! 785: self->svflags |= SVF_NOCLIENT; ! 786: } ! 787: gi.linkentity (self); ! 788: } ! 789: ! 790: ! 791: /*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST ! 792: This is solid bmodel that will fall if it's support it removed. ! 793: */ ! 794: ! 795: void func_object_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 796: { ! 797: // only squash thing we fall on top of ! 798: if (!plane) ! 799: return; ! 800: if (plane->normal[2] < 1.0) ! 801: return; ! 802: if (other->takedamage == DAMAGE_NO) ! 803: return; ! 804: T_Damage (other, self, self, vec3_origin, self->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH); ! 805: } ! 806: ! 807: void func_object_release (edict_t *self) ! 808: { ! 809: self->movetype = MOVETYPE_TOSS; ! 810: self->touch = func_object_touch; ! 811: } ! 812: ! 813: void func_object_use (edict_t *self, edict_t *other, edict_t *activator) ! 814: { ! 815: self->solid = SOLID_BSP; ! 816: self->svflags &= ~SVF_NOCLIENT; ! 817: self->use = NULL; ! 818: KillBox (self); ! 819: func_object_release (self); ! 820: } ! 821: ! 822: void SP_func_object (edict_t *self) ! 823: { ! 824: gi.setmodel (self, self->model); ! 825: ! 826: self->mins[0] += 1; ! 827: self->mins[1] += 1; ! 828: self->mins[2] += 1; ! 829: self->maxs[0] -= 1; ! 830: self->maxs[1] -= 1; ! 831: self->maxs[2] -= 1; ! 832: ! 833: if (!self->dmg) ! 834: self->dmg = 100; ! 835: ! 836: if (self->spawnflags == 0) ! 837: { ! 838: self->solid = SOLID_BSP; ! 839: self->movetype = MOVETYPE_PUSH; ! 840: self->think = func_object_release; ! 841: self->nextthink = level.time + 2 * FRAMETIME; ! 842: } ! 843: else ! 844: { ! 845: self->solid = SOLID_NOT; ! 846: self->movetype = MOVETYPE_PUSH; ! 847: self->use = func_object_use; ! 848: self->svflags |= SVF_NOCLIENT; ! 849: } ! 850: ! 851: if (self->spawnflags & 2) ! 852: self->s.effects |= EF_ANIM_ALL; ! 853: if (self->spawnflags & 4) ! 854: self->s.effects |= EF_ANIM_ALLFAST; ! 855: ! 856: self->clipmask = MASK_MONSTERSOLID; ! 857: ! 858: gi.linkentity (self); ! 859: } ! 860: ! 861: ! 862: /*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST ! 863: Any brush that you want to explode or break apart. If you want an ! 864: ex0plosion, set dmg and it will do a radius explosion of that amount ! 865: at the center of the bursh. ! 866: ! 867: If targeted it will not be shootable. ! 868: ! 869: health defaults to 100. ! 870: ! 871: mass defaults to 75. This determines how much debris is emitted when ! 872: it explodes. You get one large chunk per 100 of mass (up to 8) and ! 873: one small chunk per 25 of mass (up to 16). So 800 gives the most. ! 874: */ ! 875: void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) ! 876: { ! 877: vec3_t origin; ! 878: vec3_t chunkorigin; ! 879: vec3_t size; ! 880: int count; ! 881: int mass; ! 882: ! 883: // bmodel origins are (0 0 0), we need to adjust that here ! 884: VectorScale (self->size, 0.5, size); ! 885: VectorAdd (self->absmin, size, origin); ! 886: VectorCopy (origin, self->s.origin); ! 887: ! 888: self->takedamage = DAMAGE_NO; ! 889: ! 890: if (self->dmg) ! 891: T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE); ! 892: ! 893: VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity); ! 894: VectorNormalize (self->velocity); ! 895: VectorScale (self->velocity, 150, self->velocity); ! 896: ! 897: // start chunks towards the center ! 898: VectorScale (size, 0.5, size); ! 899: ! 900: mass = self->mass; ! 901: if (!mass) ! 902: mass = 75; ! 903: ! 904: // big chunks ! 905: if (mass >= 100) ! 906: { ! 907: count = mass / 100; ! 908: if (count > 8) ! 909: count = 8; ! 910: while(count--) ! 911: { ! 912: chunkorigin[0] = origin[0] + crandom() * size[0]; ! 913: chunkorigin[1] = origin[1] + crandom() * size[1]; ! 914: chunkorigin[2] = origin[2] + crandom() * size[2]; ! 915: ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin); ! 916: } ! 917: } ! 918: ! 919: // small chunks ! 920: count = mass / 25; ! 921: if (count > 16) ! 922: count = 16; ! 923: while(count--) ! 924: { ! 925: chunkorigin[0] = origin[0] + crandom() * size[0]; ! 926: chunkorigin[1] = origin[1] + crandom() * size[1]; ! 927: chunkorigin[2] = origin[2] + crandom() * size[2]; ! 928: ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin); ! 929: } ! 930: ! 931: G_UseTargets (self, attacker); ! 932: ! 933: if (self->dmg) ! 934: BecomeExplosion1 (self); ! 935: else ! 936: G_FreeEdict (self); ! 937: } ! 938: ! 939: void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator) ! 940: { ! 941: func_explosive_explode (self, self, other, self->health, vec3_origin); ! 942: } ! 943: ! 944: void func_explosive_spawn (edict_t *self, edict_t *other, edict_t *activator) ! 945: { ! 946: self->solid = SOLID_BSP; ! 947: self->svflags &= ~SVF_NOCLIENT; ! 948: self->use = NULL; ! 949: KillBox (self); ! 950: gi.linkentity (self); ! 951: } ! 952: ! 953: void SP_func_explosive (edict_t *self) ! 954: { ! 955: if (deathmatch->value) ! 956: { // auto-remove for deathmatch ! 957: G_FreeEdict (self); ! 958: return; ! 959: } ! 960: ! 961: self->movetype = MOVETYPE_PUSH; ! 962: ! 963: gi.modelindex ("models/objects/debris1/tris.md2"); ! 964: gi.modelindex ("models/objects/debris2/tris.md2"); ! 965: ! 966: gi.setmodel (self, self->model); ! 967: ! 968: if (self->spawnflags & 1) ! 969: { ! 970: self->svflags |= SVF_NOCLIENT; ! 971: self->solid = SOLID_NOT; ! 972: self->use = func_explosive_spawn; ! 973: } ! 974: else ! 975: { ! 976: self->solid = SOLID_BSP; ! 977: if (self->targetname) ! 978: self->use = func_explosive_use; ! 979: } ! 980: ! 981: if (self->spawnflags & 2) ! 982: self->s.effects |= EF_ANIM_ALL; ! 983: if (self->spawnflags & 4) ! 984: self->s.effects |= EF_ANIM_ALLFAST; ! 985: ! 986: if (self->use != func_explosive_use) ! 987: { ! 988: if (!self->health) ! 989: self->health = 100; ! 990: self->die = func_explosive_explode; ! 991: self->takedamage = DAMAGE_YES; ! 992: } ! 993: ! 994: gi.linkentity (self); ! 995: } ! 996: ! 997: ! 998: /*QUAKED misc_explobox (0 .5 .8) (-16 -16 0) (16 16 40) ! 999: Large exploding box. You can override its mass (100), ! 1000: health (80), and dmg (150). ! 1001: */ ! 1002: ! 1003: void barrel_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 1004: ! 1005: { ! 1006: float ratio; ! 1007: vec3_t v; ! 1008: ! 1009: if ((!other->groundentity) || (other->groundentity == self)) ! 1010: return; ! 1011: ! 1012: ratio = (float)other->mass / (float)self->mass; ! 1013: VectorSubtract (self->s.origin, other->s.origin, v); ! 1014: M_walkmove (self, vectoyaw(v), 20 * ratio * FRAMETIME); ! 1015: } ! 1016: ! 1017: void barrel_explode (edict_t *self) ! 1018: { ! 1019: vec3_t org; ! 1020: float spd; ! 1021: vec3_t save; ! 1022: ! 1023: T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_BARREL); ! 1024: ! 1025: VectorCopy (self->s.origin, save); ! 1026: VectorMA (self->absmin, 0.5, self->size, self->s.origin); ! 1027: ! 1028: // a few big chunks ! 1029: spd = 1.5 * (float)self->dmg / 200.0; ! 1030: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1031: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1032: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1033: ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org); ! 1034: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1035: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1036: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1037: ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org); ! 1038: ! 1039: // bottom corners ! 1040: spd = 1.75 * (float)self->dmg / 200.0; ! 1041: VectorCopy (self->absmin, org); ! 1042: ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org); ! 1043: VectorCopy (self->absmin, org); ! 1044: org[0] += self->size[0]; ! 1045: ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org); ! 1046: VectorCopy (self->absmin, org); ! 1047: org[1] += self->size[1]; ! 1048: ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org); ! 1049: VectorCopy (self->absmin, org); ! 1050: org[0] += self->size[0]; ! 1051: org[1] += self->size[1]; ! 1052: ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org); ! 1053: ! 1054: // a bunch of little chunks ! 1055: spd = 2 * self->dmg / 200; ! 1056: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1057: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1058: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1059: ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); ! 1060: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1061: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1062: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1063: ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); ! 1064: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1065: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1066: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1067: ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); ! 1068: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1069: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1070: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1071: ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); ! 1072: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1073: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1074: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1075: ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); ! 1076: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1077: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1078: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1079: ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); ! 1080: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1081: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1082: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1083: ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); ! 1084: org[0] = self->s.origin[0] + crandom() * self->size[0]; ! 1085: org[1] = self->s.origin[1] + crandom() * self->size[1]; ! 1086: org[2] = self->s.origin[2] + crandom() * self->size[2]; ! 1087: ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); ! 1088: ! 1089: VectorCopy (save, self->s.origin); ! 1090: if (self->groundentity) ! 1091: BecomeExplosion2 (self); ! 1092: else ! 1093: BecomeExplosion1 (self); ! 1094: } ! 1095: ! 1096: void barrel_delay (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) ! 1097: { ! 1098: self->takedamage = DAMAGE_NO; ! 1099: self->nextthink = level.time + 2 * FRAMETIME; ! 1100: self->think = barrel_explode; ! 1101: self->activator = attacker; ! 1102: } ! 1103: ! 1104: void SP_misc_explobox (edict_t *self) ! 1105: { ! 1106: if (deathmatch->value) ! 1107: { // auto-remove for deathmatch ! 1108: G_FreeEdict (self); ! 1109: return; ! 1110: } ! 1111: ! 1112: gi.modelindex ("models/objects/debris1/tris.md2"); ! 1113: gi.modelindex ("models/objects/debris2/tris.md2"); ! 1114: gi.modelindex ("models/objects/debris3/tris.md2"); ! 1115: ! 1116: self->solid = SOLID_BBOX; ! 1117: self->movetype = MOVETYPE_STEP; ! 1118: ! 1119: self->model = "models/objects/barrels/tris.md2"; ! 1120: self->s.modelindex = gi.modelindex (self->model); ! 1121: VectorSet (self->mins, -16, -16, 0); ! 1122: VectorSet (self->maxs, 16, 16, 40); ! 1123: ! 1124: if (!self->mass) ! 1125: self->mass = 400; ! 1126: if (!self->health) ! 1127: self->health = 10; ! 1128: if (!self->dmg) ! 1129: self->dmg = 150; ! 1130: ! 1131: self->die = barrel_delay; ! 1132: self->takedamage = DAMAGE_YES; ! 1133: self->monsterinfo.aiflags = AI_NOSTEP; ! 1134: ! 1135: self->touch = barrel_touch; ! 1136: ! 1137: self->think = M_droptofloor; ! 1138: self->nextthink = level.time + 2 * FRAMETIME; ! 1139: ! 1140: gi.linkentity (self); ! 1141: } ! 1142: ! 1143: ! 1144: // ! 1145: // miscellaneous specialty items ! 1146: // ! 1147: ! 1148: /*QUAKED misc_blackhole (1 .5 0) (-8 -8 -8) (8 8 8) ! 1149: */ ! 1150: ! 1151: void misc_blackhole_use (edict_t *ent, edict_t *other, edict_t *activator) ! 1152: { ! 1153: /* ! 1154: gi.WriteByte (svc_temp_entity); ! 1155: gi.WriteByte (TE_BOSSTPORT); ! 1156: gi.WritePosition (ent->s.origin); ! 1157: gi.multicast (ent->s.origin, MULTICAST_PVS); ! 1158: */ ! 1159: G_FreeEdict (ent); ! 1160: } ! 1161: ! 1162: void misc_blackhole_think (edict_t *self) ! 1163: { ! 1164: if (++self->s.frame < 19) ! 1165: self->nextthink = level.time + FRAMETIME; ! 1166: else ! 1167: { ! 1168: self->s.frame = 0; ! 1169: self->nextthink = level.time + FRAMETIME; ! 1170: } ! 1171: } ! 1172: ! 1173: void SP_misc_blackhole (edict_t *ent) ! 1174: { ! 1175: ent->movetype = MOVETYPE_NONE; ! 1176: ent->solid = SOLID_NOT; ! 1177: VectorSet (ent->mins, -64, -64, 0); ! 1178: VectorSet (ent->maxs, 64, 64, 8); ! 1179: ent->s.modelindex = gi.modelindex ("models/objects/black/tris.md2"); ! 1180: ent->s.renderfx = RF_TRANSLUCENT; ! 1181: ent->use = misc_blackhole_use; ! 1182: ent->think = misc_blackhole_think; ! 1183: ent->nextthink = level.time + 2 * FRAMETIME; ! 1184: gi.linkentity (ent); ! 1185: } ! 1186: ! 1187: /*QUAKED misc_eastertank (1 .5 0) (-32 -32 -16) (32 32 32) ! 1188: */ ! 1189: ! 1190: void misc_eastertank_think (edict_t *self) ! 1191: { ! 1192: if (++self->s.frame < 293) ! 1193: self->nextthink = level.time + FRAMETIME; ! 1194: else ! 1195: { ! 1196: self->s.frame = 254; ! 1197: self->nextthink = level.time + FRAMETIME; ! 1198: } ! 1199: } ! 1200: ! 1201: void SP_misc_eastertank (edict_t *ent) ! 1202: { ! 1203: ent->movetype = MOVETYPE_NONE; ! 1204: ent->solid = SOLID_BBOX; ! 1205: VectorSet (ent->mins, -32, -32, -16); ! 1206: VectorSet (ent->maxs, 32, 32, 32); ! 1207: ent->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2"); ! 1208: ent->s.frame = 254; ! 1209: ent->think = misc_eastertank_think; ! 1210: ent->nextthink = level.time + 2 * FRAMETIME; ! 1211: gi.linkentity (ent); ! 1212: } ! 1213: ! 1214: /*QUAKED misc_easterchick (1 .5 0) (-32 -32 0) (32 32 32) ! 1215: */ ! 1216: ! 1217: ! 1218: void misc_easterchick_think (edict_t *self) ! 1219: { ! 1220: if (++self->s.frame < 247) ! 1221: self->nextthink = level.time + FRAMETIME; ! 1222: else ! 1223: { ! 1224: self->s.frame = 208; ! 1225: self->nextthink = level.time + FRAMETIME; ! 1226: } ! 1227: } ! 1228: ! 1229: void SP_misc_easterchick (edict_t *ent) ! 1230: { ! 1231: ent->movetype = MOVETYPE_NONE; ! 1232: ent->solid = SOLID_BBOX; ! 1233: VectorSet (ent->mins, -32, -32, 0); ! 1234: VectorSet (ent->maxs, 32, 32, 32); ! 1235: ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2"); ! 1236: ent->s.frame = 208; ! 1237: ent->think = misc_easterchick_think; ! 1238: ent->nextthink = level.time + 2 * FRAMETIME; ! 1239: gi.linkentity (ent); ! 1240: } ! 1241: ! 1242: /*QUAKED misc_easterchick2 (1 .5 0) (-32 -32 0) (32 32 32) ! 1243: */ ! 1244: ! 1245: ! 1246: void misc_easterchick2_think (edict_t *self) ! 1247: { ! 1248: if (++self->s.frame < 287) ! 1249: self->nextthink = level.time + FRAMETIME; ! 1250: else ! 1251: { ! 1252: self->s.frame = 248; ! 1253: self->nextthink = level.time + FRAMETIME; ! 1254: } ! 1255: } ! 1256: ! 1257: void SP_misc_easterchick2 (edict_t *ent) ! 1258: { ! 1259: ent->movetype = MOVETYPE_NONE; ! 1260: ent->solid = SOLID_BBOX; ! 1261: VectorSet (ent->mins, -32, -32, 0); ! 1262: VectorSet (ent->maxs, 32, 32, 32); ! 1263: ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2"); ! 1264: ent->s.frame = 248; ! 1265: ent->think = misc_easterchick2_think; ! 1266: ent->nextthink = level.time + 2 * FRAMETIME; ! 1267: gi.linkentity (ent); ! 1268: } ! 1269: ! 1270: ! 1271: /*QUAKED monster_commander_body (1 .5 0) (-32 -32 0) (32 32 48) ! 1272: Not really a monster, this is the Tank Commander's decapitated body. ! 1273: There should be a item_commander_head that has this as it's target. ! 1274: */ ! 1275: ! 1276: void commander_body_think (edict_t *self) ! 1277: { ! 1278: if (++self->s.frame < 24) ! 1279: self->nextthink = level.time + FRAMETIME; ! 1280: else ! 1281: self->nextthink = 0; ! 1282: ! 1283: if (self->s.frame == 22) ! 1284: gi.sound (self, CHAN_BODY, gi.soundindex ("tank/thud.wav"), 1, ATTN_NORM, 0); ! 1285: } ! 1286: ! 1287: void commander_body_use (edict_t *self, edict_t *other, edict_t *activator) ! 1288: { ! 1289: self->think = commander_body_think; ! 1290: self->nextthink = level.time + FRAMETIME; ! 1291: gi.sound (self, CHAN_BODY, gi.soundindex ("tank/pain.wav"), 1, ATTN_NORM, 0); ! 1292: } ! 1293: ! 1294: void commander_body_drop (edict_t *self) ! 1295: { ! 1296: self->movetype = MOVETYPE_TOSS; ! 1297: self->s.origin[2] += 2; ! 1298: } ! 1299: ! 1300: void SP_monster_commander_body (edict_t *self) ! 1301: { ! 1302: self->movetype = MOVETYPE_NONE; ! 1303: self->solid = SOLID_BBOX; ! 1304: self->model = "models/monsters/commandr/tris.md2"; ! 1305: self->s.modelindex = gi.modelindex (self->model); ! 1306: VectorSet (self->mins, -32, -32, 0); ! 1307: VectorSet (self->maxs, 32, 32, 48); ! 1308: self->use = commander_body_use; ! 1309: self->takedamage = DAMAGE_YES; ! 1310: self->flags = FL_GODMODE; ! 1311: self->s.renderfx |= RF_FRAMELERP; ! 1312: gi.linkentity (self); ! 1313: ! 1314: gi.soundindex ("tank/thud.wav"); ! 1315: gi.soundindex ("tank/pain.wav"); ! 1316: ! 1317: self->think = commander_body_drop; ! 1318: self->nextthink = level.time + 5 * FRAMETIME; ! 1319: } ! 1320: ! 1321: ! 1322: /*QUAKED misc_banner (1 .5 0) (-4 -4 -4) (4 4 4) ! 1323: The origin is the bottom of the banner. ! 1324: The banner is 128 tall. ! 1325: */ ! 1326: void misc_banner_think (edict_t *ent) ! 1327: { ! 1328: ent->s.frame = (ent->s.frame + 1) % 16; ! 1329: ent->nextthink = level.time + FRAMETIME; ! 1330: } ! 1331: ! 1332: void SP_misc_banner (edict_t *ent) ! 1333: { ! 1334: ent->movetype = MOVETYPE_NONE; ! 1335: ent->solid = SOLID_NOT; ! 1336: ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2"); ! 1337: ent->s.frame = rand() % 16; ! 1338: gi.linkentity (ent); ! 1339: ! 1340: ent->think = misc_banner_think; ! 1341: ent->nextthink = level.time + FRAMETIME; ! 1342: } ! 1343: ! 1344: /*QUAKED misc_deadsoldier (1 .5 0) (-16 -16 0) (16 16 16) ON_BACK ON_STOMACH BACK_DECAP FETAL_POS SIT_DECAP IMPALED ! 1345: This is the dead player model. Comes in 6 exciting different poses! ! 1346: */ ! 1347: void misc_deadsoldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) ! 1348: { ! 1349: int n; ! 1350: ! 1351: if (self->health > -80) ! 1352: return; ! 1353: ! 1354: gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); ! 1355: for (n= 0; n < 4; n++) ! 1356: ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); ! 1357: ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); ! 1358: } ! 1359: ! 1360: void SP_misc_deadsoldier (edict_t *ent) ! 1361: { ! 1362: if (deathmatch->value) ! 1363: { // auto-remove for deathmatch ! 1364: G_FreeEdict (ent); ! 1365: return; ! 1366: } ! 1367: ! 1368: ent->movetype = MOVETYPE_NONE; ! 1369: ent->solid = SOLID_BBOX; ! 1370: ent->s.modelindex=gi.modelindex ("models/deadbods/dude/tris.md2"); ! 1371: ! 1372: // Defaults to frame 0 ! 1373: if (ent->spawnflags & 2) ! 1374: ent->s.frame = 1; ! 1375: else if (ent->spawnflags & 4) ! 1376: ent->s.frame = 2; ! 1377: else if (ent->spawnflags & 8) ! 1378: ent->s.frame = 3; ! 1379: else if (ent->spawnflags & 16) ! 1380: ent->s.frame = 4; ! 1381: else if (ent->spawnflags & 32) ! 1382: ent->s.frame = 5; ! 1383: else ! 1384: ent->s.frame = 0; ! 1385: ! 1386: VectorSet (ent->mins, -16, -16, 0); ! 1387: VectorSet (ent->maxs, 16, 16, 16); ! 1388: ent->deadflag = DEAD_DEAD; ! 1389: ent->takedamage = DAMAGE_YES; ! 1390: ent->svflags |= SVF_MONSTER|SVF_DEADMONSTER; ! 1391: ent->die = misc_deadsoldier_die; ! 1392: ent->monsterinfo.aiflags |= AI_GOOD_GUY; ! 1393: ! 1394: gi.linkentity (ent); ! 1395: } ! 1396: ! 1397: /*QUAKED misc_viper (1 .5 0) (-16 -16 0) (16 16 32) ! 1398: This is the Viper for the flyby bombing. ! 1399: It is trigger_spawned, so you must have something use it for it to show up. ! 1400: There must be a path for it to follow once it is activated. ! 1401: ! 1402: "speed" How fast the Viper should fly ! 1403: */ ! 1404: ! 1405: extern void train_use (edict_t *self, edict_t *other, edict_t *activator); ! 1406: extern void func_train_find (edict_t *self); ! 1407: ! 1408: void misc_viper_use (edict_t *self, edict_t *other, edict_t *activator) ! 1409: { ! 1410: self->svflags &= ~SVF_NOCLIENT; ! 1411: self->use = train_use; ! 1412: train_use (self, other, activator); ! 1413: } ! 1414: ! 1415: void SP_misc_viper (edict_t *ent) ! 1416: { ! 1417: if (!ent->target) ! 1418: { ! 1419: gi.dprintf ("misc_viper without a target at %s\n", vtos(ent->absmin)); ! 1420: G_FreeEdict (ent); ! 1421: return; ! 1422: } ! 1423: ! 1424: if (!ent->speed) ! 1425: ent->speed = 300; ! 1426: ! 1427: ent->movetype = MOVETYPE_PUSH; ! 1428: ent->solid = SOLID_NOT; ! 1429: ent->s.modelindex = gi.modelindex ("models/ships/viper/tris.md2"); ! 1430: VectorSet (ent->mins, -16, -16, 0); ! 1431: VectorSet (ent->maxs, 16, 16, 32); ! 1432: ! 1433: ent->think = func_train_find; ! 1434: ent->nextthink = level.time + FRAMETIME; ! 1435: ent->use = misc_viper_use; ! 1436: ent->svflags |= SVF_NOCLIENT; ! 1437: ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed; ! 1438: ! 1439: gi.linkentity (ent); ! 1440: } ! 1441: ! 1442: /*QUAKED misc_crashviper (1 .5 0) (-176 -120 -24) (176 120 72) ! 1443: This is a large viper about to crash ! 1444: */ ! 1445: void SP_misc_crashviper (edict_t *ent) ! 1446: { ! 1447: if (!ent->target) ! 1448: { ! 1449: gi.dprintf ("misc_viper without a target at %s\n", vtos(ent->absmin)); ! 1450: G_FreeEdict (ent); ! 1451: return; ! 1452: } ! 1453: ! 1454: if (!ent->speed) ! 1455: ent->speed = 300; ! 1456: ! 1457: ent->movetype = MOVETYPE_PUSH; ! 1458: ent->solid = SOLID_NOT; ! 1459: ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2"); ! 1460: VectorSet (ent->mins, -16, -16, 0); ! 1461: VectorSet (ent->maxs, 16, 16, 32); ! 1462: ! 1463: ! 1464: ent->think = func_train_find; ! 1465: ent->nextthink = level.time + FRAMETIME; ! 1466: ent->use = misc_viper_use; ! 1467: ent->svflags |= SVF_NOCLIENT; ! 1468: ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed; ! 1469: ! 1470: gi.linkentity (ent); ! 1471: } ! 1472: ! 1473: ! 1474: /*QUAKED misc_bigviper (1 .5 0) (-176 -120 -24) (176 120 72) ! 1475: This is a large stationary viper as seen in Paul's intro ! 1476: */ ! 1477: void SP_misc_bigviper (edict_t *ent) ! 1478: { ! 1479: ent->movetype = MOVETYPE_NONE; ! 1480: ent->solid = SOLID_BBOX; ! 1481: VectorSet (ent->mins, -176, -120, -24); ! 1482: VectorSet (ent->maxs, 176, 120, 72); ! 1483: ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2"); ! 1484: gi.linkentity (ent); ! 1485: } ! 1486: ! 1487: ! 1488: /*QUAKED misc_viper_bomb (1 0 0) (-8 -8 -8) (8 8 8) ! 1489: "dmg" how much boom should the bomb make? ! 1490: */ ! 1491: void misc_viper_bomb_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 1492: { ! 1493: G_UseTargets (self, self->activator); ! 1494: ! 1495: self->s.origin[2] = self->absmin[2] + 1; ! 1496: T_RadiusDamage (self, self, self->dmg, NULL, self->dmg+40, MOD_BOMB); ! 1497: BecomeExplosion2 (self); ! 1498: } ! 1499: ! 1500: void misc_viper_bomb_prethink (edict_t *self) ! 1501: { ! 1502: vec3_t v; ! 1503: float diff; ! 1504: ! 1505: self->groundentity = NULL; ! 1506: ! 1507: diff = self->timestamp - level.time; ! 1508: if (diff < -1.0) ! 1509: diff = -1.0; ! 1510: ! 1511: VectorScale (self->moveinfo.dir, 1.0 + diff, v); ! 1512: v[2] = diff; ! 1513: ! 1514: diff = self->s.angles[2]; ! 1515: vectoangles (v, self->s.angles); ! 1516: self->s.angles[2] = diff + 10; ! 1517: } ! 1518: ! 1519: void misc_viper_bomb_use (edict_t *self, edict_t *other, edict_t *activator) ! 1520: { ! 1521: edict_t *viper; ! 1522: ! 1523: self->solid = SOLID_BBOX; ! 1524: self->svflags &= ~SVF_NOCLIENT; ! 1525: self->s.effects |= EF_ROCKET; ! 1526: self->use = NULL; ! 1527: self->movetype = MOVETYPE_TOSS; ! 1528: self->prethink = misc_viper_bomb_prethink; ! 1529: self->touch = misc_viper_bomb_touch; ! 1530: self->activator = activator; ! 1531: ! 1532: viper = G_Find (NULL, FOFS(classname), "misc_viper"); ! 1533: VectorScale (viper->moveinfo.dir, viper->moveinfo.speed, self->velocity); ! 1534: ! 1535: self->timestamp = level.time; ! 1536: VectorCopy (viper->moveinfo.dir, self->moveinfo.dir); ! 1537: } ! 1538: ! 1539: ! 1540: void SP_misc_viper_bomb (edict_t *self) ! 1541: { ! 1542: self->movetype = MOVETYPE_NONE; ! 1543: self->solid = SOLID_NOT; ! 1544: VectorSet (self->mins, -8, -8, -8); ! 1545: VectorSet (self->maxs, 8, 8, 8); ! 1546: ! 1547: self->s.modelindex = gi.modelindex ("models/objects/bomb/tris.md2"); ! 1548: ! 1549: if (!self->dmg) ! 1550: self->dmg = 1000; ! 1551: ! 1552: self->use = misc_viper_bomb_use; ! 1553: self->svflags |= SVF_NOCLIENT; ! 1554: ! 1555: gi.linkentity (self); ! 1556: } ! 1557: ! 1558: ! 1559: // RAFAEL ! 1560: /*QUAKED misc_viper_missile (1 0 0) (-8 -8 -8) (8 8 8) ! 1561: "dmg" how much boom should the bomb make? the default value is 250 ! 1562: */ ! 1563: ! 1564: void misc_viper_missile_use (edict_t *self, edict_t *other, edict_t *activator) ! 1565: { ! 1566: ! 1567: vec3_t forward, right, up; ! 1568: vec3_t start, dir; ! 1569: vec3_t vec; ! 1570: ! 1571: AngleVectors (self->s.angles, forward, right, up); ! 1572: ! 1573: self->enemy = G_Find (NULL, FOFS(targetname), self->target); ! 1574: ! 1575: VectorCopy (self->enemy->s.origin, vec); ! 1576: vec[2] + 16; ! 1577: ! 1578: VectorCopy (self->s.origin, start); ! 1579: VectorSubtract (vec, start, dir); ! 1580: VectorNormalize (dir); ! 1581: ! 1582: monster_fire_rocket (self, start, dir, self->dmg, 500, MZ2_CHICK_ROCKET_1); ! 1583: ! 1584: self->nextthink = level.time + 0.1; ! 1585: self->think = G_FreeEdict; ! 1586: ! 1587: ! 1588: } ! 1589: ! 1590: ! 1591: void SP_misc_viper_missile (edict_t *self) ! 1592: { ! 1593: self->movetype = MOVETYPE_NONE; ! 1594: self->solid = SOLID_NOT; ! 1595: VectorSet (self->mins, -8, -8, -8); ! 1596: VectorSet (self->maxs, 8, 8, 8); ! 1597: ! 1598: if (!self->dmg) ! 1599: self->dmg = 250; ! 1600: ! 1601: self->s.modelindex = gi.modelindex ("models/objects/bomb/tris.md2"); ! 1602: ! 1603: self->use = misc_viper_missile_use; ! 1604: self->svflags |= SVF_NOCLIENT; ! 1605: ! 1606: gi.linkentity (self); ! 1607: } ! 1608: ! 1609: ! 1610: /*QUAKED misc_strogg_ship (1 .5 0) (-16 -16 0) (16 16 32) ! 1611: This is a Storgg ship for the flybys. ! 1612: It is trigger_spawned, so you must have something use it for it to show up. ! 1613: There must be a path for it to follow once it is activated. ! 1614: ! 1615: "speed" How fast it should fly ! 1616: */ ! 1617: ! 1618: extern void train_use (edict_t *self, edict_t *other, edict_t *activator); ! 1619: extern void func_train_find (edict_t *self); ! 1620: ! 1621: void misc_strogg_ship_use (edict_t *self, edict_t *other, edict_t *activator) ! 1622: { ! 1623: self->svflags &= ~SVF_NOCLIENT; ! 1624: self->use = train_use; ! 1625: train_use (self, other, activator); ! 1626: } ! 1627: ! 1628: void SP_misc_strogg_ship (edict_t *ent) ! 1629: { ! 1630: if (!ent->target) ! 1631: { ! 1632: gi.dprintf ("%s without a target at %s\n", ent->classname, vtos(ent->absmin)); ! 1633: G_FreeEdict (ent); ! 1634: return; ! 1635: } ! 1636: ! 1637: if (!ent->speed) ! 1638: ent->speed = 300; ! 1639: ! 1640: ent->movetype = MOVETYPE_PUSH; ! 1641: ent->solid = SOLID_NOT; ! 1642: ent->s.modelindex = gi.modelindex ("models/ships/strogg1/tris.md2"); ! 1643: VectorSet (ent->mins, -16, -16, 0); ! 1644: VectorSet (ent->maxs, 16, 16, 32); ! 1645: ! 1646: ent->think = func_train_find; ! 1647: ent->nextthink = level.time + FRAMETIME; ! 1648: ent->use = misc_strogg_ship_use; ! 1649: ent->svflags |= SVF_NOCLIENT; ! 1650: ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed; ! 1651: ! 1652: gi.linkentity (ent); ! 1653: } ! 1654: ! 1655: ! 1656: // RAFAEL 17-APR-98 ! 1657: /*QUAKED misc_transport (1 0 0) (-8 -8 -8) (8 8 8) TRIGGER_SPAWN ! 1658: Maxx's transport at end of game ! 1659: */ ! 1660: void SP_misc_transport (edict_t *ent) ! 1661: { ! 1662: ! 1663: if (!ent->target) ! 1664: { ! 1665: gi.dprintf ("%s without a target at %s\n", ent->classname, vtos(ent->absmin)); ! 1666: G_FreeEdict (ent); ! 1667: return; ! 1668: } ! 1669: ! 1670: if (!ent->speed) ! 1671: ent->speed = 300; ! 1672: ! 1673: ent->movetype = MOVETYPE_PUSH; ! 1674: ent->solid = SOLID_NOT; ! 1675: ent->s.modelindex = gi.modelindex ("models/objects/ship/tris.md2"); ! 1676: ! 1677: VectorSet (ent->mins, -16, -16, 0); ! 1678: VectorSet (ent->maxs, 16, 16, 32); ! 1679: ! 1680: ent->think = func_train_find; ! 1681: ent->nextthink = level.time + FRAMETIME; ! 1682: ent->use = misc_strogg_ship_use; ! 1683: ent->svflags |= SVF_NOCLIENT; ! 1684: ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed; ! 1685: ! 1686: if (!(ent->spawnflags & 1)) ! 1687: { ! 1688: ent->spawnflags |= 1; ! 1689: } ! 1690: ! 1691: gi.linkentity (ent); ! 1692: } ! 1693: // END 17-APR-98 ! 1694: ! 1695: ! 1696: /*QUAKED misc_satellite_dish (1 .5 0) (-64 -64 0) (64 64 128) ! 1697: */ ! 1698: void misc_satellite_dish_think (edict_t *self) ! 1699: { ! 1700: self->s.frame++; ! 1701: if (self->s.frame < 38) ! 1702: self->nextthink = level.time + FRAMETIME; ! 1703: } ! 1704: ! 1705: void misc_satellite_dish_use (edict_t *self, edict_t *other, edict_t *activator) ! 1706: { ! 1707: self->s.frame = 0; ! 1708: self->think = misc_satellite_dish_think; ! 1709: self->nextthink = level.time + FRAMETIME; ! 1710: } ! 1711: ! 1712: void SP_misc_satellite_dish (edict_t *ent) ! 1713: { ! 1714: ent->movetype = MOVETYPE_NONE; ! 1715: ent->solid = SOLID_BBOX; ! 1716: VectorSet (ent->mins, -64, -64, 0); ! 1717: VectorSet (ent->maxs, 64, 64, 128); ! 1718: ent->s.modelindex = gi.modelindex ("models/objects/satellite/tris.md2"); ! 1719: ent->use = misc_satellite_dish_use; ! 1720: gi.linkentity (ent); ! 1721: } ! 1722: ! 1723: ! 1724: /*QUAKED light_mine1 (0 1 0) (-2 -2 -12) (2 2 12) ! 1725: */ ! 1726: void SP_light_mine1 (edict_t *ent) ! 1727: { ! 1728: ent->movetype = MOVETYPE_NONE; ! 1729: ent->solid = SOLID_BBOX; ! 1730: ent->s.modelindex = gi.modelindex ("models/objects/minelite/light1/tris.md2"); ! 1731: gi.linkentity (ent); ! 1732: } ! 1733: ! 1734: ! 1735: /*QUAKED light_mine2 (0 1 0) (-2 -2 -12) (2 2 12) ! 1736: */ ! 1737: void SP_light_mine2 (edict_t *ent) ! 1738: { ! 1739: ent->movetype = MOVETYPE_NONE; ! 1740: ent->solid = SOLID_BBOX; ! 1741: ent->s.modelindex = gi.modelindex ("models/objects/minelite/light2/tris.md2"); ! 1742: gi.linkentity (ent); ! 1743: } ! 1744: ! 1745: ! 1746: /*QUAKED misc_gib_arm (1 0 0) (-8 -8 -8) (8 8 8) ! 1747: Intended for use with the target_spawner ! 1748: */ ! 1749: void SP_misc_gib_arm (edict_t *ent) ! 1750: { ! 1751: gi.setmodel (ent, "models/objects/gibs/arm/tris.md2"); ! 1752: ent->solid = SOLID_NOT; ! 1753: ent->s.effects |= EF_GIB; ! 1754: ent->takedamage = DAMAGE_YES; ! 1755: ent->die = gib_die; ! 1756: ent->movetype = MOVETYPE_TOSS; ! 1757: ent->svflags |= SVF_MONSTER; ! 1758: ent->deadflag = DEAD_DEAD; ! 1759: ent->avelocity[0] = random()*200; ! 1760: ent->avelocity[1] = random()*200; ! 1761: ent->avelocity[2] = random()*200; ! 1762: ent->think = G_FreeEdict; ! 1763: ent->nextthink = level.time + 30; ! 1764: gi.linkentity (ent); ! 1765: } ! 1766: ! 1767: /*QUAKED misc_gib_leg (1 0 0) (-8 -8 -8) (8 8 8) ! 1768: Intended for use with the target_spawner ! 1769: */ ! 1770: void SP_misc_gib_leg (edict_t *ent) ! 1771: { ! 1772: gi.setmodel (ent, "models/objects/gibs/leg/tris.md2"); ! 1773: ent->solid = SOLID_NOT; ! 1774: ent->s.effects |= EF_GIB; ! 1775: ent->takedamage = DAMAGE_YES; ! 1776: ent->die = gib_die; ! 1777: ent->movetype = MOVETYPE_TOSS; ! 1778: ent->svflags |= SVF_MONSTER; ! 1779: ent->deadflag = DEAD_DEAD; ! 1780: ent->avelocity[0] = random()*200; ! 1781: ent->avelocity[1] = random()*200; ! 1782: ent->avelocity[2] = random()*200; ! 1783: ent->think = G_FreeEdict; ! 1784: ent->nextthink = level.time + 30; ! 1785: gi.linkentity (ent); ! 1786: } ! 1787: ! 1788: /*QUAKED misc_gib_head (1 0 0) (-8 -8 -8) (8 8 8) ! 1789: Intended for use with the target_spawner ! 1790: */ ! 1791: void SP_misc_gib_head (edict_t *ent) ! 1792: { ! 1793: gi.setmodel (ent, "models/objects/gibs/head/tris.md2"); ! 1794: ent->solid = SOLID_NOT; ! 1795: ent->s.effects |= EF_GIB; ! 1796: ent->takedamage = DAMAGE_YES; ! 1797: ent->die = gib_die; ! 1798: ent->movetype = MOVETYPE_TOSS; ! 1799: ent->svflags |= SVF_MONSTER; ! 1800: ent->deadflag = DEAD_DEAD; ! 1801: ent->avelocity[0] = random()*200; ! 1802: ent->avelocity[1] = random()*200; ! 1803: ent->avelocity[2] = random()*200; ! 1804: ent->think = G_FreeEdict; ! 1805: ent->nextthink = level.time + 30; ! 1806: gi.linkentity (ent); ! 1807: } ! 1808: ! 1809: //===================================================== ! 1810: ! 1811: /*QUAKED target_character (0 0 1) ? ! 1812: used with target_string (must be on same "team") ! 1813: "count" is position in the string (starts at 1) ! 1814: */ ! 1815: ! 1816: void SP_target_character (edict_t *self) ! 1817: { ! 1818: self->movetype = MOVETYPE_PUSH; ! 1819: gi.setmodel (self, self->model); ! 1820: self->solid = SOLID_BSP; ! 1821: self->s.frame = 12; ! 1822: gi.linkentity (self); ! 1823: return; ! 1824: } ! 1825: ! 1826: ! 1827: /*QUAKED target_string (0 0 1) (-8 -8 -8) (8 8 8) ! 1828: */ ! 1829: ! 1830: void target_string_use (edict_t *self, edict_t *other, edict_t *activator) ! 1831: { ! 1832: edict_t *e; ! 1833: int n, l; ! 1834: char c; ! 1835: ! 1836: l = strlen(self->message); ! 1837: for (e = self->teammaster; e; e = e->teamchain) ! 1838: { ! 1839: if (!e->count) ! 1840: continue; ! 1841: n = e->count - 1; ! 1842: if (n > l) ! 1843: { ! 1844: e->s.frame = 12; ! 1845: continue; ! 1846: } ! 1847: ! 1848: c = self->message[n]; ! 1849: if (c >= '0' && c <= '9') ! 1850: e->s.frame = c - '0'; ! 1851: else if (c == '-') ! 1852: e->s.frame = 10; ! 1853: else if (c == ':') ! 1854: e->s.frame = 11; ! 1855: else ! 1856: e->s.frame = 12; ! 1857: } ! 1858: } ! 1859: ! 1860: void SP_target_string (edict_t *self) ! 1861: { ! 1862: if (!self->message) ! 1863: self->message = ""; ! 1864: self->use = target_string_use; ! 1865: } ! 1866: ! 1867: ! 1868: /*QUAKED func_clock (0 0 1) (-8 -8 -8) (8 8 8) TIMER_UP TIMER_DOWN START_OFF MULTI_USE ! 1869: target a target_string with this ! 1870: ! 1871: The default is to be a time of day clock ! 1872: ! 1873: TIMER_UP and TIMER_DOWN run for "count" seconds and the fire "pathtarget" ! 1874: If START_OFF, this entity must be used before it starts ! 1875: ! 1876: "style" 0 "xx" ! 1877: 1 "xx:xx" ! 1878: 2 "xx:xx:xx" ! 1879: */ ! 1880: ! 1881: #define CLOCK_MESSAGE_SIZE 16 ! 1882: ! 1883: // don't let field width of any clock messages change, or it ! 1884: // could cause an overwrite after a game load ! 1885: ! 1886: static void func_clock_reset (edict_t *self) ! 1887: { ! 1888: self->activator = NULL; ! 1889: if (self->spawnflags & 1) ! 1890: { ! 1891: self->health = 0; ! 1892: self->wait = self->count; ! 1893: } ! 1894: else if (self->spawnflags & 2) ! 1895: { ! 1896: self->health = self->count; ! 1897: self->wait = 0; ! 1898: } ! 1899: } ! 1900: ! 1901: static void func_clock_format_countdown (edict_t *self) ! 1902: { ! 1903: if (self->style == 0) ! 1904: { ! 1905: Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i", self->health); ! 1906: return; ! 1907: } ! 1908: ! 1909: if (self->style == 1) ! 1910: { ! 1911: Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60); ! 1912: if (self->message[3] == ' ') ! 1913: self->message[3] = '0'; ! 1914: return; ! 1915: } ! 1916: ! 1917: if (self->style == 2) ! 1918: { ! 1919: Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60); ! 1920: if (self->message[3] == ' ') ! 1921: self->message[3] = '0'; ! 1922: if (self->message[6] == ' ') ! 1923: self->message[6] = '0'; ! 1924: return; ! 1925: } ! 1926: } ! 1927: ! 1928: void func_clock_think (edict_t *self) ! 1929: { ! 1930: if (!self->enemy) ! 1931: { ! 1932: self->enemy = G_Find (NULL, FOFS(targetname), self->target); ! 1933: if (!self->enemy) ! 1934: return; ! 1935: } ! 1936: ! 1937: if (self->spawnflags & 1) ! 1938: { ! 1939: func_clock_format_countdown (self); ! 1940: self->health++; ! 1941: } ! 1942: else if (self->spawnflags & 2) ! 1943: { ! 1944: func_clock_format_countdown (self); ! 1945: self->health--; ! 1946: } ! 1947: else ! 1948: { ! 1949: struct tm *ltime; ! 1950: time_t gmtime; ! 1951: ! 1952: time(&gmtime); ! 1953: ltime = localtime(&gmtime); ! 1954: Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec); ! 1955: if (self->message[3] == ' ') ! 1956: self->message[3] = '0'; ! 1957: if (self->message[6] == ' ') ! 1958: self->message[6] = '0'; ! 1959: } ! 1960: ! 1961: self->enemy->message = self->message; ! 1962: self->enemy->use (self->enemy, self, self); ! 1963: ! 1964: if (((self->spawnflags & 1) && (self->health > self->wait)) || ! 1965: ((self->spawnflags & 2) && (self->health < self->wait))) ! 1966: { ! 1967: if (self->pathtarget) ! 1968: { ! 1969: char *savetarget; ! 1970: char *savemessage; ! 1971: ! 1972: savetarget = self->target; ! 1973: savemessage = self->message; ! 1974: self->target = self->pathtarget; ! 1975: self->message = NULL; ! 1976: G_UseTargets (self, self->activator); ! 1977: self->target = savetarget; ! 1978: self->message = savemessage; ! 1979: } ! 1980: ! 1981: if (!(self->spawnflags & 8)) ! 1982: return; ! 1983: ! 1984: func_clock_reset (self); ! 1985: ! 1986: if (self->spawnflags & 4) ! 1987: return; ! 1988: } ! 1989: ! 1990: self->nextthink = level.time + 1; ! 1991: } ! 1992: ! 1993: void func_clock_use (edict_t *self, edict_t *other, edict_t *activator) ! 1994: { ! 1995: if (!(self->spawnflags & 8)) ! 1996: self->use = NULL; ! 1997: if (self->activator) ! 1998: return; ! 1999: self->activator = activator; ! 2000: self->think (self); ! 2001: } ! 2002: ! 2003: void SP_func_clock (edict_t *self) ! 2004: { ! 2005: if (!self->target) ! 2006: { ! 2007: gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin)); ! 2008: G_FreeEdict (self); ! 2009: return; ! 2010: } ! 2011: ! 2012: if ((self->spawnflags & 2) && (!self->count)) ! 2013: { ! 2014: gi.dprintf("%s with no count at %s\n", self->classname, vtos(self->s.origin)); ! 2015: G_FreeEdict (self); ! 2016: return; ! 2017: } ! 2018: ! 2019: if ((self->spawnflags & 1) && (!self->count)) ! 2020: self->count = 60*60;; ! 2021: ! 2022: func_clock_reset (self); ! 2023: ! 2024: self->message = gi.TagMalloc (CLOCK_MESSAGE_SIZE, TAG_LEVEL); ! 2025: ! 2026: self->think = func_clock_think; ! 2027: ! 2028: if (self->spawnflags & 4) ! 2029: self->use = func_clock_use; ! 2030: else ! 2031: self->nextthink = level.time + 1; ! 2032: } ! 2033: ! 2034: //================================================================================= ! 2035: ! 2036: void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 2037: { ! 2038: edict_t *dest; ! 2039: int i; ! 2040: ! 2041: if (!other->client) ! 2042: return; ! 2043: dest = G_Find (NULL, FOFS(targetname), self->target); ! 2044: if (!dest) ! 2045: { ! 2046: gi.dprintf ("Couldn't find destination\n"); ! 2047: return; ! 2048: } ! 2049: ! 2050: // unlink to make sure it can't possibly interfere with KillBox ! 2051: gi.unlinkentity (other); ! 2052: ! 2053: VectorCopy (dest->s.origin, other->s.origin); ! 2054: VectorCopy (dest->s.origin, other->s.old_origin); ! 2055: other->s.origin[2] += 10; ! 2056: ! 2057: // clear the velocity and hold them in place briefly ! 2058: VectorClear (other->velocity); ! 2059: other->client->ps.pmove.pm_time = 160>>3; // hold time ! 2060: other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT; ! 2061: ! 2062: // draw the teleport splash at source and on the player ! 2063: self->owner->s.event = EV_PLAYER_TELEPORT; ! 2064: other->s.event = EV_PLAYER_TELEPORT; ! 2065: ! 2066: // set angles ! 2067: for (i=0 ; i<3 ; i++) ! 2068: other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]); ! 2069: ! 2070: VectorClear (other->s.angles); ! 2071: VectorClear (other->client->ps.viewangles); ! 2072: VectorClear (other->client->v_angle); ! 2073: ! 2074: // kill anything at the destination ! 2075: KillBox (other); ! 2076: ! 2077: gi.linkentity (other); ! 2078: } ! 2079: ! 2080: /*QUAKED misc_teleporter (1 0 0) (-32 -32 -24) (32 32 -16) ! 2081: Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object. ! 2082: */ ! 2083: void SP_misc_teleporter (edict_t *ent) ! 2084: { ! 2085: edict_t *trig; ! 2086: ! 2087: if (!ent->target) ! 2088: { ! 2089: gi.dprintf ("teleporter without a target.\n"); ! 2090: G_FreeEdict (ent); ! 2091: return; ! 2092: } ! 2093: ! 2094: gi.setmodel (ent, "models/objects/dmspot/tris.md2"); ! 2095: ent->s.skinnum = 1; ! 2096: ent->s.effects = EF_TELEPORTER; ! 2097: ent->s.sound = gi.soundindex ("world/amb10.wav"); ! 2098: ent->solid = SOLID_BBOX; ! 2099: ! 2100: VectorSet (ent->mins, -32, -32, -24); ! 2101: VectorSet (ent->maxs, 32, 32, -16); ! 2102: gi.linkentity (ent); ! 2103: ! 2104: trig = G_Spawn (); ! 2105: trig->touch = teleporter_touch; ! 2106: trig->solid = SOLID_TRIGGER; ! 2107: trig->target = ent->target; ! 2108: trig->owner = ent; ! 2109: VectorCopy (ent->s.origin, trig->s.origin); ! 2110: VectorSet (trig->mins, -8, -8, 8); ! 2111: VectorSet (trig->maxs, 8, 8, 24); ! 2112: gi.linkentity (trig); ! 2113: ! 2114: } ! 2115: ! 2116: /*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16) ! 2117: Point teleporters at these. ! 2118: */ ! 2119: void SP_misc_teleporter_dest (edict_t *ent) ! 2120: { ! 2121: gi.setmodel (ent, "models/objects/dmspot/tris.md2"); ! 2122: ent->s.skinnum = 0; ! 2123: ent->solid = SOLID_BBOX; ! 2124: // ent->s.effects |= EF_FLIES; ! 2125: VectorSet (ent->mins, -32, -32, -24); ! 2126: VectorSet (ent->maxs, 32, 32, -16); ! 2127: gi.linkentity (ent); ! 2128: } ! 2129: ! 2130: ! 2131: /*QUAKED misc_amb4 (1 0 0) (-16 -16 -16) (16 16 16) ! 2132: Mal's amb4 loop entity ! 2133: */ ! 2134: static int amb4sound; ! 2135: ! 2136: void amb4_think (edict_t *ent) ! 2137: { ! 2138: ent->nextthink = level.time + 2.7; ! 2139: gi.sound(ent, CHAN_VOICE, amb4sound, 1, ATTN_NONE, 0); ! 2140: } ! 2141: ! 2142: void SP_misc_amb4 (edict_t *ent) ! 2143: { ! 2144: ent->think = amb4_think; ! 2145: ent->nextthink = level.time + 1; ! 2146: amb4sound = gi.soundindex ("world/amb4.wav"); ! 2147: gi.linkentity (ent); ! 2148: } ! 2149: ! 2150: /*QUAKED misc_nuke (1 0 0) (-16 -16 -16) (16 16 16) ! 2151: */ ! 2152: ! 2153: void use_nuke (edict_t *self, edict_t *other, edict_t *activator) ! 2154: { ! 2155: edict_t *from = g_edicts; ! 2156: ! 2157: for ( ; from < &g_edicts[globals.num_edicts]; from++) ! 2158: { ! 2159: if (from == self) ! 2160: continue; ! 2161: if (from->client) ! 2162: { ! 2163: T_Damage (from, self, self, vec3_origin, from->s.origin, vec3_origin, 100000, 1, 0, MOD_TRAP); ! 2164: } ! 2165: else if (from->svflags & SVF_MONSTER) ! 2166: { ! 2167: G_FreeEdict (from); ! 2168: } ! 2169: } ! 2170: ! 2171: self->use = NULL; ! 2172: } ! 2173: ! 2174: void SP_misc_nuke (edict_t *ent) ! 2175: { ! 2176: ent->use = use_nuke; ! 2177: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.