How to make a script that influences every NPC close to you?

Post » Tue May 17, 2011 1:49 am

Hello all,

I have a couple of ideas for mods and I am missing a way to make the following condition work:

if ( npcDistanceFromPlayer < aNumber )

...do stuff...
endif

I have a quest script for the player. My problem is how to get the references of the actors (or creatures) to a variable. I haven't found a function in FOSE or GECK wiki but I'm sure I am missing something since people have obviously done it before :banghead:

I think it's done by using tokens, but I'm still missing the way to add the token to the NPCs via additem!

Any help would be great! :goodjob:
User avatar
tiffany Royal
 
Posts: 3340
Joined: Mon Dec 25, 2006 1:48 pm

Post » Tue May 17, 2011 9:26 am

I'm not sure there is a way to get NPCs or Creatures around you without knowing ahead of time or doing something to them. I think at best you'd have to make an explosion that is silent/does nothing with a script attached to it that adds the tokens, and spawn it on the PC as often as you need. I'm sure it has some annoying side effects other then performance though; hopefully there is a better way to do it someone can share.
User avatar
Sharra Llenos
 
Posts: 3399
Joined: Wed Jan 17, 2007 1:09 pm

Post » Tue May 17, 2011 8:01 am

The explosion solution is not bad, I don't really need it to update very often.

Could it be done with http://geck.gamesas.com/index.php/AddSpell? That way you could e.g. modify all raiders to do something since it applies to the base object.

I'd prefer a better way though, if anyone has a suggestion it'd be great!
User avatar
ijohnnny
 
Posts: 3412
Joined: Sun Oct 22, 2006 12:15 am

Post » Tue May 17, 2011 11:39 am

Here's an example script snippet that should get you on the right track:
(loops through nearby actors, adds tokens if conditions are met etc.)

        if player.isInInterior == 1		set depth to 0	else		set depth to 2	endif	set actor to apple	set actor to (getFirstRef 200 depth 0)	Label 1	if actor != 0			; Nearby living, allied actor I'm aware of?		if actor.getDead == 0 && actor != player && actor != self && actor.getFactionRelation self == 2 && self.getCurrentAIProcedure != 16			if actor.getDistance self < RKRMaxInteractionDistance && self.getDetected actor == 1 && actor.getDetected player == 0				; Add control token to actor if he doesnt have one yet				if actor.getItemCount RKRMode3ControllerToken == 0					actor.addItem RKRMode3ControllerToken 1 1				endif				; If im currently engaging, instruct actor to do the same if he's smart enough to understand				if RKRReactionMode >= 2 && self.getIsCurrentPackage RKREngagePak == 1 && actor.getIsCurrentPackage RKREngagePak == 0					if actor.getType == 42 || actor.getIsCreatureType 4 == 1 || actor.getIsCreatureType 6 == 1 						actor.addItem RKRCmdEngageToken 1 1					endif				endif			endif		endif		set actor to apple		set actor to getNextRef		goto 1	endif


I hope this helps
User avatar
D IV
 
Posts: 3406
Joined: Fri Nov 24, 2006 1:32 am

Post » Tue May 17, 2011 9:24 am

You would place the explosion at the players feet. The radius of the explosion would determine how many close by NPC's are affected by the explosions script. The script on the explosion could then do what-ever you need it to do. It could even pass a 'Reference ID' to the quests script if you need the reference.

For example, the quest could have 10 reference name variables. The explosion script woudl check if one of the variables is empty, if it is, then fill it with the variable.
The quest then processes the reference variable and clears it when its done with it so it can be reused by another explosion.

player.PlaceAtMe ExplosionName 1


You never really said why you want to do this, so its hard to be specific on a good solution to what your attempting. ;)
User avatar
Kayleigh Williams
 
Posts: 3397
Joined: Wed Aug 23, 2006 10:41 am

Post » Tue May 17, 2011 3:19 pm

Here's an example script snippet that should get you on the right track:
(loops through nearby actors, adds tokens if conditions are met etc.)


This will be very helpful, thanks a lot! Btw, should the token have any particular properties? All I'm guessing is that it should remove itself when the actor dies or otherwise stops being affected by the script.

Edit: Thanks for the tips on the explosion! I am trying to create a "fear" system, where if your character is wearing Power Armor some enemies will flee!
User avatar
Scott
 
Posts: 3385
Joined: Fri Nov 30, 2007 2:59 am

Post » Tue May 17, 2011 1:48 am

This will be very helpful, thanks a lot! Btw, should the token have any particular properties? All I'm guessing is that it should remove itself when the actor dies or otherwise stops being affected by the script.

Edit: Thanks for the tips on the explosion! I am trying to create a "fear" system, where if your character is wearing Power Armor some enemies will flee!

Yes such a token would remove itself once its on longer needed. In the onAdd block of the token you should add
; Fix passive NPCs bugself.addItem apple 1 1self.removeItem apple 1 1

to prevent a certain bug.

