Jump to content

Trouble with despawning follower


Recommended Posts

Hi, there! I want my follower to die when the leader attacks him or to despawn when the leader logs out. I wanted to use abigail's code when she gets attacked, but I realised that my follower stops following when getting attacked and that it wouldn't make it despawn when logging out anyway.

 

Any ideas? :)

 

(Sorry for posting so much)

Link to comment
Share on other sites

--wurm.lua

local function onattacked(inst, data)
	if data.attacker == inst.components.follower:GetLeader() then
		inst.components.health:Kill()
	else
		inst.components.combat:SetTarget(data.attacker)
		inst.components.combat:ShareTarget(data.attacker, 30, 
			function(friend)
              return not friend.components.health:IsDead()
                  and friend.components.follower ~= nil
                  and friend.components.follower.leader == inst.components.follower.leader
			end, 10)
	end
		
end

-- main function

inst:ListenForEvent("attacked", onattacked)

and in the previous listening for "stopfollowing" do

--under local wurmleader = data.leader

inst:DoTaskInTime(0.5, --wait a bit to make sure the leader is nil (not positive on how much this actually works)
function()
	if wurmleader == nil then
	inst:Remove()-- or inst.components.health:Kill()
	end
end)

--note, this would probably only work on dedicated servers or clients, since as a host, the server would just close

-- you could add this to the main function to make it disappear when the server closes
inst.persists = false

 

Edited by Aquaterion
Link to comment
Share on other sites

@Aquaterion Thank you for replying again :)

Sorry, it doesn't work. To be clear, I put the local function onattacked in the lua, thought of listening for the event in the main function and for the stopfollowing I did this :    inst:ListenForEvent("stopfollowing", 

    function(inst, data)
        local wurmleader = data.leader
      if wurmleader ~= nil and not wurmleader:HasTag("wurm_thibaud_builder") then
      -- print("Game knows wurmleader can't craft wurms")
        local wurms = wurmleader.components.leader:CountFollowers("wurm")
        -- print("Game counts followers again")

        if wurmleader.components.leader:CountFollowers("wurm") < 4 then
        -- print("Game knows there are less than 4 followers")
            wurmleader:AddTag("wurm_thibaud_builder")
            -- print("Character is now able to craft wurms again")
        end
      end
    
    inst:DoTaskInTime(0.5, --wait a bit to make sure the leader is nil (not positive on how much this actually works)
    function()
    if wurmleader == nil then
        inst:Remove()-- or inst.components.health:Kill()
    end
end)
    end)

And this is exactly how the code is set up, the forum didn't make any spacing mistakes :)

Link to comment
Share on other sites

Just now, Thibooms said:

@Aquaterion Thank you for replying again :)

Sorry, it doesn't work. To be clear, I put the local function onattacked in the lua, thought of listening for the event in the main function and for the stopfollowing I did this :    inst:ListenForEvent("stopfollowing", 


    function(inst, data)
        local wurmleader = data.leader
      if wurmleader ~= nil and not wurmleader:HasTag("wurm_thibaud_builder") then
      -- print("Game knows wurmleader can't craft wurms")
        local wurms = wurmleader.components.leader:CountFollowers("wurm")
        -- print("Game counts followers again")

        if wurmleader.components.leader:CountFollowers("wurm") < 4 then
        -- print("Game knows there are less than 4 followers")
            wurmleader:AddTag("wurm_thibaud_builder")
            -- print("Character is now able to craft wurms again")
        end
      end
    
    inst:DoTaskInTime(0.5, --wait a bit to make sure the leader is nil (not positive on how much this actually works)
    function()
    if wurmleader == nil then
        inst:Remove()-- or inst.components.health:Kill()
    end
end)
    end)

And this is exactly how the code is set up, the forum didn't make any spacing mistakes :)

so what didn't work? both? or the despawn on leave? did you see the inst.persists things?

Link to comment
Share on other sites

1 minute ago, Aquaterion said:

