|
|
1.1 ! root 1: ! 2: entity stemp, otemp, s, old; ! 3: ! 4: ! 5: void() trigger_reactivate = ! 6: { ! 7: self.solid = SOLID_TRIGGER; ! 8: }; ! 9: ! 10: //============================================================================= ! 11: ! 12: float SPAWNFLAG_NOMESSAGE = 1; ! 13: float SPAWNFLAG_NOTOUCH = 1; ! 14: ! 15: // the wait time has passed, so set back up for another activation ! 16: void() multi_wait = ! 17: { ! 18: if (self.max_health) ! 19: { ! 20: self.health = self.max_health; ! 21: self.takedamage = DAMAGE_YES; ! 22: self.solid = SOLID_BBOX; ! 23: } ! 24: }; ! 25: ! 26: ! 27: // the trigger was just touched/killed/used ! 28: // self.enemy should be set to the activator so it can be held through a delay ! 29: // so wait for the delay time before firing ! 30: void() multi_trigger = ! 31: { ! 32: if (self.nextthink > time) ! 33: { ! 34: return; // allready been triggered ! 35: } ! 36: ! 37: if (self.classname == "trigger_secret") ! 38: { ! 39: if (self.enemy.classname != "player") ! 40: return; ! 41: found_secrets = found_secrets + 1; ! 42: WriteByte (MSG_ALL, SVC_FOUNDSECRET); ! 43: } ! 44: ! 45: if (self.noise) ! 46: sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); ! 47: ! 48: // don't trigger again until reset ! 49: self.takedamage = DAMAGE_NO; ! 50: ! 51: activator = self.enemy; ! 52: ! 53: SUB_UseTargets(); ! 54: ! 55: if (self.wait > 0) ! 56: { ! 57: self.think = multi_wait; ! 58: self.nextthink = time + self.wait; ! 59: } ! 60: else ! 61: { // we can't just remove (self) here, because this is a touch function ! 62: // called wheil C code is looping through area links... ! 63: self.touch = SUB_Null; ! 64: self.nextthink = time + 0.1; ! 65: self.think = SUB_Remove; ! 66: } ! 67: }; ! 68: ! 69: void() multi_killed = ! 70: { ! 71: self.enemy = damage_attacker; ! 72: multi_trigger(); ! 73: }; ! 74: ! 75: void() multi_use = ! 76: { ! 77: self.enemy = activator; ! 78: multi_trigger(); ! 79: }; ! 80: ! 81: void() multi_touch = ! 82: { ! 83: if (other.classname != "player") ! 84: return; ! 85: ! 86: // if the trigger has an angles field, check player's facing direction ! 87: if (self.movedir != '0 0 0') ! 88: { ! 89: makevectors (other.angles); ! 90: if (v_forward * self.movedir < 0) ! 91: return; // not facing the right way ! 92: } ! 93: ! 94: self.enemy = other; ! 95: multi_trigger (); ! 96: }; ! 97: ! 98: /*QUAKED trigger_multiple (.5 .5 .5) ? notouch ! 99: Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time. ! 100: If "delay" is set, the trigger waits some time after activating before firing. ! 101: "wait" : Seconds between triggerings. (.2 default) ! 102: If notouch is set, the trigger is only fired by other entities, not by touching. ! 103: NOTOUCH has been obsoleted by trigger_relay! ! 104: sounds ! 105: 1) secret ! 106: 2) beep beep ! 107: 3) large switch ! 108: 4) ! 109: set "message" to text string ! 110: */ ! 111: void() trigger_multiple = ! 112: { ! 113: if (self.sounds == 1) ! 114: { ! 115: precache_sound ("misc/secret.wav"); ! 116: self.noise = "misc/secret.wav"; ! 117: } ! 118: else if (self.sounds == 2) ! 119: { ! 120: precache_sound ("misc/talk.wav"); ! 121: self.noise = "misc/talk.wav"; ! 122: } ! 123: else if (self.sounds == 3) ! 124: { ! 125: precache_sound ("misc/trigger1.wav"); ! 126: self.noise = "misc/trigger1.wav"; ! 127: } ! 128: ! 129: if (!self.wait) ! 130: self.wait = 0.2; ! 131: self.use = multi_use; ! 132: ! 133: InitTrigger (); ! 134: ! 135: if (self.health) ! 136: { ! 137: if (self.spawnflags & SPAWNFLAG_NOTOUCH) ! 138: objerror ("health and notouch don't make sense\n"); ! 139: self.max_health = self.health; ! 140: self.th_die = multi_killed; ! 141: self.takedamage = DAMAGE_YES; ! 142: self.solid = SOLID_BBOX; ! 143: setorigin (self, self.origin); // make sure it links into the world ! 144: } ! 145: else ! 146: { ! 147: if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) ) ! 148: { ! 149: self.touch = multi_touch; ! 150: } ! 151: } ! 152: }; ! 153: ! 154: ! 155: /*QUAKED trigger_once (.5 .5 .5) ? notouch ! 156: Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching ! 157: "targetname". If "health" is set, the trigger must be killed to activate. ! 158: If notouch is set, the trigger is only fired by other entities, not by touching. ! 159: if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. ! 160: if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. ! 161: sounds ! 162: 1) secret ! 163: 2) beep beep ! 164: 3) large switch ! 165: 4) ! 166: set "message" to text string ! 167: */ ! 168: void() trigger_once = ! 169: { ! 170: self.wait = -1; ! 171: trigger_multiple(); ! 172: }; ! 173: ! 174: //============================================================================= ! 175: ! 176: /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) ! 177: This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages. ! 178: */ ! 179: void() trigger_relay = ! 180: { ! 181: self.use = SUB_UseTargets; ! 182: }; ! 183: ! 184: ! 185: //============================================================================= ! 186: ! 187: /*QUAKED trigger_secret (.5 .5 .5) ? ! 188: secret counter trigger ! 189: sounds ! 190: 1) secret ! 191: 2) beep beep ! 192: 3) ! 193: 4) ! 194: set "message" to text string ! 195: */ ! 196: void() trigger_secret = ! 197: { ! 198: total_secrets = total_secrets + 1; ! 199: self.wait = -1; ! 200: if (!self.message) ! 201: self.message = "You found a secret area!"; ! 202: if (!self.sounds) ! 203: self.sounds = 1; ! 204: ! 205: if (self.sounds == 1) ! 206: { ! 207: precache_sound ("misc/secret.wav"); ! 208: self.noise = "misc/secret.wav"; ! 209: } ! 210: else if (self.sounds == 2) ! 211: { ! 212: precache_sound ("misc/talk.wav"); ! 213: self.noise = "misc/talk.wav"; ! 214: } ! 215: ! 216: trigger_multiple (); ! 217: }; ! 218: ! 219: //============================================================================= ! 220: ! 221: ! 222: void() counter_use = ! 223: { ! 224: local string junk; ! 225: ! 226: self.count = self.count - 1; ! 227: if (self.count < 0) ! 228: return; ! 229: ! 230: if (self.count != 0) ! 231: { ! 232: if (activator.classname == "player" ! 233: && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0) ! 234: { ! 235: if (self.count >= 4) ! 236: centerprint (activator, "There are more to go..."); ! 237: else if (self.count == 3) ! 238: centerprint (activator, "Only 3 more to go..."); ! 239: else if (self.count == 2) ! 240: centerprint (activator, "Only 2 more to go..."); ! 241: else ! 242: centerprint (activator, "Only 1 more to go..."); ! 243: } ! 244: return; ! 245: } ! 246: ! 247: if (activator.classname == "player" ! 248: && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0) ! 249: centerprint(activator, "Sequence completed!"); ! 250: self.enemy = activator; ! 251: multi_trigger (); ! 252: }; ! 253: ! 254: /*QUAKED trigger_counter (.5 .5 .5) ? nomessage ! 255: Acts as an intermediary for an action that takes multiple inputs. ! 256: ! 257: If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. ! 258: ! 259: After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself. ! 260: */ ! 261: void() trigger_counter = ! 262: { ! 263: self.wait = -1; ! 264: if (!self.count) ! 265: self.count = 2; ! 266: ! 267: self.use = counter_use; ! 268: }; ! 269: ! 270: ! 271: /* ! 272: ============================================================================== ! 273: ! 274: TELEPORT TRIGGERS ! 275: ! 276: ============================================================================== ! 277: */ ! 278: ! 279: float PLAYER_ONLY = 1; ! 280: float SILENT = 2; ! 281: ! 282: void() play_teleport = ! 283: { ! 284: local float v; ! 285: local string tmpstr; ! 286: ! 287: v = random() * 5; ! 288: if (v < 1) ! 289: tmpstr = "misc/r_tele1.wav"; ! 290: else if (v < 2) ! 291: tmpstr = "misc/r_tele2.wav"; ! 292: else if (v < 3) ! 293: tmpstr = "misc/r_tele3.wav"; ! 294: else if (v < 4) ! 295: tmpstr = "misc/r_tele4.wav"; ! 296: else ! 297: tmpstr = "misc/r_tele5.wav"; ! 298: ! 299: sound (self, CHAN_VOICE, tmpstr, 1, ATTN_NORM); ! 300: remove (self); ! 301: }; ! 302: ! 303: void(vector org) spawn_tfog = ! 304: { ! 305: s = spawn (); ! 306: s.origin = org; ! 307: s.nextthink = time + 0.2; ! 308: s.think = play_teleport; ! 309: ! 310: WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); ! 311: WriteByte (MSG_MULTICAST, TE_TELEPORT); ! 312: WriteCoord (MSG_MULTICAST, org_x); ! 313: WriteCoord (MSG_MULTICAST, org_y); ! 314: WriteCoord (MSG_MULTICAST, org_z); ! 315: multicast (org, MULTICAST_PHS); ! 316: }; ! 317: ! 318: ! 319: void() tdeath_touch = ! 320: { ! 321: local entity other2; ! 322: ! 323: if (other == self.owner) ! 324: return; ! 325: ! 326: // frag anyone who teleports in on top of an invincible player ! 327: if (other.classname == "player") ! 328: { ! 329: if (other.invincible_finished > time && ! 330: self.owner.invincible_finished > time) { ! 331: self.classname = "teledeath3"; ! 332: other.invincible_finished = 0; ! 333: self.owner.invincible_finished = 0; ! 334: T_Damage (other, self, self, 50000); ! 335: other2 = self.owner; ! 336: self.owner = other; ! 337: T_Damage (other2, self, self, 50000); ! 338: } ! 339: ! 340: if (other.invincible_finished > time) ! 341: { ! 342: self.classname = "teledeath2"; ! 343: T_Damage (self.owner, self, self, 50000); ! 344: return; ! 345: } ! 346: ! 347: } ! 348: ! 349: if (other.health) ! 350: { ! 351: T_Damage (other, self, self, 50000); ! 352: } ! 353: }; ! 354: ! 355: ! 356: void(vector org, entity death_owner) spawn_tdeath = ! 357: { ! 358: local entity death; ! 359: ! 360: death = spawn(); ! 361: death.classname = "teledeath"; ! 362: death.movetype = MOVETYPE_NONE; ! 363: death.solid = SOLID_TRIGGER; ! 364: death.angles = '0 0 0'; ! 365: setsize (death, death_owner.mins - '1 1 1', death_owner.maxs + '1 1 1'); ! 366: setorigin (death, org); ! 367: death.touch = tdeath_touch; ! 368: death.nextthink = time + 0.2; ! 369: death.think = SUB_Remove; ! 370: death.owner = death_owner; ! 371: ! 372: force_retouch = 2; // make sure even still objects get hit ! 373: }; ! 374: ! 375: void() teleport_touch = ! 376: { ! 377: local entity t; ! 378: local vector org; ! 379: ! 380: if (self.targetname) ! 381: { ! 382: if (self.nextthink < time) ! 383: { ! 384: return; // not fired yet ! 385: } ! 386: } ! 387: ! 388: if (self.spawnflags & PLAYER_ONLY) ! 389: { ! 390: if (other.classname != "player") ! 391: return; ! 392: } ! 393: ! 394: // only teleport living creatures ! 395: if (other.health <= 0 || other.solid != SOLID_SLIDEBOX) ! 396: return; ! 397: ! 398: SUB_UseTargets (); ! 399: ! 400: // put a tfog where the player was ! 401: spawn_tfog (other.origin); ! 402: ! 403: t = find (world, targetname, self.target); ! 404: if (!t) ! 405: objerror ("couldn't find target"); ! 406: ! 407: // spawn a tfog flash in front of the destination ! 408: makevectors (t.mangle); ! 409: org = t.origin + 32 * v_forward; ! 410: ! 411: spawn_tfog (org); ! 412: spawn_tdeath(t.origin, other); ! 413: ! 414: // move the player and lock him down for a little while ! 415: if (!other.health) ! 416: { ! 417: other.origin = t.origin; ! 418: other.velocity = (v_forward * other.velocity_x) + (v_forward * other.velocity_y); ! 419: return; ! 420: } ! 421: ! 422: setorigin (other, t.origin); ! 423: other.angles = t.mangle; ! 424: if (other.classname == "player") ! 425: { ! 426: other.fixangle = 1; // turn this way immediately ! 427: other.teleport_time = time + 0.7; ! 428: if (other.flags & FL_ONGROUND) ! 429: other.flags = other.flags - FL_ONGROUND; ! 430: other.velocity = v_forward * 300; ! 431: } ! 432: other.flags = other.flags - other.flags & FL_ONGROUND; ! 433: }; ! 434: ! 435: /*QUAKED info_teleport_destination (.5 .5 .5) (-8 -8 -8) (8 8 32) ! 436: This is the destination marker for a teleporter. It should have a "targetname" field with the same value as a teleporter's "target" field. ! 437: */ ! 438: void() info_teleport_destination = ! 439: { ! 440: // this does nothing, just serves as a target spot ! 441: self.mangle = self.angles; ! 442: self.angles = '0 0 0'; ! 443: self.model = ""; ! 444: self.origin = self.origin + '0 0 27'; ! 445: if (!self.targetname) ! 446: objerror ("no targetname"); ! 447: }; ! 448: ! 449: void() teleport_use = ! 450: { ! 451: self.nextthink = time + 0.2; ! 452: force_retouch = 2; // make sure even still objects get hit ! 453: self.think = SUB_Null; ! 454: }; ! 455: ! 456: /*QUAKED trigger_teleport (.5 .5 .5) ? PLAYER_ONLY SILENT ! 457: Any object touching this will be transported to the corresponding info_teleport_destination entity. You must set the "target" field, and create an object with a "targetname" field that matches. ! 458: ! 459: If the trigger_teleport has a targetname, it will only teleport entities when it has been fired. ! 460: */ ! 461: void() trigger_teleport = ! 462: { ! 463: local vector o; ! 464: ! 465: InitTrigger (); ! 466: self.touch = teleport_touch; ! 467: // find the destination ! 468: if (!self.target) ! 469: objerror ("no target"); ! 470: self.use = teleport_use; ! 471: ! 472: if (!(self.spawnflags & SILENT)) ! 473: { ! 474: precache_sound ("ambience/hum1.wav"); ! 475: o = (self.mins + self.maxs)*0.5; ! 476: ambientsound (o, "ambience/hum1.wav",0.5 , ATTN_STATIC); ! 477: } ! 478: }; ! 479: ! 480: /* ! 481: ============================================================================== ! 482: ! 483: trigger_setskill ! 484: ! 485: ============================================================================== ! 486: */ ! 487: ! 488: /*QUAKED trigger_setskill (.5 .5 .5) ? ! 489: sets skill level to the value of "message". ! 490: Only used on start map. ! 491: */ ! 492: void() trigger_setskill = ! 493: { ! 494: remove (self); ! 495: }; ! 496: ! 497: ! 498: /* ! 499: ============================================================================== ! 500: ! 501: ONLY REGISTERED TRIGGERS ! 502: ! 503: ============================================================================== ! 504: */ ! 505: ! 506: void() trigger_onlyregistered_touch = ! 507: { ! 508: if (other.classname != "player") ! 509: return; ! 510: if (self.attack_finished > time) ! 511: return; ! 512: ! 513: self.attack_finished = time + 2; ! 514: if (cvar("registered")) ! 515: { ! 516: self.message = ""; ! 517: SUB_UseTargets (); ! 518: remove (self); ! 519: } ! 520: else ! 521: { ! 522: if (self.message != "") ! 523: { ! 524: centerprint (other, self.message); ! 525: sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); ! 526: } ! 527: } ! 528: }; ! 529: ! 530: /*QUAKED trigger_onlyregistered (.5 .5 .5) ? ! 531: Only fires if playing the registered version, otherwise prints the message ! 532: */ ! 533: void() trigger_onlyregistered = ! 534: { ! 535: precache_sound ("misc/talk.wav"); ! 536: InitTrigger (); ! 537: self.touch = trigger_onlyregistered_touch; ! 538: }; ! 539: ! 540: //============================================================================ ! 541: ! 542: void() hurt_on = ! 543: { ! 544: self.solid = SOLID_TRIGGER; ! 545: self.nextthink = -1; ! 546: }; ! 547: ! 548: void() hurt_touch = ! 549: { ! 550: if (other.takedamage) ! 551: { ! 552: self.solid = SOLID_NOT; ! 553: T_Damage (other, self, self, self.dmg); ! 554: self.think = hurt_on; ! 555: self.nextthink = time + 1; ! 556: } ! 557: ! 558: return; ! 559: }; ! 560: ! 561: /*QUAKED trigger_hurt (.5 .5 .5) ? ! 562: Any object touching this will be hurt ! 563: set dmg to damage amount ! 564: defalt dmg = 5 ! 565: */ ! 566: void() trigger_hurt = ! 567: { ! 568: InitTrigger (); ! 569: self.touch = hurt_touch; ! 570: if (!self.dmg) ! 571: self.dmg = 5; ! 572: }; ! 573: ! 574: //============================================================================ ! 575: ! 576: float PUSH_ONCE = 1; ! 577: ! 578: void() trigger_push_touch = ! 579: { ! 580: if (other.classname == "grenade") ! 581: other.velocity = self.speed * self.movedir * 10; ! 582: else if (other.health > 0) ! 583: { ! 584: other.velocity = self.speed * self.movedir * 10; ! 585: if (other.classname == "player") ! 586: { ! 587: if (other.fly_sound < time) ! 588: { ! 589: other.fly_sound = time + 1.5; ! 590: sound (other, CHAN_AUTO, "ambience/windfly.wav", 1, ATTN_NORM); ! 591: } ! 592: } ! 593: } ! 594: if (self.spawnflags & PUSH_ONCE) ! 595: remove(self); ! 596: }; ! 597: ! 598: ! 599: /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE ! 600: Pushes the player ! 601: */ ! 602: void() trigger_push = ! 603: { ! 604: InitTrigger (); ! 605: precache_sound ("ambience/windfly.wav"); ! 606: self.touch = trigger_push_touch; ! 607: if (!self.speed) ! 608: self.speed = 1000; ! 609: }; ! 610: ! 611: //============================================================================ ! 612: ! 613: void() trigger_monsterjump_touch = ! 614: { ! 615: if ( other.flags & (FL_MONSTER | FL_FLY | FL_SWIM) != FL_MONSTER ) ! 616: return; ! 617: ! 618: // set XY even if not on ground, so the jump will clear lips ! 619: other.velocity_x = self.movedir_x * self.speed; ! 620: other.velocity_y = self.movedir_y * self.speed; ! 621: ! 622: if ( !(other.flags & FL_ONGROUND) ) ! 623: return; ! 624: ! 625: other.flags = other.flags - FL_ONGROUND; ! 626: ! 627: other.velocity_z = self.height; ! 628: }; ! 629: ! 630: /*QUAKED trigger_monsterjump (.5 .5 .5) ? ! 631: Walking monsters that touch this will jump in the direction of the trigger's angle ! 632: "speed" default to 200, the speed thrown forward ! 633: "height" default to 200, the speed thrown upwards ! 634: */ ! 635: void() trigger_monsterjump = ! 636: { ! 637: if (!self.speed) ! 638: self.speed = 200; ! 639: if (!self.height) ! 640: self.height = 200; ! 641: if (self.angles == '0 0 0') ! 642: self.angles = '0 360 0'; ! 643: InitTrigger (); ! 644: self.touch = trigger_monsterjump_touch; ! 645: }; ! 646:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.