Jump to content

(Help) Trying to let a koalefant chop trees


Recommended Posts

Hello, I have this code that allows me to turn koalefants into followers, spawning a new "copy" of the koalefant so I can do specific stuff with it. I tried to make them chop trees like pigs do, when the leader chops trees as well.

 

I've had a look at the piggy files, including brain and this is what I got.

 

In the follower's prefab lua I put at the very top : 

local function SuggestTreeTarget(inst, data)    if data and data.tree and inst:GetBufferedAction() ~= ACTIONS.CHOP then        inst.tree_target = data.tree    endend

 

Then I have the function making the actual koalefant (listing its anime, health, locomoter, etc) and in it I have : 

inst:ListenForEvent("suggest_tree_target", SuggestTreeTarget)

 

And I've got this in the brain (which I did specify in the script, saying "require brain...") for the chopping :

local function KeepChoppingAction(inst)    local keep_chop = inst.components.follower.leader and inst.components.follower.leader:GetDistanceSqToInst(inst) <= KEEP_CHOPPING_DIST*KEEP_CHOPPING_DIST    local target = FindEntity(inst, SEE_TREE_DIST/3, function(item)        return item.prefab == "deciduoustree" and item.monster and item.components.workable and item.components.workable.action == ACTIONS.CHOP     end)        if inst.tree_target ~= nil then target = inst.tree_target end    return (keep_chop or target ~= nil)endlocal function StartChoppingCondition(inst)    local start_chop = inst.components.follower.leader and inst.components.follower.leader.sg and inst.components.follower.leader.sg:HasStateTag("chopping")    local target = FindEntity(inst, SEE_TREE_DIST/3, function(item)         return item.prefab == "deciduoustree" and item.monster and item.components.workable and item.components.workable.action == ACTIONS.CHOP     end)    if inst.tree_target ~= nil then target = inst.tree_target end        return (start_chop or target ~= nil)endlocal function FindTreeToChopAction(inst)    local target = FindEntity(inst, SEE_TREE_DIST, function(item) return item.components.workable and item.components.workable.action == ACTIONS.CHOP end)    if target then        local decid_monst_target = FindEntity(inst, SEE_TREE_DIST/3, function(item)            return item.prefab == "deciduoustree" and item.monster and item.components.workable and item.components.workable.action == ACTIONS.CHOP         end)        if decid_monst_target ~= nil then             target = decid_monst_target         end        if inst.tree_target then             target = inst.tree_target            inst.tree_target = nil         end        return BufferedAction(inst, target, ACTIONS.CHOP)    endend

 

And it's also listed in here like pigs do (I know there's a pig talker in there, I put it in just so I could test the thing out) :

function FollowerBrain:OnStart()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),IfNode(function() return StartChoppingCondition(self.inst) end, "chop",                 WhileNode(function() return KeepChoppingAction(self.inst) end, "keep chopping",                    LoopNode{                         ChattyNode(self.inst, STRINGS.PIG_TALK_HELP_CHOP_WOOD,                            DoAction(self.inst, FindTreeToChopAction ))})),}, 1)            self.bt = BT(self.inst, root)end

 

So, to sum up, the follower itself is working and everything BUT the chopping isn't. I guess that it's lacking some information like the anim. If that's the case by the way, I just want them to use their attack animation.

 

Does anyone know what to do to make this work? What's missing?

 

Thank you for your time!  :-)

 

Edit: I only have this in the require behaviours of the follower's brain, maybe something's missing here?

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

 

Edited by Thibooms
Link to comment
Share on other sites

@Kzisor, I now added a new stategraph for the koalefantfollower. I did this by copying everything frm the original SGkoalefant and assigned the koalefantfollower prefab to it.

 

I added this to it, which I found in the pig's stategraph : 


State{        name = "chop",        tags = {"chopping"},                onenter = function(inst)            inst.Physics:Stop()            inst.AnimState:PlayAnimation("atk")        end,                timeline=        {                        TimeEvent(13*FRAMES, function(inst) inst:PerformBufferedAction() end ),        },                events=        {            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),        },    }, 

It didn't work so I figured changing it to this, comparing the attack state : 

 

State{        name = "chop",        tags = {"chopping"},                onenter = function(inst)            inst.Physics:Stop()            inst.AnimState:PlayAnimation("atk")        end,                timeline=        {                        TimeEvent(15*FRAMES, function(inst) inst.components.combat:DoAttack() end),        },                events=        {            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),        },    },

 

