1 2void() trigger_reactivate = 3{ 4 self.solid = SOLID_TRIGGER; 5}; 6 7//============================================================================= 8 9float SPAWNFLAG_NOMESSAGE = 1; 10float SPAWNFLAG_NOTOUCH = 1; 11 12// the wait time has passed, so set back up for another activation 13void() multi_wait = 14{ 15 if (self.max_health) 16 { 17 self.health = self.max_health; 18 self.takedamage = DAMAGE_YES; 19 self.solid = SOLID_BBOX; 20 } 21}; 22 23 24// the trigger was just touched/killed/used 25// self.enemy should be set to the activator so it can be held through a delay 26// so wait for the delay time before firing 27void() multi_trigger = 28{ 29 if (self.nextthink > time) 30 return; // already triggered 31 32 if (self.classname == "trigger_secret") 33 { 34 if (self.enemy.classname != "player") 35 return; 36 found_secrets = found_secrets + 1; 37 WriteByte (MSG_ALL, SVC_FOUNDSECRET); 38 } 39 40 if (self.noise) 41 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); 42 43// don't trigger again until reset 44 self.takedamage = DAMAGE_NO; 45 46 activator = self.enemy; 47 48 SUB_UseTargets(); 49 50 if (self.wait > 0) 51 { 52 self.think = multi_wait; 53 self.nextthink = time + self.wait; 54 } 55 else 56 { // we can't just remove (self) here, because this is a touch function 57 // called while C code is looping through area links... 58 self.touch = SUB_Null; 59 self.nextthink = time + 0.1; 60 self.think = SUB_Remove; 61 } 62}; 63 64void() multi_killed = 65{ 66 self.enemy = damage_attacker; 67 multi_trigger(); 68}; 69 70void() multi_use = 71{ 72 self.enemy = activator; 73 multi_trigger(); 74}; 75 76void() multi_touch = 77{ 78 //if (other.classname != "player") 79 if (!other.cantrigger) 80 return; 81 82// if the trigger has an angles field, check player's facing direction 83 if (self.movedir != '0 0 0') 84 { 85 makevectors (other.angles); 86 if (v_forward * self.movedir < 0) 87 return; // not facing the right way 88 } 89 90 self.enemy = other; 91 multi_trigger (); 92}; 93 94/*QUAKED trigger_multiple (.5 .5 .5) ? notouch 95Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time. 96If "delay" is set, the trigger waits some time after activating before firing. 97"wait" : Seconds between triggerings. (.2 default) 98If notouch is set, the trigger is only fired by other entities, not by touching. 99NOTOUCH has been obsoleted by trigger_relay! 100sounds 1011) secret 1022) beep beep 1033) large switch 1044) 105set "message" to text string 106*/ 107void() trigger_multiple = 108{ 109 if (self.sounds == 1) 110 { 111 precache_sound ("misc/secret.wav"); 112 self.noise = "misc/secret.wav"; 113 } 114 else if (self.sounds == 2) 115 { 116 precache_sound ("misc/talk.wav"); 117 self.noise = "misc/talk.wav"; 118 } 119 else if (self.sounds == 3) 120 { 121 precache_sound ("misc/trigger1.wav"); 122 self.noise = "misc/trigger1.wav"; 123 } 124 125 if (!self.wait) 126 self.wait = 0.2; 127 self.use = multi_use; 128 129 InitTrigger (); 130 131 if (self.health) 132 { 133 if (self.spawnflags & SPAWNFLAG_NOTOUCH) 134 objerror ("trigger_multiple or trigger_once: health and notouch don't make sense\n"); 135 self.max_health = self.health; 136 self.th_die = multi_killed; 137 self.takedamage = DAMAGE_YES; 138 self.solid = SOLID_BBOX; 139 setorigin (self, self.origin); // make sure it links into the world 140 } 141 else if (!(self.spawnflags & SPAWNFLAG_NOTOUCH)) 142 self.touch = multi_touch; 143}; 144 145void() trigger_message2 = 146{ 147 self.noise = "misc/talk.wav"; 148 precache_sound (self.noise); 149 150 if (!self.wait) 151 self.wait = 0.2; 152 self.use = multi_use; 153 154 if (self.movedir == '0 0 0') 155 if (self.angles != '0 0 0') 156 SetMovedir (); 157 self.solid = SOLID_TRIGGER; 158 self.movetype = MOVETYPE_NONE; 159 setsize (self, self.mins, self.maxs); 160 161 self.touch = multi_touch; 162}; 163 164 165/*QUAKED trigger_once (.5 .5 .5) ? notouch 166Variable 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 167"targetname". If "health" is set, the trigger must be killed to activate. 168If notouch is set, the trigger is only fired by other entities, not by touching. 169if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. 170if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. 171sounds 1721) secret 1732) beep beep 1743) large switch 1754) 176set "message" to text string 177*/ 178void() trigger_once = 179{ 180 self.wait = -1; 181 trigger_multiple(); 182}; 183 184//============================================================================= 185 186/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) 187This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages. 188*/ 189void() trigger_relay = 190{ 191 self.use = SUB_UseTargets; 192}; 193 194 195//============================================================================= 196 197/*QUAKED trigger_secret (.5 .5 .5) ? 198secret counter trigger 199sounds 2001) secret 2012) beep beep 2023) 2034) 204set "message" to text string 205*/ 206void() trigger_secret = 207{ 208 total_secrets = total_secrets + 1; 209 self.wait = -1; 210 if (!self.message) 211 self.message = "You found a secret area!"; 212 if (!self.sounds) 213 self.sounds = 1; 214 215 if (self.sounds == 1) 216 { 217 precache_sound ("misc/secret.wav"); 218 self.noise = "misc/secret.wav"; 219 } 220 else if (self.sounds == 2) 221 { 222 precache_sound ("misc/talk.wav"); 223 self.noise = "misc/talk.wav"; 224 } 225 226 trigger_multiple (); 227}; 228 229//============================================================================= 230 231 232void() counter_use = 233{ 234 self.count = self.count - 1; 235 if (self.count < 0) 236 return; 237 238 if (self.count != 0) 239 { 240 if ((activator.flags & FL_CLIENT) && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0) 241 { 242 if (self.count >= 4) 243 centerprint (activator, "There are more to go..."); 244 else if (self.count == 3) 245 centerprint (activator, "Only 3 more to go..."); 246 else if (self.count == 2) 247 centerprint (activator, "Only 2 more to go..."); 248 else 249 centerprint (activator, "Only 1 more to go..."); 250 } 251 return; 252 } 253 254 if ((activator.flags & FL_CLIENT) && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0) 255 centerprint(activator, "Sequence completed!"); 256 self.enemy = activator; 257 multi_trigger (); 258}; 259 260/*QUAKED trigger_counter (.5 .5 .5) ? nomessage 261Acts as an intermediary for an action that takes multiple inputs. 262 263If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. 264 265After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself. 266*/ 267void() trigger_counter = 268{ 269 self.wait = -1; 270 if (!self.count) 271 self.count = 2; 272 273 self.use = counter_use; 274}; 275 276 277/* 278============================================================================== 279 280TELEPORT TRIGGERS 281 282============================================================================== 283*/ 284 285float PLAYER_ONLY = 1; 286float SILENT = 2; 287 288void() play_teleport = 289{ 290 local float v; 291 local string tmpstr; 292 293 v = random() * 5; 294 if (v < 1) 295 tmpstr = "misc/r_tele1.wav"; 296 else if (v < 2) 297 tmpstr = "misc/r_tele2.wav"; 298 else if (v < 3) 299 tmpstr = "misc/r_tele3.wav"; 300 else if (v < 4) 301 tmpstr = "misc/r_tele4.wav"; 302 else 303 tmpstr = "misc/r_tele5.wav"; 304 305 sound (self, CHAN_VOICE, tmpstr, 1, ATTN_NORM); 306 remove (self); 307}; 308 309void(vector org) spawn_tfog = 310{ 311 local entity s; 312 s = spawn (); 313 s.nextthink = time + 0.2; 314 s.think = play_teleport; 315 setorigin(s, org); 316 317 te_teleport(org); 318}; 319 320void(entity targ, entity attacker, string dmsg, float dtype) Obituary_Telefrag = 321{ 322 if (dtype == DTYPE_TEAMKILL) 323 { 324 deathstring1 = targ.netname; 325 deathstring2 = " was telefragged by his teammate "; 326 deathstring3 = attacker.netname; 327 deathstring4 = ""; 328 } 329 else 330 { 331 deathstring1 = targ.netname; 332 deathstring2 = " was telefragged by "; 333 deathstring3 = attacker.netname; 334 deathstring4 = ""; 335 } 336}; 337 338void(entity targ, entity attacker, string dmsg, float dtype) Obituary_TriedToTelefrag = 339{ 340 if (dtype == DTYPE_TEAMKILL) 341 { 342 deathstring1 = targ.netname; 343 deathstring2 = "'s telefrag was deflected by his teammate "; 344 deathstring3 = attacker.netname; 345 deathstring4 = ""; 346 } 347 else 348 { 349 deathstring1 = targ.netname; 350 deathstring2 = "'s telefrag was deflected by "; 351 deathstring3 = attacker.netname; 352 deathstring4 = ""; 353 } 354}; 355 356float chthonisdead; // set when chthon dies 357void() tdeath_touch = 358{ 359 if (chthonisdead) // fix the chthon gib scene 360 if ((self.owner.health < 1) || (self.owner.flags & FL_MONSTER)) 361 { 362 T_Damage (self.owner, self, world, 0, 0, " gibbed", DT_TELEFRAG, self.owner.origin, '0 0 0', Obituary_Generic); 363 return; 364 } 365 if (other == self.owner) 366 return; 367 // so teleporting shots etc can't telefrag 368 if (!self.owner.takedamage) 369 return; 370 if (!other.takedamage) 371 return; 372 //if (other.solid == SOLID_TRIGGER) // big bug in quake engine... crashs if other is removed during a collision 373 // return; 374 if ((self.owner.classname == "player") && (self.owner.health >= 1)) 375 T_Damage (other, self, self.owner, 0, 0, "TELEFRAG", DT_TELEFRAG, other.origin, '0 0 0', Obituary_Telefrag); 376 else if (other.health < 1) // corpses gib 377 T_Damage (other, self, self.owner, 0, 0, "TELEFRAG", DT_TELEFRAG, other.origin, '0 0 0', Obituary_Telefrag); 378 else // dead bodies and monsters gib themselves instead of telefragging 379 T_Damage (self.owner, self, other, 0, 0, "TRIEDTOTELEFRAG", DT_TELEFRAG, self.owner.origin, '0 0 0', Obituary_TriedToTelefrag); 380}; 381 382// org2 is where they will return to if the teleport fails 383void(vector org, entity death_owner, vector org2) spawn_tdeath = 384{ 385 local entity death; 386 387 death = spawn(); 388// death.classname = "teledeath"; 389 death.movetype = MOVETYPE_NONE; 390 death.solid = SOLID_TRIGGER; 391 death.angles = '0 0 0'; 392 death.dest2 = org2; 393 setsize (death, death_owner.mins - '1 1 1', death_owner.maxs + '1 1 1'); 394 setorigin (death, org); 395 death.touch = tdeath_touch; 396 death.nextthink = time + 0.2; 397 death.think = SUB_Remove; 398 death.owner = death_owner; 399 400 force_retouch = 2; // make sure even still objects get hit 401}; 402 403.float monsterawaitingteleport; 404 405void() teleport_changevelocityent = 406{ 407 if (self.owner.solid) // make sure it still exists 408 self.owner.velocity = self.dest; 409 remove(self); 410}; 411 412void() teleport_touch = 413{ 414 local entity t; 415 416 //if (!other.takedamage) 417 // return; 418 if (self.targetname) 419 if (self.nextthink < time) 420 { 421 if (world.worldtype < 3) // normal quake maps 422 if (other.flags & FL_MONSTER) // it's a monster 423 if ((self.spawnflags & PLAYER_ONLY) == 0) // not player only 424 other.monsterawaitingteleport = TRUE; // freeze it 425 return; // not fired yet 426 } 427 428 if (self.spawnflags & PLAYER_ONLY) 429 if (other.classname != "player") 430 return; 431 432 // only teleport living creatures 433 if (other.health < 1) 434 return; 435 if (other.solid != SOLID_SLIDEBOX) 436 return; 437 if (other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_PUSH || other.solid == SOLID_NOT) 438 return; 439 440 other.monsterawaitingteleport = FALSE; // unfreeze monster AI 441 442 SUB_UseTargets (); 443 444 // put a tfog where the player was 445 spawn_tfog (other.origin); 446 447 t = find(world, targetname, self.target); 448 if (!t) 449 objerror ("trigger_teleport: couldn't find target"); 450 451 // spawn a tfog flash in front of the destination 452 makevectors (t.mangle); 453 //org = t.origin + 32 * v_forward; 454 455 spawn_tfog (t.origin); //org); 456 spawn_tdeath(t.origin, other, other.origin); 457 458 // move the player and lock him down for a little while 459 setorigin (other, t.origin); 460 // LordHavoc: made all things behave the same 461 newmis = spawn(); 462 newmis.think = teleport_changevelocityent; 463 newmis.nextthink = time + 0.01; 464 newmis.owner = other; 465 //if (other.teleportsavevelocity) 466 // other.velocity = other.teleportsavevelocity; 467 if (other.health < 1) 468 { 469 other.origin = t.origin; 470 other.velocity = (v_forward * other.velocity_x) - (v_right * other.velocity_y) + (v_up * other.velocity_z) + self.dest; 471 newmis.velocity = other.velocity; 472 other.flags = other.flags - (other.flags & FL_ONGROUND); 473 return; 474 } 475 other.velocity = t.dest; 476 newmis.velocity = other.velocity; 477 478 other.angles = t.mangle; 479 if (other.classname == "player") 480 { 481 other.fixangle = 1; // turn this way immediately 482 483 other.teleport_time = time + 0.5; 484 //other.velocity = t.dest; 485 } 486 other.flags = other.flags - (other.flags & FL_ONGROUND); 487}; 488 489/*QUAKED info_teleport_destination (.5 .5 .5) (-8 -8 -8) (8 8 32) 490This is the destination 491marker for a teleporter. 492 493It should have a 494"targetname" field with 495the same value as a 496teleporter's "target" 497field. 498 499Keys: 500"dest" 501 velocity on exiting 502 teleport, nice for 503 tricks. 504 default: normal 505 (throws player out 506 a bit) 507*/ 508void() info_teleport_destination = 509{ 510 // this does nothing, just serves as a target spot 511 self.mangle = self.angles; 512 self.angles = '0 0 0'; 513 self.model = ""; 514 setorigin(self, self.origin + '0 0 27'); 515 if (!self.targetname) 516 objerror ("no targetname"); 517 if (self.dest == '0 0 0') // the usual 518 { 519 makevectors(self.mangle); 520 self.dest = v_forward * 200; //300; 521 } 522}; 523 524void() teleport_use = 525{ 526 self.nextthink = time + 0.2; 527 force_retouch = 2; // make sure even still objects get hit 528 self.think = SUB_Null; 529}; 530 531/*QUAKED trigger_teleport (.5 .5 .5) ? PLAYER_ONLY SILENT 532Any 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. 533 534If the trigger_teleport has a targetname, it will only teleport entities when it has been fired. 535*/ 536void() trigger_teleport = 537{ 538 self.mdl = self.model; 539 if (deathmatch) // teleporters teleport shots in DM :) 540 { 541 if (self.targetname) 542 InitTrigger (); 543 else 544 InitSolidBSPTrigger (); 545 } 546 else 547 InitTrigger (); 548 self.touch = teleport_touch; 549 // find the destination 550 if (!self.target) 551 objerror ("trigger_teleport: no target"); 552 self.use = teleport_use; 553 554 if (!(self.spawnflags & SILENT)) 555 { 556 precache_sound ("ambience/hum1.wav"); 557 ambientsound ((self.absmin + self.absmax)*0.5, "ambience/hum1.wav",0.5 , ATTN_STATIC); 558 } 559}; 560 561void() trigger_teleport2 = 562{ 563 if (self.movedir == '0 0 0') 564 if (self.angles != '0 0 0') 565 SetMovedir (); 566 self.solid = SOLID_TRIGGER; 567 self.movetype = MOVETYPE_NONE; 568 setsize (self, self.mins, self.maxs); 569 570 self.touch = teleport_touch; 571 if (!self.target) 572 objerror ("trigger_teleport2: no target"); 573 self.use = teleport_use; 574 575 if (!(self.spawnflags & SILENT)) 576 { 577 precache_sound ("ambience/hum1.wav"); 578 ambientsound (self.origin, "ambience/hum1.wav", 0.5, ATTN_STATIC); 579 } 580}; 581 582/* 583============================================================================== 584 585trigger_setskill 586 587============================================================================== 588*/ 589 590void() trigger_skill_touch = 591{ 592 if (other.classname != "player") 593 return; 594 595 cvar_set ("skill", self.message); 596}; 597 598/*QUAKED trigger_setskill (.5 .5 .5) ? 599sets skill level to the value of "message". 600Only used on start map. 601*/ 602void() trigger_setskill = 603{ 604 InitTrigger (); 605 self.touch = trigger_skill_touch; 606}; 607 608void() trigger_setskill2 = 609{ 610 if (self.movedir == '0 0 0') 611 if (self.angles != '0 0 0') 612 SetMovedir (); 613 self.solid = SOLID_TRIGGER; 614 self.movetype = MOVETYPE_NONE; 615 setsize (self, self.mins, self.maxs); 616 self.touch = trigger_skill_touch; 617}; 618 619/* 620============================================================================== 621 622ONLY REGISTERED TRIGGERS 623 624============================================================================== 625*/ 626 627void() trigger_onlyregistered_touch = 628{ 629 if (other.classname != "player") 630 return; 631 if (self.attack_finished > time) 632 return; 633 634 self.attack_finished = time + 2; 635 if (cvar("registered")) 636 { 637 self.message = ""; 638 SUB_UseTargets (); 639 remove (self); 640 } 641 else 642 { 643 if (self.message != "") 644 { 645 if (other.flags & FL_CLIENT) 646 centerprint (other, self.message); 647 sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); 648 } 649 } 650}; 651 652/*QUAKED trigger_onlyregistered (.5 .5 .5) ? 653Only fires if playing the registered version, otherwise prints the message 654*/ 655void() trigger_onlyregistered = 656{ 657 precache_sound ("misc/talk.wav"); 658 InitTrigger (); 659 self.touch = trigger_onlyregistered_touch; 660}; 661 662//============================================================================ 663 664 665void( entity ent, float amount ) hurt_setdamage = 666{ 667 ent.dmg = amount; 668 if (!amount) 669 ent.solid = SOLID_NOT; 670 else 671 ent.solid = SOLID_TRIGGER; 672 ent.nextthink = -1; 673}; 674 675void() hurt_on = 676{ 677 self.solid = SOLID_TRIGGER; 678 self.nextthink = -1; 679}; 680 681void() hurt_touch = 682{ 683 if (other.takedamage) 684 { 685 self.solid = SOLID_NOT; 686 T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_HURT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic); 687 self.think = hurt_on; 688 self.nextthink = time + 1; 689 if (self.cnt > 0) 690 { 691 self.cnt = self.cnt - 1; 692 if (self.cnt == 0) 693 { 694 self.touch = SUB_Null; 695 self.nextthink = time + 0.1; 696 self.think = SUB_Remove; 697 } 698 } 699 } 700 return; 701}; 702 703/*QUAKED trigger_hurt (.5 .5 .5) ? 704Anything touching will be hurt. 705 706Keys: 707"dmg" 708 damage amount 709 default: 5 710"cnt" 711 how many times to trigger, 712 default: unlimited 713*/ 714void() trigger_hurt = 715{ 716 if (!self.deathtype) // map makers can override this 717 self.deathtype = " died"; 718 InitTrigger (); 719 self.touch = hurt_touch; 720 if (!self.dmg) 721 self.dmg = 5; 722}; 723 724//============================================================================ 725 726float PUSH_ONCE = 1; 727float PUSH_SILENT = 2; 728 729void() target_position = {}; 730 731void() trigger_push_touch = 732{ 733 local float flighttime, dist, grav; 734 local vector org, v; 735 if (other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_PUSH) 736 return; 737 other.flags = other.flags - (other.flags & FL_ONGROUND); 738 other.velocity = self.movedir; 739 if (self.enemy) 740 { 741 /* 742 // old code for hitting a target landing spot 743 if (self.wait) // flight time 744 t = self.wait; 745 else 746 t = vlen(self.enemy.origin - other.origin) / self.speed - 0.1; 747 // direct path, with boost to counter gravity 748 other.velocity = (self.enemy.origin - other.origin) * (1 / t) + '0 0 1' * (t * t * cvar("sv_gravity")); 749 */ 750 751 // start point 752 org = other.origin; 753 754 // figure out how long it will take to hit the point considering gravity 755 grav = cvar("sv_gravity"); 756 flighttime = sqrt((self.enemy.origin_z - org_z) / (0.5 * grav)); 757 if (!flighttime) 758 { 759 remove(self); 760 return; 761 } 762 763 // how far in X and Y to move 764 v = (self.enemy.origin - org); 765 v_z = 0; 766 dist = vlen(v); 767 768 // finally calculate the velocity 769 other.velocity = normalize(v) * (dist / flighttime); 770 other.velocity_z = flighttime * grav; 771 } 772 else 773 other.velocity = self.movedir; 774 if (self.noise != "") 775 if (other.classname == "player" || (other.flags & FL_MONSTER)) 776 if (other.fly_sound < time) 777 { 778 if (self.target) 779 { 780 other.fly_sound = time + 0.2; 781 if (game == GAME_NEXUIZ) 782 sound (other, CHAN_BODY, "level/jumppad.wav", 1, ATTN_NORM); 783 else 784 sound (other, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); 785 } 786 else 787 { 788 other.fly_sound = time + 1.5; 789 sound (other, CHAN_AUTO, "ambience/windfly.wav", 1, ATTN_NORM); 790 } 791 } 792 if (self.spawnflags & PUSH_ONCE) 793 { 794 self.touch = SUB_Null; 795 self.think = SUB_Remove; 796 self.nextthink = time; 797 } 798}; 799 800void() trigger_push_findtarget = 801{ 802 // find the target 803 self.enemy = find(world, targetname, self.target); 804 if (!self.enemy) 805 objerror("trigger_push: target not found\n"); 806}; 807 808/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE SILENT 809Improved version of normal trigger_push. 810 811Pushes anything that touches it, 812or acts as a jump pad, hitting "target" 813at the apogee (peak) of the jump. 814 815Target should be an info_notnull. 816 817Flags: 818"PUSH_ONCE" 819 removes itself after push 820"SILENT" 821 no 'windtunnel' noise 822Keys: 823"angles" 824 direction to push. 825 (not for jumppad) 826"speed" 827 how fast. 828 (not for jumppad) 829"movedir" 830 direction of push, 831 this is turned into 832 a direction. (no speed) 833 (not for jumppad) 834"target" 835 acts as jump pad, hits this entity 836*/ 837void() trigger_push = 838{ 839 InitTrigger (); 840 if (!(self.spawnflags & PUSH_SILENT)) 841 { 842 if (self.target) 843 { 844 if (game == GAME_NEXUIZ) 845 self.noise = "level/jumppad.wav"; 846 else 847 self.noise = "player/plyrjmp8.wav"; 848 } 849 else 850 self.noise = "ambience/windfly.wav"; 851 } 852 if (self.noise != "") 853 precache_sound (self.noise); 854 self.touch = trigger_push_touch; 855 if (!self.speed) 856 self.speed = 1000; 857 self.movedir = self.movedir * self.speed * 10; // why the * 10 I dunno... 858 if (self.target) 859 { 860 self.think = trigger_push_findtarget; 861 self.nextthink = time + 0.2; 862 } 863}; 864 865//============================================================================ 866 867void() trigger_monsterjump_touch = 868{ 869 if ( other.flags & (FL_MONSTER | FL_FLY | FL_SWIM) != FL_MONSTER ) 870 return; 871 872// set XY even if not on ground, so the jump will clear lips 873 other.velocity_x = self.movedir_x * self.speed; 874 other.velocity_y = self.movedir_y * self.speed; 875 876 if ( !(other.flags & FL_ONGROUND) ) 877 return; 878 879 other.flags = other.flags - FL_ONGROUND; 880 881 other.velocity_z = self.height; 882}; 883 884/*QUAKED trigger_monsterjump (.5 .5 .5) ? 885Walking monsters touching 886this will jump in the 887direction of the angle. 888 889Keys: 890"speed" 891 horizontal speed 892 default: 200 893"height" 894 upward speed 895 default: 200 896*/ 897void() trigger_monsterjump = 898{ 899 if (!self.speed) 900 self.speed = 200; 901 if (!self.height) 902 self.height = 200; 903 if (self.angles == '0 0 0') 904 self.angles = '0 360 0'; 905 InitTrigger (); 906 self.touch = trigger_monsterjump_touch; 907}; 908 909