Jump to content

How to make custom mob neutral?


Recommended Posts

Heya, so I'm making a modded mob for my mod here, which is basically a grass gekko, but doesnt run away and is neutral towards the player. I successfully removed the scared mechanic whenever the player gets near it, but I'm having trouble making the grass gekko clone hostile when hit!

My mob's brain:

Spoiler

require "behaviours/wander"
require "behaviours/faceentity"
require "behaviours/panic"
require "behaviours/runaway"
require "behaviours/leash"
require "behaviours/chaseandattack"
require "behaviours/attackwall"

local BrainCommon = require("brains/braincommon")

local MIN_FOLLOW_DIST = 0
local MAX_FOLLOW_DIST = 25
local TARGET_FOLLOW_DIST = 6
local MAX_WANDER_DIST = 8

local LEASH_RETURN_DIST = 15
local LEASH_MAX_DIST = 30

local MAX_CHASE_TIME = 4
local MAX_CHASE_DIST = 15

local RUN_AWAY_DIST = 6
local STOP_RUN_AWAY_DIST = 10

local AVOID_PLAYER_DIST = 7
local AVOID_PLAYER_STOP = 12

local AVOID_DIST = 7
local AVOID_STOP = 12


local NO_TAGS = {"FX", "NOCLICK", "DECOR","INLIMBO", "stump", "burnt"}

local function GetWanderDistFn(inst)
    return MAX_WANDER_DIST
end

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

function RockroachBrain:OnStart()
    local root =
    PriorityNode(
    {
		WhileNode(function() return self.inst.components.health.takingfiredamage end, "OnFire",
            Panic(self.inst)),
		IfNode(function() return self.inst.components.combat.target ~= nil end, "hastarget",
            AttackWall(self.inst)),
        ChaseAndAttack(self.inst, MAX_CHASE_TIME),
	
        WhileNode( function() return self.inst.components.health.takingfiredamage end, "OnFire", Panic(self.inst)),
        --RunAway(self.inst, "scarytoprey", AVOID_PLAYER_DIST, AVOID_PLAYER_STOP , function() return true end ),
        --RunAway(self.inst, "player", AVOID_DIST, AVOID_STOP, nil, nil, NO_TAGS),
        --Wander(self.inst, function() return self.inst:GetPosition() end, MAX_WANDER_DIST),
        Wander(self.inst, function() return self.inst.components.knownlocations:GetLocation("herd") end, GetWanderDistFn)
    }, .25)
    self.bt = BT(self.inst, root)
end

return RockroachBrain

 


Stagegraph:

Spoiler

require("stategraphs/commonstates")

local actionhandlers =
{
    ActionHandler(ACTIONS.GOHOME, "gohome"),
}

local events =
{
    CommonHandlers.OnSleep(),
    CommonHandlers.OnFreeze(),
    CommonHandlers.OnAttacked(),
    CommonHandlers.OnDeath(),
    CommonHandlers.OnLocomote(false,true),
	
	EventHandler("attacked", function(inst)
        if not inst.components.health:IsDead() then
            inst.sg:GoToState("hit")
        end
    end),
    EventHandler("doattack", function(inst)
        if not (inst.sg:HasStateTag("busy") or inst.components.health:IsDead()) then
            inst.sg:GoToState("attack")
        end
    end),
	
    EventHandler("locomote",
        function(inst)
            if not inst.sg:HasStateTag("idle") and not inst.sg:HasStateTag("moving") then return end

            local is_moving = inst.sg:HasStateTag("moving")
            local is_running = inst.sg:HasStateTag("running")
            local is_idling = inst.sg:HasStateTag("idle")

            local should_move = inst.components.locomotor:WantsToMoveForward()
            local should_run = inst.components.locomotor:WantsToRun()

            if not should_move then
                if not inst.sg:HasStateTag("idle") then
                    if not inst.sg:HasStateTag("running") then
                        inst.sg:GoToState("idle")
                    elseif is_moving then
                        inst.sg:GoToState(is_running and "run_stop" or "walk_stop")
                    else
                        inst.sg:GoToState("idle")
                    end
                end
            elseif should_run then
                if not inst.sg:HasStateTag("running") then
                    inst.sg:GoToState("scare")
                end
            else
                if not inst.sg:HasStateTag("moving") then
                    inst.sg:GoToState("walk_start")
                end
            end
        end),
}