FYI, this is the attack state of a koalefant : 

 


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("atk_pre")            inst.AnimState:PushAnimation("atk", false)        end,                        timeline=        {            TimeEvent(15*FRAMES, function(inst) inst.components.combat:DoAttack() end),        },                events=        {            EventHandler("animqueueover", function(inst) inst.sg:GoToState("idle") end),        },    },    

Later I realized I also needed this : 

local actionhandlers = { ActionHandler(ACTIONS.CHOP, "chop"),}local events={    CommonHandlers.OnStep(),    CommonHandlers.OnLocomote(true,true),    CommonHandlers.OnSleep(),    CommonHandlers.OnFreeze(),    EventHandler("doattack", function(inst) if not inst.components.health:IsDead() then inst.sg:GoToState("attack") end end),    EventHandler("death", function(inst) inst.sg:GoToState("death") end),    EventHandler("attacked", function(inst) if inst.components.health:GetPercent() > 0 and not inst.sg:HasStateTag("attack") then inst.sg:GoToState("hit") end end),EventHandler("doaction",         function(inst, data)             if not inst.components.health:IsDead() and not inst.sg:HasStateTag("busy") then                if data.action == ACTIONS.CHOP then                    inst.sg:GoToState("chop", data.target)                end            end        en

Didn't work either

d),
}

 

I really don't know what to do anymore

 

Edited by Thibooms
Link to comment
Share on other sites

@Thibooms,

put in print("describe the position in the code for yourself here") at different points to find out, what point of the code it reaches.

It obviously starts in the brain, should buffer the action, then, once u reach the target, it should trigger the actionhandler, which should initiate the state.

if u find the point which it doesnt cross, u can ofc also print the variable, to find out why, if u cant figure it out by just reading the code.

Edited by Seiai
Link to comment
Share on other sites

@Thibooms,

yeah, u just add something like print("here the action get buffered") and then u can see that string in the Debugoverlay(Ctrl+L in game) and in the logfile.

its just a regular functioncall, so u can place it pretty freely.

to give u an example from an Eventhandler above:

EventHandler("doaction",         function(inst, data)             if not inst.components.health:IsDead() and not inst.sg:HasStateTag("busy") then                if data.action == ACTIONS.CHOP then                    inst.sg:GoToState("chop", data.target)                end            end        en
to check how far u get:

EventHandler("doaction",         function(inst, data)         print("ok, it triggers the handler")            if not inst.components.health:IsDead() and not inst.sg:HasStateTag("busy") then                print("i got into the first if") print(data.action)                if data.action == ACTIONS.CHOP then print("and it goes to the state chop!")                    inst.sg:GoToState("chop", data.target)                end            end        en
Link to comment
Share on other sites

@Isosurface, Yes, I do. At the very top, after 

require("stategraphs/commonstates")

.

local actionhandlers = { ActionHandler(ACTIONS.CHOP, "chop"),}

@Seiai, Tried it and tried comparing pigs and mods to see what I'm missing but it won't show up. I didn't see any string I set up.

 

I don't know what's wrong, honestly. Would you like me to upload any files? 

Edited by Thibooms
Link to comment
Share on other sites

@Seiai, Ok. Here's the code, starting with the stategraph (I'm going to try to skip as much unrelevant code as I can) : 

 


require("stategraphs/commonstates")local actionhandlers = { ActionHandler(ACTIONS.CHOP, "chop"),}local events={    CommonHandlers.OnStep(),    CommonHandlers.OnLocomote(true,true),    CommonHandlers.OnSleep(),    CommonHandlers.OnFreeze(),    EventHandler("doattack", function(inst) if not inst.components.health:IsDead() then inst.sg:GoToState("attack") end end),    EventHandler("death", function(inst) inst.sg:GoToState("death") end),    EventHandler("attacked", function(inst) if inst.components.health:GetPercent() > 0 and not inst.sg:HasStateTag("attack") then inst.sg:GoToState("hit") end end),EventHandler("doaction",         function(inst, data)print("it triggers the handler")            if not inst.components.health:IsDead() and not inst.sg:HasStateTag("busy") then print("i got into the first if")                if data.action == ACTIONS.CHOP then print("and it goes to the state chop")                    inst.sg:GoToState("chop", data.target)                end            end        end),}

   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("atk_pre")            inst.AnimState:PushAnimation("atk", false)        end,                        timeline=        {            TimeEvent(15*FRAMES, function(inst) inst.components.combat:DoAttack() end),        },                events=        {            EventHandler("animqueueover", function(inst) inst.sg:GoToState("idle") end),        },    },   State{        name = "chop",        tags = {"chopping"},                onenter = function(inst)            inst.Physics:Stop()            inst.AnimState:PlayAnimation("atk")        end,                timeline=        {                        TimeEvent(15*FRAMES, function(inst) inst:PerformBufferedAction() end ),        },                events=        {            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),        },    },

