KeepEyeOn and LOS help

Post » Mon Nov 19, 2012 12:23 pm

Hello,

I have two questions that maybe someone can answer. I have a randomly picked NPC following the player around trying to stay unnoticed through a FollowPlayer package. It works, but it's quite obvious that the player is being followed by the way the Follow packages work. I would like to use SandboxAndKeepEyeOn, but it doesn't seem to work. The NPC doesn't follow around. Does anybody have experience with this package and why it might not be working?

The next thing, I want the NPC to engage in dialogue or ambush the player at the moment that the player is in a lonely spot. That means, the NPC follows the player around trying to stay unnoticed until the player is not seen anymore by anybody but the ambushing NPC. I have been looking on ways to achieve this, but I haven't found a decent solution. The nearest way I think might work is through the SKSE function GetNumRefs tied with GetLOS.

Something like the following...
int numNPC = Cell.GetNumRefs(43) ; kNPC = 43int index = 0int NPCwithLOS = 0While index < numNPCif Cell.GetNthRef(index, 43).getLOS PlayerRef && Cell.GetNthRef(index, 43) != AmbusherRef  NPCwithLOS += 1EndIfindex += 1EndWhile

This is supposed to loop through all NPC's in the cell and check for LOS with each one. Everytime it finds an NPC with LOS, it will add one to the NPCwithLOS variable, except if it is the ambusher. If this returns 0, then the ambusher would proceed with the ambush, if not he will keep following. I'm not sure if this would work or if there might be an easier way. But the problem I see with this is that it is only checking one cell, and there might be other NPC's with LOS in nearby cells...

Any idea on how to do this better than the above code? Would this code work at all???

Thanks!
User avatar
Nauty
 
Posts: 3410
Joined: Wed Jan 24, 2007 6:58 pm

Post » Mon Nov 19, 2012 5:58 am

If you use the follow player package, you can adjust the minimum and maximum distance the follower is to the target. But I would advise you to build your own packages from scratch.

You could create a follow/sandbox package and set the minimum radius to be fairly large (and the maximum radius larger). If you did that, I think your NPC would follow the player while keeping his/her distance and should sandbox unless the player is further from the NPC than the maximum radius (then your NPC will start to follow the player again). Keep in mind this would require the creation of a new package.

The KeepAnEyeOn procedure in my custom package required that the target was the PlayerRef, the observation area was near the PlayerRef (with a radius of 100 I think?) and the end pursuit location was near the PlayerRef with a radius of 10000. That worked for me.
User avatar
James Shaw
 
Posts: 3399
Joined: Sun Jul 08, 2007 11:23 pm

Post » Mon Nov 19, 2012 9:25 am

Thanks a lot, Zartar...

The part with the KeepEyeOn worked like a charm. I had to play a bit with the values until I achieved the effect that I wanted. Now the NPC follows the player around really discretely, and is hard to spot. The player has to look behind all the time to see if he is being followed...

I stopped using the follow package because it has a hardcoded distance at which the NPC starts to run. It's very obvious that he is following the player. It might have been possible to solve it with a completely new package as you suggest though, but KeepEyeOn works really nice...

Now to see if I can solve the LOS issue...
User avatar
maya papps
 
Posts: 3468
Joined: Mon Aug 07, 2006 3:44 pm

Post » Mon Nov 19, 2012 4:25 am

Good to hear, I spent ages tearing my hair out trying to get the KeepAnEyeOn procedure to work! I was getting crashes because of inappropriate EndPursuitLocation values. FYI there is check box for preferred running speed in the flags tab for packages.

As for the LOS, here's what I would try:

First create 15 new global variables.

Then create a quest and in the quest data tab tick the Start Game Enabled box (it would be best to start the quest using the Story Manager for a number of reasons but for the moment try this), untick the Run Once box and give the quest a priority of 99. In the quest aliases tab create a new reference alias and tick the Optional, Find Matching Reference, In Loaded Area and Closest check boxes. In the match conditions tab create a condition that uses the condition function IsActor on the subject == 1. In the scripts tab attach a script like this one:

Spoiler
ScriptName MyScript extends ReferenceAliasGlobal Property MyGlobalVariable autoReferenceAlias Property MyRefAlias autoActor Property PlayerRef autoActor MyActorEvent OnInit()	 RegisterForSingleUpdate(1.0)EndEventEvent OnUpdate()	 MyActor=MyRefAlias.GetReference() as Actor	 If PlayerRef.IsDetectedBy(MyActor)		  MyGlobalVariable.SetValue(1.0)	 Else		  MyGlobalVariable.SetValue(0)	 EndIf	 RegisterForSingleUpdate(5.0)EndEvent

