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