Jump to content

Recommended Posts

Hi,

I wanted to add some hound with special attack. One have an electric effect that works fine, but i have a problem with the other hound. This one should have an effect making the target lose sanity (if the target have sanity) when attacked. My problem is : this effect happen even if the attack doesn't "hit".

For example, if you are close to the hound, and he start to attack, you move out of reach, you don't take damage but you loose sanity. So i guess i don't have a test somewhere or something. Here is how the code looks like :

        timeline =
        {

            TimeEvent(14*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/attack") end),
            TimeEvent(16*FRAMES, function(inst) inst.components.combat:DoAttack(inst.sg.statemem.target, nil, nil, "electric") end),
        },

This one is the one working fine

        timeline =
        {

            TimeEvent(14*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/attack") end),
            TimeEvent(16*FRAMES, function(inst) inst.components.combat:DoAttack()
				if inst.components.combat.target and inst.components.combat.target.components.sanity then
					inst.components.combat.target.components.sanity:DoDelta(-TUNING.SANITY_TINY)
					end
				end),
        },

This one is the one with the "bug".

(Since it's a part of a bigger mod i don't link the entire mod but let me know if you need a functional mod, i'll put all the hound file in a separate mod for test if needed).

Complete stategraph :

Spoiler

require("stategraphs/commonstates")

local actionhandlers =
{
    ActionHandler(ACTIONS.EAT, "eat"),
}

local events =
{
    EventHandler("attacked", function(inst) if not inst.components.health:IsDead() and not inst.sg:HasStateTag("attack") then inst.sg:GoToState("hit") end end),
    EventHandler("death", function(inst) inst.sg:GoToState("death") end),
    EventHandler("doattack", function(inst, data) if not inst.components.health:IsDead() and (inst.sg:HasStateTag("hit") or not inst.sg:HasStateTag("busy")) then inst.sg:GoToState("attack", data.target) end end),
    CommonHandlers.OnSleep(),
    CommonHandlers.OnLocomote(true, false),
    CommonHandlers.OnFreeze(),
}

local states =
{

    State{
        name = "idle",
        tags = { "idle", "canrotate" },
        onenter = function(inst, playanim)
            inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/pant")
            inst.Physics:Stop()
            if playanim then
                inst.AnimState:PlayAnimation(playanim)
                inst.AnimState:PushAnimation("idle", true)
            else
                inst.AnimState:PlayAnimation("idle", true)
            end
            inst.sg:SetTimeout(2*math.random()+.5)
        end,
    },

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

        onenter = function(inst, target)
            inst.sg.statemem.target = target
            inst.Physics:Stop()
            inst.components.combat:StartAttack()
            inst.AnimState:PlayAnimation("atk_pre")
            inst.AnimState:PushAnimation("atk", false)
        end,

        timeline =
        {

            TimeEvent(14*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/attack") end),
            TimeEvent(16*FRAMES, function(inst) inst.components.combat:DoAttack()
                if inst.components.combat.target and inst.components.combat.target.components.sanity then
                    inst.components.combat.target.components.sanity:DoDelta(-TUNING.SANITY_TINY)
                    end
                end),
        },

        events =
        {
            EventHandler("animqueueover", function(inst) if math.random() < .333 then inst.components.combat:SetTarget(nil) inst.sg:GoToState("taunt") else inst.sg:GoToState("idle", "atk_pst") end end),
        },
    },

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

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.components.combat:StartAttack()
            inst.AnimState:PlayAnimation("atk_pre")
            inst.AnimState:PushAnimation("atk", false)
        end,

        timeline =
        {
            TimeEvent(14*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/bite") end),
        },

        events =
        {
            EventHandler("animqueueover", function(inst) if inst:PerformBufferedAction() then inst.components.combat:SetTarget(nil) inst.sg:GoToState("taunt") else inst.sg:GoToState("idle", "atk_pst") end end),
        },
    },

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

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

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

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

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("taunt")
        end,

        timeline =
        {
            TimeEvent(13*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/bark") end),
            TimeEvent(24*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/bark") end),
        },

        events =
        {
            EventHandler("animover", function(inst) if math.random() < .333 then inst.sg:GoToState("taunt") else inst.sg:GoToState("idle") end end),
        },
    },

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

        onenter = function(inst)
            inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/death")
            inst.AnimState:PlayAnimation("death")
            inst.Physics:Stop()
            RemovePhysicsColliders(inst)            
            inst.components.lootdropper:DropLoot(Vector3(inst.Transform:GetWorldPosition()))            
        end,
    },

    State{
        name = "forcesleep",
        tags = { "busy", "sleeping" },

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

CommonStates.AddSleepStates(states,
{
    sleeptimeline = {
        TimeEvent(30*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/sleep") end),
    },
})

CommonStates.AddRunStates(states,
{
    runtimeline = {
        TimeEvent(0, function(inst)
            inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/growl")
            PlayFootstep(inst)
        end),
        TimeEvent(4*FRAMES, PlayFootstep),
    },
})
CommonStates.AddFrozenStates(states)

return StateGraph("hound", states, events, "taunt", actionhandlers)

 

(Also, it's possible the stategraph itself is a little outdated since i made it before the gobbler year event and i'm not sure they didn't change something to add the "startled by Firecrackers", but it isn't related with the bug anyway since it was here before the update.)

 

Thanks for any help.

9 hours ago, Lumina said:

Thanks, @CarlZalph :) It seems to works fine !

The idea for stategraphs is to match up actions with animations, and anything caused by it shouldn't really be handled in the stategraph itself but rather in the entity prefab.

Time critical versus action dependent.

Yeah i think i used the wrong way because i found this in dragonfly stategraph :


        timeline =
        {
            TimeEvent(7*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/dragonfly/swipe") end),
            TimeEvent(15*FRAMES, function(inst)
                inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/dragonfly/punchimpact")
                inst.components.combat:DoAttack(inst.sg.statemem.target)
                if inst.components.combat.target and inst.components.combat.target.components.health and inst.enraged then
                    inst.components.combat.target.components.health:DoFireDamage(5)
                end
            end),
        },

And so was thinking it was the proper way to manage special attacks, but it's not :D

46 minutes ago, Lumina said:

Yeah i think i used the wrong way because i found this in dragonfly stategraph :



        timeline =
        {
            TimeEvent(7*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/dragonfly/swipe") end),
            TimeEvent(15*FRAMES, function(inst)
                inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/dragonfly/punchimpact")
                inst.components.combat:DoAttack(inst.sg.statemem.target)
                if inst.components.combat.target and inst.components.combat.target.components.health and inst.enraged then
                    inst.components.combat.target.components.health:DoFireDamage(5)
                end
            end),
        },

And so was thinking it was the proper way to manage special attacks, but it's not :D

Yeah, that's a special case with the dragonfly in its enraged state.

If it swings, then you are guaranteed to get hurt there.

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