-- 生命移除伤害，只会计算少女之抵抗，参数：单位、目标、百分比值、是否按当前生命值
function UnitDamageHpRemove(caster, target, percent, isCurrentHp)        
    if THTD_IsValid(caster) and THTD_IsValid(target) then
        local tower = nil
        if caster:THTD_IsTower() then
            tower = caster
        elseif THTD_IsValid(caster.thtd_spawn_unit_owner) and caster.thtd_spawn_unit_owner:THTD_IsTower() then
            tower = caster.thtd_spawn_unit_owner
        end
        
        local health = target:GetHealth()
        local damage = 0
        if isCurrentHp == true then 
            damage = health * percent / 100
        else
            damage = target:GetMaxHealth() * percent / 100
        end

        local factor = 1.0
        if target.unlimited_resist ~= nil then
            factor = 1 - target.unlimited_resist/100
        end

        if damage * factor >= health then             
            if tower ~= nil then  
                tower:THTD_AddTowerDamage(health) 
            end
            target:SetHealth(1)
            local DamageTable = {
                ability = nil,
                victim = target, 
                attacker = caster, 
                damage = 10000, 
                damage_type = DAMAGE_TYPE_PURE, 
                damage_flags = DOTA_DAMAGE_FLAG_NONE
            }
            ApplyDamage(DamageTable)
        else
            target:SetHealth(health - damage * factor)
            if tower ~= nil then  
                tower:THTD_AddTowerDamage(damage * factor)                                         
            end
        end
    end 
end

-- 强制击杀
function CDOTA_BaseNPC:NpcKill(target) 
    if target == nil or target:IsNull() or target:IsAlive() == false then 
        return 
    end
    local health = target:GetHealth()
    target.diseble_buff = true
    target:ForceKill(false)
    self:THTD_AddTowerDamage(health)
end

-- 卡牌秒杀技能，具有统一的上限
function CDOTA_BaseNPC:AbilityKill(target, ability)
    local tower
    if self:THTD_IsTower() then 
        tower = self
    elseif self.thtd_spawn_unit_owner ~= nil and self.thtd_spawn_unit_owner:THTD_IsTower() then 
        tower = self.thtd_spawn_unit_owner
    else
        print("----- error : AbilityKill is not a tower cast")
        return
    end

    -- if GameRules.player_bb_buff[playerid]["item_3019"] > 0 and GameRules.player_bb_buff[playerid]["item_3019_enable"] then
    --     factor = 1 + GameRules.player_bb_buff[playerid]["item_3019"]/100		
    -- end

    local damage = tower:GetKillDamage()
    local damageType = DAMAGE_TYPE_PURE
    if ability ~= nil then 
        damageType = ability:GetAbilityDamageType()
    end

    local DamageTable = {
        ability = ability,
        victim = target, 
        attacker = tower, 
        damage = damage, 
        damage_type = damageType, 
        damage_flags = DOTA_DAMAGE_FLAG_NONE
    }
    UnitDamageTarget(DamageTable)
end

-- 获取卡牌秒杀伤害
function CDOTA_BaseNPC:GetKillDamage()
    return self:THTD_GetStarDamage() * 100
end

-- 造成溢出伤害
function THTD_OverDamage(caster, ability, damage, point, range)
    if not THTD_IsValid(caster) then return end
    if damage == nil or damage <= 0 then return end

    local targetRange = range or 400
    local damageType = DAMAGE_TYPE_PURE
    if ability ~= nil then
        damageType = ability:GetAbilityDamageType()
    end

    caster:SetContextThink(DoUniqueString("thtd_over_damage"), 
        function()
            if GameRules:IsGamePaused() then return 0.03 end
            local targets = THTD_FindUnitsInRadius(caster,point,range)
            for k,v in pairs(targets) do
                local DamageTable = {
                    ability = ability,
                    victim = v, 
                    attacker = caster, 
                    damage = damage, 
                    damage_type = damageType,  
                    damage_flags = DOTA_DAMAGE_FLAG_NONE
                }
                UnitDamageTarget(DamageTable)
        
                local effectIndex = ParticleManager:CreateParticle("particles/heroes/thtd_flandre/abiilty_flandre_02_explosion.vpcf", PATTACH_CUSTOMORIGIN, caster)
                ParticleManager:SetParticleControl(effectIndex , 0 , v:GetOrigin())
                ParticleManager:DestroyParticleSystem(effectIndex,false)
            end            
            return nil
        end, 
    0.1)
