Jump to content

Recommended Posts

I have tried the entire day to figure out the coding and how to make the possible. I honestly have no idea where to start. I read through the game's coding and found "stunlock" under every character and "STUNLOCK_TIMES" under Tuning. I'm not sure if this is what I'm looking for. In the Tuning part of the script, it gives Often, Sometimes, and Rarely. I figured if I set StunLock_Times to 0 it would maybe remove the stunlocked from attacks entirely. Also there is a data.stimuli named "stun", maybe that has something to do with it? I donno, I'm lost and out of all of the languages I've dealt with, LUA seems very difficult. I honestly can't figure out how to start my functions. Please help so I have an idea of what I'm supposed to do so I can learn more moving forward.

I also cannot find another MOD that actually does this. Searching the forums, everyone just provided broken scripts that didn't work, or stopped working with newer updates. What's worse is that there isn't an actual API. So finding what I'm looking to change requires me to look deep in the game's files.

Link to comment
https://forums.kleientertainment.com/forums/topic/118530-no-stun-when-attacked/
Share on other sites

So what I think I'm actually looking for is trying to make all characters not stop moving when hit. I noticed that in State "hit" there is inst.components.locomotor:Stop() and inst:ClearBufferedAction(). I'm not sure if these are what is preventing the character from moving and basically doing anything after being hit. Reading all over the forums, I'm just finding old code that doesn't work and very rarely does anything involve changing original code but rather just adds.

Yet how do I override existing code? If I liked the way DST was, I wouldn't be modding it in the first place. Here is a bunch of stuff I was messing around with. I used mods, I used forum posts, I used even API... which isn't really an API because it appears outdated and some functions don't even work.

local State = GLOBAL.State
local TimeEvent = GLOBAL.TimeEvent
local EventHandler = GLOBAL.EventHandler
local FRAMES = GLOBAL.FRAMES

