cenarius451 Posted April 24, 2021 Share Posted April 24, 2021 Hi there. I'm working on a script to make it so npcs loot bodies around the player character. My script compiles and executes in the game but it doesn't work. If someone could give me a hand i would really appreciate it. Here is the code: Scriptname NPCLootingScript extends ReferenceAlias Actor Property PlayerRef Auto Const Actor Property Corpse1 Auto Actor Property Corpse2 Auto Actor Property Corpse3 Auto Actor Property Looter1 Auto Actor Property Looter2 Auto Actor Property Looter3 Auto int Property TimerDuration Auto Const Keyword Property ActorTypeNPC Auto Keyword Property RELootedCorpse Auto Const int Property distance Auto Const ObjectReference[] Property NPCs Auto Event OnInit() Self.StartTimer(TimerDuration, 0) EndEvent Event OnTimer(int aiTimerID) Debug.Notification("Script running") If !PlayerRef.IsInCombat() NPCs = PlayerRef.FindAllReferencesWithKeyword(ActorTypeNPC, distance) int i = 0 While i < NPCs.Length Actor MyActor = NPCs[i] as Actor ActorBase PlayerBase = MyActor.GetActorBase() String name = PlayerBase.GetName() as String Debug.Notification("Found " + name + " in" + i as string) if MyActor == PlayerRef NPCs.Remove(i) ElseIf MyActor.IsDead() && !MyActor.HasKeyword(RELootedCorpse) if !Corpse1 Corpse1 = MyActor ElseIf !Corpse2 Corpse2 = MyActor ElseIf !Corpse3 Corpse3 = MyActor EndIf Else if !Looter1 Looter1 = MyActor ElseIf !Looter2 Looter2 = MyActor ElseIf !Looter3 Looter3 = MyActor EndIf EndIf i+=1 EndWHile If Looter1 && Corpse1 Looter1.PathToReference(Corpse1, 1.0) EndIf If Looter2 && Corpse2 Looter2.PathToReference(Corpse2, 1.0) EndIf If Looter3 && Corpse3 Looter1.PathToReference(Corpse3, 1.0) EndIf If Looter1 && Corpse1 Corpse1.RemoveAllItems(Looter1) Corpse1.AddKeyword(RELootedCorpse) EndIf If Looter2 && Corpse2 Corpse2.RemoveAllItems(Looter2) Corpse2.AddKeyword(RELootedCorpse) EndIf If Looter3 && Corpse3 Corpse3.RemoveAllItems(Looter3) Corpse3.AddKeyword(RELootedCorpse) EndIf EndIf Self.StartTimer(TimerDuration, 0) EndEvent This is attached into the player reference alias in a quest. Link to comment Share on other sites More sharing options...
DieFeM Posted April 24, 2021 Share Posted April 24, 2021 If I had to guess I would say that the OnInit runs on the reference, and the player's reference is already initialized when this script runs, so the timer never happens. Link to comment Share on other sites More sharing options...
cenarius451 Posted April 24, 2021 Author Share Posted April 24, 2021 Thanks for the reply, though i don't know how it could be done, as the timer must be initialized and it works ingame, though only a couple of cycles before stopping. Link to comment Share on other sites More sharing options...
LarannKiar Posted April 24, 2021 Share Posted April 24, 2021 (edited) I wouldn't use 0 as Timer ID and what is the value of TimerDuration? int Property TimerDuration = X Auto Const int Property TimerID = Y Auto Const ;Y!=0 Event OnInit() StartTimer(TimerDuration, TimerID) debug.notification("My Alias is initialized.") EndEvent OnTimer(int aiTimerID) if aiTimerID == TimerID StartTimer(TimerDuration, TimerID) debug.notification("My Timer is expired.") endif EndEvent What reference does the Alias points at? The Player? If not, does the Alias get cleared? Edited April 24, 2021 by LarannKiar Link to comment Share on other sites More sharing options...
cenarius451 Posted April 25, 2021 Author Share Posted April 25, 2021 I wouldn't use 0 as Timer ID and what is the value of TimerDuration? int Property TimerDuration = X Auto Const int Property TimerID = Y Auto Const ;Y!=0 Event OnInit() StartTimer(TimerDuration, TimerID) debug.notification("My Alias is initialized.") EndEvent OnTimer(int aiTimerID) if aiTimerID == TimerID StartTimer(TimerDuration, TimerID) debug.notification("My Timer is expired.") endif EndEvent What reference does the Alias points at? The Player? If not, does the Alias get cleared?Here is a screenshot: Now about the timer id, it doesn't matter outside the script, it could be any number. Still at this point i'm desperated so i changed it to 5 (both at the beginning and the end) and it's the same. Damn i could be doing some real work if i were not stuck with this :/ TimerDuration is set to 30 seconds, hope its enough time to process the npcs pathing but i can't test this yet as i'm unable to make this to work. Link to comment Share on other sites More sharing options...
NoCashNoExp Posted April 25, 2021 Share Posted April 25, 2021 (edited) Looter variables or corpse variables are not being assigned properly. Even if the actor failed to path to their target, the items should still be moved to them. Also, PathToReference is latent meaning it blocks script execution until it's done so your code should be like this: Scriptname NPCLootingScript extends ReferenceAlias Actor Property PlayerRef Auto Const Actor Property Corpse1 Auto Actor Property Corpse2 Auto Actor Property Corpse3 Auto Actor Property Looter1 Auto Actor Property Looter2 Auto Actor Property Looter3 Auto int Property TimerDuration Auto Const Keyword Property ActorTypeNPC Auto Keyword Property RELootedCorpse Auto Const int Property distance Auto Const ObjectReference[] Property NPCs Auto Event OnInit() Self.StartTimer(TimerDuration, 0) EndEvent Event OnTimer(int aiTimerID) Debug.Notification("Script running") If !PlayerRef.IsInCombat() NPCs = PlayerRef.FindAllReferencesWithKeyword(ActorTypeNPC, distance) int i = 0 While i < NPCs.Length Actor MyActor = NPCs[i] as Actor ActorBase PlayerBase = MyActor.GetActorBase() String name = PlayerBase.GetName() as String Debug.Notification("Found " + name + " in" + i as string) if MyActor == PlayerRef NPCs.Remove(i) ElseIf MyActor.IsDead() && !MyActor.HasKeyword(RELootedCorpse) if !Corpse1 Debug.Notification("Corpse1 Assigned") <---- Corpse1 = MyActor ElseIf !Corpse2 Corpse2 = MyActor ElseIf !Corpse3 Corpse3 = MyActor EndIf Else if !Looter1 Debug.Notification("Looter1 Assigned") <---- Looter1 = MyActor ElseIf !Looter2 Looter2 = MyActor ElseIf !Looter3 Looter3 = MyActor EndIf EndIf i+=1 EndWHile If Looter1 && Corpse1 Debug.Notification("Looter1 is moving") <---- Looter1.PathToReference(Corpse1, 1.0) Corpse1.RemoveAllItems(Looter1) Corpse1.AddKeyword(RELootedCorpse) Debug.Notification("Looter1 is done looting") <---- EndIf If Looter2 && Corpse2 Debug.Notification("Looter2 is moving") <---- Looter2.PathToReference(Corpse2, 1.0) Corpse2.RemoveAllItems(Looter2) Corpse2.AddKeyword(RELootedCorpse) Debug.Notification("Looter2 is done looting") <---- EndIf If Looter3 && Corpse3 Debug.Notification("Looter3 is moving") <---- Looter3.PathToReference(Corpse3, 1.0) Corpse3.RemoveAllItems(Looter3) Corpse3.AddKeyword(RELootedCorpse) Debug.Notification("Looter3 is done looting") <---- EndIf EndIf Self.StartTimer(TimerDuration, 0) EndEvent Edited April 25, 2021 by NoCashNoExp Link to comment Share on other sites More sharing options...
NoCashNoExp Posted April 25, 2021 Share Posted April 25, 2021 (edited) Do not modify array length while looping on it. Example: Array has 5 ObjectReferences and the 3rd is the player. Demonstration: - [Actor, Actor, Player, Actor, Actor] i=0, len=5 At i = 2 (Remove Player) - [Actor,Actor,Actor,Actor] BUT len was resolved to = 5 At i = 4 [Actor,Actor,Actor,Actor,??? <---- Out of bounds] len is still = 5 Edited April 25, 2021 by NoCashNoExp Link to comment Share on other sites More sharing options...
cenarius451 Posted April 25, 2021 Author Share Posted April 25, 2021 Thanks Do not modify array length while looping on it. Example: Array has 5 ObjectReferences and the 3rd is the player. Demonstration: - [Actor, Actor, Player, Actor, Actor] i=0, len=5 At i = 2 (Remove Player) - [Actor,Actor,Actor,Actor] BUT len was resolved to = 5 At i = 4 [Actor,Actor,Actor,Actor,??? <---- Out of bounds] len is still = 5Thanks for the help. I did a similar edit to my script, added several debugging notifications and i realized my script works, not as intended but it does what it does. I still tried yours though it's the same base.Screenshot: My updated script: Scriptname NPCLootingScript extends ReferenceAlias Actor Property PlayerRef Auto Const Actor Property Corpse1 Auto Actor Property Corpse2 Auto Actor Property Corpse3 Auto Actor Property Looter1 Auto Actor Property Looter2 Auto Actor Property Looter3 Auto int Property TimerDuration Auto Const Keyword Property ActorTypeNPC Auto Keyword Property RELootedCorpse Auto Const int Property distance Auto Const ObjectReference[] Property NPCs Auto Event OnInit() Self.StartTimer(TimerDuration, 5) EndEvent Event OnTimer(int aiTimerID) Debug.Notification("Script running") If !PlayerRef.IsInCombat() NPCs = PlayerRef.FindAllReferencesWithKeyword(ActorTypeNPC, distance) int i = 0 int Size = NPCs.Length as int If size > 6 size = 6 EndIf While i <= Size Actor MyActor = NPCs[i] as Actor String name = MyActor.GetActorBase().GetName() Debug.Notification("Found " + name + " in" + i as string) if MyActor == PlayerRef Debug.Notification("Found the player and removed it") NPCs.Remove(i) ElseIf MyActor.IsDead() && !MyActor.HasKeyword(RELootedCorpse) if !Corpse1 Corpse1 = MyActor Debug.Notification("Found body1") ElseIf !Corpse2 Corpse2 = MyActor Debug.Notification("Found body2") ElseIf !Corpse3 Corpse3 = MyActor Debug.Notification("Found body3") EndIf Else if !Looter1 Looter1 = MyActor Debug.Notification("Found looter1") ElseIf !Looter2 Looter2 = MyActor Debug.Notification("Found looter2") ElseIf !Looter3 Looter3 = MyActor Debug.Notification("Found looter3") EndIf EndIf i+=1 EndWHile Debug.Notification("While cycle ended") If Looter1 && Corpse1 Looter1.PathToReference(Corpse1 as ObjectReference, 1.0) Debug.Notification("Processing looting 1") EndIf If Looter2 && Corpse2 Looter2.PathToReference(Corpse2 as ObjectReference, 1.0) Debug.Notification("Processing looting 2") EndIf If Looter3 && Corpse3 Looter1.PathToReference(Corpse3 as ObjectReference, 1.0) Debug.Notification("Processing looting 3") EndIf If Looter1 && Corpse1 Corpse1.RemoveAllItems(Looter1) Corpse1.AddKeyword(RELootedCorpse) EndIf If Looter2 && Corpse2 Corpse2.RemoveAllItems(Looter2) Corpse2.AddKeyword(RELootedCorpse) EndIf If Looter3 && Corpse3 Corpse3.RemoveAllItems(Looter3) Corpse3.AddKeyword(RELootedCorpse) EndIf EndIf Corpse1 = None Corpse2 = None Corpse3 = None Looter1 = None Looter2 = None Looter3 = None Self.StartTimer(TimerDuration, 5) Debug.Notification("Timer reset") EndEvent 30 seconds seemed fine for each cycle to complete, but regardless the npcs don't do the pathing, they just stand in their possitions, but the bodies are "looted". The issue remains as my quest stops working after a while. Maybe a solution would be adding a reduced version of my script to each npc template so they search individually instead of making it around the player character? idk, i don't like to touch so many vanilla records, but some cool stuff could be done if i go this way, for example making a script for animals so they eat ("loot") the npcs they kill or other animals, with animations and all, if possible? just dreaming here :p Link to comment Share on other sites More sharing options...
cenarius451 Posted April 25, 2021 Author Share Posted April 25, 2021 (edited) Also forgot to mention, for some reason i can't get the name of the npcs :/ Also i realize the size should be set to 7, excluding the player character that would make 6 npcs to process (up to 3 bodies and up to 3 looters). Edited April 25, 2021 by cenarius451 Link to comment Share on other sites More sharing options...
NoCashNoExp Posted April 25, 2021 Share Posted April 25, 2021 (edited) Sadly, pathing is handled by the engine. PathToReference() function can fail due to a couple of reasons. You can check if the pathing worked or not. bool success = Looter1.PathToReference(Corpse1, 1.0) Debug.Notification("Did Looter go to corpse? " + success)You need to test the intricacies of this function because I have no clue what it does. Try a simple straight path first. One more advice for your sanity, enable papyrus logging and start using Debug.Trace() instead. The output should be in Documents/My Games/Fallout4/Logs/Script/Script0.log Edited April 25, 2021 by NoCashNoExp Link to comment Share on other sites More sharing options...
Recommended Posts