return StateGraph("koalefantfollower", states, events, "idle", actionhandlers)

So I added some prints as you can see. To test it, I had a koalefant follower with me and tried chopping a tree. No effect.

 

I have this in the koalefantfollower's lua to make it use the brain and the stategraph : 

local brain = require "brains/koalefantfollowerbrain"

inst:SetBrain(brain)inst:SetStateGraph("SGkoalefantfollower")

And also this so it enables the tree targeting :

inst:ListenForEvent("suggest_tree_target", SuggestTreeTarget)

 

And I use the following in the brain for chopping : 

require "behaviours/doaction"

local function KeepChoppingAction(inst)    local keep_chop = inst.components.follower.leader and inst.components.follower.leader:GetDistanceSqToInst(inst) <= KEEP_CHOPPING_DIST*KEEP_CHOPPING_DIST    local target = FindEntity(inst, SEE_TREE_DIST/3, function(item)        return item.prefab == "deciduoustree" and item.monster and item.components.workable and item.components.workable.action == ACTIONS.CHOP     end)        if inst.tree_target ~= nil then target = inst.tree_target end    return (keep_chop or target ~= nil)endlocal function StartChoppingCondition(inst)    local start_chop = inst.components.follower.leader and inst.components.follower.leader.sg and inst.components.follower.leader.sg:HasStateTag("chopping")    local target = FindEntity(inst, SEE_TREE_DIST/3, function(item)         return item.prefab == "deciduoustree" and item.monster and item.components.workable and item.components.workable.action == ACTIONS.CHOP     end)    if inst.tree_target ~= nil then target = inst.tree_target end        return (start_chop or target ~= nil)endlocal function FindTreeToChopAction(inst)    local target = FindEntity(inst, SEE_TREE_DIST, function(item) return item.components.workable and item.components.workable.action == ACTIONS.CHOP end)    if target then        local decid_monst_target = FindEntity(inst, SEE_TREE_DIST/3, function(item)            return item.prefab == "deciduoustree" and item.monster and item.components.workable and item.components.workable.action == ACTIONS.CHOP         end)        if decid_monst_target ~= nil then             target = decid_monst_target         end        if inst.tree_target then             target = inst.tree_target            inst.tree_target = nil         end        return BufferedAction(inst, target, ACTIONS.CHOP)    endend

I have this in the FollowerBrain:OnStart() function : 

IfNode(function() return StartChoppingCondition(self.inst) end, "chop",                 WhileNode(function() return KeepChoppingAction(self.inst) end, "keep chopping",                    LoopNode{                                                     DoAction(self.inst, FindTreeToChopAction )})),

Edited by Thibooms
Link to comment
Share on other sites

So I added some prints as you can see. To test it, I had a koalefant follower with me and tried chopping a tree. No effect.

no effect as in no prints, or no prints AND no chopping?

if he doesnt even chop, then his brain doesnt tell him too, u should add print in relevant functions in the brain to check whats goin on.

btw, where did u take the relevant code for the brain and the stategraph from?

Edited by Seiai
Link to comment
Share on other sites

The wander behaviour has to be the last behaviour in any brain.

Or else, contained in an IfNode.

Because every time you get to a wander behaviour, you run it, so everything down that is inaccessible.

 

Put the chopping behaviour between Follow and Wander.

Link to comment
Share on other sites

The wander behaviour has to be the last behaviour in any brain.

ah yeah, thats the main problem. if u put prints in your brain like that, u would still get nothing cause he never even tries to chop, cause hes busy wandering^^

also, @DarkXero, yourcodeglommer is cut off on the top :razz:

Edited by Seiai
Link to comment
Share on other sites

no effect as in no prints, or no prints AND no chopping?

No prints AND no chopping :p

 

btw, where did u take the relevant code for the brain and the stategraph from?

From the pig files. I later also compared with the DS mod "Helpful Spiders" (to see if something was missing because it obviously wasn't working) that basically does what I want to do to koalefants to spiders.

 

 

@DarkXero, Thanks, Dark! Can't believe it was something so stupid! :D

 

 

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...