local assets =
{
    Asset("ANIM", "anim/tf2baseball.zip"),
    Asset("ANIM", "anim/sandman_stun.zip"),
}

local prefabs =
{
    "baseball",
    "splash_ocean",
}

local function LostBall(baseball)
    if not baseball.components.inventoryitem:IsHeld() then
        local x, y, z = baseball.Transform:GetWorldPosition()
        if not baseball:IsOnValidGround() or TheWorld.Map:IsPointNearHole(Vector3(x, 0, z)) then
            SpawnPrefab("splash_ocean").Transform:SetPosition(x, y, z)
            baseball:Remove()
        end
    end
end

local function SpawnBall(inst, owner, target)
    local baseball = SpawnPrefab("baseball")
    inst.components.lootdropper:FlingItem(baseball)
    if baseball:IsAsleep() then
	LostBall(baseball)
    else
	baseball:DoTaskInTime(8 * FRAMES, LostBall)
    end
end

local function OnHit(inst, owner, target)
    if not target:HasTag("bonked") then
	target:PushEvent("attacked", { attacker = owner, damage = 0 })
    end
    if target.components.health ~= nil then
        target.components.health:DoDelta(-TUNING.TF2SANDMAN_BASEBALL_DAMAGE)
    end
    SpawnBall(inst, owner, target)
    inst:Remove()
end

local function OnHitHomer(inst, owner, target)
    if owner and owner ~= nil then
	owner.components.talker:Say(GetString(owner, "ANNOUNCE_HOMERUN"))
    end
--	inst.SoundEmitter:PlaySound("dontstarve/common/magic_sparkle")
    if not target:HasTag("bonked") then
	target:PushEvent("attacked", { attacker = owner, damage = 0 })
    end
    if target.components.health ~= nil then
        target.components.health:DoDelta(-TUNING.TF2SANDMAN_BASEBALL_DAMAGE)
    end
    if target and target.homerstun == true then
	SpawnBall(inst, owner, target)
	inst:Remove()
	return
    end

    if target and target.brain and target.homerstun ~= true and not (target:HasTag("player") or target:HasTag("epic")) then
	target.homerstun = true
	target.stunfx = SpawnPrefab("sandman_stunfx")

	if target:HasTag("smallcreature") then
            target:AddChild(target.stunfx)
            target.stunfx.Transform:SetPosition(0, 0, 0)
	end
	if not target:HasTag("smallcreature") then
            local follower = target.stunfx.entity:AddFollower()
            follower:FollowSymbol(target.GUID, target.components.combat.hiteffectsymbol, 0, 0, 0)
	end

        if target.components.sleeper ~= nil then
            target.components.sleeper:GoToSleep(TUNING.HOMERSTUN)
        end

        if target.components.combat ~= nil then
            target.components.combat:SetTarget(nil)
        end

        if target.components.locomotor ~= nil then
            target.components.locomotor:Stop()
	    target.components.locomotor:SetExternalSpeedMultiplier(target, "homerunstun", .25)
        end
        target:DoTaskInTime(TUNING.HOMERSTUN, function()
        if target.components.locomotor ~= nil then
           target.components.locomotor:RemoveExternalSpeedMultiplier(target, "homerunstun")
        end
           target.homerstun = false
           target.stunfx:Remove()
        end)
    end

    if target:HasTag("player") and not target:HasTag("bonked") then
	target.homerstun = true
	target.stunfx = SpawnPrefab("sandman_stunfx")
        local follower = target.stunfx.entity:AddFollower()
        follower:FollowSymbol(target.GUID, "swap_body", 0, 0, 0)
        target.stunfx.persists = false
	target.components.locomotor:SetExternalSpeedMultiplier(target, "homerunstun", .5)
	target:AddTag("groggy")

        target:DoTaskInTime(TUNING.HOMERSTUN, function()
            target.components.locomotor:RemoveExternalSpeedMultiplier(target, "homerunstun")
	    target:RemoveTag("groggy")
            target.stunfx:Remove()
	    target.homerstun = false
        end)
    end

    SpawnBall(inst, owner, target)
    inst:Remove()
end

local function OnMiss(inst, owner, target)
    SpawnBall(inst, owner, nil)
    inst:Remove()
end

local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddNetwork()

    inst.Transform:SetFourFaced()

    MakeInventoryPhysics(inst)
    RemovePhysicsColliders(inst)

    inst.AnimState:SetBank("tf2baseball")
    inst.AnimState:SetBuild("tf2baseball")
    inst.AnimState:PlayAnimation("spin_loop")

    --projectile (from projectile component) added to pristine state for optimization
    inst:AddTag("projectile")

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

    inst.persists = false

    inst:AddComponent("lootdropper")

    inst:AddComponent("projectile")
    inst.components.projectile:SetSpeed(25)
    inst.components.projectile:SetHoming(false)
    inst.components.projectile:SetHitDist(1.5)
    inst.components.projectile:SetOnHitFn(OnHit)
    inst.components.projectile:SetOnMissFn(OnMiss)
    inst.components.projectile.range = 30

    return inst
end

local function homerfn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddNetwork()

    inst.Transform:SetFourFaced()

    MakeInventoryPhysics(inst)
    RemovePhysicsColliders(inst)

    inst.AnimState:SetBank("tf2baseball")
    inst.AnimState:SetBuild("tf2baseball")
    inst.AnimState:PlayAnimation("spin_loop")

    --projectile (from projectile component) added to pristine state for optimization
    inst:AddTag("projectile")

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

    inst.persists = false

    inst:AddComponent("lootdropper")

    inst:AddComponent("projectile")
    inst.components.projectile:SetSpeed(25)
    inst.components.projectile:SetHoming(false)
    inst.components.projectile:SetHitDist(1.5)
    inst.components.projectile:SetOnHitFn(OnHitHomer)
    inst.components.projectile:SetOnMissFn(OnMiss)
    inst.components.projectile.range = 30

    return inst
end

local function stunfxfn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddPhysics()
    inst.entity:AddNetwork()

    inst:AddTag("NOBLOCK")
    inst:AddTag("NOCLICK")
    inst:AddTag("FX")

    inst.AnimState:SetBank("sandman_stunn")
    inst.AnimState:SetBuild("sandman_stun")
    inst.AnimState:PlayAnimation("loop", true)

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end
    inst.persists = false

    return inst
end

return Prefab("baseballprojectile", fn, assets, prefabs),
	Prefab("baseballprohr", homerfn, assets),
	Prefab("sandman_stunfx", stunfxfn, assets)