local brain = require "brains/krampuserbrain"

local WAKE_TO_FOLLOW_DISTANCE = 12
local SLEEP_NEAR_LEADER_DISTANCE = 6
local assets =
{
    Asset("ANIM", "anim/krampuser.zip"),
    Asset("ANIM", "anim/krampuser_basic.zip"),
    Asset("IMAGE", "images/ui_chest_5x16.tex"),
    Asset("ATLAS", "images/ui_chest_5x16.xml"),
    Asset("SOUND", "sound/krampus.fsb"),
    Asset("IMAGE", "images/inventoryimages/krampuser.tex"),
    Asset("ATLAS", "images/inventoryimages/krampuser.xml"),
}
-----------------------------------------------------------
local function GetTeleportPoint(pt)
    local theta = math.random() * 2 * PI
    local radius = 6

	local offset = FindWalkableOffset(pt, theta, radius, 12, true)
	if offset then
		return pt+offset
	end
end

local function FollowPlayer(inst)
      local player = GetPlayer() 
        if  inst.components.follower.leader ~= player then
             inst.components.follower:SetLeader(player)
        end 
        if  inst.components.combat.target == player then
             inst.components.combat:SetTarget(nil)
        end 
	local pt = Vector3(GetPlayer().Transform:GetWorldPosition())
	
	if (inst:GetDistanceSqToInst(player) > (24*24)) then
            if inst.components.combat.target ~= nil then
                inst.components.combat:SetTarget(nil)
                inst.components.combat.retargettask = nil
                inst.components.combat.target = nil
            end
		local spawn_pt = GetTeleportPoint(pt)
                inst.Physics:Teleport(spawn_pt:Get())
                inst:FacePoint(pt)
	end
end
			
-----------------------------------------------------------

local function getitem(inst, item)

    inst.components.container:GiveItem(item)

end

local function pickup(inst)
    local pt = inst:GetPosition()
    local ents = TheSim:FindEntities(pt.x, pt.y, pt.z, 1.5)

    for k,v in pairs(ents) do
        if v.components.inventoryitem and v.components.inventoryitem.canbepickedup and v.components.inventoryitem.cangoincontainer and not
            v.components.inventoryitem:IsHeld() then

            if not inst.components.container:IsFull() then
                getitem(inst, v)
                return

            elseif v.components.stackable then
                local stack = inst.components.container:FindItem(function(item) return (item.prefab == v.prefab and not item.components.stackable:IsFull()
                    and item ~= inst.components.container.activeitem) end)
                if stack then
                    getitem(inst, v)
                    return
                end
            end
        end
    end
    
