Jump to content

Trying to turn Frogs into Followers, help with behavior nodes?


Recommended Posts

Hello! I'm trying to change frog behavior so that they will:
a) Be passive towards prefabs with the "froggyfren" tag
b) Follow the player if they have aforementioned tag as well as fed them popcorn (more trade than fed, since they don't have an eat anim)
c) Defend the player when attacked, or when leader/player is attacking an entity

So I've this bit of code in my modmain:

local BrainCommon = require("brains/braincommon")
local Follow = require("behaviours/follow")

AddPrefabPostInit("frog", function(inst)
    local SEE_PLAYER_DIST = 5 -- set to default

    if not inst.components.follower then
        inst:AddComponent("follower")
    end
    
    if not inst.components.trader then
        inst:AddComponent("trader")
        inst.components.trader:SetAcceptTest(function(inst, item)
            return item.prefab == "corn_cooked"
        end)
        inst.components.trader.onaccept = function(inst, giver, item)
            if giver:HasTag("froggyfren") then
                inst.components.follower:SetLeader(giver)
                inst.components.follower:AddLoyaltyTime(TUNING.TOTAL_DAY_TIME)
                giver:PushEvent("makefriend")
                inst.components.follower:StartLeashing()
            end
        end
        inst.components.trader.onrefuse = function(inst, item)
            if inst.components.sleeper and inst.components.sleeper:IsAsleep() then
                inst.components.sleeper:WakeUp()
            end
        end
    end

   local function ModifyFrogBrain(inst)
        if inst.brain then
            function inst.brain:OnStart()
                local root = PriorityNode({
                    IfNode(function() return inst.components.follower and inst.components.follower.leader ~= nil end, "HasLeader",
                        PriorityNode({
                            Follow(inst, function() return inst.components.follower.leader end, 2, 5, 10),  -- Maybe adjust distance buffer, cause of unleashing?
                            WhileNode(function() return inst.components.combat.target ~= nil or (inst.components.follower.leader and inst.components.follower.leader.components.combat and inst.components.follower.leader.components.combat.target) end, "DefendLeader",
                                ChaseAndAttack(inst, SpringCombatMod(MAX_CHASE_TIME), SpringCombatMod(MAX_CHASE_DIST))),
                        }, 0.5)),
                }, .25)
                
                self.bt = BT(inst, root)
            end
            inst.brain:OnStart()  -- Reinitialize the brain with the new logic
        end
    end

    ModifyFrogBrain(inst)

    inst:ListenForEvent("entitywake", function(inst)
        if inst.components.follower.leader and not inst:IsNear(inst.components.follower.leader, 3) then
            inst.components.follower:SetLeader(nil)
            inst.components.follower:StopLeashing()
        end
    end)

    inst:ListenForEvent("loseloyalty", function(inst)
        if inst.components.follower then
            inst.components.follower:StopLeashing()
        end
    end)

    local RETARGET_MUST_TAGS = { "_combat", "_health" }
    local RETARGET_CANT_TAGS = { "merm", "froggyfren" }
    local LUNAR_RETARGET_CANT_TAGS = { "merm", "lunar_aligned", "froggyfren" }

    inst.components.combat:SetRetargetFunction(3, function(inst)
        if not inst.components.health:IsDead() and inst.components.follower and inst.components.follower.leader then
            local leader = inst.components.follower.leader
            local target_dist = SEE_PLAYER_DIST
            local leader_target = leader.components.combat and leader.components.combat.target or nil
            if leader_target then
                return leader_target
            else
                return FindEntity(inst, target_dist, function(guy)
                    return guy.components.inventory ~= nil and not guy:HasTag("froggyfren")
                end, RETARGET_MUST_TAGS, RETARGET_CANT_TAGS)
            end
        end
    end)
end)