end

-- 汇总式伤害结算
function UnitDamageApply(unit)
    if unit == nil or unit:IsNull() or unit:IsAlive() == false then return end
    if unit.thtd_player_index == nil then return end
    if unit.incoming_damage == nil or unit.incoming_damage == 0 then return end

    local DamageTable = {
        ability = nil,
        victim = unit, 
        attacker = GameRules.HeroList[unit.thtd_player_index], 
        damage = unit.incoming_damage, 
        damage_type = DAMAGE_TYPE_PURE,  
        damage_flags = DOTA_DAMAGE_FLAG_NONE
    }
    unit.incoming_damage = 0
    ApplyDamage(DamageTable)    
end

-- 汇总式伤害计算，如果isTest为true则返回生命/伤害占比，即目标当前生命值/本次伤害量的值，isAttack为普通攻击
function UnitDamageTarget(DamageTable, isTest, isAttack)
    local caster = DamageTable.attacker
    local target = DamageTable.victim
    -- local ability = DamageTable.ability
    local damageType = DamageTable.damage_type
    local damage = DamageTable.damage or 0
    local returnNull = 9999
    if damage <= 0 then return returnNull end

    if target == nil or target:IsNull() or target:IsAlive() == false then return returnNull end
    if target.thtd_damage_lock == true then	return returnNull end
 
    -- 召唤物继承主人的装备和buff效果
    local tower
	if caster:THTD_IsTower() then
		tower = caster
	elseif caster.thtd_spawn_unit_owner ~= nil and caster.thtd_spawn_unit_owner:THTD_IsTower() then
        tower = caster.thtd_spawn_unit_owner
    else
        return returnNull
	end

    -- 伤害类型转换
    if tower:HasModifier("modifier_junko_01") then
        damageType = DAMAGE_TYPE_PURE
    elseif tower:HasModifier("modifier_daiyousei_03") then 
        damageType = DAMAGE_TYPE_MAGICAL             
    elseif tower:HasModifier("modifier_momiji_02") then        
        damageType = DAMAGE_TYPE_PHYSICAL          
    elseif target:HasModifier("modifier_sunny_02_debuff") then
        damageType = DAMAGE_TYPE_PURE
    end

    -- 附加星能伤害（如相机、BOSS键山雏）
    local extra = tower:GetExtraStarDamagePercentage()
    if extra >= 1000000 then 
        local down = math.floor(extra/10000)
        local up = extra - down * 10000 - 5000
        if up ~= 0 then 
            damage = damage + tower:THTD_GetStarDamage() * up/100
        end      
        if damage > tower:THTD_GetStarDamage() * math.floor(down/100) then 
            damage = damage * (down - math.floor(down/100) * 100)/100
        end
    elseif extra ~= 0 then
        damage = damage + tower:THTD_GetStarDamage() * extra/100
    end    
    
    -- 计算双抗伤害
    if isAttack == true then --普通攻击已经是税后伤害
        if damageType ~= DAMAGE_TYPE_PHYSICAL then      
            damage = damage / target:GetPhysicalFactor()  
            if damageType == DAMAGE_TYPE_MAGICAL then        
                damage = damage * target:GetMagicalFactor()
            end
        end
    else
        if damageType == DAMAGE_TYPE_MAGICAL then        
            damage = damage * target:GetMagicalFactor()
        elseif damageType == DAMAGE_TYPE_PHYSICAL then        
            damage = damage * target:GetPhysicalFactor()            
        end
    end

    -- 装备4件套
    if target:GetHealthPercent() > 70 and tower:HasModifier("modifier_item_2009_damage") then
        damage = damage * 2     
    end    
    if target:GetHealthPercent() < 30 and tower:HasModifier("modifier_item_2010_damage") then
        damage = damage * 2        
    end

    -- 爆击伤害       
    if RollPercentage(tower:THTD_GetCritChance()) then
        damage = damage * (1 + tower:THTD_GetCritDamage()/100)
    end
        
    -- 增伤效果
    if damageType == DAMAGE_TYPE_PHYSICAL then        
        -- 攻击者物理增伤
        damage = damage * (1 + tower:GetDamageOutgoingPhysical()/100)
        -- 被攻击者物理伤害加深
        damage = damage * (1 + target:GetDamageIncomingPhysical()/100)
        -- 被攻击者物理伤害抵挡或附加        
        -- print("---- damage : ", damage)
        damage = damage - target:GetDamageBlockPhysical()  
        -- print("damage block: ", damage)      
    elseif damageType == DAMAGE_TYPE_MAGICAL then        
        -- 攻击者魔法增伤
        damage = damage * (1 + tower:GetDamageOutgoingMagical()/100)
        -- 被攻击者魔法伤害加深
        damage = damage * (1 + target:GetDamageIncomingMagical()/100)
        -- 被攻击者魔法伤害抵挡或附加
        damage = damage - target:GetDamageBlockMagical()
    elseif damageType == DAMAGE_TYPE_PURE then        
        -- 攻击者纯粹增伤
        damage = damage * (1 + tower:GetDamageOutgoingPure()/100)
        -- 被攻击者纯粹伤害加深
        damage = damage * (1 + target:GetDamageIncomingPure()/100)
        -- 被攻击者纯粹伤害抵挡或附加
        damage = damage - target:GetDamageBlockPure()
    end

    if damage <= 0 then return returnNull end
   
    -- 少女之抵抗
    if target.unlimited_resist ~= nil then
        damage = damage * (1 - target.unlimited_resist/100)
    end

    damage = math.floor(damage)

    -- 伤害统计
    if target.incoming_damage == nil then 
        target.incoming_damage = 0
    end
    local health = math.max(0, target:GetHealth() - target.incoming_damage)
    if isTest ~= true then 
        local towerName = tower:GetUnitName()   
        tower:THTD_AddTowerDamage(math.min(damage, health))
        -- 击杀则立即结算
        if damage >= health then
            local isDamageLock = false

            if target.komachi_04_damage_lock == true then 
                isDamageLock = true
            elseif target.flandre_damage_lock == true then
                isDamageLock = true
                if towerName == "flandre" then 
                    if target.flandre_04_lock == true then 
                        if DamageTable.ability ~= nil and DamageTable.ability:GetAbilityName() == "thtd_flandre_04" then 
                            isDamageLock = false
                        end
                    else
                        isDamageLock = false
                    end
                end
            end

            if isDamageLock == true then                 
                target.incoming_damage = target.incoming_damage + math.max(0, health - 100)
                UnitDamageApply(target)
            else
                target.incoming_damage = target.incoming_damage + damage    
                UnitDamageOnKill(tower, target)
                UnitDamageApply(target)
                if towerName == "flandre" and damage - health > 100 then            
                    THTD_OverDamage(tower, tower:FindAbilityByName("thtd_flandre_02"), damage - health, target:GetOrigin(), 400)
                end
            end
        else
            target.incoming_damage = target.incoming_damage + damage
        end        
        return returnNull
    else
        return health/damage
    end