so what didn't work? both? or the despawn on leave? did you see the inst.persists things?

Both, sadly. Forgot about the inst.persists, doing it now

Edit: Ok, the despawning upon logging out now works. But will this then not work when hosting a normal server?

Edited by Thibooms
Link to comment
Share on other sites

Just now, Aquaterion said:

You sure the onattacked thing didn't work? because I have it for mine and it works just fine, you could try inst:Remove() instead of the inst......Kill()

Yeah I'm sure it didn't work. Don't know why though.

Again, to be clear, this is what I got.

 

In the lua

local function onattacked(inst, data)
    if data.attacker == inst.components.follower:GetLeader() then
        inst.components.health:Kill()
    else
        inst.components.combat:SetTarget(data.attacker)
        inst.components.combat:ShareTarget(data.attacker, 30, 
            function(friend)
              return not friend.components.health:IsDead()
                  and friend.components.follower ~= nil
                  and friend.components.follower.leader == inst.components.follower.leader
            end, 10)
    end
        
end

In the main function

    inst:ListenForEvent("attacked", onattacked)

 

Link to comment
Share on other sites

Just now, Thibooms said:

Yeah I'm sure it didn't work. Don't know why though.

Again, to be clear, this is what I got.

 

In the lua


local function onattacked(inst, data)
    if data.attacker == inst.components.follower:GetLeader() then
        inst.components.health:Kill()
    else
        inst.components.combat:SetTarget(data.attacker)
        inst.components.combat:ShareTarget(data.attacker, 30, 
            function(friend)
              return not friend.components.health:IsDead()
                  and friend.components.follower ~= nil
                  and friend.components.follower.leader == inst.components.follower.leader
            end, 10)
    end
        
end

In the main function


    inst:ListenForEvent("attacked", onattacked)

 

that's all in the wurm.lua right?

well add some prints to see if it's even getting there

print("Onattacked")

print(data.attacker)

Link to comment
Share on other sites

3 minutes ago, Aquaterion said:

that's all in the wurm.lua right?

Yes

3 minutes ago, Aquaterion said:

well add some prints to see if it's even getting there

I guess it's not getting there but I'll try the prints now :)

FYI: I tried by replacing the kill by

inst:Remove()

and then I tried

inst.components.health:SetVal(0)

 

Edit: Ok so I see this in the log (I attacked the thing to death)


[00:00:48]: onattacked function gets called    
[00:00:49]: onattacked function gets called    
[00:00:49]: onattacked function gets called    
[00:00:52]: onattacked function gets called    
[00:00:52]: onattacked function gets called    
 

I printed by adding 

print("onattacked function gets called")

directly under the function, before the if

 

 

Edited by Thibooms
Link to comment
Share on other sites

Just now, Thibooms said:

Where do I put this?

client_log.txt

[00:00:47]: onattacked function gets called    
[00:00:48]: onattacked function gets called    
[00:00:49]: onattacked function gets called    
[00:00:49]: onattacked function gets called    
[00:00:52]: onattacked function gets called    
[00:00:52]: onattacked function gets called   

seems like it is getting called

and its print(data.attacker), without the " ", put it right below the other 1, its to print the attacker, to check if for some reason hes nil

Link to comment
Share on other sites

[00:00:44]: onattacked function gets called    
[00:00:44]: 110793 - thibaud    
[00:00:45]: onattacked function gets called    
[00:00:45]: 110793 - thibaud    
[00:00:46]: onattacked function gets called    
[00:00:46]: 110793 - thibaud    
[00:00:46]: onattacked function gets called    
[00:00:46]: 110793 - thibaud    
[00:00:47]: onattacked function gets called    
[00:00:47]: 110793 - thibaud    
[00:00:47]: onattacked function gets called    
[00:00:47]: 110793 - thibaud    

 

client_log.txt

 

Don't know what this means ^^

I made sure to not put the " "

Edited by Thibooms
Link to comment
Share on other sites

Just now, Thibooms said:

