Jump to content

Recommended Posts

I think I know how to do this, but it's not working the way I expect it to.

print("Entity Tracker: ", inst.components.entitytracker:GetEntity("leader"))
print("Combat Target: ", inst.components.combat.target)
print("Attacker: ", inst.components.combat.attacker)

I've coded some dogs to follow the player as followers, and when they stop following the player they die.  This was meant to keep the hounds from going feral once the player exits the game.  To my surprise, these hounds 'stop following the player' if the leader punches the dogs.  This has resulted in some of my testers punching and resummoning the dogs for infinite meat.  I'm sort of fixed this by limiting the likelihood of respawning to 80% as well as another punishment, but I figured I'd just make the respawn rate super low if the leader was the attacker.

Well, for some reason the hounds consistently register 'nil' as an attacker.
Does anyone know why this might be?

function Follower:StopFollowing()
    if self.inst:IsValid() then
        self.inst:PushEvent("loseloyalty", { leader = self.leader })
        self:SetLeader(nil)
    end
end

I've been looking through the code to figure out exactly why the hounds stop following the player when punched, but it's a little weird.  I figure they're likely rejecting the player as their leader before registering the player as an attacker, but there may be something else going on, since I think I told the hounds they can't attack the player.

hound_ai.lua

Link to comment
https://forums.kleientertainment.com/forums/topic/127394-detecting-your-attacker/
Share on other sites

2 hours ago, FurryEskimo said:

To my surprise, these hounds 'stop following the player' if the leader punches the dogs.

I've been looking through the code to figure out exactly why the hounds stop following the player when punched, but it's a little weird.  I figure they're likely rejecting the player as their leader before registering the player as an attacker

It's because the combat component has EngageTarget which when the player is starting to punch is considered engagement, and it tries breaking the leader-follower relationship.

Then there's a case in the follower component that also tries to clear the relationship.

But there's a handy function that stops both cases in one call:

hound.components.follower:KeepLeaderOnAttacked()

  • Like 1
  • Health 1

@CarlZalph
Wow, cool!  I'll give that a try soon!

Edit 1:  It appears to be working!

Edit 2:  I actually did manage to figure out a general solution to this.  I can now compare the name of the player against a hound's follower, and vise-versa.  This made it so I can cause a penalty for killing wild hounds or another player's hounds, and a heavier penalty for killing your own, discouraging players from summoning and killing their pet hounds (which has been an issue in the beta, as players could farm hounds for food.)

local function onkilled(inst, data)  --Negative sanity penalty when you kill hounds.
	print("Hound killed!")  --Test code.
	local victim = data.victim
	if victim and victim:HasTag("hound") and not victim:HasTag("companion") then
		print("Killed a wild hound.")  --Test code.
		inst.components.sanity:DoDelta(victim.sanityreward or -TUNING.SANITY_SMALL)
		--Note: Tiny=5 Sanity, Small=10 Sanity, Med=15 Sanity, MED_LARGE=XXX Sanity, Large=33 Sanity, Huge=50 Sanity, Superhuge=XXX Sanity

	elseif victim and victim:HasTag("hound") and victim:HasTag("companion") then
		if inst.name == victim.components.follower.leader.name then
			print("Killed your own trained hound.")  --Test code.
			inst.components.sanity:DoDelta(victim.sanityreward or -TUNING.SANITY_MED)
			--Note: Tiny=5 Sanity, Small=10 Sanity, Med=15 Sanity, MED_LARGE=XXX Sanity, Large=33 Sanity, Huge=50 Sanity, Superhuge=XXX Sanity

		else
			print("Killed someone else's trained hound.")  --Test code.
			inst.components.sanity:DoDelta(victim.sanityreward or -TUNING.SANITY_SMALL)
			--Note: Tiny=5 Sanity, Small=10 Sanity, Med=15 Sanity, MED_LARGE=XXX Sanity, Large=33 Sanity, Huge=50 Sanity, Superhuge=XXX Sanity
		end
		print("Player's name: ", inst.name)  --Test code.
		print("Victim's Leader: ", victim.components.follower.leader.name)
	end
end

I've reviewing this old hound AI code though and wow, it's a little weird.  The hounds are generally well behaved, but they can get into fights with one another, and PvP with the hounds wasn't possible before now.  I think I can tell them not to attack targets with the same leader as they have, but for some reason I can't remember what code prevents the hounds attacking players..  I was hoping to remove that code and replace it with new, updated code.

		if inst.components.combat then
			-- Prevent hounds from attacking other players
			local targetfn_orig = inst.components.combat.targetfn
			local targetfn_new = function(inst)
				local target = nil
				-- Choose target normally
				if targetfn_orig then
					target = targetfn_orig(inst)
				end
				-- Check if this hound has a hound tamer as a leader.
				if target ~= nil and inst.components.follower and inst.components.follower.leader and inst.components.follower.leader:HasTag("player") then
					-- Check if target should be kept  Note: Hounds are mostly useless in PvP?
					if target:HasTag("player")
					or target:HasTag("companion")
				--	or target:HasTag("trainedhound")  --Redundant?
					or target:HasTag("character")  --Prevents hounds starting fights with pigs, bunnymen, and rock lobsters, but they will still attack trained hounds.
					or target:AddTag("largecreature")  --Usually prevents hounds starting fights with larger enemies, like beefalo.  --Note: Hounds attacking targets (like birds) very close to a beefalo often go on to attack the beefalo.
				--	or target:AddTag("epic")  --Prevents hounds starting fights with giants, but these are also taged with 'largecreature' so this would be redundant.
					or target:HasTag("insect")  --Prevents hounds starting fights with bees, mosquitos, and butterflies.  This is mostly to prevent hounds resulting in endless loot when players stand next to flowers.
					or target:HasTag("hive")  --Prevents hounds attacking beehives, spider dens.
				--	or target:HasTag("prey")
				--	or target:HasTag("structure")
				--	or target.name == inst.components.follower.leader.name  --Test code.
						--Note: Walruses have the tag 'houndfriend', meaning they may be partially immune to these trained hounds.
					then
						print("Hound's Target: Not Valid")
						print("Target's Name: ", target.name)  --Test code.
						print("Hound's Leader's Name: ", inst.components.follower.leader.name)
						target = nil
					else
						print("Hound's Target: Valid")
						print("Target's Name: ", target.name)  --Test code.
						print("Hound's Leader's Name: ", inst.components.follower.leader.name)
					end
				end

				return target
			end
			inst.components.combat.targetfn = targetfn_new

			local ShareTarget_prev = inst.components.combat.ShareTarget
			function inst.components.combat:ShareTarget(target, ...)
				-- Share target normally if being led by someone other than hound tamer.
				if inst.components.follower and inst.components.follower.leader and not inst.components.follower.leader:HasTag("player") then
					return ShareTarget_prev(self, target, ...)
				end
				-- Prevents hound tamers from being shared as a target.
				if target:HasTag("houndtamer") then  --Note: "inst.components.follower.leader.name == target.components.follower.leader.name"
					return
				end
				-- Prevents players and companions from being shared as a target.
				if target:HasTag("player")
				or target:HasTag("companion")
				then
					local houndtamer = GLOBAL.FindEntity(inst, 20, function(guy)
						return guy:HasTag("houndtamer")
					end)
					if houndtamer ~= nil then
						return
					end
				end
				return ShareTarget_prev(self, target, ...)
			end

		end

My memory is hazy, but I thought I coded it to act normally with normally hounds, not to pick fights with players or big monsters, and not to gang up on players if a fight did start.

hound_ai.lua

Edited by FurryEskimo

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...