local states=
{
    State{
        name = "idle",
        tags = {"idle", "canrotate"},

        onenter = function(inst)
            inst.components.locomotor:StopMoving()
            if inst.tailGrowthPending then
                inst.sg:GoToState("regrow_tail")
            else
                inst.AnimState:PlayAnimation("idle_loop")
            end
        end,

        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },

    State{
        name = "walk_start",
        tags = {"moving", "canrotate"},

        onenter = function(inst)
            inst.AnimState:PlayAnimation("walk_pre")
        end,

        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("walk") end ),
        },
    },

    State{
        name = "walk",
        tags = {"moving", "canrotate"},

        onenter = function(inst)
            inst.components.locomotor:WalkForward()
            inst.AnimState:PlayAnimation("walk_loop")
        end,
        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("walk") end ),
        },
        timeline=
        {
            TimeEvent(FRAMES, function(inst) PlayFootstep(inst) end),
            TimeEvent(8*FRAMES, function(inst) PlayFootstep(inst) end),
            TimeEvent(15*FRAMES, function(inst) PlayFootstep(inst) end),
            TimeEvent(23*FRAMES, function(inst) PlayFootstep(inst) end),
        },
    },

    State{
        name = "walk_stop",
        tags = {"canrotate"},

        onenter = function(inst)
            inst.components.locomotor:StopMoving()
            inst.AnimState:PlayAnimation("walk_pst")
        end,

        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },
    },

    State{
        name = "run_start",
        tags = {"moving", "canrotate"},

        onenter = function(inst)
            inst.AnimState:PlayAnimation("walk_pre")
        end,

        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("run") end ),
        },
    },

    State{
        name = "scare",
        tags = {"moving", "canrotate","running"},

        onenter = function(inst)
            inst.components.locomotor:StopMoving()
            inst.AnimState:PlayAnimation("tail_off")
        end,
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("run") end ),
        },
        timeline=
        {
            TimeEvent(3*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/together/grass_gekko/tail_off") end),

            TimeEvent(4*FRAMES, function(inst)
                if inst.hasTail then
                    inst.components.lootdropper:SpawnLootPrefab("cutgrass")
                    inst.hasTail = false
                    inst.components.timer:StartTimer("growTail", TUNING.GRASSGEKKO_REGROW_TIME )
                end
            end),

            TimeEvent(15*FRAMES, function(inst) inst.sg:GoToState("run") end),
        },
        onexit = function(inst)
            if not inst.hasTail then
                inst.AnimState:Hide("tail")
            end
        end,
    },

    State{
        name = "run",
        tags = {"moving", "canrotate","running"},

        onenter = function(inst)
            inst.components.locomotor:RunForward()
            inst.AnimState:PlayAnimation("run_loop")
        end,
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("run") end ),
        },
        timeline=
        {
            TimeEvent(FRAMES, function(inst) PlayFootstep(inst) end),
            TimeEvent(8*FRAMES, function(inst) PlayFootstep(inst) end),
            TimeEvent(15*FRAMES, function(inst) PlayFootstep(inst) end),
            TimeEvent(23*FRAMES, function(inst) PlayFootstep(inst) end),
        },
    },

    State{
        name = "run_stop",
        tags = {"canrotate"},

        onenter = function(inst)
            inst.components.locomotor:StopMoving()
            inst.AnimState:PlayAnimation("run_pst")
        end,

        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },
    },

    State{
        name = "regrow_tail",
        tags = {"busy"},

        onenter = function(inst)
            inst.AnimState:PlayAnimation("tail_regrow")
            inst.tailGrowthPending = nil
            inst.AnimState:Show("tail")
            inst.hasTail = true
        end,
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },
        timeline=
        {
            TimeEvent(5*FRAMES, function(inst)
                inst.SoundEmitter:PlaySound("dontstarve/creatures/together/grass_gekko/tail_regrow")
            end),
        },
    },
	
	State{
        name = "attack",
        tags = { "attack" },

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.components.combat:StartAttack()
            inst.AnimState:PlayAnimation("idle_loop")
        end,

        timeline =
        {
            TimeEvent(10 * FRAMES, function(inst)
                inst.SoundEmitter:PlaySound(inst.sounds.attack)
            end),
            TimeEvent(15 * FRAMES, function(inst)
                inst.components.combat:DoAttack()
            end),
        },

        events =
        {
            EventHandler("animover", function(inst)
                inst.sg:GoToState("idle")
            end),
        },
    },
	
	State{
        name = "hit",
        tags = { "busy" },

        onenter = function(inst)
            inst.SoundEmitter:PlaySound(inst.sounds.hit)
            inst.AnimState:PlayAnimation("hit")
            inst.Physics:Stop()
        end,

        events =
        {
            EventHandler("animover", function(inst)
                inst.sg:GoToState("idle")
            end),
        },
    },

    State{
        name = "emerge",
        tags = { "busy" },

        onenter = function(inst)
            inst.components.locomotor:StopMoving()

            local player = inst:GetNearestPlayer()
            if player ~= nil and inst:IsNear(player, 7) then
                inst:FaceAwayFromPoint(player:GetPosition(), true)
            else
                inst.Transform:SetRotation(math.random(360))
            end

            inst.AnimState:PlayAnimation("gecko_pop")
        end,

        timeline =
        {
            TimeEvent(12 * FRAMES, function(inst)
                inst.SoundEmitter:PlaySound("dontstarve/wilson/pickup_reeds")
            end),
            TimeEvent(32 * FRAMES, function(inst)
                inst.SoundEmitter:PlaySound("dontstarve/creatures/together/grass_gekko/emerge")
            end),
        },

        events =
        {
            EventHandler("animover", function(inst)
                if inst.AnimState:AnimDone() then
                    inst.sg:GoToState("idle")
                end
            end),
        },
    },
}

