require("stategraphs/commonstates")

function TableConcat(t1,t2)
    for i=1,#t2 do
        t1[#t1+1] = t2[i]
    end
    return t1
end

local actionhandlers =
{
	ActionHandler(ACTIONS.EAT, "action"),
	ActionHandler(ACTIONS.FEED, "action"),
	ActionHandler(ACTIONS.ATTACK, "spin_pre"),
	ActionHandler(ACTIONS.PICKUP, "action2"),
	ActionHandler(ACTIONS.HARVEST, "action2"),
	ActionHandler(ACTIONS.DROP, "meep2"),
	ActionHandler(ACTIONS.FEED, "meep2"),
	ActionHandler(ACTIONS.GIVE, "meep2"),
	ActionHandler(ACTIONS.GIVETOPLAYER, "meep2"),
	ActionHandler(ACTIONS.GIVEALLTOPLAYER, "meep2"),
	ActionHandler(ACTIONS.HEAL, "action"),
	ActionHandler(ACTIONS.SLEEPIN, "sleep"),
	ActionHandler(ACTIONS.FAN, "wake"),
	ActionHandler(ACTIONS.JUMPIN, "meep2"),
	ActionHandler(ACTIONS.PICK, "action2"),
	ActionHandler(ACTIONS.SUMMONGUARDIAN, "meep"),
	ActionHandler(ACTIONS.COMBINESTACK, "action"),
	ActionHandler(ACTIONS.UNWRAP, "action"),
	ActionHandler(ACTIONS.GOHOME, "flyaway"),
	ActionHandler(ACTIONS.MIGRATE, "action2"),
}

local mobCraftActions =
{
ActionHandler(ACTIONS.GOHOME, "gohome"),
	ActionHandler(ACTIONS.ATTACK, "spin_pre"),
	ActionHandler(ACTIONS.ACTIVATE, "meep2"),	
	ActionHandler(ACTIONS.FEED, "meep2"),
	ActionHandler(ACTIONS.PICKUP, "action2"),
	ActionHandler(ACTIONS.PICK, "action2"),
	ActionHandler(ACTIONS.DROP, "meep2"),
	ActionHandler(ACTIONS.SLEEPIN, "sleep"),
	ActionHandler(ACTIONS.EAT, "action2"),
	ActionHandler(ACTIONS.HEAL, "action2"),
	ActionHandler(ACTIONS.FAN, "meep2"),
	ActionHandler(ACTIONS.DIG, "meep2"),
	ActionHandler(ACTIONS.CHOP, "meep2"),
	ActionHandler(ACTIONS.MINE, "meep2"),
	ActionHandler(ACTIONS.COOK, "meep2"),
	ActionHandler(ACTIONS.FILL, "meep2"),
	ActionHandler(ACTIONS.DRY, "meep2"),
	ActionHandler(ACTIONS.ADDFUEL, "meep2"),
	ActionHandler(ACTIONS.ADDWETFUEL, "meep2"),
	ActionHandler(ACTIONS.LIGHT, "meep2"),
	ActionHandler(ACTIONS.BAIT, "meep2"),
	ActionHandler(ACTIONS.BUILD, "meep2"),
	ActionHandler(ACTIONS.PLANT, "meep2"),
	ActionHandler(ACTIONS.REPAIR, "meep2"),
	ActionHandler(ACTIONS.HARVEST, "meep2"),
	ActionHandler(ACTIONS.STORE, "meep2"),
	ActionHandler(ACTIONS.RUMMAGE, "meep2"),
	ActionHandler(ACTIONS.DEPLOY, "meep2"),
	ActionHandler(ACTIONS.HAMMER, "meep2"),
	ActionHandler(ACTIONS.FERTILIZE, "meep2"),
	ActionHandler(ACTIONS.MURDER, "meep2"),
	ActionHandler(ACTIONS.INVESTIGATE, "meep2"),
	ActionHandler(ACTIONS.UNLOCK, "meep2"),
	ActionHandler(ACTIONS.TURNOFF, "meep2"),
	ActionHandler(ACTIONS.TURNON, "meep2"),
	ActionHandler(ACTIONS.SEW, "meep2"),
	ActionHandler(ACTIONS.COMBINESTACK, "meep2"),
	ActionHandler(ACTIONS.UPGRADE, "meep2"),
	ActionHandler(ACTIONS.WRITE, "meep2"),
	ActionHandler(ACTIONS.FEEDPLAYER, "meep2"),
	ActionHandler(ACTIONS.TERRAFORM, "meep2"),
	ActionHandler(ACTIONS.NET, "meep2"),
	ActionHandler(ACTIONS.CHECKTRAP, "meep2"),
	ActionHandler(ACTIONS.SHAVE, "meep2"),
	ActionHandler(ACTIONS.FISH, "meep2"),
	ActionHandler(ACTIONS.REEL, "meep2"),
	ActionHandler(ACTIONS.CATCH, "meep2"),
	ActionHandler(ACTIONS.TEACH, "meep2"),
	ActionHandler(ACTIONS.MANUALEXTINGUISH, "meep2"),
	ActionHandler(ACTIONS.RESETMINE, "meep2"),
	ActionHandler(ACTIONS.BLINK, "meep2"),
	ActionHandler(ACTIONS.GIVE, "meep2"),
	ActionHandler(ACTIONS.GIVEALLTOPLAYER, "meep2"),
	ActionHandler(ACTIONS.SMOTHER, "meep2"),
	ActionHandler(ACTIONS.CASTSPELL, "meep2"),
	---PetActions--
	ActionHandler(ACTIONS.PET, "meep2"),
	ActionHandler(ACTIONS.ABANDON, "meep2"),
	ActionHandler(ACTIONS.WRAPBUNDLE, "meep2"),
	ActionHandler(ACTIONS.UNWRAP, "meep2"),
	ActionHandler(ACTIONS.UNLOCK, "meep2"),
	ActionHandler(ACTIONS.USEKLAUSSACKKEY, "meep2"),
}


local extraActions = 
{
	ActionHandler(ACTIONS.TRAVEL, "taunt"),
	ActionHandler(ACTIONS.LOOKAT, "taunt"),
}

if MOBCRAFT == "Enable" then
	extraActions = mobCraftActions
end

actionhandlers = TableConcat(actionhandlers, extraActions)

local events=
{
	CommonHandlers.OnSleep(),
	CommonHandlers.OnFreeze(),
	EventHandler("doattack", function(inst)
		if inst.components.health and not inst.components.health:IsDead()
			and (inst.sg:HasStateTag("hit") or not inst.sg:HasStateTag("busy")) then
			if not inst.mother_dead then
				inst.sg:GoToState("attack")
			else
				inst.sg:GoToState("spin_pre")
			end
		end
	end),
	CommonHandlers.OnAttacked(),
	EventHandler("death", function(inst) inst.sg:GoToState("death") end),

	EventHandler("flyaway", function(inst)
		if not inst.components.health:IsDead() and not inst.sg:HasStateTag("busy") then
			inst.sg:GoToState("flyaway")
		end
	end),
	EventHandler("locomote", function(inst)
		local is_moving = inst.sg:HasStateTag("moving")
		local is_idling = inst.sg:HasStateTag("idle")
		local is_spinning = inst.sg:HasStateTag("spinning")
		local should_move = inst.components.locomotor:WantsToMoveForward()

		if (is_moving and not should_move) or (is_spinning and not should_move) then
			if is_spinning then
				--Stop Moving
				inst.sg.statemem.move = false
			else
				inst.sg:GoToState("walk_stop")
			end
		elseif (is_idling or is_moving or is_spinning) and should_move then
			if is_spinning then
				--Start Moving
				inst.sg.statemem.move = true
			elseif not is_moving then
				inst.sg:GoToState("walk_start")
			end
		end
	end),
	
	EventHandler("ms_opengift",
        function(inst)
            if not inst.sg:HasStateTag("busy") then
                inst.sg:GoToState("opengift")
            end
        end),
}

local function ShouldMooseStep(inst)
	--local ents = TheSim:FindEntities(x, y, z)
end

local function ShouldStopSpin(inst)
	local pos = inst:GetPosition()

	local nearby_player = FindClosestPlayerInRange(pos.x, pos.y, pos.z, 7.5, true)
	local time_out = inst.numSpins >= 2

	return not nearby_player or time_out
end

local function LightningStrike(inst)
	local rad = math.random(0,3)
	local angle = math.random() * 2 * PI
	local offset = Vector3(rad * math.cos(angle), 0, -rad * math.sin(angle))

	local pos = inst:GetPosition() + offset

	TheWorld:PushEvent("ms_sendlightningstrike", pos)
	TheWorld:PushEvent("ms_forceprecipitation", true)
end

local states=
{

	State{

		name = "idle",
		tags = {"idle", "canrotate"},
		onenter = function(inst, playanim)
			inst.Physics:Stop()
			inst.AnimState:PlayAnimation("idle")
		end,

		events=
		{
			EventHandler("animover", function(inst)
				if inst.components.combat.target then
					if math.random() < 0.25 then
						inst.sg:GoToState("taunt")
						return
					end
				end
				inst.sg:GoToState("idle")
			end),
		},
	},
	
	State{
        name = "death",
        tags = {"busy", "pausepredict", "nomorph"},

        onenter = function(inst)
            inst.components.locomotor:Stop()
            inst.components.locomotor:Clear()
            inst:ClearBufferedAction()
			
			inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/death") 
            inst.AnimState:PlayAnimation("death")
			--inst.components.lootdropper:DropLoot(Vector3(inst.Transform:GetWorldPosition()))
			inst.components.lootdropper:DropLoot(inst:GetPosition())
			inst.components.inventory:DropEverything(true)
            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" then
                     inst:PushEvent(inst.ghostenabled and "makeplayerghost" or "playerdied", { skeleton = false })
					else
						TheWorld:PushEvent("ms_playerdespawnanddelete", inst)
					end
                end
            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", 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 = "action",
		tags = {"busy"},

		onenter = function(inst)
			inst.Physics:Stop()
			inst.AnimState:PlayAnimation("action")
			inst.AnimState:PushAnimation("eat", false)
			inst.sg:SetTimeout(math.random()*2+1)
		end,

		timeline=
		{
			TimeEvent(7*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/eat") end),

			TimeEvent(10*FRAMES, function(inst)
				inst:PerformBufferedAction()
				inst.sg:RemoveStateTag("busy")
				--inst.brain:ForceUpdate()
				inst.sg:AddStateTag("wantstoeat")
			end),
		},

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

		ontimeout = function(inst)
			inst.sg:GoToState("eat_pst")
		end,
	},

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

		onenter = function(inst)
			inst.Physics:Stop()
			inst.AnimState:PlayAnimation("action")
			--inst.AnimState:PushAnimation("eat", false)
			--inst.sg:SetTimeout(math.random()*2+1)
		end,

		timeline=
		{
			TimeEvent(7*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/eat") end),

			TimeEvent(10*FRAMES, function(inst)
				inst:PerformBufferedAction()
				inst.sg:RemoveStateTag("busy")
				--inst.brain:ForceUpdate()
				inst.sg:AddStateTag("wantstoeat")
			end),
		},

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

		--ontimeout = function(inst)
			--inst.sg:GoToState("eat_pst")
		--end,
	},
	
	State{
		name = "eat_loop",
		tags = {"busy"},

		onenter = function(inst)
			inst.Physics:Stop()
			inst.AnimState:PushAnimation("eat", false)
		end,

		events =
		{
			EventHandler("animqueueover", function(inst)
				inst:PerformBufferedAction()
				inst.sg:GoToState("eat_pst")
			end)
		},

		timeline =
		{
			TimeEvent(22*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/chew") end),
		},
	},

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

		onenter = function(inst)
			inst.Physics:Stop()
			inst.AnimState:PlayAnimation("eat_pst")
			inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/strain")
		end,

		timeline = {},

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

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

		onenter = function(inst)
			inst.Physics:Stop()
			inst.AnimState:PlayAnimation("taunt_pre")
			inst.AnimState:PushAnimation("taunt")
			inst.AnimState:PushAnimation("taunt_pst", false)
		end,

		timeline=
		{
			TimeEvent(5*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(7*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/taunt") end),
			TimeEvent(9*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(13*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(17*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(21*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
		},

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


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

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

		timeline=
		{
			TimeEvent(7*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			--TimeEvent(10*FRAMES, function(inst) inst:PerformBufferedAction() end),
			TimeEvent(10*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/honk") end),
			TimeEvent(11*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(15*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(19*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(23*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
		},

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

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

		timeline=
		{
			TimeEvent(7*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(10*FRAMES, function(inst) inst:PerformBufferedAction() end),
			TimeEvent(10*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/honk") end),
			TimeEvent(11*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(15*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(19*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
			TimeEvent(23*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap") end),
		},

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

	State{
		name = "flyaway",
		tags = {"flying", "busy"},
		onenter = function(inst)
			inst.Physics:Stop()
			inst.DynamicShadow:Enable(false)
			inst.AnimState:PlayAnimation("takeoff_pre_vertical")
			inst.sg.statemem.strainSound = 20*FRAMES
			inst.sg.statemem.flapSound = 9*FRAMES
		end,

		onupdate = function(inst, dt)
			inst.sg.statemem.strainSound = inst.sg.statemem.strainSound - dt
			if inst.sg.statemem.strainSound <= 0 then
				inst.sg.statemem.strainSound = 70*FRAMES
				inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/strain")
			end

			inst.sg.statemem.flapSound = inst.sg.statemem.flapSound - dt
			if inst.sg.statemem.flapSound <= 0 then
				inst.sg.statemem.flapSound = 3*FRAMES
				inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/flap")
			end
		end,

		timeline =
		{
			TimeEvent(9*FRAMES, function(inst)
				inst.AnimState:PushAnimation("takeoff_vertical", true)
				inst.Physics:SetMotorVel(-2 + math.random()*4,3+math.random()*2,-2 + math.random()*4)
			end),
			TimeEvent(10, function(inst) inst:Remove() end)
		}
	},

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

		onenter = function(inst)
			local angle = math.random()*2*PI
			local speed = GetRandomWithVariance(3, 2)
			inst.Physics:SetMotorVel(speed*math.cos(angle), 0, speed*math.sin(angle))
			inst.AnimState:PlayAnimation("hatch")
		end,

		timeline =
		{
			TimeEvent(FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/hatch") end),
			TimeEvent(20*FRAMES, function(inst) inst.Physics:SetMotorVel(0,0,0) end),
			TimeEvent(47*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/pop") end)
		},

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

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

		onenter = function(inst)
			inst.Physics:Stop()
			inst.AnimState:PlayAnimation("spin_pre")
			inst.components.burnable:Extinguish()
			inst.numSpins = 0
		end,

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

		timeline =
		{
			TimeEvent(6*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/attack") end),
		},
	},

	State{
		name = "transform_loop", --transform into angry and non angry builds without having to attack.
		tags = {"busy", "spinning"},

		onenter = function(inst)
			inst.components.locomotor:StopMoving()
			if inst.isangry == false then
			inst.isangry = true
			inst.DynamicShadow:SetSize(2.5,1.25)
			inst.components.sizetweener:StartTween(1.55, 2)
				if inst.isshiny ~= 0 then
				inst.AnimState:SetBuild("mossling_angry_shiny_build_0"..inst.isshiny)
				else
				inst.AnimState:SetBuild("mossling_angry_build")
				end
			elseif inst.isangry == true then
			inst.isangry = false
			inst.DynamicShadow:SetSize(1.5,1.25)
			inst.components.sizetweener:StartTween(1, 1)
				if inst.isshiny ~= 0 then
					inst.AnimState:SetBuild("mossling_shiny_build_0"..inst.isshiny)
				else
					inst.AnimState:SetBuild("mossling_build")
				end
			end
			
			inst.AnimState:PlayAnimation("spin_loop")
			inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/spin", "spinLoop")
			
			local fx = SpawnPrefab("mossling_spin_fx")
			fx.entity:SetParent(inst.entity)
			fx.Transform:SetPosition(0,0.1,0)
			inst.components.burnable:Extinguish()
		end,

		onupdate = function(inst)
			if inst.sg.statemem.move then
				inst.components.locomotor:WalkForward()
			else
				inst.components.locomotor:StopMoving()
			end
		end,

		onexit = function(inst)
			inst.SoundEmitter:KillSound("spinLoop")
			inst.components.locomotor:StopMoving()
		end,

		timeline=
		{
		
		},

		events=
		{
			EventHandler("animover",
			function(inst)
				--inst.numSpins = inst.numSpins + 1
				--if ShouldStopSpin(inst) then
					inst.sg:GoToState("transform_pst")
				--else
					--inst.sg:GoToState("spin_loop")
				--end
			end),
		},
	},

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

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

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

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

		onenter = function(inst)
			inst.AnimState:PlayAnimation("spin_pst_loop", true)
			inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/dizzy", "dizzy")
			inst.sg:SetTimeout(math.random() + 4.5)
		end,

		onexit = function(inst)
			inst.SoundEmitter:KillSound("dizzy")
		end,

		timeline=
		{
		},

		ontimeout = function(inst)
			inst.sg:GoToState("spin_pst_loop_pst")
		end,
	},

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

		onenter = function(inst)
			inst.Physics:Stop()
			inst.AnimState:PlayAnimation("spin_pre")
			inst.components.burnable:Extinguish()
			inst.numSpins = 0
			inst.isangry = true
		end,

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

		timeline =
		{
			TimeEvent(6*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/attack") end),
		},
	},

	State{
		name = "spin_loop",
		tags = {"busy", "spinning"},

		onenter = function(inst)
		
			local buffaction = inst:GetBufferedAction()
			local target = buffaction ~= nil and buffaction.target or nil
			inst.components.combat:SetTarget(target)
			if target ~= nil then
            if target:IsValid() then
                inst:FacePoint(target:GetPosition())
                inst.sg.statemem.attacktarget = target
				end
			end

			inst.components.combat:StartAttack()
			inst.DynamicShadow:SetSize(2.5,1.25)
			inst.components.sizetweener:StartTween(1.55, 2)
			if inst.isshiny ~= 0 then
			inst.AnimState:SetBuild("mossling_angry_shiny_build_0"..inst.isshiny)
			else
			inst.AnimState:SetBuild("mossling_angry_build")
			end
			--inst.sg.statemem.target = target
			
			inst.AnimState:PlayAnimation("spin_loop")
			inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/spin", "spinLoop")

			local fx = SpawnPrefab("mossling_spin_fx")
			fx.entity:SetParent(inst.entity)
			fx.Transform:SetPosition(0,0.1,0)
			inst.components.burnable:Extinguish()
		end,

		onupdate = function(inst)
			--if inst.sg.statemem.move then
				inst.components.locomotor:WalkForward()
			--else
				--inst.components.locomotor:StopMoving()
			--end
		end,

		onexit = function(inst)
			inst.SoundEmitter:KillSound("spinLoop")
			inst.components.locomotor:StopMoving()
			inst.components.combat:SetTarget(nil)
		end,

		timeline=
		{
			--TimeEvent(5*FRAMES, function(inst)
				--if math.random() < 0.1 then
					--LightningStrike(inst)
				--end
			--end),
			TimeEvent(0*FRAMES, function(inst) inst.components.combat:DoAttack(inst.sg.statemem.target) end),
			TimeEvent(36*FRAMES, function(inst) inst.components.combat:DoAttack(inst.sg.statemem.target) end),
			TimeEvent(70*FRAMES, function(inst) inst.components.combat:DoAttack(inst.sg.statemem.target) end),
			TimeEvent(100*FRAMES, function(inst) inst.components.combat:DoAttack(inst.sg.statemem.target) end),
		},

		events=
		{
			EventHandler("animover",
			function(inst)
				inst.numSpins = inst.numSpins + 1
				if ShouldStopSpin(inst) then
					inst.sg:GoToState("spin_pst")
				else
					inst.sg:GoToState("spin_loop")
				end
			end),
		},
	},

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

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

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

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

		onenter = function(inst)
			inst.AnimState:PlayAnimation("spin_pst_loop", true)
			inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/dizzy", "dizzy")
			inst.sg:SetTimeout(math.random() + 4.5)
		end,

		onexit = function(inst)
			inst.SoundEmitter:KillSound("dizzy")
		end,

		timeline=
		{
		},

		ontimeout = function(inst)
			inst.sg:GoToState("spin_pst_loop_pst")
		end,
	},

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

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

		events =
		{
			EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
		},
	},
	
	State {
        name = "sleep",
        tags = { "sleeping" }, --add tag "busy" if you hate sliding

        onenter = function(inst)
            if inst.components.locomotor ~= nil then
                inst.components.locomotor:StopMoving()
            end
            inst.AnimState:PlayAnimation("sleep_pre")
            --if fns ~= nil and fns.onsleep ~= nil then
                --fns.onsleep(inst)
            --end
        end,

        --timeline = timelines ~= nil and timelines.starttimeline or nil,
		timeline =
		{
			TimeEvent(15*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/yawn") end)
		},
		
        events =
        {
            EventHandler("animqueueover", function(inst) inst.sg:GoToState("sleeping") end ),
            EventHandler("onwakeup", function(inst) inst.sg:GoToState("wake") end),
        },
    },

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

        --onenter = onentersleeping,
		
		onenter = function(inst)
				inst.components.locomotor:StopMoving()
				local hungerpercent = inst.components.hunger:GetPercent()
				if hungerpercent ~= nil and hungerpercent ~= 0 then -- We don't want players to heal out starvation.
				inst.components.health:DoDelta(5, false)
				end
				--inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/bearger/sleep")
				inst.AnimState:PlayAnimation("sleep_loop")
			end,

        --timeline = timelines ~= nil and timelines.sleeptimeline or nil,
		timeline =
		{
			TimeEvent(25*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/sleep") end)
		},

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

    State
    {
        name = "wake",
        tags = { "busy", "waking" },

        onenter = function(inst)
            if inst.components.locomotor ~= nil then
                inst.components.locomotor:StopMoving()
            end
            inst.AnimState:PlayAnimation("sleep_pst")
            if inst.components.sleeper ~= nil and inst.components.sleeper:IsAsleep() then
                inst.components.sleeper:WakeUp()
            end
            --if fns ~= nil and fns.onwake ~= nil then
                --fns.onwake(inst)
            --end
        end,

        --timeline = timelines ~= nil and timelines.waketimeline or nil,
		
		timeline =
		{
			TimeEvent(10*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/mossling/hatch") end)
		},
		
        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },
	
}

CommonStates.AddFrozenStates(states)
CommonStates.AddWalkStates(states,
{
	walktimeline =
	{
		TimeEvent(FRAMES, function(inst) PlayFootstep(inst) end),
		TimeEvent(5*FRAMES, function(inst) PlayFootstep(inst) end),
		TimeEvent(10*FRAMES, function(inst) PlayFootstep(inst) end),
	}
})



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