Jump to content

Help with NPC Looting Bodies Script


Recommended Posts

@LarannKiar After some tweaking and testing to for example excluding companions and turrets of being looters, i come to the conclusion that your little mod works... but the only think is that it takes its bloody damn time to npcs to loot.

 

 

I wonder if would be possible to hurry up npcs a bit?

Link to comment
Share on other sites

  • Replies 40
  • Created
  • Last Reply

Top Posters In This Topic

Already did that, alongside with "weapon drawn". I limited the quest to filter only actors with the "ActorTypeNPC" keyword and things got a bit faster, got to see a raider running and looting the exact same body the cat looted in that video, god knows where he was. A shame because i liked the idea of animals looting preys as well. We'll see, in the meantime i will play with the mod as it is and see how things go. Maybe adding more looters and bodies at the same time, we'll see.

 

Thank you very much. This was a nice discovery for me.

Edited by cenarius451
Link to comment
Share on other sites

Intersting.. the Preferred Speed flag usually do the trick. You can add animals to the looter alias:

 

GetInFaction CurrentCompanionFaction == 0 AND

GetInFaction RaiderFaction == 0 AND Also you can exclude raiders from looters.

HasKeyword ActorTypeNPC == 1 OR

HasKeyword ActorTypeAnimal == 1 OR

 

Ahh, and yes.. if you're using the "Find Matching Reference" on the Alias_Looter, you should use the GetDistance condition on it as well.

Edited by LarannKiar
Link to comment
Share on other sites

Interesting indeed, as i noticed the npc "running" towars the body only works for the first one, it never happends again, but the bodies are looted, one by one, as shown in the video. Something related with the package i guess.

 

I followed your idea and have the looter set as the following:

TEST.jpg

 

As expected it also works. Hope adding more bodies and looters doesn't impact the performance overall. Will continue playing and testing.

Link to comment
Share on other sites

Don't forget to remove the "looted" keyword from actors (I guess this function was in the game timer?) and then also remove the actors from being script variables (maybe LootedBody_01_Actor).

 

