Timed fire and spike traps

Author
Gilgon Avalrock

What It Does
These are some scripts so you can set up spike and fire traps that trigger automatically every few seconds. The player will have to time carefully when he walks past them, or else take damage.

In order to have these traps fire by themselves, we'll need a heartbeat script. But heartbeat scripts can be CPU intensive, and we don't want these traps firing off when no one is around to see them.

Here's a handy trick you can use for all areas that have heartbeat scripts, or things in them with heartbeat scripts...

Put this in your area's

Area OnEnter event
/// /// /// /// /// /// /// /// /// /// /// /// /// enter_area /// Tally all entering PC's so the heartbeat /// for this area only updates the traps when /// someone's in the area. /// /// Created by Gilgon Avalrock /// /// /// /// /// /// /// /// /// /// /// /// void main {   object oEntering = GetEnteringObject; if(GetIsObjectValid(oEntering)){ if(GetIsPC(oEntering)){ int nNumEntered = GetLocalInt(OBJECT_SELF,"nNumEntered"); SetLocalInt(OBJECT_SELF,"nNumEntered",nNumEntered+1); }   } }

Area OnExit
/// /// /// /// /// /// /// /// /// /// /// /// /// exit_area /// Decrement tally of players in the timing area. /// When tally reaches 0, heart_area returns /// immediately. /// /// Created by Gilgon Avalrock /// /// /// /// /// /// /// /// /// /// /// /// void main {   object oExiting = GetExitingObject; if(GetIsObjectValid(oExiting)){ if(GetIsPC(oExiting)){ int nNumEntered = GetLocalInt(OBJECT_SELF,"nNumEntered"); SetLocalInt(OBJECT_SELF,"nNumEntered",nNumEntered-1); }   } }

What these two scripts will do is track how many PC's are in the area. Any heartbeat script can check the local int stored on the area nNumEntered. If that value is 0, noone is in the area.

Area OnHeartbeat
Next, we need the heartbeat script. I've chosen to put this in the area's OnHeartbeat script.

/// /// /// /// /// /// /// /// /// /// /// /// /// heart_area /// If no one is in the area, this returns /// immediately. If a PC is in the area, then /// set delayed triggers for the timed traps. /// /// Created by Gilgon Avalrock /// /// /// /// /// /// /// /// /// /// /// /// //this is in a seperate function so it can be called after a delay... void ApplyDamage(object oSource, int nTrapType){ int i = 0; object oCreature = GetNearestObject(OBJECT_TYPE_CREATURE, oSource, i); //Check for anyone standing in the wrong place while(GetIsObjectValid(oCreature) && GetDistanceBetween(oSource, oCreature) <= 1.5f) { //apply damage based on trap type if(nTrapType == 0){ ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d3(3),DAMAGE_TYPE_PIERCING), oCreature); }else{ ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d3(3),DAMAGE_TYPE_FIRE), oCreature); }       i++; oCreature = GetNearestObject(OBJECT_TYPE_CREATURE, oSource, i); } } void main {   if(GetLocalInt(OBJECT_SELF, "nNumEntered")==0) return; //no one is in this area int s=0; int f=0; float fDelay; object oWP = GetFirstObjectInArea(OBJECT_SELF); while(GetIsObjectValid(oWP)){ if(GetTag(oWP)=="WP_SPIKE"){//check spike traps //two seconds delay between each spike fDelay = IntToFloat(s)*2.f;           //Delay the visual effect and damage DelayCommand(fDelay,ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_SPIKE_TRAP), GetLocation(oWP))); DelayCommand(fDelay,ApplyDamage(oWP,0)); //set local int for trigger DelayCommand(fDelay,SetLocalInt(oWP,"nTrapArmed",1)); DelayCommand(fDelay+2.0f,SetLocalInt(oWP,"nTrapArmed",0)); s++; }else if(GetTag(oWP)=="WP_FIRE"){//check fire traps //These fire off in pairs, offset timing from spikes (spreads out the calls to ApplyDamage) //one second delay between each pair of flames //remove the /2 if you want them to fire singly fDelay = IntToFloat(f/2)+0.5f; DelayCommand(fDelay,ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FLAME_M), GetLocation(oWP))); DelayCommand(fDelay,ApplyDamage(oWP,1)); //set local int for trigger DelayCommand(fDelay,SetLocalInt(oWP,"nTrapArmed",1)); DelayCommand(fDelay+1.0f,SetLocalInt(oWP,"nTrapArmed",0)); f++; }       oWP = GetNextObjectInArea(OBJECT_SELF); } }

This will look through everything in the area, and find waypoints with the tag WP_SPIKE and WP_FIRE. Since the spike effect lasts for 2 seconds, each spike will fire off 2 seconds after the last, in the order they were created. The flame effect only lasts 1 second, but for the fire I've chosen to sync every 2 flames, also in the order they were created. (order not always consistant...see note at bottom of post)

You can place any number of spike and fire waypoints, but the more you place, the more it will slow down peoples computers. I recommend 3-6 spikes, and 4-8 flames.

If someone is standing on the trap when it fires, they will take damage. But what if the spikes of a trap are already up when I walk into them? Well, right now, nothing. In order to apply damage after that initial activation, we'll need some triggers.

For each spike trap or pair of fire traps (if placed right next to eachother), you will need to place a generic trigger. The trigger should cover the same area that would damage the player in the above script (roughly a 1.5 radius area around the waypoint). Remember that the trap is centered on the "flagpole" of the waypoint, not the arrow base.

Triggers OnEnter
If your trigger is on a spike trap, place this script in the trigger's OnEnter event:

/// /// /// /// /// /// /// /// /// /// /// /// /// trig_fire /// This detects if you've walked into a timed /// trap that is currently firing. /// /// Created by Gilgon Avalrock /// /// /// /// /// /// /// /// /// /// /// /// void main {   object oEntering = GetEnteringObject; object oWP = GetNearestObjectByTag("WP_SPIKE"); if(GetIsObjectValid(oWP)){ if(GetLocalInt(oWP,"nTrapArmed")){ ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d4(3),DAMAGE_TYPE_PIERCING), oEntering); }   } }

Trigger OnEnter
If the trigger is for a flame trap, use this OnEnter:

/// /// /// /// /// /// /// /// /// /// /// /// /// trig_fire /// This detects if you've walked into a timed /// trap that is currently firing. /// /// Created by Gilgon Avalrock /// /// /// /// /// /// /// /// /// /// /// /// void main {   object oEntering = GetEnteringObject; object oWP = GetNearestObjectByTag("WP_FIRE"); if(GetIsObjectValid(oWP)){ if(GetLocalInt(oWP,"nTrapArmed")){ ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d4(3),DAMAGE_TYPE_FIRE), oEntering); }   } }

And that should do it! The spikes fit nicely into an empty doorway, and twoflames plus a boulder will nicely block a hallway. For an example of this script in action, check out my script-laden mini-module: Quest of Chronos ... Click Here

note: If you're having trouble getting the traps to fire off in the order you want, try using the heart_timing script in the above listed module instead of the one shown above. It is not as efficient, and can't be used for multiple areas, but the order is more predictable.