require("stategraphs/commonstates")

local function PlayCreatureSound(inst, sound, creature)
    local creature = creature or inst.soundgroup or inst.prefab
    inst.SoundEmitter:PlaySound("dontstarve/creatures/" .. creature .. "/" .. sound)
end

local actionhandlers = 
{ 
	
	--ActionHandler(ACTIONS.FAN, "action"), 
    ActionHandler(ACTIONS.GOHOME, "gohome"),
	ActionHandler(ACTIONS.ATTACK, function(inst)
	 if not inst.components.health:IsDead() and not inst.sg:HasStateTag("attack") then
                local weapon = inst.components.combat ~= nil and inst.components.combat:GetWeapon() or nil
                return (weapon == nil and "attack")
                    or (weapon:HasTag("blowdart") and "blowdart")
					or "attack"
					end
				end),
	ActionHandler(ACTIONS.PICKUP, "pickup"),
	ActionHandler(ACTIONS.DROP, "pickup"),
	ActionHandler(ACTIONS.EAT, "eat"),
	ActionHandler(ACTIONS.HEAL, "eat"),
	ActionHandler(ACTIONS.FAN, "pickup"),
	ActionHandler(ACTIONS.SLEEPIN,  function(inst, action)
            if action.invobject ~= nil then
                if action.invobject.onuse ~= nil then
                    --action.invobject.onuse(inst) --for somereason this causes a crash. Not that its needed anyways, we want to use the normal sleep anims.
                end
                return "bedroll"
            else
                return "tent"
            end
        end),
	ActionHandler(ACTIONS.PICK, "pickup"),
	ActionHandler(ACTIONS.DIG, "pickup"),
	ActionHandler(ACTIONS.CHOP, "work"),
	ActionHandler(ACTIONS.MINE, "work"),
	ActionHandler(ACTIONS.COOK, "pickup"),
	ActionHandler(ACTIONS.FILL, "pickup"),
	ActionHandler(ACTIONS.DRY, "pickup"),
	ActionHandler(ACTIONS.ADDFUEL, "pickup"),
	ActionHandler(ACTIONS.ADDWETFUEL, "pickup"),
	ActionHandler(ACTIONS.LIGHT, "pickup"),
	ActionHandler(ACTIONS.BAIT, "pickup"),
	ActionHandler(ACTIONS.BUILD, "pickup"),
	ActionHandler(ACTIONS.PLANT, "pickup"),
	ActionHandler(ACTIONS.REPAIR, "pickup"),
	ActionHandler(ACTIONS.HARVEST, "pickup"),
	ActionHandler(ACTIONS.STORE, "pickup"),
	ActionHandler(ACTIONS.RUMMAGE, "pickup"),
	ActionHandler(ACTIONS.DEPLOY, "pickup"),
	ActionHandler(ACTIONS.FEED, "pickup"),
	ActionHandler(ACTIONS.HAMMER, "attack"),
	ActionHandler(ACTIONS.FERTILIZE, "pickup"),
	ActionHandler(ACTIONS.MURDER, "pickup"),
	ActionHandler(ACTIONS.UNLOCK, "action"),
	ActionHandler(ACTIONS.TURNOFF, "pickup"),
	ActionHandler(ACTIONS.TURNON, "pickup"),
	ActionHandler(ACTIONS.SEW, "pickup"),
	ActionHandler(ACTIONS.COMBINESTACK, "pickup"),
	ActionHandler(ACTIONS.UPGRADE, "pickup"),
	ActionHandler(ACTIONS.ACTIVATE, "pickup"),	
	ActionHandler(ACTIONS.WRITE, "action"),
	ActionHandler(ACTIONS.GIVE, "pickup"),
	ActionHandler(ACTIONS.GIVETOPLAYER, "pickup"),
	ActionHandler(ACTIONS.FEEDPLAYER, "pickup"),
	ActionHandler(ACTIONS.TERRAFORM, "pickup"),
	ActionHandler(ACTIONS.GIVEALLTOPLAYER, "pickup"),
	ActionHandler(ACTIONS.JUMPIN, "pickup"),
	ActionHandler(ACTIONS.NET, "attack"),
	ActionHandler(ACTIONS.MIGRATE, "pickup"),
	ActionHandler(ACTIONS.CHECKTRAP, "pickup"),
	ActionHandler(ACTIONS.SHAVE, "pickup"),
	ActionHandler(ACTIONS.FISH, "pickup"),
	ActionHandler(ACTIONS.REEL, "pickup"),
	ActionHandler(ACTIONS.CATCH, "pickup"),
	ActionHandler(ACTIONS.MANUALEXTINGUISH, "pickup"),
	ActionHandler(ACTIONS.RESETMINE, "pickup"),
	ActionHandler(ACTIONS.BLINK, "pickup"),
	ActionHandler(ACTIONS.SMOTHER, "pickup"),
	ActionHandler(ACTIONS.CASTSPELL, "pickup"),
	ActionHandler(ACTIONS.TEACH, "pickup"),
	ActionHandler(ACTIONS.WRAPBUNDLE, "pickup"),
	ActionHandler(ACTIONS.UNWRAP, "pickup"),
	ActionHandler(ACTIONS.UNLOCK, "pickup"),
	ActionHandler(ACTIONS.USEKLAUSSACKKEY, "pickup"),
	

}