[00:00:44]: onattacked function gets called    
[00:00:44]: 110793 - thibaud    
[00:00:45]: onattacked function gets called    
[00:00:45]: 110793 - thibaud    
[00:00:46]: onattacked function gets called    
[00:00:46]: 110793 - thibaud    
[00:00:46]: onattacked function gets called    
[00:00:46]: 110793 - thibaud    
[00:00:47]: onattacked function gets called    
[00:00:47]: 110793 - thibaud    
[00:00:47]: onattacked function gets called    
[00:00:47]: 110793 - thibaud    

 

client_log.txt

 

Don't know what this means ^^

I made sure to not put the " "

wait, do you have a character called thibaud? because if you do, then that's normal, can you put another print in the "if" as well?

Link to comment
Share on other sites

Just now, Aquaterion said:

wait, do you have a character called thibaud? because if you do, then that's normal, can you put another print in the "if" as well?

Yes I do. I added the print in the if :)

I don't see anything about the if print though. It put it like this :

local function onattacked(inst, data)
print("onattacked function gets called")
print(data.attacker)
    if data.attacker == inst.components.follower:GetLeader() then
    print("the if got fired")

client_log.txt

Link to comment
Share on other sites

if inst.components.follower:GetLeader() == nil then
	inst:Remove() -- or kill
end

Oh wait, I just realised what it is, change the "if" to the one above ^

 

It wasnt working because the follower component makes it that if a follower is attacked by its owner, it stops "following" it, so the leader was always being nil, and to combat that, we'll check if it has a leader instead.

 

Link to comment
Share on other sites

1 minute ago, Aquaterion said:

if inst.components.follower:GetLeader() == nil then
	inst:Remove() -- or kill
end

Oh wait, I just realised what it is, change the "if" to the one above ^

 

It wasnt working because the follower component makes it that if a follower is attacked by its owner, it stops "following" it, so the leader was always being nil, and to combat that, we'll check if it has a leader instead.

 

Oh that's a cool way of doing it. Thanks! Works now :)

Link to comment
Share on other sites

4 minutes ago, Thibooms said:

Oh that's a cool way of doing it. Thanks! Works now :)

what the weird thing is, technically, when you attack it, "stopfollowing" should have been triggered, making it despawn at 0.5 seconds.. hmmm

Can you comment the onattack thing for now and try this?(you only need to comment the listener part)

--change the "if" in the "inst:DoTaskInTime()" to this:

    if inst.components.follower:GetLeader() == nil then
        inst:Remove()-- or inst.components.health:Kill()
    end

 

Edited by Aquaterion
Link to comment
Share on other sites

9 minutes ago, Aquaterion said:

what the weird thing is, technically, when you attack it, "stopfollowing" should have been triggered, making it despawn at 0.5 seconds.. hmmm

Can you comment the onattack thing for now and try this?(you only need to comment the listener part)


--change the "if" in the "inst:DoTaskInTime()" to this:

    if inst.components.follower:GetLeader() == nil then
        inst:Remove()-- or inst.components.health:Kill()
    end

 

Yeah That works, it dies after half a second (like you'd think it does). So best to keep this then? Which one do you think is most practical when coding (if I want to add anything, which I don't at the moment)

Link to comment
Share on other sites

Just now, Thibooms said:

Yeah That works, it dies after half a second (like you'd think it does). So best to keep this then? Which one do you think is most practical when coding (if I want to add anything, which I don't at the moment)

you could probably lower the time to like 0.1 or 0.2

The new DoTaskInTime would be required in multiplayer I believe so that 1 will have to stay, and the other, well its kinda pointless if its gonna get removed before anyways, although I also put some code in there for targetting, sharing targets with friendly followers and not attacking friendlies, so just remove the inst:remove() line from the onattacked

 

BTW, You should probably try making your forum titles less specific, that way you don't have to do  4-5 topics for 1 creature :p

Edited by Aquaterion
Link to comment
Share on other sites

Just now, Aquaterion said:

you could probably lower the time to like 0.1 or 0.2