end
-----------------------------------------------------------
local function Scalekrampuser(inst)
	local krampuser_healthpercent = inst.components.health:GetPercent()
     if krampuser_healthpercent <= 0.04 and (not inst:HasTag("krampuser1")) then
    inst.Transform:SetScale(0.2, 0.2, 0.2)
    inst.components.locomotor.runspeed = TUNING.KRAMPUSER_SPEED * 5
    inst.components.combat:SetDefaultDamage(0.2*TUNING.KRAMPUSER_DAMAGE)
    inst.components.combat:SetAreaDamage(nil, nil)
    inst.components.combat:SetAttackPeriod(TUNING.KRAMPUSER_ATTACK_PERIOD)
    inst.components.health:StopRegen()
    inst.components.health:StartRegen(0.01*TUNING.KRAMPUSER_HEALTH, 20)
    inst:AddTag("krampuser1")
    if inst:HasTag("krampuser2") then inst:RemoveTag("krampuser2") end
    if inst:HasTag("krampuser3") then inst:RemoveTag("krampuser3") end
    if inst:HasTag("krampuser4") then inst:RemoveTag("krampuser4") end
    if inst:HasTag("krampuser5") then inst:RemoveTag("krampuser5") end

     elseif krampuser_healthpercent > 0.04 and krampuser_healthpercent <= 0.25 and not inst:HasTag("krampuser2")  then
    inst.Transform:SetScale(0.4, 0.4, 0.4)
    inst.components.locomotor.runspeed = TUNING.KRAMPUSER_SPEED * 2.5
    inst.components.combat:SetDefaultDamage(0.4*TUNING.KRAMPUSER_DAMAGE)
    if inst:HasTag("krampuser1") then inst:RemoveTag("krampuser1") end
    inst:AddTag("krampuser2")
    if inst:HasTag("krampuser3") then inst:RemoveTag("krampuser3") end
    if inst:HasTag("krampuser4") then inst:RemoveTag("krampuser4") end
    if inst:HasTag("krampuser5") then inst:RemoveTag("krampuser5") end

     elseif krampuser_healthpercent > 0.25 and krampuser_healthpercent <= 0.5 and not inst:HasTag("krampuser3") then
    inst.Transform:SetScale(0.8, 0.8, 0.8)
    inst.components.locomotor.runspeed = TUNING.KRAMPUSER_SPEED * 1.25
    inst.components.combat:SetDefaultDamage(0.8*TUNING.KRAMPUSER_DAMAGE)
    if inst:HasTag("krampuser1") then inst:RemoveTag("krampuser1") end
    if inst:HasTag("krampuser2") then inst:RemoveTag("krampuser2") end
    inst:AddTag("krampuser3")
    if inst:HasTag("krampuser4") then inst:RemoveTag("krampuser4") end
    if inst:HasTag("krampuser5") then inst:RemoveTag("krampuser5") end

     elseif krampuser_healthpercent > 0.5 and krampuser_healthpercent <= 0.75 and not inst:HasTag("krampuser4") then
    inst.Transform:SetScale(1.2, 1.2, 1.2)
    inst.components.locomotor.runspeed = TUNING.KRAMPUSER_SPEED * 5/6
    inst.components.combat:SetDefaultDamage(1.2*TUNING.KRAMPUSER_DAMAGE)
    if inst:HasTag("krampuser1") then inst:RemoveTag("krampuser1") end
    if inst:HasTag("krampuser2") then inst:RemoveTag("krampuser2") end
    if inst:HasTag("krampuser3") then inst:RemoveTag("krampuser3") end
    inst:AddTag("krampuser4")
    if inst:HasTag("krampuser5") then inst:RemoveTag("krampuser5") end

    elseif krampuser_healthpercent > 0.75 and not inst:HasTag("krampuser5") then 
                inst.Transform:SetScale(1.6, 1.6, 1.6)
                inst.components.locomotor.runspeed = TUNING.KRAMPUSER_SPEED * 0.625
               inst.components.combat:SetDefaultDamage(1.6*TUNING.KRAMPUSER_DAMAGE)
    if inst:HasTag("krampuser1") then inst:RemoveTag("krampuser1") end
    if inst:HasTag("krampuser2") then inst:RemoveTag("krampuser2") end
    if inst:HasTag("krampuser3") then inst:RemoveTag("krampuser3") end
    if inst:HasTag("krampuser4") then inst:RemoveTag("krampuser4") end
    inst:AddTag("krampuser5")

    end
end
-----------------------------------------------------------
-----------------------------------------------------------
local function ShouldWakeUp(inst)
    return DefaultWakeTest(inst) or not inst.components.follower:IsNearLeader(WAKE_TO_FOLLOW_DISTANCE)
end

local function ShouldSleep(inst)
    return DefaultSleepTest(inst) and inst.components.follower:IsNearLeader(SLEEP_NEAR_LEADER_DISTANCE)
end

local function OnOpen(inst)
    if not inst.components.health:IsDead() then
	inst.AnimState:Hide("SACK")
	inst.AnimState:Show("ARM")
    end
end 

local function OnClose(inst) 
    if not inst.components.health:IsDead() then
	inst.AnimState:Show("SACK")
	inst.AnimState:Hide("ARM")
    end
end 
-----------------------------------------------------------
-----------------------------------------------------------

local function SetBurnArea(inst,range,damage)
    local pos = Vector3(inst.Transform:GetWorldPosition())
    local ents = TheSim:FindEntities(pos.x, pos.y, pos.z, range)
    for i,ent in ipairs(ents) do
        if ent ~= GetPlayer() and ent ~= inst and not ent:HasTag("krampuse") and not ent:HasTag("rockypet") then

          if ent.components.health  then
              ent.components.health:DoDelta(-damage)
          end

         if ent.components.burnable and not ent.components.burnable:IsBurning() then
         if ent.components.freezable and ent.components.freezable:IsFrozen() then           
            ent.components.freezable:Unfreeze()            
         else            
            ent.components.burnable:Ignite()
         end   
         end

        if ent.components.freezable then
        ent.components.freezable:AddColdness(-1)
        if ent.components.freezable:IsFrozen() then
            ent.components.freezable:Unfreeze()            
        end
        end

        if ent.components.sleeper and ent.components.sleeper:IsAsleep() then
        ent.components.sleeper:WakeUp()
        end

       if ent.components.combat then
        ent.components.combat:SuggestTarget(inst)
        if ent.sg and ent.sg.sg.states.hit then
            ent.sg:GoToState("hit")
        end
       end

     end
   end
end

local function Skill1(inst) 
    inst.components.machine.ison = true
local krampuserhealthpercent = inst.components.health:GetPercent()
if  not inst:HasTag("skill1") and inst:HasTag("skill1ready") then
    inst.components.combat:SetAreaDamage(6, 0.8)
    inst.components.health:StopRegen()
    inst.components.health:StartRegen(-0.01*TUNING.KRAMPUSER_HEALTH, 4)
    inst:AddTag("skill1")
    inst:RemoveTag("skill1ready")
    inst:DoTaskInTime(5, function() if not inst:HasTag("skill1ready") then inst:AddTag("skill1ready") end end)

