ksaab

  • Content count

    72
  • Joined

  • Last visited

 Content Type 

Profiles

Forums

Downloads

Klei Bug Tracker

Game Updates

Hot Lava Bug Reporter

Posts posted by ksaab


  1. 3) Check out the forum, there is a pinned thread about them;

    4) I offer variants to you. How you will implement dependng on your preferences. The last variant doesn't requie a client stategraph;

    5) How do you use dodge without weapon? GetPointSpecialActions? Or key binding? How do you realize cooldown on the client side? You can remove my AddComponentAction if you don't need them.

    • Thanks 1

  2. AddAction("DODGE", "Dodge", function(act)
        act.doer:PushEvent("letsdododge", {pos = act.pos or Vector3(act.target.Transform:GetWorldPosition())})
        return true
    end)
    
    ACTIONS.DODGE.distance = math.huge
    ACTIONS.DODGE.instant = true
    
    AddStategraphEvent("wilson", EventHandler("letsdododge", function(inst, data)
    		inst.sg:GoToState("dodge_pre", data)
    	end)
    )

    I think you want something like this — use dodge while player is moving. It's a bit dirty-tricky and looks weird on clients. But the second could be fixed I suppose.

    Client-stategraph doesn't need any code at all. Other things from the previous post. Dodge direction should be handled in the "pre" state with data.pos.

    One more thing — pos = act.pos will work incorrect after RoT release. Klei has changed this filed. Check out bufferedaction.lua after update.

    Two more thing — 0.25 widnow is too short. Clients with high unstable ping will have problems (I did a parry spell with 0.5 seconds window in The Forge Battle Pack and recieved a lot of complaints)

    • Thanks 1

  3. AddStategraphState("wilson", State 
    {
    	name = "dodge_pre",
    	tags = {"doing", "busy", "evade", "no_stun"},
    
    	onenter = function(inst)
    		inst.components.locomotor:Stop()
    		inst.AnimState:PlayAnimation("parry_pre", false)
    	end,
    
    	events =
    	{
    		EventHandler("animover", function(inst)
    			inst.sg:GoToState("dodge")
    		end),
    	}
    })
    
    AddStategraphState("wilson", State
    {
    	name = "dodge",
    	tags = {"doing", "evade", "no_stun", "nopredict", "nomorph",},
    
    	onenter = function(inst)
    		inst.AnimState:PlayAnimation("parry_loop", true)
    		inst.components.health:SetInvincible(true)
    		inst.components.locomotor:EnableGroundSpeedMultiplier(true)
    		inst.last_dodge_time = GLOBAL.GetTime()
    		inst.Physics:SetMotorVel(-20,0,0)
    
    		--this should be moved to the action code
    		-----------------------------------------
    		if GLOBAL.TheNet:GetServerGameMode() == "lavaarena" then
    			COMMON_FNS.DoFrontAOE(inst, 5, 0, 3.25, "strong", nil)
    			inst:DoTaskInTime(0.5, function()
    				COMMON_FNS.DoFrontAOE(inst, 5, 0, 3.25, "strong", nil)
    			end)
    
    			if inst.laserdodge ~= nil then
    				inst.laserdodge:Cancel()
    				inst.laserdodge = nil
    			end
    		end
    		-----------------------------------------
    
    		inst.SoundEmitter:PlaySound("dontstarve_DLC003/characters/wheeler/slide")
    		inst:PerformBufferedAction()
    
    		--not the best idea
    		--because of latency character will dash for shorter distance then you're expecting
    		--will be much better to calculate target postion and use onupdate until character reaches it; 
    		--after fire your custom event and catch it in EventHandler("yourevent", function() place code from ontimeout end)
    		inst.sg:SetTimeout(0.25)
    	end,
    
    	events =
    	{
    		EventHandler("animqueueover", function(inst)
    			--this happens only after inst.AnimState:PlayAnimation("parry_pst", false) will be complete
    			if inst.AnimState:AnimDone() then
    				inst.sg:GoToState("idle")
    			end
    		end),
    	},
    
    	ontimeout = function(inst)
    		inst.Physics:SetMotorVel(0, 0, 0)
    		inst.components.health:SetInvincible(false)
    		inst.components.locomotor:EnableGroundSpeedMultiplier(false)
    		inst.AnimState:PlayAnimation("parry_pst", false)
    	end,
    
    	onexit = function(inst)
    		--need to double this code — case when we will leave the state before timeout
    		inst.Physics:SetMotorVel(0, 0, 0)
    		inst.components.health:SetInvincible(false)
    		inst.components.locomotor:EnableGroundSpeedMultiplier(false)
    	end,
    })
    
    AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.DODGE, "dodge_pre"))
    
    AddStategraphState("wilson_client",
    	State {
        name = "dodge_pre",
        tags = {"doing", "busy", "evade", "no_stun"},
    
        onenter = function(inst)
            inst.components.locomotor:Stop()
            inst.AnimState:PlayAnimation("parry_pre", false)
    		inst.AnimState:PushAnimation("parry_loop", true)
            inst:PerformPreviewBufferedAction()
            inst.sg:SetTimeout(2)
        end,
    	
    	onupdate = function(inst) 
    		if inst:HasTag("doing") then
    			if inst.entity:FlattenMovementPrediction() then
    				inst.sg:GoToState("idle", "noanim")
    			end
    		elseif inst.bufferedaction == nil then
    			inst.sg:GoToState("idle")
    		end
    	end,
    	
        ontimeout = function(inst)
    		inst:ClearBufferedAction()
    		inst.sg:GoToState("idle")
    	end,
    	}
    )
    
    AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.DODGE, "dodge_pre"))
    
    --actions collectors, dodge will work with any equipped weapon. Not good but it's just an example
    --I'm not sure overriding onlocomote event handler is a good idea
    --check out the wortox prefab if you want use dodge like wortox's soul hop
    AddComponentAction("EQUIPPED", "weapon", function(inst, doer, target, actions, right)
    	if right then table.insert(actions, ACTIONS.DODGE) end
    end)
    
    AddComponentAction("POINT", "weapon", function(inst, doer, pos, actions, right)
    	if right then table.insert(actions, ACTIONS.DODGE) end
    end)

    don't forget to rename animation


  4. Your character moves after dodging because of inst.Physics:SetMotorVelOverride(20,0,0). Client draws fake position for character, but real doesn't change (actually it doesn't work at all). Any client state should contain animation and tag things only.

    AddStategraphState("wilson_client", State {
        name = "dodge",
        tags = {"busy", "evade", "no_stun"},
    
        onenter = function(inst)
            inst.components.locomotor:Stop()
            inst.AnimState:PlayAnimation("slide_pre", false) --only pre animation, the slide animation command must come from server
            inst:PerformPreviewBufferedAction() --this thing says to server "hey man, I'm doing something"
            inst.sg:SetTimeout(2)
        end,
        
        --[[I use this chunk, but I don't have idea what it really does. Sometime state doesn't work without "onupdate". It requires "doing" tag for server and client states
        onupdate = function(inst)
    		if inst:HasTag("doing") then
    			if inst.entity:FlattenMovementPrediction() then
    				inst.sg:GoToState("idle", "noanim")
    			end
    		elseif inst.bufferedaction == nil then
    			inst.sg:GoToState("idle")
    		end
    	end,
        ]]--
    
        --timeout happens only if player have a lag
        ontimeout = function(inst)
    		inst:ClearBufferedAction()
    		inst.sg:GoToState("idle")
    	end,
    )

    I think the second state is not requied for the client stategraph.

    • Thanks 1

  5. There is "wilson_client" stategraph. The game uses it if lag compenstion is enabled on client (when you're playing as host without caves you are actually not a client and don't use this stategraph). It is almost the same but doesn't contain any game logic.

    The solution for the problem — you need to add lightweight versions of your states to "wilson_client".

    • Like 1
    • Thanks 2