local function SetSleeperAwakeState(inst)
    if inst.components.grue ~= nil then
        inst.components.grue:RemoveImmunity("sleeping")
    end
    if inst.components.talker ~= nil then
        inst.components.talker:StopIgnoringAll("sleeping")
    end
    if inst.components.firebug ~= nil then
        inst.components.firebug:Enable()
    end
    if inst.components.playercontroller ~= nil then
        inst.components.playercontroller:EnableMapControls(true)
        inst.components.playercontroller:Enable(true)
    end
    inst:OnWakeUp()
    inst.components.inventory:Show()
    inst:ShowActions(true)
end

local events=
{
    --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.OnLocomote(true,true),
	EventHandler("locomote", function(inst, data)
        if inst.sg:HasStateTag("busy") then
            return
        end
        local is_moving = inst.sg:HasStateTag("moving")
        local should_move = inst.components.locomotor:WantsToMoveForward()

        if inst.sg:HasStateTag("bedroll") or inst.sg:HasStateTag("tent") or inst.sg:HasStateTag("waking") then -- wakeup on locomote
            if inst.sleepingbag ~= nil and inst.sg:HasStateTag("sleeping") then
                inst.sleepingbag.components.sleepingbag:DoWakeUp()
                inst.sleepingbag = nil
				inst:Show()
				--inst.AnimState:PushAnimation("pig_pickup")
				SetSleeperAwakeState(inst)
				--inst.AnimState:PushAnimation("pig_pickup")
				--inst.sg:GoToState("idle", true)
				
            end 
			elseif is_moving and not should_move then
            inst.sg:GoToState("run_stop")
        elseif not is_moving and should_move then
            inst.sg:GoToState("run_start")
        elseif data.force_idle_state and not (is_moving or should_move or inst.sg:HasStateTag("idle")) then
            inst.sg:GoToState("idle")
        end
    end),
    CommonHandlers.OnSleep(),
    CommonHandlers.OnFreeze(),
    CommonHandlers.OnAttack(),
    CommonHandlers.OnAttacked(),
    EventHandler("death", function(inst)
        if inst.sleepingbag ~= nil and (inst.sg:HasStateTag("bedroll") or inst.sg:HasStateTag("tent")) then -- wakeup on death to "consume" sleeping bag first
            inst.sleepingbag.components.sleepingbag:DoWakeUp()
            inst.sleepingbag = nil
        end

        inst.sg:GoToState("death")
    end),
	
	 EventHandler("ms_opengift",
        function(inst)
            if not inst.sg:HasStateTag("busy") then
                inst.sg:GoToState("opengift")
            end
        end),
}