Which should make it so that frogs leash and follow the player when fed popcorn. Everything works except for overwriting the frog nodes. Am I doing something wrong in terms of priority, can they just not do this behavior, or do I just have to make another frogbrain.lua and rewrite that, OR do I just turn the frogs into something else when fed popcorn (a longer implementation, but at this point I can't figure out how to make default frogs just.. follow me.)

Any expert help would be appreciated, thank you!

Edited by sournvitriol2
Link to comment
Share on other sites

use a AddBrainPostInit to modify mob brains, or import the brain using require and override its methods. Just use the require method actually, it's much faster.

  • Like 1
Link to comment
Share on other sites

Posted (edited)

Did the require method, but game isn't loading the brain properly. Code as follows:

Modmain:


local ModdedFrogBrain = require("brains/moddedfrogbrain")

AddPrefabPostInit("frog", function(inst)
     local SEE_PLAYER_DIST = 10 
	 
inst:SetBrain(ModdedFrogBrain)
    if inst.brain then
        print("Brain has been set to the frog: ", inst.brain.name)
    else
        print("Failed to set brain to the frog")
    end

    -- Ensure the trader component is set up properly
    if not inst.components.trader then
        inst:AddComponent("trader")
        inst.components.trader:SetAcceptTest(function(inst, item)
            return item.prefab == "corn_cooked" -- Only accept cooked corn
        end)
        
        local playedfriendsfx = false 

        inst.components.trader.onaccept = function(inst, giver, item)
            if not inst.components.follower then
                inst:AddComponent("follower")
            end

            if giver:HasTag("froggyfren") then
                print("Frog is now following the player.")  
                giver.components.leader:AddFollower(inst)
                inst.components.follower:AddLoyaltyTime(480)
                if not playedfriendsfx then
                    giver:PushEvent("makefriend")
                    playedfriendsfx = true -- Trigger UI/sound effects for making a friend
                end
            end
        end
        
        inst.components.trader.onrefuse = function(inst, item)
            if inst.components.sleeper and inst.components.sleeper:IsAsleep() then
                inst.components.sleeper:WakeUp()
            end
        end
    end

    local function DefendLeader(inst)
        local leader = inst.components.follower and inst.components.follower.leader
        if leader and leader.components.combat and leader.components.combat.target then
            return leader.components.combat.target
        end
        return nil
    end

    inst:ListenForEvent("entitywake", function(inst)
        if inst.components.follower and inst.components.follower.leader and not inst:IsNear(inst.components.follower.leader, 3) then
            inst.components.follower:SetLeader(nil)
            inst.components.follower:StopLeashing()
        end
    end)

    inst:ListenForEvent("loseloyalty", function(inst)
        if inst.components.follower then
            inst.components.follower:StopLeashing()
        end
    end)

    local RETARGET_MUST_TAGS = { "_combat", "_health" }
    local RETARGET_CANT_TAGS = { "merm", "froggyfren" }
    local LUNAR_RETARGET_CANT_TAGS = { "merm", "lunar_aligned", "froggyfren" }

    inst.components.combat:SetRetargetFunction(3, function(inst)
        if not inst.components.health:IsDead() and inst.components.follower and inst.components.follower.leader then
            local leader = inst.components.follower.leader
            local target_dist = 30
            local leader_target = leader.components.combat and leader.components.combat.target 
            if leader_target then
                return leader_target
            else
                return FindEntity(inst, target_dist, function(guy)
                    return guy.components.inventory ~= nil and not guy:HasTag("froggyfren")
                end, RETARGET_MUST_TAGS, RETARGET_CANT_TAGS)
            end
        end
    end)
end)

Print return is failstate for brain loading. Could also be an issue with brain logic, so here's moddedfrogbrain.lua:
 

require "behaviours/wander"
require "behaviours/doaction"
require "behaviours/chaseandattack"
require "behaviours/standstill"
require "behaviours/follow"
local BrainCommon = require("brains/braincommon")

local STOP_RUN_DIST = 10
local SEE_PLAYER_DIST = 5
local MAX_WANDER_DIST = 20
local SEE_TARGET_DIST = 6
local MAX_CHASE_DIST = 7
local MAX_CHASE_TIME = 8
local MIN_FOLLOW_DIST = 1
local TARGET_FOLLOW_DIST = 2
local MAX_FOLLOW_DIST = 3

local function GoHomeAction(inst)
    if inst.components.homeseeker and inst.components.homeseeker.home and inst.components.homeseeker.home:IsValid() then
        return BufferedAction(inst, inst.components.homeseeker.home, ACTIONS.GOHOME)
    end
end

local function ShouldGoHome(inst)
    return (not inst.islunar) and (not inst.components.follower or not inst.components.follower.leader) and (not TheWorld.state.isday or TheWorld.state.iswinter)
end

local function ShouldFollowLeader(inst)
    return inst.components.follower and inst.components.follower.leader ~= nil
end

local function GetLeader(inst)
    return inst.components.follower and inst.components.follower.leader
end

local ModdedFrogBrain = Class(Brain, function(self, inst)
    Brain._ctor(self, inst)
end)

function ModdedFrogBrain:OnStart()
    local root = PriorityNode(
    {
        BrainCommon.PanicTrigger(self.inst),
        ChaseAndAttack(self.inst, MAX_CHASE_TIME),
        IfNode(function() return ShouldFollowLeader(self.inst) end, "HasLeader",
            PriorityNode({
                Follow(self.inst, function() return GetLeader(self.inst) end, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST),
                WhileNode(function() 
                    return self.inst.components.combat.target ~= nil or 
                          (GetLeader(self.inst) and GetLeader(self.inst).components.combat and GetLeader(self.inst).components.combat.target) 
                end, "DefendLeader",
                    ChaseAndAttack(self.inst, MAX_CHASE_TIME)),
            }, 0.5)),
        WhileNode(function() return ShouldGoHome(self.inst) end, "ShouldGoHome",
            DoAction(self.inst, function() return GoHomeAction(self.inst) end, "go home", true )),
        WhileNode(function() return not ShouldFollowLeader(self.inst) and not self.inst.islunar end, "DefaultWander",
            Wander(self.inst, function() return self.inst.components.knownlocations:GetLocation("home") end, MAX_WANDER_DIST)),
        StandStill(self.inst, function() return self.inst.sg:HasStateTag("idle") end),
    }, .25)

    self.bt = BT(self.inst, root)
end

return ModdedFrogBrain

Not sure what's the hiccup here. I also tried to set the brain via console, I don't think it was working either. Any help is appreciated.

EDIT: Nevermind. Just made a new frog prefab spawn, and added a function to set a leader via tag when it spawns. But yes, I still haven't made default frogs turn friendly. Could be because of the hostile tag found in frog.lua, the brain logic as it is currently or something along those lines.
 

Edited by Cigg
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...