elseif  inst:HasTag("skill1") and inst:HasTag("skill3ready") and krampuserhealthpercent > 0.1 then
    inst.components.combat:SetAreaDamage(nil, nil)
    inst.components.health:StopRegen()
inst.components.health:StartRegen(0.01*TUNING.KRAMPUSER_HEALTH, 20)
         inst.components.health:DoDelta(-0.08*TUNING.KRAMPUSER_HEALTH)
    SetBurnArea(inst,50,50)
    inst:RemoveTag("skill1")
    inst:RemoveTag("skill3ready")
    inst:DoTaskInTime(15, function() if not inst:HasTag("skill3ready") then inst:AddTag("skill3ready") end end)
end
end

-----------------------------------------------------------

local function SetHealArea(inst,range,heal)
    local pos = Vector3(inst.Transform:GetWorldPosition())
    local ents = TheSim:FindEntities(pos.x, pos.y, pos.z, range)
    for i,ent in ipairs(ents) do
        if ent.components.health and ent.components.combat then
            if ent == GetPlayer() or ent.components.combat:IsAlly(GetPlayer()) or ent.prefab == "rockypet" then
                   if ent.components.health then
                      ent.components.health:DoDelta(heal)
                   end
            elseif ent == inst then
                   ent.components.health:DoDelta(0.1*TUNING.KRAMPUSER_HEALTH)
            end
        end
    end
end
local function GetSpawnPoint(ptt)
    local theta = math.random() * 2 * PI
    local radius = 25

	local offset = FindWalkableOffset(ptt, theta, radius, 12, true)
	if offset then
		return ptt+offset
	end
end

local function Spawnrockypet(inst)

    local ptt = Vector3(inst.Transform:GetWorldPosition())       
		local spawn_pos = GetSpawnPoint(ptt)
    if spawn_pos then
           local rockypet = SpawnPrefab("rockypet")
            rockypet.Physics:Teleport(spawn_pos:Get())
            return rockypet
     end
end

local function Skill2(inst) 
    inst.components.machine.ison = false
    inst.components.combat:SetAreaDamage(nil, nil)
    inst.components.health:StopRegen()
inst.components.health:StartRegen(0.01*TUNING.KRAMPUSER_HEALTH, 20)
if  not inst:HasTag("skill2") and inst:HasTag("skill2ready") then
    SetHealArea(inst,6,0.025*TUNING.KRAMPUSER_HEALTH)

    inst:AddTag("skill2")
    inst:RemoveTag("skill2ready")
    inst:DoTaskInTime(10, function() if not inst:HasTag("skill2ready") then inst:AddTag("skill2ready") end end)

elseif inst:HasTag("skill4ready") then
     inst.AnimState:PlayAnimation("exit")
    inst:DoTaskInTime(5, function() Spawnrockypet(inst) end)
    inst:DoTaskInTime(10, function() Spawnrockypet(inst) end)
    inst:DoTaskInTime(15, function() Spawnrockypet(inst) end)
    inst:RemoveTag("skill2")
    inst:RemoveTag("skill4ready")
    inst:DoTaskInTime(20, function() if not inst:HasTag("skill4ready") then inst:AddTag("skill4ready") end end)
end
end
-----------------------------------------------------------
-----------------------------------------------------------
local function Retarget(inst)
 return FindEntity(inst, TUNING.KRAMPUSER_TARGET_DIST,
        function(guy)
            if not guy.LightWatcher or guy.LightWatcher:IsInLight() and inst.components.follower:IsNearLeader(WAKE_TO_FOLLOW_DISTANCE) then
                return guy:HasTag("monster") and guy.components.health and not guy.components.health:IsDead() and inst.components.combat:CanTarget(guy) and not (guy:HasTag("player") or guy == GetPlayer() or guy:HasTag("krampus"))
            end
        end)

end

local function KeepTarget(inst, target)
    return inst:IsNear(target, TUNING.KRAMPUSER_LOSETARGET_DIST) and (not target.LightWatcher or target.LightWatcher:IsInLight() and inst.components.follower:IsNearLeader(WAKE_TO_FOLLOW_DISTANCE))
end

local function OnAttacked(inst, data)
      local player = GetPlayer() 
if  data.attacker ~= player then
    inst.components.combat:SetTarget(data.attacker)
    inst.components.combat:ShareTarget(data.attacker, 30, function(dude)
        return dude:HasTag("krampus") and dude:HasTag("rockypet") and not dude.components.health:IsDead()
    end, 6)
end
end

local slotpos = {}
	for y = 4, 0, -1 do
	for x = 0, 15 do
	table.insert(slotpos, Vector3(80*x-346*2+90, 80*y-100*2+40,0))
	end