As for your fear system, depending on the level of processing oyu might not need tokens at all. You could, for examplle, have a quest script which runs your base loop that iterates through all nearby actors, and if they arent wearing PA and the player is, they loose confidence. This would not require tokens at all. Thats probably an initial implemenation you should go for.

The next step could be that actors also consider their nearby allies. Some ideas:
- the player gets a threat value, based on his armor and weapon
- a quest scripts adds controller tokens to nearby actors
- these controller tokens compute a local confidence value based the actors equipment. for a confidence of 10, the controller token adds 10 confidence tokens to the actor.
- then the controller tokens process the nearby allies and sum up their confidence (with getItemCount for confidence tokens). if the confidence of itself + the nearby allies is smaller than the one of the player, the actor flees
User avatar
Emily Jones
 
Posts: 3425
Joined: Mon Jul 17, 2006 3:33 pm

Post » Tue May 17, 2011 4:14 pm

This is some excellent advice! I have started a [WIPz] thread http://www.gamesas.com/index.php?/topic/1112904-wipz-npc-tin-man-fear-system-or-ntfs/. I will try out the different methodologies and post if (or when) I'm stuck! Hopefully I'll have something good soon!
User avatar
^~LIL B0NE5~^
 
Posts: 3449
Joined: Wed Oct 31, 2007 12:38 pm

Post » Tue May 17, 2011 2:22 pm

[edit] Opps, ignore...
User avatar
NEGRO
 
Posts: 3398
Joined: Sat Sep 01, 2007 12:14 am

Post » Tue May 17, 2011 10:16 am

To remove the token just use RemoveMe. You can use it either in an OnAdd block or GameMode, contrary to the wiki, and I think others have said it works in other blocktypes as well. Also I'd recommend schlangsters method, using FOSE is likely much more lightweight and less error prone then the explosion method; I'm not to familiar with FOSEs functions though I probably should be...
User avatar
Sweets Sweets
 
Posts: 3339
Joined: Tue Jun 13, 2006 3:26 am

Post » Tue May 17, 2011 9:38 am

To remove the token just use RemoveMe. You can use it either in an OnAdd block or GameMode, contrary to the wiki, and I think others have said it works in other blocktypes as well. Also I'd recommend schlangsters method, using FOSE is likely much more lightweight and less error prone then the explosion method; I'm not to familiar with FOSEs functions though I probably should be...


I will probably use the FOSE method eventually, but I am trying to do some quick testing of the NPC behavior using the explosion method. How exactly do you attach a script to the explosion?
User avatar
Izzy Coleman
 
Posts: 3336
Joined: Tue Jun 20, 2006 3:34 am

Post » Tue May 17, 2011 9:53 am

I don't know off the top of my head I'd have to look but it will involve base and/or object/actor effects if its not right there in the explosion menu.
User avatar
Ownie Zuliana
 
Posts: 3375
Joined: Thu Jun 15, 2006 4:31 am

Post » Tue May 17, 2011 4:44 pm

You create a >Base Effect and place the script on it.
You create an >Object Effect and attach the Base Effect from above to it.
You create an >Explosion and attach the Object Effect from above to it using the 'Enchantment' drop-down box.
User avatar
Ella Loapaga
 
Posts: 3376
Joined: Fri Mar 09, 2007 2:45 pm

Post » Tue May 17, 2011 10:56 am

Thanks a lot!

I have created the base script effect and attached the script but I don't see a way to attach the base effect to the object effect. It doesn't appear in the drop-down menu in the object effect -> new -> effect tab :banghead: Is there an option I missed or something?

Edit: Nevermind, I got it. You must also check the "touch" box :celebration:
User avatar
Lew.p
 
Posts: 3430
Joined: Thu Jun 07, 2007 5:31 pm

Post » Tue May 17, 2011 2:52 pm

Ok, I think I'm close to the end :celebration:

All I need is a way to read the refIDs of the affected actors and pass them to the quest script. Then I'm thinking about a form list.

Any ideas???
User avatar
Monika Fiolek
 
Posts: 3472
Joined: Tue Jun 20, 2006 6:57 pm

Post » Tue May 17, 2011 9:15 am

This will be very helpful, thanks a lot! Btw, should the token have any particular properties? All I'm guessing is that it should remove itself when the actor dies or otherwise stops being affected by the script.

Edit: Thanks for the tips on the explosion! I am trying to create a "fear" system, where if your character is wearing Power Armor some enemies will flee!


You should not use FOSE for this as even with a Depth of 0 it will catch Actors that are in completely different areas then the player -> then forcing you to use GetLOS and multiple other functions just to try to prevent actors not in direct sight and distance from being effected -> something that Explosions will not have an issue with as they obey LOS by default and any actors not within thier radius will not be effected as well -> its just easier for this type of effect.

Also avoid Tokens especially when they are used in combat situations as any item added to actors resets their AI and in most cases it causes them to do nothing instead of continuing with the Fight or Flight response...

