|
|
1.1 ! root 1: #include "g_local.h" ! 2: ! 3: ! 4: void InitTrigger (edict_t *self) ! 5: { ! 6: if (!VectorCompare (self->s.angles, vec3_origin)) ! 7: G_SetMovedir (self->s.angles, self->movedir); ! 8: ! 9: self->solid = SOLID_TRIGGER; ! 10: self->movetype = MOVETYPE_NONE; ! 11: gi.setmodel (self, self->model); ! 12: self->svflags = SVF_NOCLIENT; ! 13: } ! 14: ! 15: ! 16: // the wait time has passed, so set back up for another activation ! 17: void multi_wait (edict_t *ent) ! 18: { ! 19: ent->nextthink = 0; ! 20: } ! 21: ! 22: ! 23: // the trigger was just activated ! 24: // ent->activator should be set to the activator so it can be held through a delay ! 25: // so wait for the delay time before firing ! 26: void multi_trigger (edict_t *ent) ! 27: { ! 28: if (ent->nextthink) ! 29: return; // already been triggered ! 30: ! 31: G_UseTargets (ent, ent->activator); ! 32: ! 33: if (ent->wait > 0) ! 34: { ! 35: ent->think = multi_wait; ! 36: ent->nextthink = level.time + ent->wait; ! 37: } ! 38: else ! 39: { // we can't just remove (self) here, because this is a touch function ! 40: // called while looping through area links... ! 41: ent->touch = NULL; ! 42: ent->nextthink = level.time + FRAMETIME; ! 43: ent->think = G_FreeEdict; ! 44: } ! 45: } ! 46: ! 47: void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator) ! 48: { ! 49: ent->activator = activator; ! 50: multi_trigger (ent); ! 51: } ! 52: ! 53: void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 54: { ! 55: if(other->client) ! 56: { ! 57: if (self->spawnflags & 2) ! 58: return; ! 59: } ! 60: else if (other->svflags & SVF_MONSTER) ! 61: { ! 62: if (!(self->spawnflags & 1)) ! 63: return; ! 64: } ! 65: else ! 66: return; ! 67: ! 68: if (!VectorCompare(self->movedir, vec3_origin)) ! 69: { ! 70: vec3_t forward; ! 71: ! 72: AngleVectors(other->s.angles, forward, NULL, NULL); ! 73: if (_DotProduct(forward, self->movedir) < 0) ! 74: return; ! 75: } ! 76: ! 77: self->activator = other; ! 78: multi_trigger (self); ! 79: } ! 80: ! 81: /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED ! 82: Variable sized repeatable trigger. Must be targeted at one or more entities. ! 83: If "delay" is set, the trigger waits some time after activating before firing. ! 84: "wait" : Seconds between triggerings. (.2 default) ! 85: sounds ! 86: 1) secret ! 87: 2) beep beep ! 88: 3) large switch ! 89: 4) ! 90: set "message" to text string ! 91: */ ! 92: void trigger_enable (edict_t *self, edict_t *other, edict_t *activator) ! 93: { ! 94: self->solid = SOLID_TRIGGER; ! 95: self->use = Use_Multi; ! 96: gi.linkentity (self); ! 97: } ! 98: ! 99: void SP_trigger_multiple (edict_t *ent) ! 100: { ! 101: if (ent->sounds == 1) ! 102: ent->noise_index = gi.soundindex ("misc/secret.wav"); ! 103: else if (ent->sounds == 2) ! 104: ent->noise_index = gi.soundindex ("misc/talk.wav"); ! 105: else if (ent->sounds == 3) ! 106: ent->noise_index = gi.soundindex ("misc/trigger1.wav"); ! 107: ! 108: if (!ent->wait) ! 109: ent->wait = 0.2; ! 110: ent->touch = Touch_Multi; ! 111: ent->movetype = MOVETYPE_NONE; ! 112: ent->svflags |= SVF_NOCLIENT; ! 113: ! 114: ! 115: if (ent->spawnflags & 4) ! 116: { ! 117: ent->solid = SOLID_NOT; ! 118: ent->use = trigger_enable; ! 119: } ! 120: else ! 121: { ! 122: ent->solid = SOLID_TRIGGER; ! 123: ent->use = Use_Multi; ! 124: } ! 125: ! 126: if (!VectorCompare(ent->s.angles, vec3_origin)) ! 127: G_SetMovedir (ent->s.angles, ent->movedir); ! 128: ! 129: gi.setmodel (ent, ent->model); ! 130: gi.linkentity (ent); ! 131: } ! 132: ! 133: ! 134: /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED ! 135: Triggers once, then removes itself. ! 136: You must set the key "target" to the name of another object in the level that has a matching "targetname". ! 137: ! 138: If TRIGGERED, this trigger must be triggered before it is live. ! 139: ! 140: sounds ! 141: 1) secret ! 142: 2) beep beep ! 143: 3) large switch ! 144: 4) ! 145: ! 146: "message" string to be displayed when triggered ! 147: */ ! 148: ! 149: void SP_trigger_once(edict_t *ent) ! 150: { ! 151: // make old maps work because I messed up on flag assignments here ! 152: // triggered was on bit 1 when it should have been on bit 4 ! 153: if (ent->spawnflags & 1) ! 154: { ! 155: vec3_t v; ! 156: ! 157: VectorMA (ent->mins, 0.5, ent->size, v); ! 158: ent->spawnflags &= ~1; ! 159: ent->spawnflags |= 4; ! 160: gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v)); ! 161: } ! 162: ! 163: ent->wait = -1; ! 164: SP_trigger_multiple (ent); ! 165: } ! 166: ! 167: /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) ! 168: This fixed size trigger cannot be touched, it can only be fired by other events. ! 169: */ ! 170: void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator) ! 171: { ! 172: G_UseTargets (self, activator); ! 173: } ! 174: ! 175: void SP_trigger_relay (edict_t *self) ! 176: { ! 177: self->use = trigger_relay_use; ! 178: } ! 179: ! 180: ! 181: /* ! 182: ============================================================================== ! 183: ! 184: trigger_key ! 185: ! 186: ============================================================================== ! 187: */ ! 188: ! 189: /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8) ! 190: A relay trigger that only fires it's targets if player has the proper key. ! 191: Use "item" to specify the required key, for example "key_data_cd" ! 192: */ ! 193: void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator) ! 194: { ! 195: int index; ! 196: ! 197: if (!self->item) ! 198: return; ! 199: if (!activator->client) ! 200: return; ! 201: ! 202: index = ITEM_INDEX(self->item); ! 203: if (!activator->client->pers.inventory[index]) ! 204: { ! 205: if (level.time < self->touch_debounce_time) ! 206: return; ! 207: self->touch_debounce_time = level.time + 5.0; ! 208: gi.centerprintf (activator, "You need the %s", self->item->pickup_name); ! 209: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0); ! 210: return; ! 211: } ! 212: ! 213: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0); ! 214: if (coop->value) ! 215: { ! 216: int player; ! 217: edict_t *ent; ! 218: ! 219: if (strcmp(self->item->classname, "key_power_cube") == 0) ! 220: { ! 221: int cube; ! 222: ! 223: for (cube = 0; cube < 8; cube++) ! 224: if (activator->client->pers.power_cubes & (1 << cube)) ! 225: break; ! 226: for (player = 1; player <= game.maxclients; player++) ! 227: { ! 228: ent = &g_edicts[player]; ! 229: if (!ent->inuse) ! 230: continue; ! 231: if (!ent->client) ! 232: continue; ! 233: if (ent->client->pers.power_cubes & (1 << cube)) ! 234: { ! 235: ent->client->pers.inventory[index]--; ! 236: ent->client->pers.power_cubes &= ~(1 << cube); ! 237: } ! 238: } ! 239: } ! 240: else ! 241: { ! 242: for (player = 1; player <= game.maxclients; player++) ! 243: { ! 244: ent = &g_edicts[player]; ! 245: if (!ent->inuse) ! 246: continue; ! 247: if (!ent->client) ! 248: continue; ! 249: ent->client->pers.inventory[index] = 0; ! 250: } ! 251: } ! 252: } ! 253: else ! 254: { ! 255: activator->client->pers.inventory[index]--; ! 256: } ! 257: ! 258: G_UseTargets (self, activator); ! 259: ! 260: self->use = NULL; ! 261: } ! 262: ! 263: void SP_trigger_key (edict_t *self) ! 264: { ! 265: if (!st.item) ! 266: { ! 267: gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin)); ! 268: return; ! 269: } ! 270: self->item = FindItemByClassname (st.item); ! 271: ! 272: if (!self->item) ! 273: { ! 274: gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin)); ! 275: return; ! 276: } ! 277: ! 278: if (!self->target) ! 279: { ! 280: gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin)); ! 281: return; ! 282: } ! 283: ! 284: gi.soundindex ("misc/keytry.wav"); ! 285: gi.soundindex ("misc/keyuse.wav"); ! 286: ! 287: self->use = trigger_key_use; ! 288: } ! 289: ! 290: ! 291: /* ! 292: ============================================================================== ! 293: ! 294: trigger_counter ! 295: ! 296: ============================================================================== ! 297: */ ! 298: ! 299: /*QUAKED trigger_counter (.5 .5 .5) ? nomessage ! 300: Acts as an intermediary for an action that takes multiple inputs. ! 301: ! 302: If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. ! 303: ! 304: After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself. ! 305: */ ! 306: ! 307: void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator) ! 308: { ! 309: if (self->count == 0) ! 310: return; ! 311: ! 312: self->count--; ! 313: ! 314: if (self->count) ! 315: { ! 316: if (! (self->spawnflags & 1)) ! 317: { ! 318: gi.centerprintf(activator, "%i more to go...", self->count); ! 319: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); ! 320: } ! 321: return; ! 322: } ! 323: ! 324: if (! (self->spawnflags & 1)) ! 325: { ! 326: gi.centerprintf(activator, "Sequence completed!"); ! 327: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); ! 328: } ! 329: self->activator = activator; ! 330: multi_trigger (self); ! 331: } ! 332: ! 333: void SP_trigger_counter (edict_t *self) ! 334: { ! 335: self->wait = -1; ! 336: if (!self->count) ! 337: self->count = 2; ! 338: ! 339: self->use = trigger_counter_use; ! 340: } ! 341: ! 342: ! 343: /* ! 344: ============================================================================== ! 345: ! 346: trigger_always ! 347: ! 348: ============================================================================== ! 349: */ ! 350: ! 351: /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8) ! 352: This trigger will always fire. It is activated by the world. ! 353: */ ! 354: void SP_trigger_always (edict_t *ent) ! 355: { ! 356: // we must have some delay to make sure our use targets are present ! 357: if (ent->delay < 0.2) ! 358: ent->delay = 0.2; ! 359: G_UseTargets(ent, ent); ! 360: } ! 361: ! 362: ! 363: /* ! 364: ============================================================================== ! 365: ! 366: trigger_push ! 367: ! 368: ============================================================================== ! 369: */ ! 370: #if 0 ! 371: #define PUSH_ONCE 1 ! 372: ! 373: static int windsound; ! 374: ! 375: void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 376: { ! 377: if (strcmp(other->classname, "grenade") == 0) ! 378: { ! 379: VectorScale (self->movedir, self->speed * 10, other->velocity); ! 380: } ! 381: else if (other->health > 0) ! 382: { ! 383: VectorScale (self->movedir, self->speed * 10, other->velocity); ! 384: ! 385: if (other->client) ! 386: { ! 387: // don't take falling damage immediately from this ! 388: VectorCopy (other->velocity, other->client->oldvelocity); ! 389: if (other->fly_sound_debounce_time < level.time) ! 390: { ! 391: other->fly_sound_debounce_time = level.time + 1.5; ! 392: gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0); ! 393: } ! 394: } ! 395: } ! 396: if (self->spawnflags & PUSH_ONCE) ! 397: G_FreeEdict (self); ! 398: } ! 399: ! 400: void SP_trigger_push (edict_t *self) ! 401: { ! 402: InitTrigger (self); ! 403: windsound = gi.soundindex ("misc/windfly.wav"); ! 404: self->touch = trigger_push_touch; ! 405: if (!self->speed) ! 406: self->speed = 1000; ! 407: gi.linkentity (self); ! 408: } ! 409: #endif ! 410: ! 411: // RAFAEL ! 412: #define PUSH_ONCE 1 ! 413: ! 414: static int windsound; ! 415: ! 416: void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 417: { ! 418: if (strcmp(other->classname, "grenade") == 0) ! 419: { ! 420: VectorScale (self->movedir, self->speed * 10, other->velocity); ! 421: } ! 422: else if (other->health > 0) ! 423: { ! 424: VectorScale (self->movedir, self->speed * 10, other->velocity); ! 425: ! 426: if (other->client) ! 427: { ! 428: // don't take falling damage immediately from this ! 429: VectorCopy (other->velocity, other->client->oldvelocity); ! 430: if (other->fly_sound_debounce_time < level.time) ! 431: { ! 432: other->fly_sound_debounce_time = level.time + 1.5; ! 433: gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0); ! 434: } ! 435: } ! 436: } ! 437: if (self->spawnflags & PUSH_ONCE) ! 438: G_FreeEdict (self); ! 439: } ! 440: ! 441: ! 442: /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE PUSH_PLUS PUSH_RAMP ! 443: Pushes the player ! 444: "speed" defaults to 1000 ! 445: "wait" defaults to 10 must use PUSH_PLUS used for on ! 446: */ ! 447: ! 448: void trigger_push_active (edict_t *self); ! 449: ! 450: void trigger_effect (edict_t *self) ! 451: { ! 452: vec3_t origin; ! 453: vec3_t size; ! 454: int i; ! 455: ! 456: VectorScale (self->size, 0.5, size); ! 457: VectorAdd (self->absmin, size, origin); ! 458: ! 459: for (i=0; i<10; i++) ! 460: { ! 461: origin[2] += (self->speed * 0.01) * (i + random()); ! 462: gi.WriteByte (svc_temp_entity); ! 463: gi.WriteByte (TE_TUNNEL_SPARKS); ! 464: gi.WriteByte (1); ! 465: gi.WritePosition (origin); ! 466: gi.WriteDir (vec3_origin); ! 467: gi.WriteByte (0x74 + (rand()&7)); ! 468: gi.multicast (self->s.origin, MULTICAST_PVS); ! 469: } ! 470: ! 471: } ! 472: ! 473: void trigger_push_inactive (edict_t *self) ! 474: { ! 475: if (self->delay > level.time) ! 476: { ! 477: self->nextthink = level.time + 0.1; ! 478: } ! 479: else ! 480: { ! 481: self->touch = trigger_push_touch; ! 482: self->think = trigger_push_active; ! 483: self->nextthink = level.time + 0.1; ! 484: self->delay = self->nextthink + self->wait; ! 485: } ! 486: } ! 487: ! 488: void trigger_push_active (edict_t *self) ! 489: { ! 490: if (self->delay > level.time) ! 491: { ! 492: self->nextthink = level.time + 0.1; ! 493: trigger_effect (self); ! 494: } ! 495: else ! 496: { ! 497: self->touch = NULL; ! 498: self->think = trigger_push_inactive; ! 499: self->nextthink = level.time + 0.1; ! 500: self->delay = self->nextthink + self->wait; ! 501: } ! 502: } ! 503: ! 504: void SP_trigger_push (edict_t *self) ! 505: { ! 506: InitTrigger (self); ! 507: windsound = gi.soundindex ("misc/windfly.wav"); ! 508: self->touch = trigger_push_touch; ! 509: ! 510: if (self->spawnflags & 2) ! 511: { ! 512: if (!self->wait) ! 513: self->wait = 10; ! 514: ! 515: self->think = trigger_push_active; ! 516: self->nextthink = level.time + 0.1; ! 517: self->delay = self->nextthink + self->wait; ! 518: } ! 519: ! 520: if (!self->speed) ! 521: self->speed = 1000; ! 522: ! 523: gi.linkentity (self); ! 524: ! 525: } ! 526: ! 527: /* ! 528: ============================================================================== ! 529: ! 530: trigger_hurt ! 531: ! 532: ============================================================================== ! 533: */ ! 534: ! 535: /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW ! 536: Any entity that touches this will be hurt. ! 537: ! 538: It does dmg points of damage each server frame ! 539: ! 540: SILENT supresses playing the sound ! 541: SLOW changes the damage rate to once per second ! 542: NO_PROTECTION *nothing* stops the damage ! 543: ! 544: "dmg" default 5 (whole numbers only) ! 545: ! 546: */ ! 547: void hurt_use (edict_t *self, edict_t *other, edict_t *activator) ! 548: { ! 549: if (self->solid == SOLID_NOT) ! 550: self->solid = SOLID_TRIGGER; ! 551: else ! 552: self->solid = SOLID_NOT; ! 553: gi.linkentity (self); ! 554: ! 555: if (!(self->spawnflags & 2)) ! 556: self->use = NULL; ! 557: } ! 558: ! 559: ! 560: void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 561: { ! 562: int dflags; ! 563: ! 564: if (!other->takedamage) ! 565: return; ! 566: ! 567: if (self->timestamp > level.time) ! 568: return; ! 569: ! 570: if (self->spawnflags & 16) ! 571: self->timestamp = level.time + 1; ! 572: else ! 573: self->timestamp = level.time + FRAMETIME; ! 574: ! 575: if (!(self->spawnflags & 4)) ! 576: { ! 577: if ((level.framenum % 10) == 0) ! 578: gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0); ! 579: } ! 580: ! 581: if (self->spawnflags & 8) ! 582: dflags = DAMAGE_NO_PROTECTION; ! 583: else ! 584: dflags = 0; ! 585: T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT); ! 586: } ! 587: ! 588: void SP_trigger_hurt (edict_t *self) ! 589: { ! 590: InitTrigger (self); ! 591: ! 592: self->noise_index = gi.soundindex ("world/electro.wav"); ! 593: self->touch = hurt_touch; ! 594: ! 595: if (!self->dmg) ! 596: self->dmg = 5; ! 597: ! 598: if (self->spawnflags & 1) ! 599: self->solid = SOLID_NOT; ! 600: else ! 601: self->solid = SOLID_TRIGGER; ! 602: ! 603: if (self->spawnflags & 2) ! 604: self->use = hurt_use; ! 605: ! 606: gi.linkentity (self); ! 607: } ! 608: ! 609: ! 610: /* ! 611: ============================================================================== ! 612: ! 613: trigger_gravity ! 614: ! 615: ============================================================================== ! 616: */ ! 617: ! 618: /*QUAKED trigger_gravity (.5 .5 .5) ? ! 619: Changes the touching entites gravity to ! 620: the value of "gravity". 1.0 is standard ! 621: gravity for the level. ! 622: */ ! 623: ! 624: void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 625: { ! 626: other->gravity = self->gravity; ! 627: } ! 628: ! 629: void SP_trigger_gravity (edict_t *self) ! 630: { ! 631: if (st.gravity == 0) ! 632: { ! 633: gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin)); ! 634: G_FreeEdict (self); ! 635: return; ! 636: } ! 637: ! 638: InitTrigger (self); ! 639: self->gravity = atoi(st.gravity); ! 640: self->touch = trigger_gravity_touch; ! 641: } ! 642: ! 643: ! 644: /* ! 645: ============================================================================== ! 646: ! 647: trigger_monsterjump ! 648: ! 649: ============================================================================== ! 650: */ ! 651: ! 652: /*QUAKED trigger_monsterjump (.5 .5 .5) ? ! 653: Walking monsters that touch this will jump in the direction of the trigger's angle ! 654: "speed" default to 200, the speed thrown forward ! 655: "height" default to 200, the speed thrown upwards ! 656: */ ! 657: ! 658: void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 659: { ! 660: if (other->flags & (FL_FLY | FL_SWIM) ) ! 661: return; ! 662: if (other->svflags & SVF_DEADMONSTER) ! 663: return; ! 664: if ( !(other->svflags & SVF_MONSTER)) ! 665: return; ! 666: ! 667: // set XY even if not on ground, so the jump will clear lips ! 668: other->velocity[0] = self->movedir[0] * self->speed; ! 669: other->velocity[1] = self->movedir[1] * self->speed; ! 670: ! 671: if (!other->groundentity) ! 672: return; ! 673: ! 674: other->groundentity = NULL; ! 675: other->velocity[2] = self->movedir[2]; ! 676: } ! 677: ! 678: void SP_trigger_monsterjump (edict_t *self) ! 679: { ! 680: if (!self->speed) ! 681: self->speed = 200; ! 682: if (!st.height) ! 683: st.height = 200; ! 684: if (self->s.angles[YAW] == 0) ! 685: self->s.angles[YAW] = 360; ! 686: InitTrigger (self); ! 687: self->touch = trigger_monsterjump_touch; ! 688: self->movedir[2] = st.height; ! 689: } ! 690:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.