Actually that's only annoying when using Remove. With kill it dies just fine (which sounds awkard to say)

 

Just now, Aquaterion said:

The new DoTaskInTime would be required in multiplayer I believe so that 1 will have to stay, and the other, well its kinda pointless if its gonna get removed before anyways, although I also put some code in there for targetting, sharing targets with friendly followers and not attacking friendlies, so just remove the inst:remove() line from the onattacked

Ok, thanks :)

 

Just now, Aquaterion said:

BTW, You should probably try making your forum titles less specific, that way you don't have to do  4-5 topics for 1 creature :p

Yeah sorry but every single time I'm done with one topic I think of another thing I forgot x). I'll try being less specific next time ^^

Thank you so much :D

Link to comment
Share on other sites

 

@Aquaterion Hi man sorry to bother you by pushing this notification but I thought it was best to do this rather than to make another post on this same damn creature. I promise this is the last thing! ^^'

 

So I wanted him to explode when getting attacked, which I managed to code by myself (yay me)!

But I'm having a little trouble making him attack back. Right now, he will GO to a creature that attacks him or that the leader attacks but he WIL NOT actually attack (opponent doesn't go to "hit" state). Here's the code I used (that I got from an old mod I made, but someone coded for me) along with some questions (because I've forgotten how it works :

This gets fired by the "attacked" event

local function attackback(inst, data)
    inst.components.combat:SetTarget(data.attacker) -- The Wurm sets the target (guy who attacked him)?
    inst.components.combat:ShareTarget(data.attacker, 30,function(dude) -- Here the wurm is supposed to go after the same guy the leader attacks?
        return dude:HasTag("paperdrawing") and not dude:HasTag("player") and not dude.components.health:IsDead() -- The Wurm makes sure it's not attacking a Wurm or player or something that's dead?
    end, 5) -- What's this 5? (Also, what's the 30 above?)
end

This is how I made sure he should be able to do damage (main function)

    inst:AddComponent("combat")
    inst.components.combat:SetDefaultDamage(TUNING.KOALEFANT_DAMAGE)

This is in the stategraph and originally comes from the koealefant :

    State{
        name = "attack",
        tags = {"attack"},
        
        onenter = function(inst)    
            -- inst.SoundEmitter:PlaySound("dontstarve/creatures/koalefant/angry")
            inst.components.combat:StartAttack()
            inst.components.locomotor:StopMoving()
            inst.AnimState:PlayAnimation("attack_down") --this said "atk_pre"
            inst.AnimState:PushAnimation("attack_down", false) -- this said "atk"
        end,
        
        
        timeline=
        {
            TimeEvent(15*FRAMES, function(inst) inst.components.combat:DoAttack() end), -- What's this?
        },
        
        events=
        {
            EventHandler("animqueueover", function(inst) inst.sg:GoToState("idle") end), -- What's this?
        },
    },   

And this is the brain :

require "behaviours/follow"
require "behaviours/wander"

local MIN_FOLLOW = 0
local MAX_FOLLOW = 8
local MED_FOLLOW = 6
local MAX_WANDER_DIST = 10
local MAX_CHASE_TIME = 6

--Here we create a new brain 
local wurm_thibaudbrain = Class(Brain, function(self, inst)
    Brain._ctor(self, inst)
    self.mytarget = nil
end)

function wurm_thibaudbrain:SetTarget(target)
    self.listenerfunc = function() self.mytarget = nil end
    if target ~= self.target then
        if self.mytarget then
            self.inst:RemoveEventCallback("onremove", self.listenerfunc, self.mytarget)
        end
        if target then
            self.inst:ListenForEvent("onremove", self.listenerfunc, target)
        end
    end
    self.mytarget = target
end