--inst.components.locomotor:WantsToRun()

CommonStates.AddCombatStates(states,
{
    hittimeline = {
        TimeEvent(5*FRAMES, function(inst) inst.sg:GoToState("run") end),
    },

    deathtimeline =
    {
        TimeEvent(3*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/together/grass_gekko/death") end),
        TimeEvent(9*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/together/grass_gekko/body_fall") end),
    },
})

CommonStates.AddSleepStates(states,
{
    starttimeline =
    {
        TimeEvent(15*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/together/grass_gekko/sleep_pre") end)
    },

    sleeptimeline =
    {
        TimeEvent(15*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/together/grass_gekko/sleep") end),
        TimeEvent(28*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/together/grass_gekko/sleep") end)
    },

    waketimeline =
    {
        TimeEvent(1*FRAMES, function(inst)
                if inst.components.locomotor:WantsToRun() then
                    inst.sg:GoToState("scare")
                end
            end),
        TimeEvent(12*FRAMES, function(inst) inst.sg:GoToState("idle") end),
    },
})
CommonStates.AddFrozenStates(states)

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

 

 

Link to comment
Share on other sites

Progress report: The mob is neutral and all, but with a slight problem; The mob becomes invisible and stops moving whenever it comes in contact with me. I'm able to hit it whilst in this state, but when it tries to come back for round 2, it does the same thing again!

Link to comment
Share on other sites

Generally, the invisibility happens when you try to play an animation that an entity doesn't have. In this case, it seems that it is happening when it tries to attack. Looking at your code, your attack state uses the idle animation which shouldn't cause any problems, but then near the bottom you call CommonStates.AddCombatStates(). When you do this, it replaces the attack state you defined with the common attack state, which plays the "atk" animation. Your mob doesn't have this animation, which is why it turns invisible.

Edited by Ziro2k
Link to comment
Share on other sites

Thanks for replying, Ziro! After I removed CommonStates.AddCombatStates() & doing some fine-tuning, the mob doesn't turn invisible, and functions normally. But now, whenever I host a world with caves enabled just to double check, my mob crashes the world when it's attacked.

Link to comment
Share on other sites

Well I have a few possible guesses but there's really know way of knowing for sure without looking at the server log. What does the error message and LUA stack traceback say? I can help you debug if you post it.

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