I have been wracking my brain trying to come up with a stable way to find the closest enemy to the player with a temporary spell and attached script on the player.
The spell lasts 2 mins and is a constant effect script type.
I have looked for hours on the boards, used code snippets from papyrus masters like Cipscis and RandomNoob and Redwood Elf, I've also play tested for about 10 times longer trying to create a decent script but the below is the best I could come up with and (by its nature of using a 'Random' function) although it does work most of the time there is a failure rate.
Scriptname LFBeginCombat extends ActiveMagicEffect{Script to run for Begin Combat instance.}Spell Property spThisSpell Auto ; This spell.Spell Property spSpellToCast Auto ; Reference of the spell too cast.Actor Property PlayerRef Auto ; Reference the Player, told this was faster than Game.GetPlayer() all the time.Actor TargetRef ; Reference for the Target.Actor CasterRef ; The casting reference point.Actor TargetRefStoreOne ; Just a hold reference for one of the actors found.Float flDistanceStore = 0.0 ; Stored Target Reference distance to player.Float flDistanceTarget = 0.0 ; Last Target Reference distance to player.Bool boUpdating = False ; Just to make sure it doesn't try to run initialisation twice.Int intCount = 0 ; Number of times the while loop has run.Int intMaxSearch = 10 ; Max number of times to run the while loop.Int intSearchRadius = 2000 ; Search Radius to 2000 units.Bool boStopUpdate = False ; Bool to stop the updating.[/color]EVENT OnEffectStart(Actor akTarget, Actor akCaster)IF !boUpdating ; Make sure an Initialisation hasn't already started. RegisterForSingleUpdate(2) ; Run this update once in three seconds time. boUpdating = TrueELSE Debug.Notification("Script tried to initialise twice!") ; WTFENDIFEndEVENTEVENT OnUpdate()Debug.Trace("Update Started")IF !boStopUpdate && PlayerRef.IsInCombat() ; Really need to learn when to use STATES!IF TargetRef == None || TargetRef == PlayerRef || TargetRef.IsDead() || !TargetRef.IsInCombat() FunctionFindNearestEnemy() ; My rubbish version of finding nearest enemy to player. Debug.Trace("Last target was " + intCount + " " + TargetRef)ENDIFELSEIF boStopUpdate PlayerRef.DispelSpell(spThisSpell) ; Dispell this spell if all else fails. ReturnENDIFIF TargetRef != None && TargetRef != PlayerRef && !TargetRef.IsDead() && TargetRef.IsInCombat() && PlayerRef.HasLOS(TargetRef) Debug.Notification("I've just seen my opponent!") Debug.Trace("I saw my opponent! " + TargetRef + " " + intCount) spSpellToCast.Cast(TargetRef, TargetRef); TargetRef.DoCombatSpellApply(spSpellToCast, TargetRef) ; Same effect doesn't have any improvment over RemoteCast() or Cast().boStopUpdate = True Utility.Wait(0.5) ; Wait just half a sec to dispell this spell effect. PlayerRef.DispelSpell(spThisSpell) ReturnENDIFIF PlayerRef.IsInCombat() RegisterForSingleUpdate(0.5) ; Make updating faster while player is in combat.ELSE RegisterForSingleUpdate(2)ENDIFEndEVENTFUNCTION FunctionFindNearestEnemy() ; Trying to find nearest actor to player who is in players line of sight and in combat with player.ObjectReference ObjPlayerRef = (PlayerRef As ObjectReference) ; Setup an object reference for the player.Bool boKeepWhileing = True ; Is this really necessary too?TargetRef = Game.FindRandomActorFromRef(ObjPlayerRef, intSearchRadius)WHILE intCount < intMaxSearch && boKeepWhileingIF TargetRef == None || TargetRef == PlayerRef || TargetRef.IsDead() || !TargetRef.IsInCombat() TargetRef = Game.FindRandomActorFromRef(ObjPlayerRef, intSearchRadius) intCount += 1 ELSE boKeepWhileing = False Return EndIF IF TargetRefStoreOne != None && TargetRef != None && TargetRef != PlayerRef && TargetRefStoreOne != PlayerRef flDistanceStore = TargetRefStoreOne.GetDistance(PlayerRef) ; Lots of checks to make sure the random actor wasn't the bloody Player! flDistanceTarget = TargetRef.GetDistance(PlayerRef)IF flDistanceStore >= flDistanceTarget TargetRefStoreOne = TargetRef Debug.Trace("New TargetRef won " + flDistanceTarget + " units away " + TargetRef + ". StoreRef " + flDistanceStore + " units away") ELSE TargetRef = TargetRefStoreOne Debug.Trace("Old Store Ref closer " + flDistanceStore + " units away " + TargetRefStoreOne + ". New TargetRef " + flDistanceTarget + " units away") ENDIFELSEIF TargetRefStoreOne == None && TargetRef != PlayerRef TargetRefStoreOne = TargetRef Debug.Trace("Set the TargetRefStoreOne to the TargetRef as it was none") ENDIFENDWHILE; Should I have a "Return" somewhere here for the closest enemy?Debug.Notification(" I didn't find a valid opponent in " + intMaxSearch + " searches")EndFUNCTIONSTATE Busy ; Empty state for when script is busy... I think(Man the formatting on this is really bad when cut and paste from Notepad++ how does one get good tab indents and spaces? Arg edited like 6 times!)
One of the posts I saw by Borgurt1337 used a cloak type spell attaching scripts dynamically to actors around the player which sounded like a good idea but I had trouble getting certain other effects or spells to fire off the actor I chose to be the closes to the player. I am so surprised there is no GetClosestActorToActor() function. I want to later expand this to include ally's for my mod.
Any help or advice would be greatly appreciated.
Leon