--This function sets up our brain's 'behavior tree'.  A behavior tree is just a prioritized list of behaviors.  
--In this case, our creature's first priority is always to runaway and it's second priority is to stand around 
--looking pretty.  You can find more behaviours in the game's data/scripts/behaviours folder.
function wurm_thibaudbrain:OnStart()

    --Some behavior trees have multiple priority nodes.  Ours has a single node with two behaviours.    
    local root = PriorityNode(
    {
        ChaseAndAttack(self.inst, MAX_CHASE_TIME),
        Follow(self.inst, function() return self.inst.components.follower.leader end, MIN_FOLLOW, MED_FOLLOW, MAX_FOLLOW, true),
        Wander(self.inst, function() if self.mytarget then return Point(self.mytarget.Transform:GetWorldPosition()) end end, MAX_WANDER_DIST)        
    --This tells the creature to check every 1 second if it should be changing which behaviour it's doing.
    }, 1)
    
    --Now we attach the behaviour tree to our brain.
    self.bt = BT(self.inst, root)
    
end

--Register our new brain so that it can later be attached to any creature we create.
return wurm_thibaudbrain

 

I hope you can help when you have the time of course :)

Edited by Thibooms
Link to comment
Share on other sites

I had this problem too, this is what DarkXero told me to do to fix it:

--wurm.lua

local function doattack(inst, data)
	--inst.sg:GoToState("attack", data.target)
	
	if inst.components.health and not inst.components.health:IsDead() and (not inst.sg:HasStateTag("busy") or inst.sg:HasStateTag("hit")) then
		local buffered_attack = BufferedAction(inst, data.target, ACTIONS.ATTACK)
		inst:PushBufferedAction(buffered_attack)
	end

end

--main function
inst:ListenForEvent("doattack", doattack)

 

Link to comment
Share on other sites

1 minute ago, Aquaterion said:

this is what DarkXero told me to do to fix it:

I told you that because you required a buffered action to properly use the attack state of the wilson stategraph.

If you guys are using the attack state of a koalefant, and the ChaseAndAttack behaviour, use the doattack handler like:

EventHandler("doattack", function(inst)
	if not inst.components.health:IsDead() then
		inst.sg:GoToState("attack")
	end
end),

 

Link to comment
Share on other sites

Just now, DarkXero said:

I told you that because you required a buffered action to properly use the attack state of the wilson stategraph.

If you guys are using the attack state of a koalefant, and the ChaseAndAttack behaviour, use the doattack handler like:


EventHandler("doattack", function(inst)
	if not inst.components.health:IsDead() then
		inst.sg:GoToState("attack")
	end
end),

 

yea when I was copying it I was like im sure he said something about mine being specific, but I forgot, mostly why I mentioned you

Link to comment
Share on other sites

Give me a second :)

11 minutes ago, DarkXero said:

I told you that because you required a buffered action to properly use the attack state of the wilson stategraph.

If you guys are using the attack state of a koalefant, and the ChaseAndAttack behaviour, use the doattack handler like:


EventHandler("doattack", function(inst)
	if not inst.components.health:IsDead() then
		inst.sg:GoToState("attack")
	end
end),

 

Ok, great, thanks that works. Although the creature becomes invisible now, but that's probably a problem on animation which I'll fix tomorrow for sure. Thank you very much for helping

 

Edit: @DarkXero It's actually really confusing me why that happens. The attack state seems fine regarding animation. Is it because of the pre attack thing? (My attack animation in spriter is called "attack_down")

 

18 minutes ago, Aquaterion said:

I had this problem too, this is what DarkXero told me to do to fix it:


--wurm.lua

local function doattack(inst, data)
	--inst.sg:GoToState("attack", data.target)
	
	if inst.components.health and not inst.components.health:IsDead() and (not inst.sg:HasStateTag("busy") or inst.sg:HasStateTag("hit")) then
		local buffered_attack = BufferedAction(inst, data.target, ACTIONS.ATTACK)
		inst:PushBufferedAction(buffered_attack)
	end

end

--main function
inst:ListenForEvent("doattack", doattack)

 

Thanks for trying to help, as always :D

Edited by Thibooms
Link to comment
Share on other sites

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
 Share

×
  • Create New...