end

-- 技能的OnKill事件
function UnitDamageOnKill(caster, target)
    local unitName = caster:GetUnitName()
    if unitName == "nue" then
        if caster:FindAbilityByName("thtd_nue_03"):GetLevel() >= 1 then
            caster:FindAbilityByName("thtd_nue_01"):EndCooldown()
            caster:FindAbilityByName("thtd_nue_02"):EndCooldown()		   
        end
    elseif unitName == "rumia" then
        if caster.rumia_01_bonus == nil then
            caster.rumia_01_bonus = 0
        end        
        local max_count = caster:GetAbilityValue("thtd_rumia_01", "max_bonus")      
        if caster:IsPower999() then 
            if caster.rumia_01_bonus < max_count * 10 then
                caster.rumia_01_bonus = caster.rumia_01_bonus + 1
                caster:THTD_AddBasePower(1)		
            end
        else
            if caster.rumia_01_bonus < max_count then 
                caster.rumia_01_bonus = caster.rumia_01_bonus + 1
                caster:THTD_AddBasePower(1)	
            elseif caster.rumia_01_bonus > max_count then 
                caster:THTD_AddBasePower(-(caster.rumia_01_bonus - max_count))	
                caster.rumia_01_bonus = max_count
            end
        end
    elseif unitName == "yuyuko" then
        if caster:HasModifier("modifier_yuyuko_03_think") then 
            if caster.yuyuko_kill_bonus_count == nil then
                caster.yuyuko_kill_bonus_count = 0
            end     

            local max_count = caster:GetAbilityValue("thtd_yuyuko_03", "max_count")
            local power_bonus = caster:GetAbilityValue("thtd_yuyuko_03", "power_bonus")

            if caster:IsPower999() then 
                if caster.yuyuko_kill_bonus_count < max_count * 3 then
                    caster.yuyuko_kill_bonus_count = caster.yuyuko_kill_bonus_count + 1
                    caster:THTD_AddBasePower(power_bonus)
                end
            else
                if caster.yuyuko_kill_bonus_count < max_count then 
                    caster.yuyuko_kill_bonus_count = caster.yuyuko_kill_bonus_count + 1
                    caster:THTD_AddBasePower(power_bonus)	
                elseif caster.yuyuko_kill_bonus_count > max_count then 
                    caster:THTD_AddBasePower(-(caster.yuyuko_kill_bonus_count - max_count) * power_bonus)
                    caster.yuyuko_kill_bonus_count = max_count
                end
            end
        end
    elseif unitName == "koishi" then
        if caster:HasModifier("passive_koishi_04_attack") then
            local effectIndex = ParticleManager:CreateParticle("particles/heroes/moluo/ability_moluo03_explosion.vpcf", PATTACH_CUSTOMORIGIN, caster)
            ParticleManager:SetParticleControl(effectIndex , 0, target:GetOrigin())
            ParticleManager:SetParticleControl(effectIndex , 3, target:GetOrigin())
            ParticleManager:DestroyParticleSystem(effectIndex,false)
        end
    elseif unitName == "sanae" or unitName == "kanako" or unitName == "suwako" then
        caster:THTD_AddFaith()
    elseif unitName == "futo" then
        local modifier = caster:FindModifierByName("modifier_futo_02_buff")
        if modifier == nil then
            local ability = caster:FindAbilityByName("thtd_futo_02")
            if ability:IsActivated() then 
                modifier = ability:ApplyDataDrivenModifier(caster, caster, "modifier_futo_02_buff", {Duration = caster:GetAbilityValue("thtd_futo_02", "duration_time")})
                modifier:SetStackCount(1)
            end
        else
            if modifier:GetStackCount() < caster:GetAbilityValue("thtd_futo_02", "max_count") then
                modifier:IncrementStackCount()
            end
            modifier:SetDuration(caster:GetAbilityValue("thtd_futo_02", "duration_time"),false)
        end
    end

    if caster:HasModifier("modifier_shinki_01_buff_kill") and caster.thtd_shinki_01_kill_count < 100 then 
        caster.thtd_shinki_01_kill_count = caster.thtd_shinki_01_kill_count + 1     
        caster:THTD_AddBasePower(1 * caster.thtd_shinki_01_kill_count, "thtd_shinki_01_kill")
        caster:FindModifierByName("modifier_shinki_01_buff_kill"):SetStackCount(caster.thtd_shinki_01_kill_count)
    end

    if target:HasModifier("modifier_thtd_yuuka_03_death") then 
        local modifier = target:FindModifierByName("modifier_thtd_yuuka_03_death")
        local yuuka = modifier:GetCaster()
        local max_count = yuuka:GetAbilityValue("thtd_yuuka_03", "max_count")
        local damage_up = yuuka:GetAbilityValue("thtd_yuuka_03", "damage_up")           
        if yuuka.thtd_yuuka_03_kill_count == nil then
            yuuka.thtd_yuuka_03_kill_count = 0
        end    
        if yuuka.thtd_yuuka_03_kill_count < max_count then               
            yuuka.thtd_yuuka_03_kill_count = yuuka.thtd_yuuka_03_kill_count + 1   
            local bonus = yuuka.thtd_yuuka_03_kill_count * damage_up    
            yuuka:AddDamageOutgoingAll(bonus, "thtd_yuuka_03_kill_bonus")
            yuuka:THTD_AddBaseAttack(bonus, "thtd_yuuka_03_kill_bonus")
            yuuka:THTD_AddBasePower(bonus, "thtd_yuuka_03_kill_bonus")
        elseif yuuka.thtd_yuuka_03_kill_count > max_count then           
            yuuka.thtd_yuuka_03_kill_count = max_count        
            yuuka:AddDamageOutgoingAll(max_count * damage_up, "thtd_yuuka_03_kill_bonus")
            yuuka:THTD_AddBaseAttack(max_count * damage_up, "thtd_yuuka_03_kill_bonus")
            yuuka:THTD_AddBasePower(max_count * damage_up, "thtd_yuuka_03_kill_bonus")
        end        
    end