end

local function fn(Sim)

    local inst = CreateEntity()
    
    inst:AddTag("companion")
    inst:AddTag("character")
    inst:AddTag("krampuser")
    inst:AddTag("notraptrigger")

    inst.entity:AddTransform()

    local minimap = inst.entity:AddMiniMapEntity()
    minimap:SetIcon( "krampus_sack.png" )


    inst.entity:AddAnimState()
    inst.AnimState:SetBank("krampus")
    inst.AnimState:SetBuild("krampuser")


    inst.entity:AddSoundEmitter()


    inst.entity:AddDynamicShadow()
    inst.DynamicShadow:SetSize( 3, 1 )

      MakeCharacterPhysics(inst, 10, .5)
    

    inst.Physics:SetCollisionGroup(COLLISION.CHARACTERS)
    inst.Physics:ClearCollisionMask()
    inst.Physics:CollidesWith(COLLISION.WORLD)
    inst.Physics:CollidesWith(COLLISION.OBSTACLES)
    inst.Physics:CollidesWith(COLLISION.CHARACTERS)

    inst.Transform:SetFourFaced()

     inst.Transform:SetScale(1.6, 1.6, 1.6)


    inst:AddComponent("combat")
    inst.components.combat.hiteffectsymbol = "krampus_torso"
    inst.components.combat:SetDefaultDamage(1.6 * TUNING.KRAMPUSER_DAMAGE)
    inst.components.combat:SetAttackPeriod(TUNING.KRAMPUSER_ATTACK_PERIOD)
    inst.components.combat:SetRetargetFunction(TUNING.KRAMPUSER_TARGET_DIST, Retarget)
    inst.components.combat:SetKeepTargetFunction(KeepTarget)
    inst:ListenForEvent("attacked", OnAttacked)


    inst:AddComponent("health")
    inst.components.health:SetMaxHealth(TUNING.KRAMPUSER_HEALTH)
    inst.components.health:StartRegen(0.01*TUNING.KRAMPUSER_HEALTH, 20)
    inst:AddTag("noauradamage")
    inst:AddComponent("lootdropper")
    inst.components.lootdropper:SetLoot({"houndfire","krampuseregg"})
    inst.components.lootdropper:AddChanceLoot("krampus_sack", .001)

    ------------------------------------------

    inst:AddComponent("inspectable")
	inst.components.inspectable:RecordViews()


    inst:AddComponent("locomotor")
    inst.components.locomotor.runspeed = TUNING.KRAMPUSER_SPEED * 0.625


    inst:AddComponent("follower")

    inst:AddComponent("knownlocations")


    inst:AddComponent("container")
    inst.components.container:SetNumSlots(#slotpos)
    
    inst.components.container.onopenfn = OnOpen
    inst.components.container.onclosefn = OnClose
    
    inst.components.container.widgetslotpos = slotpos
        inst.components.container.widgetbgimage = "ui_chest_5x16.tex"
        inst.components.container.widgetbgatlas = "images/ui_chest_5x16.xml"
    inst.components.container.widgetpos = Vector3(0,200,0)
	inst.components.container.widgetbgimagetint = {r=.57,g=.18,b=.18,a=1}


    inst:AddComponent("sleeper")
    inst.components.sleeper:SetResistance(3)
    inst.components.sleeper.testperiod = GetRandomWithVariance(6, 2)
    inst.components.sleeper:SetSleepTest(ShouldSleep)
    inst.components.sleeper:SetWakeTest(ShouldWakeUp)

        local light = inst.entity:AddLight()
    inst.Light:SetIntensity(0.5)
    inst.Light:SetRadius(1)
        light:SetColour(238/255, 17/255, 39/255)
        inst.Light:Enable(true)

    inst:SetStateGraph("SGkrampuser")
    inst.sg:GoToState("idle")


    inst:AddComponent("machine")
    inst.components.machine.turnonfn = Skill1
    inst.components.machine.turnofffn = Skill2

    inst:SetBrain(brain) 
    inst:DoTaskInTime(120, function() inst:AddTag("skill1ready") end)
    inst:DoTaskInTime(480, function() inst:AddTag("skill2ready") end)
    inst:DoTaskInTime(480, function() inst:AddTag("skill3ready") end)
    inst:DoTaskInTime(1200, function() inst:AddTag("skill4ready") end)
    inst.Followtask = inst:DoPeriodicTask(0, function()  FollowPlayer(inst) end)
    inst.Scalekrampusertask = inst:DoPeriodicTask(0.5, function()  Scalekrampuser(inst) end)
    inst.picktask = inst:DoPeriodicTask(1, function() pickup(inst) end)
    return inst
end

return Prefab( "common/krampuser", fn, assets)  