An effect that just does something similar to below will get the job done on a singluar level -> if you want a mob mentality then just use an Explosion to capture the refs around the player you also need to keep track of the number of refs passed into the quest -> very simple If Quest.Target1 == 0 set Quest.Target1 to GetSelf, Set Count to Count + 1 holding multiple targets and a current ref count (my own scripts keep reference over 30 targets I know of a few other people who keep up with 100 or more A bit much to be honest) then what you do is decide how many is to many and do an AV check for Confidence and Aggression to determine who would run and who would fight then from in the quest apply the flee magic effect.

Zero Tokens to have to clean up or worry about actors that ran into another cell and evaded high process causing issues with dynamic reference bloat, and if the actors run away with the script applied it does not matter because FO3 respawns with base stats instead of modified stats so there is zero lasting impact on save games.

In the ScriptEffectStart block
Set Active to 1
Set Aggression to GetAV Aggression
Set Confidence to GetAV Confidence
SetAV Aggression 0
SetAV Confidence 0
ForceFlee

In the ScriptEffectFinish block
If Active
SetAV Aggression Aggression
SetAV Confidence Confidence
EVP
Endif

As far as the quest script goes I would set it to only process every second and just use a switch variable to either pop the ref collection magic effect and flip the switch so the next second it will do the fear processing and flip the switch back -> in this way the quest script is light weight not being an every game frame effect and having it do stuff once per second would be imperceptible to the player.
User avatar
Terry
 
Posts: 3368
Joined: Mon Jul 09, 2007 1:21 am

Post » Tue May 17, 2011 4:30 pm

An effect that just does something similar to below will get the job done on a singluar level -> if you want a mob mentality then just use an Explosion to capture the refs around the player you also need to keep track of the number of refs passed into the quest -> very simple If Quest.Target1 == 0 set Quest.Target1 to GetSelf


Thank you very much for the excellent advice! There is however one point I'm having difficulty with; the syntax to capture the references :brokencomputer:
When you say Quest.Target1 how do I set this target? The compiler keeps telling me it's an "unknown variable" (obviously). I have looked in the Quest tabs
but I am obviously missing something :banghead:
User avatar
Naughty not Nice
 
Posts: 3527
Joined: Sat Nov 04, 2006 6:14 am

Post » Tue May 17, 2011 12:40 am

Well all i can say is that i wouldnt use explosions for anything but explosions, unless there's no alternative. You dont even have to look at real test results to conclude that the overhead of iterating through references which are in memory anyway is lower than placing a new object in the world, calculating effected actors (for which you have iterate through all of them too), doing all kinds of other stuff you dont know about, and finally adding a spell effect which will start running a script at each actor.
Imho something like this
scn ActorFearQuestScriptshort depthref actorshort playerThreatshort actorThreatBegin GameModeset playerThreat to ... (health weapon armor etc)if player.isInInterior == 1	set depth to 0else	set depth to 2endifset actor to appleset actor to (getFirstRef 200 depth 0)Label 1if actor != 0		if actor.getDead == 0 && actor != player && actor.getFactionRelation player == 1 && actor.getCurrentAIProcedure != 16		if actor.getDistance self < 5000 && actor.getDetected player == 1			set actorThreat to ... (health weapon armor)			if actorThreat < playerThreat				// flee			endif		endif	endif	set actor to apple	set actor to getNextRef	goto 1endifEnd

is much simpler
User avatar
Phillip Hamilton
 
Posts: 3457
Joined: Wed Oct 10, 2007 3:07 pm

Post » Tue May 17, 2011 12:50 am

Well all i can say is that i wouldnt use explosions for anything but explosions, unless there's no alternative. You dont even have to look at real test results to conclude that the overhead of iterating through references which are in memory anyway is lower than placing a new object in the world, calculating effected actors (for which you have iterate through all of them too), doing all kinds of other stuff you dont know about, and finally adding a spell effect which will start running a script at each actor.
Imho something like this
scn ActorFearQuestScriptshort depthref actorshort playerThreatshort actorThreatBegin GameModeset playerThreat to ... (health weapon armor etc)if player.isInInterior == 1	set depth to 0else	set depth to 2endifset actor to appleset actor to (getFirstRef 200 depth 0)Label 1if actor != 0		if actor.getDead == 0 && actor != player && actor.getFactionRelation player == 1 && actor.getCurrentAIProcedure != 16		if actor.getDistance self < 5000 && actor.getDetected player == 1			set actorThreat to ... (health weapon armor)			if actorThreat < playerThreat				// flee			endif		endif	endif	set actor to apple	set actor to getNextRef	goto 1endifEnd

is much simpler


Truth be told I tried your script and it works like a charm :celebration:

Only problem right now is that getFactionRelation only seems to be working for actors (Raiders, Talon etc.), not Super Mutants or creatures, but I'm sure this will be pretty easy to figure out! Thanks to all of you for your help!
User avatar
gemma
 
Posts: 3441
Joined: Tue Jul 25, 2006 7:10 am


Return to Fallout 3