Now duplicate this alias until you have 15 aliases. Don't forget to set the properties properly. Remember that you must point each RefAlias property at the alias itself.

What this quest is doing is it will search the loaded area (5x5 cells surronding the player) for actors and will give the closest 15 actors in this area an alias (the alias gives these actors the script).

Now create second quest the same way as the first (you should refine this later by using the story manager to start these quests) and create a reference alias. This time chose the Unique Actor and in the drop down list select your NPC. Add your KeepAnEyeOn package to this reference alias. Now attach this script to the reference alias:

Spoiler
ScriptName MyAmbushScript extends ReferenceAliasReferenceAlias Property MyNPCRefAlias autoActor Property PlayerRef autoGlobalVariable Property MyGlobalVariable[] auto   ;Fill this array with your 15 global variablesActor MyActorEvent OnInit()	 Int ArrayIndex=MyGlobalVariable[].Length	;Or Int ArrayIndex=14	 RegisterForSingleUpdate(1.0)EndEventEvent OnUpdate()	 Int MyLOSCount=0	 While ArrayIndex>0 && MyLOSCount==0		  If MyGlobalVariable[ArrayIndex].GetValue()>0			   MyLOSCount+=1		  EndIf		  ArrayIndex-=1	 EndWhile	 MyActor=MyRefAlias.GetReference() as Actor	 If MyLOSCount==0 && PlayerRef.IsDetectedBy(MyActor)		  MyActor.StartCombat(PlayerRef)	 EndIf	 RegisterForSingleUpdate(3.0)EndEvent

You will also need to attach a script to this second quest in the scripts tab. This script should look like this:

Spoiler
ScriptName MyRefreshAliasScript extends QuestQuest Property MyFirstQuest  autoEvent OnInit()	 RegisterForSingleUpdate(1.0)EndEventEvent OnUpdate()	 MyFirstQuest.Stop()	 MyFirstQuest.Start()	 RegisterForSingleUpdate(10.0)EndEvent

This script will constantly stop and start the first quest which will refresh the first quest's aliases periodically.

There are probably better ways to do this (this way is pretty messy and there are a host of potential problems) but this is all I could think of at the moment. As for the scripts you can probably find more appropriate names for the scripts, properties, variables...
User avatar
Tai Scott
 
Posts: 3446
Joined: Sat Jan 20, 2007 6:58 pm

Post » Mon Nov 19, 2012 12:26 pm

Thank you Zartar! You sure put time and work on your answer!

But before I could see this I actually found a way to do it. I have a spell casted which catches all references and checks for LOS. If there is LOS, it adds them to a formlist and the script checks the formlist to see if it meets conditions.

It works well, but I don't know if it is the best way, as I am filling and emptying this formlist every three seconds...

The spell runs this code
Event OnEffectStart(actor Target, actor Caster)Player = Game.GetPlayer()If Target != Player && Target.HasLOS(Caster)If HasLOSFormList.HasForm(Target) != True  HasLOSFormList.AddForm(Target)EndIfEndIfEndEvent

and the script this one...
	;Here come conditions to ForceGreet	FindLOSSpell.cast(Game.GetPlayer())	;Debug.Notification("Firing Spell...")	Utility.Wait(1)	if AADielosFindLOSFormList.GetSize() == 1 && AADielosFindLOSFormList.HasForm((AliasAttacker As ReferenceAlias).GetReference())	 SceneUpdateCount = AADielosFindLOSFormList.GetSize()	 Debug.Notification("The LOS list has " + SceneUpdateCount + " and the only entry is the Stalker, so it applies...")	 ApproachToTalk = 1	 Debug.Notification("ForceGreet should start now...")	ElseIf AADielosFindLOSFormList.GetSize() == 0	 SceneUpdateCount = AADielosFindLOSFormList.GetSize()	 Debug.Notification("The LOS list has " + SceneUpdateCount + " and the Stalker is still following, so it applies...")	 ApproachToTalk = 1	 Debug.Notification("ForceGreet should start now...")	Else	 ;SceneUpdateCount = AADielosFindLOSFormList.GetSize()	 ;Debug.Notification("The LOS list has " + SceneUpdateCount + " entries, thus doesn't apply for ForceGreet...")	EndIf	SceneUpdateCount = 0	AADielosFindLOSFormList.Revert()

If this should prove to not work well or too resource intensive, I will sure try your advice!

Thanks again!
User avatar
ILy- Forver
 
Posts: 3459
Joined: Sun Feb 04, 2007 3:18 am

Post » Mon Nov 19, 2012 6:25 pm

That is way, WAY better than what I suggested! Glad I could (kind of) help.
User avatar
[Bounty][Ben]
 
Posts: 3352
Joined: Mon Jul 30, 2007 2:11 pm


Return to V - Skyrim