-----------------------------------------------------------------------------------
-- This file has been developed exclusively for the mod "Jão the Great Summoner" --
--(http://steamcommunity.com/sharedfiles/filedetails/?id=572470943). 		 --
-- Any unauthorized use will be reported to the DMCA. 				 --
-- To use any file or sprite ask my permission.					 --
--										 --
-- Author: Paulo Victor de Oliveira Leal					 --
-- Contact: ciclopiano@gmail.com						 --
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------


-- Instanciar o cerebro
local brain = require "brains/summonchopbrain"

-- Imagens e animacoes a importar
local assets = {
    -- Icone
    Asset("ATLAS", "images/inventoryimages/chop.xml"),
    Asset("ATLAS", "images/inventoryimages/summonchop.xml"),
    -- Animacoes
    Asset("ANIM", "anim/leif_walking.zip"),
    Asset("ANIM", "anim/leif_actions.zip"),
    Asset("ANIM", "anim/leif_attacks.zip"),
    Asset("ANIM", "anim/leif_idles.zip"),
    Asset("ANIM", "anim/leif_build.zip"),
    Asset("ANIM", "anim/leif_lumpy_build.zip"),
    -- Sons
    Asset("SOUND", "sound/leif.fsb"),
}

-- Scripts necessarios
local prefabs = {
    "jao",
    "groundpound_fx",
    "groundpoundring_fx",
    "character_fire",
    "sourceofmagic"
}

-- Aura de Sanidade
local function CalcSanityAura(inst, observer)
    return inst.components.combat.target ~= nil 
    and -TUNING.SANITYAURA_TINY
    or -TUNING.SANITYAURA_SMALL_TINY
end

-- Pegar Fogo
local function OnBurnt(inst)
    if inst.components.propagator and inst.components.health and not inst.components.health:IsDead() then
        inst.components.propagator.acceptsheat = true
    end
end

-- Ataque em area
local function SetGroundPounderSettings(inst, mode)
    if mode == "normal" then 
        inst.components.groundpounder2.damageRings = 2
        inst.components.groundpounder2.destructionRings = 2
        inst.components.groundpounder2.numRings = 3
    end
end

-- Ao salvar
local function OnSave(inst, data)
    data.cangroundpound = inst.cangroundpound
end

-- Ao carregar
local function OnLoad(inst, data)
    if data ~= nil then
        inst.cangroundpound = data.cangroundpound
    end
end

-- Pronto para atacar em area
local function ontimerdone(inst, data)
    if data.name == "GroundPound" then
        inst.cangroundpound = true
    end
end

-- Fazer pet aceitar item do mestre
local function ShouldAcceptItem(inst, item)
    local currenthealth = inst.components.health.currenthealth / inst.components.health.maxhealth
    if item.components.edible and currenthealth < 1 and item.components.edible.healthvalue > 0 then
        return true
    end
    if item.components.equippable and 
	(item.components.equippable.equipslot == EQUIPSLOTS.HEAD or 
	item.components.equippable.equipslot == EQUIPSLOTS.HANDS or 
	item.components.equippable.equipslot == EQUIPSLOTS.BODY) and 
	not item.components.projectile then
        if item.prefab == "batbat" then
            print("refusing batbat")
            return false
        end
        return true
    end
end

-- Fazer pet pegar o item do mestre
local function OnGetItemFromPlayer(inst, giver, item)
    if item.components.equippable and 
	(item.components.equippable.equipslot == EQUIPSLOTS.HEAD or 
	item.components.equippable.equipslot == EQUIPSLOTS.HANDS or 
	item.components.equippable.equipslot == EQUIPSLOTS.BODY) then     
        local newslot = item.components.equippable.equipslot
        local current = inst.components.inventory:GetEquippedItem(newslot)
        if current then
            inst.components.inventory:DropItem(current)
        end      
        inst.components.inventory:Equip(item)
    elseif item.components.edible then
        inst.components.health:DoDelta(item.components.edible:GetHunger(inst), nil, item.prefab)
        inst:PushEvent("oneatsomething", {food = item})
        inst.sg:GoToState("eat")
    end
end

-- Fazer pet recusar item do mestre
local function OnRefuseItem(inst, item)
    inst.sg:GoToState("refuse")
    inst.components.talker:Say("I do not need this master...")
end

-- Localizar alvo
local function NormalRetargetFn(inst)
    return FindEntity(inst, TUNING.PIG_TARGET_DIST, function(guy)
        return guy:HasTag("monster") and guy.components.health and not guy.components.health:IsDead()
        and inst.components.combat:CanTarget(guy)
    end, nil, { "character" }, nil)
end

-- Ligar ao mestre
local function linkToBuilder(inst, builder)
    if not builder.components.leader then
        builder:AddComponent("leader")
    end
    builder.components.leader:AddFollower(inst, true)
    
    --builder.components.health:DoDelta(-30, nil, nil, nil, nil, true)
    builder.components.sanity:DoDelta(-20)
    
    -- Emitir sons e animacoes
    if builder.components.combat.hurtsound ~= nil and builder.SoundEmitter ~= nil then
        builder.SoundEmitter:PlaySound(builder.components.combat.hurtsound)
    end
    
    builder:PushEvent("damaged", {})
end

-- Reacao ao ser atacado
local function OnAttacked(inst, data)
    local attacker = data.attacker
    inst.components.combat:SetTarget(attacker)
    inst.components.combat:ShareTarget(attacker, 30, function(dude)
        return dude:HasTag("summonedbyplayer") and dude.components.follower.leader == inst.components.follower.leader
    end, 5)
end

-- Intrucao para atacar outro
local function OnAttackOther(inst, data)
    local target = data.target
    inst.components.combat:ShareTarget(target, 30, function(dude)
        return dude:HasTag("summonedbyplayer") and dude.components.follower.leader == inst.components.follower.leader
    end, 5)
end

-- Gerar escala do pet
local function applyscale(inst, scale)
    inst.components.combat:SetDefaultDamage(TUNING.ROCKY_DAMAGE * scale)
    local percent = inst.components.health:GetPercent()
    inst.components.health:SetMaxHealth(TUNING.ROCKY_HEALTH * scale)
    inst.components.health:SetPercent(percent)
    --MakeCharacterPhysics(inst, 200 * scale, scale)
    inst.components.locomotor.walkspeed = 1.5
end

-- Principal
local function fn()
    
    -- Instanciar pet
    local inst = CreateEntity()
    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddMiniMapEntity()
    inst.entity:AddSoundEmitter()
    inst.entity:AddDynamicShadow()
    inst.entity:AddNetwork()
    
    -- Gerar estrutura
    MakeCharacterPhysics(inst, 1000, .5)
    
    -- Construcao da sombra e outros
    inst.DynamicShadow:SetSize(4, 1.5)
    inst.entity:SetPristine()
    inst.Transform:SetFourFaced()
    
    -- Ligar animacoes ao character
    inst.AnimState:SetBank("leif")
    inst.AnimState:SetBuild("leif_build")
    inst.AnimState:PlayAnimation("idle_loop")--, true)
    inst.AnimState:Hide("ARM_carry")
    inst.AnimState:Show("ARM_normal")
    
    -- Setar icone no mapa
    inst.MiniMapEntity:SetIcon("chop.tex")
    inst.MiniMapEntity:SetPriority(4)
    
    -- Tags de controle
    inst:AddTag("summonchop")
    inst:AddTag("tree")
    inst:AddTag("sheltercarrier")
    inst:AddTag("summonedbyplayer")
    inst:AddTag("scarytoprey")
    
    if not TheWorld.ismastersim then
        return inst
    end
    
    -- Lista de componentes:
    inst:AddComponent("tibbercracker")
    
    inst:AddComponent("combat")
    inst.components.combat:SetDefaultDamage(90)
    inst.components.combat:SetAttackPeriod(2)
    inst.components.combat:SetRetargetFunction(3, NormalRetargetFn)
    
    local self = inst.components.combat
    local old = self.GetAttacked
    
    function self:GetAttacked(attacker, damage, weapon, stimuli)
        if attacker and attacker.prefab == "tentacle"  or (attacker:HasTag("player") and not attacker:HasTag("jaobuilder")) then
            return true
        end
        return old(self, attacker, damage, weapon, stimuli)
    end
    -- Fim do combate
    
    inst:AddComponent("sanityaura")
    inst.components.sanityaura.aurafn = CalcSanityAura
    
    inst:AddComponent("follower")
    
    inst:AddComponent("followersitcommand")
    
    inst:AddComponent("health")
    inst.components.health:SetMaxHealth(10000)
    inst.components.health:StartRegen(10, 10)
    
    MakeLargeBurnableCharacter(inst, "marker")
    inst.components.burnable.flammability = TUNING.LEIF_FLAMMABILITY
    inst.components.burnable:SetOnBurntFn(OnBurnt)
    inst.components.propagator.acceptsheat = true
    
    MakeHugeFreezableCharacter(inst, "marker")
    
    inst:AddComponent("inspectable")
    
    inst:AddComponent("groundpounder2")
    inst.components.groundpounder2.destroyer = true
    SetGroundPounderSettings(inst, "normal")
    
    inst:AddComponent("timer")
    
    inst:ListenForEvent("timerdone", ontimerdone)
    
    inst:AddComponent("inventory")
    
    inst:AddComponent("locomotor")
    inst.components.locomotor.walkspeed = 1.5
    
    inst:AddComponent("scaler")
    inst.components.scaler.OnApplyScale = applyscale
    inst.components.scaler:SetScale(TUNING.ROCKY_MAX_SCALE)
    
    inst:AddComponent("lootdropper")
    
    inst:AddComponent("talker")
    inst.components.talker:StopIgnoringAll()
    
    inst:AddComponent("trader")
    inst.components.trader:SetAcceptTest(ShouldAcceptItem)
    inst.components.trader.deleteitemonaccept = false
    inst.components.trader.onaccept = OnGetItemFromPlayer
    inst.components.trader.onrefuse = OnRefuseItem
    inst.components.trader:Enable()
    
    inst:ListenForEvent("equip", function()
	inst.AnimState:ClearOverrideSymbol("swap_hat")
	inst.AnimState:Show("hair")
	inst.AnimState:ClearOverrideSymbol("swap_body")
    end)
    -- Fim dos componentes
    
    -- Funcoes globais
    inst.cangroundpound = false
    
    inst.OnSave = OnSave
    inst.OnLoad = OnLoad
    
    
    inst:SetBrain(brain)
    inst:SetStateGraph("SGsummonchop")
    
    
    inst:AddComponent("perishable")
    inst.components.perishable.onperishreplacement = "sourceofmagic"
    inst.OnBuilt = linkToBuilder
    
    inst:ListenForEvent("attacked", OnAttacked)  
    inst:ListenForEvent("onattackother", OnAttackOther)
    
    return inst
end

return Prefab("common/summonchop", fn, assets, prefabs)