As for the screenshot, I'm not sure using the GetDistance like that is a good idea. You're comparing the distance between two ref aliases. The problem is that if Alias_Looter gets filled before Alias_Body01 then its GetDistance condition couldn't measure anything. So you can't check the distance of a non existing reference. (It might not happen always but there's a chance).

Link to comment
Share on other sites

Mmm i thought the aliases would overwite themselves ontimer? i could add an "Alias_Looter = none" and same for body but i thought they would re-fill every time the quest restarted. Also what did you mean then with the "GetDistance" option? seems fine to me as if there is a body it will calculate the closer looter around if there is any, if there is no body there will be no looter... unless an earlier looter got stuck in the alias?

 

In the meantime, another video showing my observation, the "looter running" occurs only at the beginning. This time it grabbed the chems vendor from the house. Don't know why it ignores the gunners. At the beginning of the video i was expecting the raider i mentioned earlier but never appeared, and all of a sudden the chems vendor appeared.

 

Link to comment
Share on other sites

if there is no body there will be no looter...

 

 

Yes, but if there's a corpse nearby but its ref alias get filled only after the looter's alias, then the looter alias couldn't fill beucase there it won't see any corpse.

 

 

 

the "looter running" occurs only at the beginning. This time it grabbed the chems vendor from the house. Don't know why it ignores the gunners.

 

 

 

The quest picks NPCs fully randomly, only depending on the conditions.

 

But why the Chems vendor gets stuck in the loot package? The package should've been stopped right after looting.

Edited by LarannKiar
Link to comment
Share on other sites

Maybe the looter gets stuck and only the bodies cycle?

 

Here it is the update script. Would this make sense? was kinda tricky to put the cleared aliases.

Scriptname TEMP_S extends Quest

Group Looters
ReferenceAlias Property Alias_Looter Auto Const
endGroup

Group Corpses
ReferenceAlias Property Alias_Body01 Auto Const
endGroup

Group Quests
Quest Property TEMP_Q_for_Aliases Auto Const
Quest Property TEMP_Q Auto Const
endGroup

Group Globals
GlobalVariable Property TEMP_G_01 Auto Const
GlobalVariable Property TEMP_G_PackageFinished Auto Const
endGroup

Group Keywords
Keyword Property TEMP_K_Looted Auto Const
endGroup


Event OnQuestInit()
	StartAliasQuest()		;START the quest TEMP_Q_for_Aliases. Corpse alias fill conditions are there. The Alias_Body01 ref alias on this quest is linked to that ref alias.
EndEvent


Function StartAliasQuest()

	if TEMP_Q_for_Aliases.IsRunning() == 1		;failsafe
		TEMP_Q_for_Aliases.Stop()
	endif

	Utility.Wait(0.5)		;wait for stopping...

	if TEMP_Q_for_Aliases.IsRunning() == 0		;Start the alias quest
		TEMP_Q_for_Aliases.Start()
	endif

	Utility.Wait(0.5)		;wait for the aliases to get filled...

	If Alias_Body01.GetReference() == none
		;Alias has not been filled (fill conditions are not met)
		StartTimer(20, 255)			;try to start the alias quest again. (LOOP timer)
	Else
		StartLoot()
	EndIf

EndFunction

Event OnTimer(int aiTimerID)
	if aiTimerID == 255		;LOOP timer
		StartAliasQuest()
	EndIf
	If aiTimerID == 555		;FALSE TIMER: if the actor can't loot the body in 60 seconds, abort the package
		End_Loot()
	Endif
EndEvent

Function StartLoot()

	TEMP_G_01.SetValueInt(1)		;for the packages

	(Alias_Looter.GetReference() as Actor).EvaluatePackage()

	StartTimer(60, 555)		;failsafe: if the looter can't path to the body, abort the package

	;WAIT FOR PACKAGE STOP

EndFunction

Function End_loot()		;called from package "on end" fragment / falsafe timer (ID: 555)

	If TEMP_G_PackageFinished.GetValueInt() == 0					;function was called from the falsafe timer
	
		if TEMP_Q_for_Aliases.IsRunning() == 1
			TEMP_Q_for_Aliases.Stop()
		endif
	
		TEMP_G_01.SetValueInt(0)

		TEMP_G_PackageFinished.SetValueInt(0)

		StartTimer(2, 255)			;start again LOOP timer. For the failsafe timer, no need for 20 seconds.

	ElseIf TEMP_G_PackageFinished.GetValueInt() == 1		;		;function was called from the package "on end" fragment

		LootProcedure()

		MarkBodyAsLooted()
	
		if TEMP_Q_for_Aliases.IsRunning() == 1
			TEMP_Q_for_Aliases.Stop()
		endif
	
		TEMP_G_01.SetValueInt(0)

		StartTimer(10, 255)			;start again LOOP timer

	EndIf

EndFunction




Function MarkBodyAsLooted()

	;AliasColl_LootedBodies.AddRef((Alias_Looter.GetReference() as Actor))		;add looted bodies to a ref coll alias. Ref coll actors have a keyword that prevents the looter from looting them again. Remove the looted bodies one by one with a Game Timer.

	LootedBody_01_Actor = (Alias_Body01.GetReference() as Actor)

	LootedBody_01_Actor.AddKeyword(TEMP_K_Looted)
Alias_Body01.Clear() <-----------------------
Alias_Looter.Clear()<------------------------
	StartTimerGameTime(0.5, 355)		;looted body has to have this keyword for at least two hours. (so looter won't loot this body in this period).

EndFunction


Actor LootedBody_01_Actor


Event OnTimerGameTime(int aiTimerID)		
	If aiTimerID == 355
		RemoveLootedBody()
	EndIf
EndEvent

Function RemoveLootedBody()

	LootedBody_01_Actor.RemoveKeyword(TEMP_K_Looted)
LootedBody_01_Actor = none <--------------------
EndFunction




Function LootProcedure()		;called rom package "on end" fragment. This is the actual "loot function".

	If (Alias_Body01.GetReference()) != none && (Alias_Looter.GetReference()) != none

		(Alias_Body01.GetReference() as Actor).RemoveAllItems((Alias_Looter.GetReference() as actor))

	EndIf

EndFunction






Edited by cenarius451
Link to comment
Share on other sites

Well, the "TEMP_Q_for_Aliases" starts in a shorter period of time than the game timer expires.. while the "LootedBody_01_Actor" still has the "TEMP_K_Looted" keyword.. the MarkBodyAsLooted() function changes the script variable "LootedBody_01_Actor" every time when the "TEMP_Q_for_Aliases" quest starts.. (this may prevent the "TEMP_K_Looted" keyword from being removed from the actor if the game timer is still running).

 

I think it can be fixed by arrays...

 

 

When a quest stops, it clears its reference aliases (the "TEMP_Q_for_Aliases" quest stops in the End_loot() function) so you don't need to clear them manually.

 

 

Also, creating failsafes like this might be useful:

	ElseIf TEMP_G_PackageFinished.GetValueInt() == 1		;		;function was called from the package "on end" fragment

            If LootedBody_01_Actor != (Alias_Body01.GetReference() as Actor)            ;<______NEW_CONDITIONS_______failsafe: make sure the previously looted body is not the new body picked by the "Temp_Q_For_Aliases" quest   

		LootProcedure()

		MarkBodyAsLooted()
	
		if TEMP_Q_for_Aliases.IsRunning() == 1
			TEMP_Q_for_Aliases.Stop()
		endif
	
		TEMP_G_01.SetValueInt(0)

		StartTimer(10, 255)			;start again LOOP timer

            Else

		debug.notification("Alias quest picked the previously looted body")

		;Do not loot

		if TEMP_Q_for_Aliases.IsRunning() == 1
			TEMP_Q_for_Aliases.Stop()
		endif
	
		TEMP_G_01.SetValueInt(0)

		StartTimer(10, 255)			;start again LOOP timer		

           EndIf

	EndIf

Well, I didn't have the time to create a more detailed version.. I only put the basics in the plugin and the scripts.. it still needs a lot of improvements.. But I think you're on the right track :smile:

Edited by LarannKiar
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...