end


-- 魔法抗性百分比更新，正增负减，如果小于0则设置为0 
function CDOTA_BaseNPC:AddMagicalResist(addCount) 
    if addCount == nil or addCount == 0 then return end   
    addCount = math.floor(addCount)

    if self.base_magical_resistance == nil then
        self.base_magical_resistance = self:GetBaseMagicalResistanceValue()
    end

    if self.magical_resistance_to_zero == true then
        self:SetBaseMagicalResistanceValue(0)
    else   
        local magical_resistance = self.base_magical_resistance + addCount
        self.base_magical_resistance = magical_resistance
        if magical_resistance > 0 then 
            self:SetBaseMagicalResistanceValue(magical_resistance)
        else
            self:SetBaseMagicalResistanceValue(0)
        end
    end
end

-- 移除魔法抗性，即一直设置为0 
function CDOTA_BaseNPC:RemoveMagicalResist()
    self.magical_resistance_to_zero = true
    self:SetBaseMagicalResistanceValue(0)
end

-- 物理护甲更新，正增负减，如果小于0则设置为0，注意只用基础护甲，Dota2自带减甲类modifier不可使用
function CDOTA_BaseNPC:AddPhysicalArmor(addCount) 
    if addCount == nil or addCount == 0 then return end   
    addCount = math.floor(addCount*100)/100

    if self.base_armor == nil then
        self.base_armor = self:GetPhysicalArmorBaseValue()
    end

    if self.physical_armor_to_zero == true then
        self:SetPhysicalArmorBaseValue(0)
    else   
        local armor = self.base_armor + addCount
        self.base_armor = armor
        if armor > 0 then 
            self:SetPhysicalArmorBaseValue(armor)
        else
            self:SetPhysicalArmorBaseValue(0)
        end
    end     