local function SetSleeperSleepState(inst)
    if inst.components.grue ~= nil then
        inst.components.grue:AddImmunity("sleeping")
    end
    if inst.components.talker ~= nil then
        inst.components.talker:IgnoreAll("sleeping")
    end
    if inst.components.firebug ~= nil then
        inst.components.firebug:Disable()
    end
    if inst.components.playercontroller ~= nil then
        inst.components.playercontroller:EnableMapControls(false)
        inst.components.playercontroller:Enable(false)
    end
    inst:OnSleepIn()
    inst.components.inventory:Hide()
    inst:PushEvent("ms_closepopups")
    inst:ShowActions(false)
end



local states=
{
		
		 State
    {
        name = "action",
        tags = {"busy"},
        onenter = function(inst)
            --inst.AnimState:PlayAnimation(getidleanim(inst), true)
        end,
		
		timeline=
        {
			--TimeEvent(14*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/hound/bite") end),
			TimeEvent(14*FRAMES, function(inst) 
				inst:PerformBufferedAction()  
			end),
        },
    },
	
	State{
        name = "opengift",
        tags = { "busy", "pausepredict" },

        onenter = function(inst)
            inst.components.locomotor:Stop()
            inst.components.locomotor:Clear()
            inst:ClearBufferedAction()

            --if IsNearDanger(inst) then
                --inst.sg.statemem.isdanger = true
                --inst.sg:GoToState("idle")
                --if inst.components.talker ~= nil then
                   -- inst.components.talker:Say(GetString(inst, "ANNOUNCE_NODANGERGIFT"))
                --end
                --return
           -- end

            inst.SoundEmitter:PlaySound("dontstarve/common/player_receives_gift")
            inst.AnimState:PlayAnimation("idle_happy", true)
            --inst.AnimState:PushAnimation("taunt", true)
            -- NOTE: the previously used ripping paper anim is called "giift_loop"

            if inst.components.playercontroller ~= nil then
                inst.components.playercontroller:RemotePausePrediction()
                inst.components.playercontroller:EnableMapControls(false)
                inst.components.playercontroller:Enable(false)
            end
            inst.components.inventory:Hide()
            inst:PushEvent("ms_closepopups")
            inst:ShowActions(false)
            inst:ShowGiftItemPopUp(true)

            if inst.components.giftreceiver ~= nil then
                inst.components.giftreceiver:OnStartOpenGift()
            end
        end,

        timeline =
        {
            -- Timing of the gift box opening animation on giftitempopup.lua
            TimeEvent(155 * FRAMES, function(inst)
               -- inst.AnimState:PlayAnimation("gift_open_pre")
                --inst.AnimState:PushAnimation("taunt", true)
            end),
        },

        events =
        {
            EventHandler("firedamage", function(inst)
                --inst.AnimState:PlayAnimation("taunt")
                inst.sg:GoToState("idle", true)
                if inst.components.talker ~= nil then
                    inst.components.talker:Say(GetString(inst, "ANNOUNCE_NODANGERGIFT"))
                end
            end),
            EventHandler("ms_doneopengift", function(inst, data)
                inst.sg:GoToState("idle", true)
            end),
        },

        onexit = function(inst)
            if inst.sg.statemem.isdanger then
                return
            elseif not inst.sg.statemem.isopeningwardrobe then
                if inst.components.playercontroller ~= nil then
                    inst.components.playercontroller:EnableMapControls(true)
                    inst.components.playercontroller:Enable(true)
                end
                inst.components.inventory:Show()
                inst:ShowActions(true)
            end
            inst:ShowGiftItemPopUp(false)
        end,
    },
	
	State{
        name = "bedroll",
        tags = { "bedroll", "busy", "nomorph" },

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

            local failreason =
                (TheWorld.state.isday and
                    (TheWorld:HasTag("cave") and "ANNOUNCE_NODAYSLEEP_CAVE" or "ANNOUNCE_NODAYSLEEP")
                )
                --or (IsNearDanger(inst) and "ANNOUNCE_NODANGERSLEEP")
                -- you can still sleep if your hunger will bottom out, but not absolutely
                or (inst.components.hunger.current < TUNING.CALORIES_MED and "ANNOUNCE_NOHUNGERSLEEP")
                or (inst.components.beaverness ~= nil and inst.components.beaverness:IsStarving() and "ANNOUNCE_NOHUNGERSLEEP")
                or nil

            if failreason ~= nil then
                inst:PushEvent("performaction", { action = inst.bufferedaction })
                inst:ClearBufferedAction()
                inst.sg:GoToState("idle")
                if inst.components.talker ~= nil then
                    inst.components.talker:Say(GetString(inst, failreason))
                end
                return
            end

            inst.AnimState:PlayAnimation("sleep_pre")
            inst.AnimState:PushAnimation("sleep_loop", false)

            SetSleeperSleepState(inst)
        end,

        timeline =
        {
            TimeEvent(20 * FRAMES, function(inst) 
                inst.SoundEmitter:PlaySound("dontstarve/wilson/use_bedroll")
            end),
        },

        events =
        {
            EventHandler("firedamage", function(inst)
                if inst.sg:HasStateTag("sleeping") then
                    inst.sg.statemem.iswaking = true
                    inst.sg:GoToState("wakeup")
                end
            end),
            EventHandler("animqueueover", function(inst)
                if inst.AnimState:AnimDone() then
                    if TheWorld.state.isday or
                        (inst.components.health ~= nil and inst.components.health.takingfiredamage) or
                        (inst.components.burnable ~= nil and inst.components.burnable:IsBurning()) then
                        inst:PushEvent("performaction", { action = inst.bufferedaction })
                        inst:ClearBufferedAction()
                        inst.sg.statemem.iswaking = true
                        inst.sg:GoToState("wakeup")
                    elseif inst:GetBufferedAction() then
                        inst:PerformBufferedAction() 
                        if inst.components.playercontroller ~= nil then
                            inst.components.playercontroller:Enable(true)
                        end
                        inst.sg:AddStateTag("sleeping")
                        inst.sg:AddStateTag("silentmorph")
                        inst.sg:RemoveStateTag("nomorph")
                        inst.sg:RemoveStateTag("busy")
                        inst.AnimState:PlayAnimation("sleep_loop", true)
                    else
                        inst.sg.statemem.iswaking = true
                        inst.sg:GoToState("wakeup")
                    end
                end
            end),
        },

        onexit = function(inst)
            if inst.sleepingbag ~= nil then
                --Interrupted while we are "sleeping"
                inst.sleepingbag.components.sleepingbag:DoWakeUp(true)
                inst.sleepingbag = nil
                SetSleeperAwakeState(inst)
            elseif not inst.sg.statemem.iswaking then
                --Interrupted before we are "sleeping"
                SetSleeperAwakeState(inst)
            end
        end,
    },
	
	State{
        name = "tent",
        tags = { "tent", "busy", "silentmorph" },

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

            local target = inst:GetBufferedAction().target
            local siesta = target:HasTag("siestahut")
            local failreason =
                (siesta ~= TheWorld.state.isday and
                    (siesta
                    and (TheWorld:HasTag("cave") and "ANNOUNCE_NONIGHTSIESTA_CAVE" or "ANNOUNCE_NONIGHTSIESTA")
                    or (TheWorld:HasTag("cave") and "ANNOUNCE_NODAYSLEEP_CAVE" or "ANNOUNCE_NODAYSLEEP"))
                )
                or (target.components.burnable ~= nil and
                    target.components.burnable:IsBurning() and
                    "ANNOUNCE_NOSLEEPONFIRE")
                --or (IsNearDanger(inst) and "ANNOUNCE_NODANGERSLEEP")
                -- you can still sleep if your hunger will bottom out, but not absolutely
                or (inst.components.hunger.current < TUNING.CALORIES_MED and "ANNOUNCE_NOHUNGERSLEEP")
                or (inst.components.beaverness ~= nil and inst.components.beaverness:IsStarving() and "ANNOUNCE_NOHUNGERSLEEP")
                or nil

            if failreason ~= nil then
                inst:PushEvent("performaction", { action = inst.bufferedaction })
                inst:ClearBufferedAction()
                inst.sg:GoToState("idle")
                if inst.components.talker ~= nil then
                    inst.components.talker:Say(GetString(inst, failreason))
                end
                return
            end

            inst.AnimState:PlayAnimation("pig_pickup")
            inst.sg:SetTimeout(11 * FRAMES)

            SetSleeperSleepState(inst)
        end,

        ontimeout = function(inst)
            local bufferedaction = inst:GetBufferedAction()
            if bufferedaction == nil then
                inst.AnimState:PlayAnimation("pig_pickup")
                inst.sg:GoToState("idle", true)
                return
            end
            local tent = bufferedaction.target
            if tent == nil or
                not tent:HasTag("tent") or
                tent:HasTag("hassleeper") or
                tent:HasTag("siestahut") ~= TheWorld.state.isday or
                (tent.components.burnable ~= nil and tent.components.burnable:IsBurning()) then
                --Edge cases, don't bother with fail dialogue
                --Also, think I will let smolderig pass this one
                inst:PushEvent("performaction", { action = inst.bufferedaction })
                inst:ClearBufferedAction()
                inst.AnimState:PlayAnimation("pig_pickup")
                inst.sg:GoToState("idle", true)
            else
                inst:PerformBufferedAction()
                inst.components.health:SetInvincible(true)
                inst:Hide()
                if inst.Physics ~= nil then
                    inst.Physics:Teleport(inst.Transform:GetWorldPosition())
                end
                if inst.DynamicShadow ~= nil then
                    inst.DynamicShadow:Enable(false)
                end
                inst.sg:AddStateTag("sleeping")
                inst.sg:RemoveStateTag("busy")
                if inst.components.playercontroller ~= nil then
                    inst.components.playercontroller:Enable(true)
                end
            end
        end,

        onexit = function(inst)
            inst.components.health:SetInvincible(false)
            inst:Show()
            if inst.DynamicShadow ~= nil then
                inst.DynamicShadow:Enable(true)
            end
            if inst.sleepingbag ~= nil then
                --Interrupted while we are "sleeping"
                inst.sleepingbag.components.sleepingbag:DoWakeUp(true)
                inst.sleepingbag = nil
                SetSleeperAwakeState(inst)
            elseif not inst.sg.statemem.iswaking then
                --Interrupted before we are "sleeping"
                SetSleeperAwakeState(inst)
            end
        end,
    },
	
	State
	{	
		name = "death",
        tags = {"busy", "pausepredict", "nomorph"},

        onenter = function(inst)
            inst.components.locomotor:Stop()
            inst.components.locomotor:Clear()
            inst:ClearBufferedAction()

            inst.AnimState:PlayAnimation("death")
			--inst.SoundEmitter:PlaySound("dontstarve/ghost/ghost_howl")
			inst.components.inventory:DropEverything(true)
			--inst.components.lootdropper:DropLoot(inst:GetPosition())

            if inst.components.playercontroller ~= nil then
                inst.components.playercontroller:RemotePausePrediction()
            end
        end,

        events =
        {
            EventHandler("animover", function(inst)
                if inst.AnimState:AnimDone() then
					if MOBGHOST == "Enable" or MOBGHOST == "Enable2" then
                     inst:PushEvent(inst.ghostenabled and "makeplayerghost" or "playerdied", { skeleton = false })
					else
						TheWorld:PushEvent("ms_playerdespawnanddelete", inst)
					end
                end
            end),
        },
	},	
	
    State{
        name= "funnyidle",
        tags = {"idle"},
        
        onenter = function(inst)
			inst.Physics:Stop()
            local daytime = not TheWorld.state.isnight
            inst.SoundEmitter:PlaySound("dontstarve/creatures/merm/attack")
            
            if inst.components.follower.leader and inst.components.follower:GetLoyaltyPercent() < 0.05 then
                inst.AnimState:PlayAnimation("hungry")
                inst.SoundEmitter:PlaySound("dontstarve/wilson/hungry")
            elseif inst:HasTag("guard") then
                inst.AnimState:PlayAnimation("idle_angry")
            elseif daytime then
                if inst.components.combat.target then
                    inst.AnimState:PlayAnimation("idle_angry")
                elseif inst.components.follower.leader and inst.components.follower:GetLoyaltyPercent() > 0.3 then
                    inst.AnimState:PlayAnimation("idle_happy")
                else
                    inst.AnimState:PlayAnimation("idle_creepy")
                end
            else
                inst.AnimState:PlayAnimation("idle_scared")
            end
        end,
        
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },        
    },
	
	State{
        name= "special_atk1",
        tags = {"idle", "busy"},
        
        onenter = function(inst)
			inst.Physics:Stop()
			PlayCreatureSound(inst, "taunt")
            inst.AnimState:PlayAnimation("idle_happy")
		end,	
		
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },        
    },
	
    
    State {
		name = "frozen",
		tags = {"busy"},
		
        onenter = function(inst)
            inst.AnimState:PlayAnimation("frozen")
            inst.Physics:Stop()
            --inst.components.highlight:SetAddColour(Vector3(82/255, 115/255, 124/255))
        end,
    },
    

    
    State{
		name = "abandon",
		tags = {"busy"},
		
		onenter = function(inst, leader)
			inst.Physics:Stop()
			inst.AnimState:PlayAnimation("abandon")
            inst:FacePoint(Vector3(leader.Transform:GetWorldPosition()))
		end,
		
        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },        
    },
    
	
	
	State{
        name = "wakeup",
        tags = { "busy", "waking", "nomorph" },

        onenter = function(inst)
            if inst.components.playercontroller ~= nil then
                inst.components.playercontroller:Enable(false)
            end
            if inst.AnimState:IsCurrentAnimation("sleep_loop") or
                inst.AnimState:IsCurrentAnimation("bedroll_sleep_loop") then
                inst.AnimState:PushAnimation("sleep_pst")
            elseif not (inst.AnimState:IsCurrentAnimation("bedroll_wakeup") or
                        inst.AnimState:IsCurrentAnimation("wakeup")) then
                inst.AnimState:PlayAnimation("pig_pickup")
            end
            if not inst:IsHUDVisible() then
                --Touch stone rez
                inst.sg.statemem.isresurrection = true
                inst.sg:AddStateTag("nopredict")
                inst.sg:AddStateTag("silentmorph")
                inst.sg:RemoveStateTag("nomorph")
                inst.components.health:SetInvincible(false)
                inst:ShowHUD(false)
                inst:SetCameraDistance(12)
            end
        end,

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

        onexit = function(inst)
            SetSleeperAwakeState(inst)
            if inst.sg.statemem.isresurrection then
                --Touch stone rez
                inst:ShowHUD(true)
                inst:SetCameraDistance()
                SerializeUserSession(inst)
            end
        end,
    },
	
    State{
		name = "transformNormal",
		tags = {"transform", "busy", "sleeping"},
		
		onenter = function(inst)
			inst.Physics:Stop()
			inst.SoundEmitter:PlaySound("dontstarve/creatures/werepig/transformToPig")
            inst.AnimState:SetBuild("werepig_build")
			inst.AnimState:PlayAnimation("transform_were_pig")
		    inst:RemoveTag("hostile")
			
		end,
		
		onexit = function(inst)
            inst.AnimState:SetBuild(pigman)
		end,
		
        events=
        {
            EventHandler("animover", function(inst)
			end ),
        },        
    },