--local hitstate = State({
--	name = "hit",
--    tags = {"busy", "pausepredict"},
--    
--    onenter = function(inst, forzen)
--        inst.AnimState:PlayAnimation("hit")

   --     if frozen == "noimpactsound" then
   --         frozen = nil
   --     else
   --         inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
   --     end
--     DoHurtSound(inst)
--
  --      local stun_frames = math.min(math.floor(inst.AnimState:GetCurrentAnimationLength() / FRAMES + .5), frozen and 10 or 6)
  --      if inst.components.playercontroller ~= nil then
  --          inst.components.playercontroller:RemotePausePrediction(stun_frames <= 7 and stun_frames or nil)
  --      end
  --      inst.sg:SetTimeout(stun_frames * FRAMES)
  --  end,
--
 --   ontimeout = function(inst)
--        inst.sg:GoToState("idle", true)
 --   end,

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

local newOnenter = function(inst)
    inst.AnimState:PlayAnimation("hit")
   
        if frozen == "noimpactsound" then
            frozen = nil
        else
            inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
        end
        DoHurtSound(inst)

        local stun_frames = math.min(math.floor(inst.AnimState:GetCurrentAnimationLength() / FRAMES + .5), frozen and 10 or 6)
        if inst.components.playercontroller ~= nil then
            inst.components.playercontroller:RemotePausePrediction(stun_frames <= 7 and stun_frames or nil)
        end
        inst.sg:SetTimeout(stun_frames * FRAMES)
    end,


local function SGWilsonPostInit(sg)
    sg.states["hit"].onenter = newOnenter
end

--AddStategraphState("wilson", hitstate)
AddStategraphPostInit("wilson", SGWilsonPostInit)

At this point I'm just frustrated and about to give up.

Edited by Trenix
-- Prevent Stunlock --
local require = GLOBAL.require
local State = GLOBAL.State
local Action = GLOBAL.Action
local ActionHandler = GLOBAL.ActionHandler
local TimeEvent = GLOBAL.TimeEvent
local EventHandler = GLOBAL.EventHandler
local ACTIONS = GLOBAL.ACTIONS
local FRAMES = GLOBAL.FRAMES 

local new_hitstate = State {
	name = "hit",
    tags = { "busy", "pausepredict" },

    onenter = function(inst, frozen)
        ForceStopHeavyLifting(inst)
        inst.components.locomotor:Stop()
        inst:ClearBufferedAction()

        inst.AnimState:PlayAnimation("hit")
        print("MyFunction was called")

        if frozen == "noimpactsound" then
            frozen = nil
        else
            inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
        end
        DoHurtSound(inst)

        --V2C: some of the woodie's were-transforms have shorter hit anims
        local stun_frames = math.min(math.floor(inst.AnimState:GetCurrentAnimationLength() / FRAMES + .5), frozen and 10 or 6)
        if inst.components.playercontroller ~= nil then
            --Specify min frames of pause since "busy" tag may be
            --removed too fast for our network update interval.
            inst.components.playercontroller:RemotePausePrediction(stun_frames <= 7 and stun_frames or nil)
        end
        inst.sg:SetTimeout(stun_frames * FRAMES)
    end,

    ontimeout = function(inst)
        inst.sg:GoToState("idle", true)
    end,

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

AddStategraphState("wilson", new_hitstate)

This is the last thing I could come up with. Results in a crash. Essentially I wanted to override being hit and tweaking a few things to see how they work. I'm just surprised why it's so complicated to do so and why we're not only required to learn LUA but also learn the codes that the developers put forth without any updated API given to us. I can now see why development in mods is low and often abandoned. If someone can explain what I'm doing wrong and maybe some operations that I've somehow missed, please let me know. I wasted an entire day trying to figure this out and I'mma go crazy if I'll continue with this.

hi this code maybe work i found it in some amazing mod

Spoiler

AddStategraphPostInit("wilson", function(sg)
	local _attacked = sg.events.attacked.fn
	sg.events.attacked.fn = function(inst, data)
		local a = data.attacker and data.attacker.components.combat or nil
		local b = a and a.playerstunlock or nil
		if inst.puturvaluefornotgettinghithere and a then
			a.playerstunlock = GLOBAL.PLAYERSTUNLOCK.NEVER
			inst.sg.timeinstate = 0
		end
		_attacked(inst, data)
		if inst.puturvaluefornotgettinghithere and a then a.playerstunlock = b end
	end
end)

 

for to work put the "puturvaluefornotgettinghithere" to true and nil when no want work and you can name whatever you want, peace bro.

and ya your right it sucks lots of these stuff are not simpler to do and no proper API or anything

Edited by --- -.-

Thanks for your response but it didn't seem to work.

local puturvaluefornotgettinghithere = true

AddStategraphPostInit("wilson", function(sg)
	local _attacked = sg.events.attacked.fn
	sg.events.attacked.fn = function(inst, data)
		local a = data.attacker and data.attacker.components.combat or nil
		local b = a and a.playerstunlock or nil
		if inst.puturvaluefornotgettinghithere and a then
			a.playerstunlock = GLOBAL.PLAYERSTUNLOCK.NEVER
			inst.sg.timeinstate = 0
		end
		_attacked(inst, data)
		if inst.puturvaluefornotgettinghithere and a then a.playerstunlock = b end
	end
end)

Is what I tried, maybe I'm doing it wrong?

I was digging deeper into SGwilson.lua and am almost certain this has something to do with it.

EventHandler("attacked", function(inst, data)
        if not inst.components.health:IsDead() and not inst.sg:HasStateTag("drowning") then
            if data.weapon ~= nil and data.weapon:HasTag("tranquilizer") and (inst.sg:HasStateTag("bedroll") or inst.sg:HasStateTag("knockout")) then
                return --Do nothing
            elseif inst.sg:HasStateTag("transform") or inst.sg:HasStateTag("dismounting") then
                -- don't interrupt transform or when bucked in the air
                inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
                DoHurtSound(inst)
            elseif inst.sg:HasStateTag("sleeping") then
                inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
                DoHurtSound(inst)
                if inst.sleepingbag ~= nil then
                    inst.sleepingbag.components.sleepingbag:DoWakeUp()
                    inst.sleepingbag = nil
                else
                    inst.sg.statemem.iswaking = true
                    inst.sg:GoToState("wakeup")
                end
            elseif inst.sg:HasStateTag("parrying") and data.redirected then
                if not inst.sg:HasStateTag("parryhit") then
                    inst.sg.statemem.parrying = true
                    inst.sg:GoToState("parry_hit", {
                        timeleft = inst.sg.statemem.task ~= nil and GetTaskRemaining(inst.sg.statemem.task) or inst.sg.statemem.parrytime,
                        pushing = data.attacker ~= nil and data.attacker.sg ~= nil and data.attacker.sg:HasStateTag("pushing"),
                    })
                end
            elseif data.attacker ~= nil
                and data.attacker:HasTag("groundspike")
                and not inst.components.rider:IsRiding()
                and not inst:HasTag("wereplayer") then
                inst.sg:GoToState("hit_spike", data.attacker)
            elseif data.attacker ~= nil
                and data.attacker.sg ~= nil
                and data.attacker.sg:HasStateTag("pushing") then
                inst.sg:GoToState("hit_push")
            elseif inst.sg:HasStateTag("shell") then
                inst.sg:GoToState("shell_hit")
            elseif inst.components.pinnable ~= nil and inst.components.pinnable:IsStuck() then
                inst.sg:GoToState("pinned_hit")
            elseif data.stimuli == "darkness" then
                inst.sg:GoToState("hit_darkness")
            elseif data.stimuli == "electric" and not inst.components.inventory:IsInsulated() then
                inst.sg:GoToState("electrocute")
            elseif inst.sg:HasStateTag("nointerrupt") then
                inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
                DoHurtSound(inst)
            else
                local t = GetTime()
                local stunlock =
                    data.stimuli ~= "stun" and
                    data.attacker ~= nil and
                    --V2C: skip stunlock protection when idle
                    -- gjans: we transition to idle for 1 frame after being hit, hence the timeinstate check
                    not (inst.sg:HasStateTag("idle") and inst.sg.timeinstate > 0) and
                    data.attacker.components.combat ~= nil and
                    data.attacker.components.combat.playerstunlock or
                    nil
                if stunlock ~= nil and
                    t - (inst.sg.mem.laststuntime or 0) <
                    (   (stunlock == PLAYERSTUNLOCK.NEVER and math.huge) or
                        (stunlock == PLAYERSTUNLOCK.RARELY and TUNING.STUNLOCK_TIMES.RARELY) or
                        (stunlock == PLAYERSTUNLOCK.SOMETIMES and TUNING.STUNLOCK_TIMES.SOMETIMES) or
                        (stunlock == PLAYERSTUNLOCK.OFTEN and TUNING.STUNLOCK_TIMES.OFTEN) or
                        0 --unsupported case
                    ) then
                    -- don't go to full hit state, just play sounds
                    inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
                    DoHurtSound(inst)
                else
                    inst.sg.mem.laststuntime = t
                    inst.sg:GoToState("hit", data.noimpactsound and "noimpactsound" or nil)
                end
            end
        end
    end),

I now need to figure how to override it with this...

--EventHandler("attacked", function(inst, data)
--    if not inst.components.health:IsDead() and not inst.sg:HasStateTag("drowning") then
--        if data.weapon ~= nil and data.weapon:HasTag("tranquilizer") and (inst.sg:HasStateTag("bedroll") or inst.sg:HasStateTag("knockout")) then
--            return --Do nothing
--        elseif inst.sg:HasStateTag("transform") or inst.sg:HasStateTag("dismounting") then
--            -- don't interrupt transform or when bucked in the air
--            inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
--            DoHurtSound(inst)
--        elseif inst.sg:HasStateTag("sleeping") then
--            inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
--            DoHurtSound(inst)
--            if inst.sleepingbag ~= nil then
--                inst.sleepingbag.components.sleepingbag:DoWakeUp()
--                inst.sleepingbag = nil
--            else
--                inst.sg.statemem.iswaking = true
--               inst.sg:GoToState("wakeup")
--            end
--        elseif inst.sg:HasStateTag("parrying") and data.redirected then
--            if not inst.sg:HasStateTag("parryhit") then
--                inst.sg.statemem.parrying = true
--                inst.sg:GoToState("parry_hit", {
--                    timeleft = inst.sg.statemem.task ~= nil and GetTaskRemaining(inst.sg.statemem.task) or inst.sg.statemem.parrytime,
--                    pushing = data.attacker ~= nil and data.attacker.sg ~= nil and data.attacker.sg:HasStateTag("pushing"),
--                })
--            end
--        elseif data.attacker ~= nil
--            and data.attacker:HasTag("groundspike")
--            and not inst.components.rider:IsRiding()
--            and not inst:HasTag("wereplayer") then
--            inst.sg:GoToState("hit_spike", data.attacker)
--        elseif data.attacker ~= nil
--            and data.attacker.sg ~= nil
--            and data.attacker.sg:HasStateTag("pushing") then
--            inst.sg:GoToState("hit_push")
--        elseif inst.sg:HasStateTag("shell") then
--            inst.sg:GoToState("shell_hit")
--        elseif inst.components.pinnable ~= nil and inst.components.pinnable:IsStuck() then
--            inst.sg:GoToState("pinned_hit")
--        elseif data.stimuli == "darkness" then
--            inst.sg:GoToState("hit_darkness")
--        elseif data.stimuli == "electric" and not inst.components.inventory:IsInsulated() then
--            inst.sg:GoToState("electrocute")
--        else
--            inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
--            DoHurtSound(inst)

It seems like the game intentionally adds a stun and prevents players also from being stun locked. It's exceptionally noticeable when you idle and get hit. I either have no idea of what I'm talking about, or I'm finally onto it. Stunlock times were also part of tuning.lua, but seems that they ended up turning it off and getting rid of it.

I'll try a bit harder, but if I can't figure it out, I'll probably move onto modding a different game. Maybe lua isn't for me. So much time wasted and I've gotten no where.

local MYACT = Action(3)
MYACT.str = "Prevent Stun"
MYACT.id = "attacked"
MYACT.fn = function(inst, data)
    if not inst.components.health:IsDead() and not inst.sg:HasStateTag("drowning") then
        if data.weapon ~= nil and data.weapon:HasTag("tranquilizer") and (inst.sg:HasStateTag("bedroll") or inst.sg:HasStateTag("knockout")) then
            return --Do nothing
        elseif inst.sg:HasStateTag("transform") or inst.sg:HasStateTag("dismounting") then
            -- don't interrupt transform or when bucked in the air
            inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
            DoHurtSound(inst)
        elseif inst.sg:HasStateTag("sleeping") then
            inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
            DoHurtSound(inst)
            if inst.sleepingbag ~= nil then
                inst.sleepingbag.components.sleepingbag:DoWakeUp()
                inst.sleepingbag = nil
            else
                inst.sg.statemem.iswaking = true
               inst.sg:GoToState("wakeup")
            end
        elseif inst.sg:HasStateTag("parrying") and data.redirected then
            if not inst.sg:HasStateTag("parryhit") then
                inst.sg.statemem.parrying = true
                inst.sg:GoToState("parry_hit", {
                    timeleft = inst.sg.statemem.task ~= nil and GetTaskRemaining(inst.sg.statemem.task) or inst.sg.statemem.parrytime,
                    pushing = data.attacker ~= nil and data.attacker.sg ~= nil and data.attacker.sg:HasStateTag("pushing"),
                })
            end
        elseif data.attacker ~= nil
            and data.attacker:HasTag("groundspike")
            and not inst.components.rider:IsRiding()
            and not inst:HasTag("wereplayer") then
            inst.sg:GoToState("hit_spike", data.attacker)
        elseif data.attacker ~= nil
            and data.attacker.sg ~= nil
            and data.attacker.sg:HasStateTag("pushing") then
            inst.sg:GoToState("hit_push")
        elseif inst.sg:HasStateTag("shell") then
            inst.sg:GoToState("shell_hit")
        elseif inst.components.pinnable ~= nil and inst.components.pinnable:IsStuck() then
            inst.sg:GoToState("pinned_hit")
        elseif data.stimuli == "darkness" then
            inst.sg:GoToState("hit_darkness")
        elseif data.stimuli == "electric" and not inst.components.inventory:IsInsulated() then
            inst.sg:GoToState("electrocute")
        else
            inst.SoundEmitter:PlaySound("dontstarve/wilson/hit")
            DoHurtSound(inst)
        end
    end
end

AddAction(MYACT)
AddStategraphActionHandler("willow",ActionHandler(MYACT, "newattack"))

Yeah this is all I got following the API the provided us which clearly doesn't work... nor does it effectively explain anything. If you can help, great. But otherwise if I don't figure this out which took me two days of reading through code and using useless API, then I much rather mod another game. I'm not sure if LUA is supposed to be this difficult, or if the developers just made it hell to work with.

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