end

-- 移除物理护甲，即强制一直设置为0 
function CDOTA_BaseNPC:RemovePhysicalArmor()
    self.physical_armor_to_zero = true
    self:SetPhysicalArmorBaseValue(0)
end

-- 获取物理护甲后的伤害系数 
function CDOTA_BaseNPC:GetPhysicalFactor()
    local armor = self:GetPhysicalArmorValue(false)             
     if armor > 0 then 
        return 1 - (0.06 * armor /(1 + 0.06 * armor))  -- 7.27版本护甲计算			
    else 
        return 1 - (0.06 * armor /(1 - 0.06 * armor))  -- 7.27版本负护甲计算，负甲增伤		
    end
end

-- 获取魔法抗性后的伤害系数 
function CDOTA_BaseNPC:GetMagicalFactor()
    return 1 - self:GetBaseMagicalResistanceValue()/100
end


--增加毒的层数，创建或更新对应buff
function CDOTA_BaseNPC:AddPoison(stackCount, caster)
    local modifierName = "modifier_touhoutd_poison"
    local modifier = self:FindModifierByName(modifierName)
    if stackCount == nil then stackCount = 1 end
    if modifier == nil then     
        if stackCount > 0 then
            if caster == nil then caster = self end 
            modifier = self:AddNewModifier(caster, nil, modifierName, nil)
            if modifier == nil then return end
            modifier:SetStackCount(stackCount)
        end
    else
        local count = modifier:GetStackCount() + stackCount
        if count > 0 then 
            modifier:SetStackCount(count)
        else
            self:RemoveModifierByName(modifierName)
        end
    end    
end

--获取毒的层数，没有则返回0
function CDOTA_BaseNPC:GetPoisonCount()    
    local modifierName = "modifier_touhoutd_poison"
    local modifier = self:FindModifierByName(modifierName)
    if modifier == nil then    
        return 0
    else
        return modifier:GetStackCount()
    end
end