State{
    name = "attack",
    tags = {"attack", "busy"},
     
    onenter = function(inst, target)
	    -- inst.SoundEmitter:PlaySound("dontstarve/pig/attack")
         inst.SoundEmitter:PlaySound("dontstarve/wilson/attack_whoosh")
        local buffaction = inst:GetBufferedAction()
        local target = buffaction ~= nil and buffaction.target or nil
        inst.components.combat:SetTarget(target)
        inst.components.combat:StartAttack()
        inst.components.locomotor:Stop()
        inst.Physics:Stop()
        inst.AnimState:PlayAnimation("atk")
		inst.AnimState:SetTime(9* FRAMES)
        if target ~= nil then
            if target:IsValid() then
                inst:FacePoint(target:GetPosition())
                inst.sg.statemem.attacktarget = target
            end
        end
    end,
     
    onexit = function(inst)
        inst.components.combat:SetTarget(nil)
    end,
     
    timeline =
    {
        TimeEvent(4*FRAMES, function(inst) inst:PerformBufferedAction() end), --13 frames
		TimeEvent(7*FRAMES, function(inst) inst.sg:RemoveStateTag("busy") end),
    },
     
    events =
    {
        EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
    },
},
	
	State{
    name = "work",
    tags = {"attack", "busy"},
     
    onenter = function(inst, target)
	     --inst.SoundEmitter:PlaySound("dontstarve/pig/attack")
         inst.SoundEmitter:PlaySound("dontstarve/wilson/attack_whoosh")
        local buffaction = inst:GetBufferedAction()
        local target = buffaction ~= nil and buffaction.target or nil
        inst.components.combat:SetTarget(target)
        inst.components.combat:StartAttack()
        inst.components.locomotor:Stop()
        inst.Physics:Stop()
        inst.AnimState:PlayAnimation("atk")
		inst.AnimState:SetTime(9* FRAMES)
        if target ~= nil then
            if target:IsValid() then
                inst:FacePoint(target:GetPosition())
                inst.sg.statemem.attacktarget = target
            end
        end
    end,
     
    onexit = function(inst)
        inst.components.combat:SetTarget(nil)
    end,
     
    timeline =
    {
        TimeEvent(4*FRAMES, function(inst) inst:PerformBufferedAction() end), --13 frames
		TimeEvent(10*FRAMES, function(inst) inst.sg:RemoveStateTag("attack") inst.sg:RemoveStateTag("busy") end),
    },
     
    events =
    {
        EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
    },
	},
	
    State{
        name = "chop",
        tags = {"chopping"},
        
        onenter = function(inst)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("atk")
        end,
        
        timeline=
        {
            
            TimeEvent(13*FRAMES, function(inst) inst:PerformBufferedAction() end ),
        },
        
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },
    
	State{
        name = "blowdart",
        tags = {"attack", "notalking", "abouttoattack", "autopredict"},
        
        onenter = function(inst)
            local buffaction = inst:GetBufferedAction()
            local target = buffaction ~= nil and buffaction.target or nil
            inst.components.combat:SetTarget(target)
            inst.components.combat:StartAttack()
            inst.components.locomotor:Stop()
            local cooldown = math.max(inst.components.combat.min_attack_period + .5 * FRAMES, 20 * FRAMES)

            inst.AnimState:PlayAnimation("atk_dart")

            inst.sg:SetTimeout(cooldown)

            if target ~= nil and target:IsValid() then
                inst:FacePoint(target.Transform:GetWorldPosition())
                inst.sg.statemem.attacktarget = target
            end
        end,
        timeline =
        {
            TimeEvent(17*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/wilson/blowdart_shoot") end),
            TimeEvent(20*FRAMES, function(inst) inst:PerformBufferedAction() end),
        },
        
        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },
	
    State{
        name = "eat",
        tags = {"busy"},
        
        onenter = function(inst)
            inst.Physics:Stop()            
            inst.AnimState:PlayAnimation("eat")
        end,
        
        timeline=
        {
            TimeEvent(10*FRAMES, function(inst) inst:PerformBufferedAction() end),
        },
        
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },        
    },
    State{
        name = "hit",
        tags = {"busy"},
        
        onenter = function(inst)
            PlayCreatureSound(inst, "hurt")
            inst.AnimState:PlayAnimation("hit")
            inst.Physics:Stop()            
        end,
        
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },        
    },    
}

CommonStates.AddWalkStates(states,
{
	walktimeline = {
		TimeEvent(0*FRAMES, PlayFootstep ),
		TimeEvent(12*FRAMES, PlayFootstep ),
	},
})
CommonStates.AddRunStates(states,
{
	runtimeline = {
		TimeEvent(0*FRAMES, PlayFootstep ),
		TimeEvent(10*FRAMES, PlayFootstep ),
	},
})

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

CommonStates.AddIdle(states)
CommonStates.AddSimpleActionState(states, "eat", "eat", 10*FRAMES, {"busy"})
CommonStates.AddFrozenStates(states)

CommonStates.AddSimpleState(states,"refuse", "pig_reject", {"busy"})

CommonStates.AddSimpleActionState(states,"pickup", "pig_pickup", 10*FRAMES, {"busy"})

CommonStates.AddSimpleActionState(states, "gohome", "pig_pickup", 4*FRAMES, {"busy"})



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

