scriptName defaultTeleportAbility extends activeMagicEffect {Attempt at a generic script for NPCs to teleport to XXX markers when threatened by melee} import game import utility ;VFX Activator property SummonFX Auto ;Summon parameters activator property teleportBase auto {Base object to search for as a teleport point} float property fSearchRadius = 1600.0 auto {How far near me to search for teleport points? DEFAULT = 768u} int property iMinToTeleport = 2 auto {Min # of hits I'll take before teleporting. DEFAULT = 2} int property iMaxToTeleport = 4 auto {Max # of hits I'll take before teleporting. DEFAULT = 4} effectShader property fadeOutFX auto effectShader property fadeInFX auto visualEffect property TrailFX auto ;{Let's try some trailing FX to show where I'm going to pop out} ;Internal variables. bool combatStarted int hitCount ObjectReference teleportGoal ObjectReference player actor caster objectReference casterRef bool inBleedout objectReference opponent Event OnEffectStart(Actor akTarget, Actor akCaster) player = (Game.GetForm(0x14) as Actor) caster = akCaster casterRef = (caster as ObjectReference) endEVENT ;Every 2 hits, the Caller teleports. Event OnHit(ObjectReference akAggressor, Form weap, Projectile proj, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) opponent = akAggressor int hitTolerance = RandomInt(iMinToTeleport, iMaxToTeleport) hitCount = hitCount + 1 if (hitCount > hitTolerance && !caster.IsDead()) hitCount = 0 if inBleedout == FALSE && caster.isDead() == FALSE Teleport() endif EndIf ; additional check - seen instances where NPC with this ability would not die! if Caster.getActorValue("Health") < 0 caster.kill() ; debug.trace("teleport NPC killed by self (HP<0 safety net): "+caster) endif EndEvent Event Teleport() ;Where's the Caller going? int i = 0 ; incrementer for while int maxSearch = 10 ; limit number of while recursions while i < maxSearch teleportGoal = FindRandomReferenceOfTypeFromRef(teleportBase, casterRef, fSearchRadius) if teleportGoal.getDistance(opponent) < 512 || (player as actor).hasLoS(teleportGoal) == FALSE ; ;debug.trace(caster.getActorBase()+" found but doesn't prefer "+teleportGoal) ; this teleport marker isn't the best, but hold onto it as a backup option ; therefore don't kick out of the loop just yet elseif teleportGoal.getDistance(opponent) > 512 || (player as actor).hasLoS(teleportGoal) == TRUE ; if we found a teleport marker that works, just use it! ; ;debug.trace(caster.getActorBase()+" found a good goal and kicking out of while loop "+teleportGoal) i = maxSearch endif i += 1 ; ;debug.trace("While Recursion #"+i+" on "+self) endWhile ;Perform the swap. ;casterRef.Disable() fadeOutFX.play(casterRef) caster.setGhost(TRUE) objectReference previousLoc = casterRef.PlaceAtMe(SummonFX) Utility.Wait(0.5) TrailFX.Play(previousLoc, 0.5, teleportGoal) casterRef.MoveTo(teleportGoal) casterRef.PlaceAtMe(SummonFX) Utility.Wait(0.5) ;casterRef.Enable() fadeOutFX.stop(casterRef) caster.setGhost(FALSE) caster.evaluatePackage() caster.startCombat(opponent as actor) EndEvent EVENT onEnterBleedout() inBleedout = TRUE ; For now never reset this boolean. Considering it part of the flow that bleeding out turns the ability off endEVENT