• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • Create a faction for Warcraft 3 and enter Hive's 19th Techtree Contest: Co-Op Commanders! Click here to enter!
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 21st Texturing Contest: Upgrade is now concluded, time to vote for your favourite set of icons! Click here to vote!

CR - Main Engine

JASS:
library MainEngine requires Main, MISC, BuffsEngine, SkillsDatabase, Events

// setups
    define { 
        STANDART_TEXTURE = 'B02Z'
        WEAPON_ON = 'A01E'
        WEAPON_OFF = 'A01F'
    }

    
    
    void SetTexture(unit u, int texture_id){
        bj_lastCreatedDestructable = CreateDestructable(texture_id, Gx(u) + Rx(10., Ga(u)), Gy(u) + Ry(10., Ga(u)), 0., 1., 0)
        UnitAddAbility(u, 'Agra')
        IssueTargetOrderById(u, order_grabtree, bj_lastCreatedDestructable)
        UnitRemoveAbility(u, 'Agra')
        RemoveDestructable(bj_lastCreatedDestructable)
        SetUnitAnimation(u, "stand")
    }

    void RemoveCustomItem(item i){
        WeaponItem weapon = GetItemData(i)
        ArmorItem armor = GetItemData(i)
        JewelryItem jewelry = GetItemData(i)
        ShieldItem shield = GetItemData(i)
        int item_cell = GetItemCell(GetItemTypeId(i))
            if ItemType[item_cell] == 1 {
                RemoveItem(weapon.weapon_item)
                weapon.weapon_item = null
                weapon.destroy()
            }
            elseif ItemType[item_cell] == 2 {
                RemoveItem(armor.armor_item)
                armor.armor_item = null
                armor.destroy()
            }
            elseif ItemType[item_cell] == 3 {
                RemoveItem(jewelry.jewelry_item)
                jewelry.jewelry_item = null
                jewelry.destroy()
            }
            elseif ItemType[item_cell] == 4 {
                RemoveItem(shield.shield_item)
                shield.shield_item = null
                shield.destroy()
            }
    }
    
    item CreateWeaponItem(int item_id, real x, real y){
        WeaponItem weapon = WeaponItem.create()
        item i = CreateItem(item_id, x, y)
        int cell = GetWeaponCell(item_id)
            weapon.setup(i, WeaponType[cell], WeaponRank[cell])
            weapon.damage =  WeaponDamage[cell]
            weapon.magical_damage =  WeaponMagicalDamage[cell]
            weapon.accuracy =  WeaponAccuracy[cell]
            weapon.magical_accuracy =  WeaponMagicalAccuracy[cell]
            weapon.model = WeaponShellModel[cell]
            weapon.shell_speed = WeaponShellSpeed[cell]
            weapon.shell_end_z = WeaponEndZ[cell]
            weapon.shell_limit_z = WeaponLimitZ[cell]
            weapon.shell_size = WeaponShellSize[cell]
            weapon.which_state_bonus[1] = WeaponParameterType[cell][1]
            weapon.which_state_value_bonus[1] = WeaponParameterBonus[cell][1]
            weapon.which_state_bonus[2] = WeaponParameterType[cell][2]
            weapon.which_state_value_bonus[2] = WeaponParameterBonus[cell][2]
            weapon.which_state_bonus[3] = WeaponParameterType[cell][3]
            weapon.which_state_value_bonus[3] = WeaponParameterBonus[cell][3]
            weapon.which_state_bonus[4] = WeaponParameterType[cell][4]
            weapon.which_state_value_bonus[4] = WeaponParameterBonus[cell][4]
            SetItemData(i, weapon)
        return i
    }
    
    item CreateArmorItem(int item_id, real x, real y){
        ArmorItem armor = ArmorItem.create()
        item i = CreateItem(item_id, x, y)
        int cell = GetArmorCell(item_id)
            armor.setup(i, ArmorRank[cell], ArmorDefence[cell])
            armor.point = ArmorPoint[cell]
            armor.which_state_bonus[1] = ArmorParameterType[cell][1]
            armor.which_state_value_bonus[1] = ArmorParameterBonus[cell][1]
            armor.which_state_bonus[2] = ArmorParameterType[cell][2]
            armor.which_state_value_bonus[2] = ArmorParameterBonus[cell][2]
            armor.which_state_bonus[3] = ArmorParameterType[cell][3]
            armor.which_state_value_bonus[3] = ArmorParameterBonus[cell][3]
            armor.which_state_bonus[4] = ArmorParameterType[cell][4]
            armor.which_state_value_bonus[4] = ArmorParameterBonus[cell][4]
            SetItemData(i, armor)
        return i
    }

    item CreateJewelryItem(int item_id, real x, real y){
        JewelryItem jewelry = JewelryItem.create()
        item i = CreateItem(item_id, x, y)
        int cell = GetJewelryCell(item_id)
            jewelry.setup(i, JewelryRank[cell], JewelrySuppression[cell], JewelryPoint[cell])
            jewelry.which_state_bonus[1] = JewelryParameterType[cell][1]
            jewelry.which_state_value_bonus[1] = JewelryParameterBonus[cell][1]
            jewelry.which_state_bonus[2] = JewelryParameterType[cell][2]
            jewelry.which_state_value_bonus[2] = JewelryParameterBonus[cell][2]
            jewelry.which_state_bonus[3] = JewelryParameterType[cell][3]
            jewelry.which_state_value_bonus[3] = JewelryParameterBonus[cell][3]
            jewelry.which_state_bonus[4] = JewelryParameterType[cell][4]
            jewelry.which_state_value_bonus[4] = JewelryParameterBonus[cell][4]
            SetItemData(i, jewelry)
        return i
    }
    
      
    item CreateShieldItem(int item_id, real x, real y){
        ShieldItem shield = ShieldItem.create()
        item i = CreateItem(item_id, x, y)
        int cell = GetShieldCell(item_id)
            shield.setup(i, ShieldRank[cell], ShieldBlock[cell])
            shield.which_state_bonus[1] = ShieldParameterType[cell][1]
            shield.which_state_value_bonus[1] = ShieldParameterBonus[cell][1]
            shield.which_state_bonus[2] = ShieldParameterType[cell][2]
            shield.which_state_value_bonus[2] = ShieldParameterBonus[cell][2]
            shield.which_state_bonus[3] = ShieldParameterType[cell][3]
            shield.which_state_value_bonus[3] = ShieldParameterBonus[cell][3]
            shield.which_state_bonus[4] = ShieldParameterType[cell][4]
            shield.which_state_value_bonus[4] = ShieldParameterBonus[cell][4]
            SetItemData(i, shield)
        return i
    }
    
    void EquipJewelryItem(unit u, item i, bool flag){
        UD ud = GetData(u)
        JewelryItem jewelry = GetItemData(i)
        JewelryItem checked
        int c = 0
            if flag {
                if ud.jewelry[1] == 0 { ud.jewelry[1] = jewelry }
                elseif ud.jewelry[2] == 0 { ud.jewelry[2] = jewelry }
                elseif ud.jewelry[3] == 0 { ud.jewelry[3] = jewelry }
                    while (c++ < 4) {
                        if jewelry.which_state_bonus[c] > 0 {
                            SetStat(jewelry.which_state_bonus[c], jewelry.which_state_value_bonus[c], true, ud)
                        }
                    }
                    c = 0
                    if jewelry.stones_cell > 0 {
                        while (c++ < 4) {
                            if GetGemCell(jewelry.inserted_stone[c]) > 0 {
                                SetStat(GemJewelParameterType[Gem_lastFinded], GemJewelParameterBonus[Gem_lastFinded], true, ud)
                            }
                        }
                    }
            }
            else {
                if ud.jewelry[1] == jewelry { ud.jewelry[1] = 0 }
                elseif ud.jewelry[2] == jewelry { ud.jewelry[2] = 0 }
                elseif ud.jewelry[3] == jewelry { ud.jewelry[3] = 0 }
                    while (c++ < 4) {
                        if jewelry.which_state_bonus[c] > 0 {
                            SetStat(jewelry.which_state_bonus[c], jewelry.which_state_value_bonus[c], false, ud)
                        }
                    }
                    c = 0
                    if jewelry.stones_cell > 0 {
                        while (c++ < 4) {
                            if GetGemCell(jewelry.inserted_stone[c]) > 0 {
                                SetStat(GemJewelParameterType[Gem_lastFinded], GemJewelParameterBonus[Gem_lastFinded], false, ud)
                            }
                        }
                    }
            }
        ud.SetMsupp(0.)
    }

    void EquipArmorItem(unit u, item i, bool flag){
        UD ud = GetData(u)
        ArmorItem armor = GetItemData(i)
        string s
        int c = 0
            if flag {
                if ud.armor[armor.point] > 0 { return }
                ud.armor[armor.point] = armor
                ud.is_covered[armor.point] = true
                if armor.point == CHEST { ud.chest_attach = AddSpecialEffectTarget(ArmorAttachModel[GetArmorCell(GetItemTypeId(i))], u, "chest") }
                elseif armor.point == HEAD { ud.head_attach = AddSpecialEffectTarget(ArmorAttachModel[GetArmorCell(GetItemTypeId(i))], u, "chest") }
                elseif armor.point == SHOULDERS { ud.shoulders_attach = AddSpecialEffectTarget(ArmorAttachModel[GetArmorCell(GetItemTypeId(i))], u, "chest") }
                
                    while (c++ < 4) {
                        if armor.which_state_bonus[c] > 0 {
                            SetStat(armor.which_state_bonus[c], armor.which_state_value_bonus[c], true, ud)
                        }
                    }
                    c = 0
                    if armor.stones_cell > 0 {
                        while(c++ < armor.stones_cell){
                            if GetGemCell(armor.inserted_stone[c]) > 0 {
                                SetStat(GemArmorParameterType[Gem_lastFinded], GemArmorParameterBonus[Gem_lastFinded], true, ud)
                            }
                        }
                    }
            }
            else {
                ud.armor[armor.point] = 0
                ud.is_covered[armor.point] = false
                DestroyEffect(ud.chest_attach)
                DestroyEffect(ud.head_attach)
                DestroyEffect(ud.shoulders_attach)
                    while (c++ < 4) {
                        if armor.which_state_bonus[c] > 0 {
                            SetStat(armor.which_state_bonus[c], armor.which_state_value_bonus[c], false, ud)
                        }
                    }
                    c = 0
                    if armor.stones_cell > 0 {
                        while(c++ < armor.stones_cell){
                            if GetGemCell(armor.inserted_stone[c]) > 0 {
                                SetStat(GemArmorParameterType[Gem_lastFinded], GemArmorParameterBonus[Gem_lastFinded], false, ud)
                            }
                        }
                    }
            }
        ud.SetPhysDef(0.)
    }

    void EquipShieldItem(unit u, item i, bool flag){
        UD ud = GetData(u)
        ShieldItem shield = GetItemData(i)
        int c = 0
            if flag {
                if ud.shield > 0 { return }
                ud.shield = shield
                ud.block_type_2 += shield.block
                ud.shield_attach = AddSpecialEffectTarget(ShieldAttachModel[GetShieldCell(GetItemTypeId(i))], u, "hand left")

                    while (c++ < 4) {
                        if shield.which_state_bonus[c] > 0 {
                            SetStat(shield.which_state_bonus[c], shield.which_state_value_bonus[c], true, ud)
                        }
                    }
                    c = 0
                    if shield.stones_cell > 0 {
                        while(c++ < shield.stones_cell){
                            if GetGemCell(shield.inserted_stone[c]) > 0 {
                                SetStat(GemShieldParameterType[Gem_lastFinded], GemShieldParameterBonus[Gem_lastFinded], true, ud)
                            }
                        }
                    }
            }
            else {
                ud.shield = 0
                ud.block_type_2 -= shield.block
                DestroyEffect(ud.shield_attach)
                    while (c++ < 4) {
                        if shield.which_state_bonus[c] > 0 {
                            SetStat(shield.which_state_bonus[c], shield.which_state_value_bonus[c], false, ud)
                        }
                    }
                    c = 0
                    if shield.stones_cell > 0 {
                        while(c++ < shield.stones_cell){
                            if GetGemCell(shield.inserted_stone[c]) > 0 {
                                SetStat(GemShieldParameterType[Gem_lastFinded], GemShieldParameterBonus[Gem_lastFinded], false, ud)
                            }
                        }
                    }
            }
        ud.SetBlock(0.)
    }

    void EquipWeaponItem(unit u, item i, bool flag){
        UD ud = GetData(u)
        WeaponItem weapon = GetItemData(i)
        string s
        int c = 0
            // проверяем одеваем или снимаем
            if flag {
                if ud.current_weapon.weapon_item != null { return }
                // смотрим пустые ли руки
                if ud.current_weapon.weapon_type == FIST {
                    ud.current_weapon.destroy()
                    ud.current_weapon = weapon
                        while (c++ < 4) {
                            if weapon.which_state_bonus[c] > 0 {
                                SetStat(weapon.which_state_bonus[c], weapon.which_state_value_bonus[c], true, ud)
                            }
                        }
                        c = 0
                        if weapon.stones_cell > 0 {
                            while(c++ < weapon.stones_cell){
                                if GetGemCell(weapon.inserted_stone[c]) > 0 {
                                    SetStat(GemWeaponParameterType[Gem_lastFinded], GemWeaponParameterBonus[Gem_lastFinded], true, ud)
                                }
                            }
                        }
                }
                else {
                    ud.current_weapon = weapon
                }
                if ud.current_weapon.relation == 2 { UnitRemoveAbility(u, ATTACK_ID); UnitAddAbility(u, RANGE_ATTACK_ID) }
                else { UnitRemoveAbility(u, RANGE_ATTACK_ID); UnitAddAbility(u, ATTACK_ID) }
                ud.right_hand_attach = AddSpecialEffectTarget(WeaponAttachModel[GetWeaponCell(GetItemTypeId(i))], u, "hand right")
            }
            else {
                while (c++ < 4) {
                    if weapon.which_state_bonus[c] > 0 {
                        SetStat(weapon.which_state_bonus[c], weapon.which_state_value_bonus[c], false, ud)
                    }
                }
                c = 0
                    if weapon.stones_cell > 0 {
                        while(c++ < weapon.stones_cell){
                            if GetGemCell(weapon.inserted_stone[c]) > 0 {
                                SetStat(GemWeaponParameterType[Gem_lastFinded], GemWeaponParameterBonus[Gem_lastFinded], false, ud)
                            }
                        }
                    }
                DestroyEffect(ud.right_hand_attach)
                if GetUnitAbilityLevel(u, WEAPON_OFF) > 0 { IssueImmediateOrderById(u, order_burrow) }
                ud.current_weapon = WeaponItem.create()
                ud.current_weapon.setup(null, FIST, LOWRANK_ITEM)
                if GetUnitAbilityLevel(u, RANGE_ATTACK_ID) > 0
                { UnitRemoveAbility(u, RANGE_ATTACK_ID); UnitAddAbility(u, ATTACK_ID) }
            }
        ud.SetPatk(0.)
        ud.SetMatk(0.)
        ud.SetPCrit(0.)
        ud.SetMCrit(0.)
        ud.SetPhysCritMult(0.) 
        ud.SetMagCritMult(0.)
        ud.SetAcc(0.)
        ud.SetMagAcc(0.)
        ud.SetAttackSpeed(0.)
    }
    
    void EquipOffhandWeaponItem(unit u, item i, bool flag){
        UD ud = GetData(u)
        WeaponItem weapon = GetItemData(i)
        int c = 0
            // проверяем одеваем или снимаем
            if flag {
                if (ud.alternate_weapon != 0 or (ud.current_weapon.weapon_type == GREATSWORD or ud.current_weapon.weapon_type == BOW or ud.current_weapon.weapon_type == GREATBLUNT or ud.current_weapon.weapon_type == GREATAXE or ud.current_weapon.weapon_type == STAFF or ud.current_weapon.weapon_type == POLE))
                { return }
                ud.alternate_weapon = weapon
                    while (c++ < 4) {
                        if weapon.which_state_bonus[c] > 0 {
                            SetStat(weapon.which_state_bonus[c], weapon.which_state_value_bonus[c], true, ud)
                        }
                    }
                    c = 0
                        if weapon.stones_cell > 0 {
                            while(c++ < weapon.stones_cell){
                                if GetGemCell(weapon.inserted_stone[c]) > 0 {
                                    SetStat(GemWeaponParameterType[Gem_lastFinded], GemWeaponParameterBonus[Gem_lastFinded], true, ud)
                                }
                            }
                        }
                    ud.left_hand_attach = AddSpecialEffectTarget(WeaponAttachModel[GetWeaponCell(GetItemTypeId(i))], u, "hand left")
                    ud.SetAttackSpeed(-(weapon.attack_speed * 0.2))
            }
            else {
                while (c++ < 4) {
                    if weapon.which_state_bonus[c] > 0 {
                        SetStat(weapon.which_state_bonus[c], weapon.which_state_value_bonus[c], false, ud)
                    }
                }
                c = 0
                    if weapon.stones_cell > 0 {
                        while(c++ < weapon.stones_cell){
                            if GetGemCell(weapon.inserted_stone[c]) > 0 {
                                SetStat(GemWeaponParameterType[Gem_lastFinded], GemWeaponParameterBonus[Gem_lastFinded], false, ud)
                            }
                        }
                    }
                DestroyEffect(ud.left_hand_attach)
                ud.SetAttackSpeed(weapon.attack_speed * 0.4)
                ud.alternate_weapon = 0
            }
        ud.SetPatk(0.)
        ud.SetMatk(0.)
        ud.SetPCrit(0.)
        ud.SetMCrit(0.)
        ud.SetPhysCritMult(0.)
        ud.SetMagCritMult(0.)
        ud.SetAcc(0.)
        ud.SetMagAcc(0.)
    }
//============================================================================
    void BroadcastDamage(int status, real damage, unit for){
        if status == EVADED then
            TextUp("Evade", for, 9.5, 100., 100., 100.)
        elseif status == NORMAL_HIT then
            TextUp(I2S(R2I(damage)), for, 9.5, 100., 20., 20.)
        elseif status == BLOCKED then
            TextUp("|c000186FFBlock |r" + "|c00FF3333"+I2S(R2I(damage))+"|r", for, 9.5, 100., 100., 100.)
        elseif status == PARRIED then
            TextUp("|c0000D5FFParry |r " + "|c00FF3333"+I2S(R2I(damage))+"|r", for, 9.5, 100., 100., 100.)
        elseif status == CRITICAL_HIT then
            TextUp("|c00FFFF33Crit! |r" + "|c00FF3333"+I2S(R2I(damage))+"|r", for, 9.5, 100., 100., 100.)
        elseif status == CRIT_PARRIED then
            TextUp("|c0000D5FFCrit! |r" + "|c00FF3333"+I2S(R2I(damage))+"|r", for, 9.5, 100., 100., 100.)
        elseif status == CRIT_BLOCKED then
            TextUp("|c000186FFCrit! |r" + "|c00FF3333"+I2S(R2I(damage))+"|r", for, 9.5, 100., 100., 100.)
        elseif status == RESISTED then
            TextUp("Resist", for, 9.5, 100., 100., 100.)
        endif
    }
    
    real GetAttributeBonus(unit A, unit B){
        UD source = GetData(A)
        UD victim = GetData(B)
            // стихия оружия
            if source.current_weapon.damage_attribute > 0 {
                return 1. + ((source.element_bonus[source.current_weapon.damage_attribute] - victim.element_resist[source.current_weapon.damage_attribute]) * 0.01)
            }
        return 1.
    }
    
    real GetPositionDamageBonus(unit A, unit B){
        UD source = GetData(A)
        UD victim = GetData(B)
            if IsSide(A, B) { return source.side_damage_bonus }
            elseif IsUnitBack(A, B) { return source.back_damage_bonus }
        return 1.
    }

    int GetAttackStatus(bool damage_type, unit A, unit B, real bonus){
        UD source = GetData(A)
        UD victim = GetData(B)
        real hit_chance, penalty = RndR(-0.06, 0.06)
        real accuracy = source.accuracy + bonus
            if damage_type {
                if (not IsUnitBack(A, B) and not IsSide(A, B)) {
                    // уклонение
                    hit_chance = (1. - (victim.evade / accuracy) + penalty) * 100.
                    if hit_chance > MAX_EVADE { hit_chance = MAX_EVADE }
                    elseif hit_chance < MIN_EVADE { hit_chance = MIN_EVADE }
                    //====================
                    if (Chance(hit_chance) or Chance(source.blind_chance)) { return EVADED }
                    else {
                        // блок
                        hit_chance = (1. - (victim.block / accuracy) + penalty) * 100.
                        if hit_chance > MAX_BLOCK { hit_chance = MAX_BLOCK }
                        elseif hit_chance < MIN_BLOCK { hit_chance = MIN_BLOCK }
                        //====================
                        if ((Chance(hit_chance)) and victim.shield > 0) { 
                            return BLOCKED
                        }
                        else {
                            // парирование
                            hit_chance = (1. - (victim.parry / accuracy) + penalty) * 100.
                            if hit_chance > MAX_PARRY { hit_chance = MAX_PARRY }
                            elseif hit_chance < MIN_PARRY { hit_chance = MIN_PARRY }
                            //====================
                            if Chance(hit_chance) {
                                return PARRIED
                            }
                        }
                    }
                }
            }
            else {
                hit_chance = (1. - (victim.magical_resist / (source.magical_accuracy + bonus)) + penalty) * 100.
                //====================
                if hit_chance > MAX_RESIST { hit_chance = MAX_RESIST }
                elseif hit_chance < MIN_RESIST { hit_chance = MIN_RESIST }
                //====================
                if Chance(hit_chance) { return RESISTED }
            }
        return NORMAL_HIT
    }
    
    real GetCriticalChance(unit A, bool damage_type, real bonus){
        UD source = GetData(A)
        real chance = 0.
            if damage_type {
                chance = source.physical_critical_chance
                    if chance > MAX_CRITICAL { return MAX_CRITICAL }
                    elseif chance < MIN_CRITICAL { return MIN_CRITICAL }
            }
            else {
                chance = source.magical_critical_chance
                    if chance > MAX_MAG_CRITICAL { return MAX_MAG_CRITICAL }
                    elseif chance < MIN_MAG_CRITICAL { return MIN_MAG_CRITICAL }
            }
        return chance
    }
    
    int MagicalDamage(unit A, unit B, real amount, bool can_crit, bool unavoidable, int eff) {
        UD source = GetData(A)
        UD victim = GetData(B)
        int attack_status = GetAttackStatus(false, A, B, BonusAccuracy[eff])
        real boost, damage = 0., critical_rate = 1., attribute_bonus = 0.
            if (attack_status != RESISTED or unavoidable) {
                if can_crit {
                    if Chance(GetCriticalChance(A, false, BonusCrit[eff])) {
                        critical_rate = source.magical_critical_multiplier - victim.magical_critical_damage_resist
                        if critical_rate < 1.1 { critical_rate = 1.1 }
                    }
                }
                
                boost = (source.magical_attack - victim.magical_suppression)
                if boost < 1. { boost = 1. }
                
                if Attribute[eff][1] > 0 {
                    attribute_bonus = 1. + (((source.element_bonus[Attribute[eff][1]] + Attribute[eff][2]) - victim.element_resist[Attribute[eff][1]]) * 0.01)
                }
                else {
                    attribute_bonus = GetAttributeBonus(A, B)
                }
                //msg(R2S(MA2P(magical_attack)))
                damage = amount * attribute_bonus * (1. + (MA2P(boost) * 0.01)) * critical_rate
                if damage < 0. { damage = 0. }
                else {
                // поглощение урона барьером
                    if (victim.absorb_amount > 0. and (victim.absorb_type == 2 or victim.absorb_type == 3)) {
                        if Chance(victim.absorb_chance) {
                            if damage * victim.absorb_perc >= victim.absorb_amount {
                                damage -= victim.absorb_amount
                                RemoveBuff(victim.absorb_buff, B)
                            }
                            else {
                                victim.absorb_amount = victim.absorb_amount - (victim * source.absorb_perc)
                                damage = 0
                            }
                        }
                    }
                    UnitDamageTarget(A, B, damage, false, false, null, null, null)
                    if victim.sleep_buff > 0 {
                        RemoveBuff(victim.sleep_buff, B)
                    }
                }
            }
            Last_Damage_Type = false
            Last_Damage = damage
            OnAttack(B, A, damage, attack_status)
            if attack_status == CRITICAL_HIT { OnCritical(B, A) }
            if attack_status == RESISTED { OnResist(B, A) }
        return attack_status
    }
    
    int PhysicalDamage(unit A, unit B, real amount, bool use_attack, bool can_crit, bool unavoidable, bool is_sound, int eff){
        UD source = GetData(A)
        UD victim = GetData(B)
        int attack_status = GetAttackStatus(true, A, B, BonusAccuracy[eff])
        real damage = 0., blocked = 1.
        real critical_rate = 1.
        weapontype wt = null
            if (attack_status != EVADED or unavoidable or Unavoidable[eff]) {
                if attack_status == PARRIED { blocked -= victim.parry_damage_absorb }
                elseif attack_status == BLOCKED { blocked -= victim.block_damage_absorb } 
                if can_crit {
                    if Chance(GetCriticalChance(A, true, BonusCrit[eff])) {
                        critical_rate = source.physical_critical_multiplier - victim.physical_critical_damage_resist
                        if critical_rate < 1.1 { critical_rate = 1.1 }
                            if attack_status == PARRIED { attack_status = CRIT_PARRIED }
                            elseif attack_status == BLOCKED { attack_status = CRIT_BLOCKED }
                            else { attack_status = CRITICAL_HIT }
                    }
                }
                // использовать базовый показатель атаки
                if use_attack {
                    damage = source.GetModifiedPatk(victim.weapons_resist[source.current_weapon.weapon_type])
                    if source.alternate_weapon > 0 { damage += ((source.GetModifiedPatkEx(victim.weapons_resist[source.alternate_weapon.weapon_type])) * 0.5) }
                }
                damage = (((damage + amount) * critical_rate * GetPositionDamageBonus(A, B) * GetAttributeBonus(A, B)) * blocked) * (1. - (D2P(source.physical_defence) * 0.01))
                damage = GetRandomReal(damage * source.current_weapon.dispersion[0], damage * source.current_weapon.dispersion[1])
                if damage < 0. { damage = 0. }
                else {
                // поглощение урона барьером
                    if (victim.absorb_amount > 0. and (victim.absorb_type == 1 or victim.absorb_type == 3)) {
                        if Chance(victim.absorb_chance) {
                            if damage * victim.absorb_perc >= victim.absorb_amount {
                                damage -= victim.absorb_amount
                                victim.absorb_amount = 0.
                                RemoveBuff(victim.absorb_buff, B)
                            }
                            else {
                                victim.absorb_amount = victim.absorb_amount - (damage * victim.absorb_perc)
                                damage = 0
                            }
                        }
                    }
                if is_sound { wt = source.current_weapon.weapon_sound }
                UnitDamageTarget(A, B, damage, false, false, null, null, wt)  
                // вампирические эффекты
                    if (source.vampiric > 0. and damage > 0.) { SetHp(A, GetHp(A) + (damage * source.vampiric)) }
                // отражающие урон эффекты
                    if (victim.phys_damage_reflect_chance > 0. and damage > 0.) {
                        if Chance(victim.phys_damage_reflect_chance) {
                            UnitDamageTarget(B, A, damage * victim.phys_damage_reflect_amount, false, false, null, null, null)  
                            TextUp(I2S(R2I(damage * victim.phys_damage_reflect_amount)), A, 10., 100., 20., 100.)
                        }
                    }
                }
                if (damage > 0. and victim.sleep_buff > 0) {
                    RemoveBuff(victim.sleep_buff, B)
                }
            }
            victim.attack_status.last_status = attack_status
            Last_Damage = damage
            Last_Damage_Type = true
            OnAttack(B, A, damage, attack_status)
                if (attack_status == CRITICAL_HIT or attack_status == CRIT_BLOCKED or attack_status == CRIT_PARRIED) {
                    OnCritical(B, A)
                }
            if attack_status == EVADED { OnEvade(B, A) }
            elseif attack_status == BLOCKED { OnBlock(B, A) }
            elseif attack_status == PARRIED { OnParry(B, A) }
        return attack_status
    }
    
    real HealUnit(unit A, unit B, real amount){
        UD data = GetData(A)
        real heal = amount * data.healing_rate + GetHp(A)
            SetHp(B, heal)
        return heal
    }

    void ApplyEffect(unit source, unit victim, real x, real y, int eff, int level){
        int attack_state
        group g
        unit temp
            if victim != null { x = Gx(victim); y = Gy(victim) }
            if StringLength(UsedSFX[eff]) > 0 {
                bj_lastCreatedEffect = AddSpecialEffect(UsedSFX[eff], x, y)
                DestroyEffect(bj_lastCreatedEffect)
            }
            if StringLength(EffectSound[eff]) > 0 {
                AddSound(EffectSound[eff], x, y)
            }
            if Power[eff][level] > 0 {
                if AreaOfEffect[eff][level] > 0. {
                    g = CG
                    ForFilter1 = source
                    GroupEnumUnitsInRange(g, x, y, AreaOfEffect[eff][level], Filter(function EnemiesFilter))
                        while(FirstOfGroup(g) != null){
                            temp = FirstOfGroup(g)
                                if DamageType[eff] {
                                    attack_state = PhysicalDamage(source, temp, Power[eff][level], true, CanCrit[eff], false, true, eff)
                                    BroadcastDamage(attack_state, Last_Damage, temp)
                                        if AppliedBuff[eff] > 0 {
                                            if (attack_state != EVADED and attack_state != RESISTED) {
                                                AddBuffToUnit(temp, source, BuffId[AppliedBuff[eff]][1], level)
                                            }
                                        }
                                }
                                else {
                                    attack_state = MagicalDamage(source, temp, Power[eff][level], CanCrit[eff], false, eff)
                                    BroadcastDamage(attack_state, Last_Damage, temp)
                                        if AppliedBuff[eff] > 0 {
                                            if (attack_state != EVADED and attack_state != RESISTED) {
                                                AddBuffToUnit(temp, source, BuffId[AppliedBuff[eff]][1], level)
                                            }
                                        }
                                }
                            GroupRemoveUnit(g, temp)
                        }
                    DG(g)
                    temp = null
                    g = null
                }
                else {
                    if DamageType[eff] {
                        attack_state = PhysicalDamage(source, victim, Power[eff][level], true, CanCrit[eff], false, true, eff)
                        BroadcastDamage(attack_state, Last_Damage, victim)
                            if AppliedBuff[eff] > 0 {
                                if (attack_state != EVADED and attack_state != RESISTED) {
                                    AddBuffToUnit(victim, source, BuffId[AppliedBuff[eff]][1], level)
                                }
                            }
                    }
                    else {
                        attack_state = MagicalDamage(source, victim, Power[eff][level], CanCrit[eff], false, eff)
                        BroadcastDamage(attack_state, Last_Damage, victim)
                            if AppliedBuff[eff] > 0 {
                                if (attack_state != EVADED and attack_state != RESISTED) {
                                    AddBuffToUnit(victim, source, BuffId[AppliedBuff[eff]][1], level)
                                }
                            }
                    }
                }
            }
            if HealAmount[eff][level] > 0. {
                HealUnit(source, victim, HealAmount[eff][level])
                    if AreaOfEffect[eff][level] > 0. {
                        g = CG
                        ForFilter1 = source
                        GroupEnumUnitsInRange(g, x, y, AreaOfEffect[eff][level], Filter(function AllyFilter))
                            while(FirstOfGroup(g) != null){
                                temp = FirstOfGroup(g)
                                TextUp(I2S(R2I(HealUnit(source, temp, HealAmount[eff][level]))), temp, 9. ,0., 100., 0.)
                                    if AppliedBuff[eff] > 0 {
                                        AddBuffToUnit(temp, source, BuffId[AppliedBuff[eff]][1], level)
                                    }
                                GroupRemoveUnit(g, temp)
                            }
                        DG(g)
                        temp = null
                        g = null
                    }
                    else {
                        TextUp(I2S(R2I(HealUnit(source, victim, HealAmount[eff][level]))), victim, 9. ,0., 100., 0.)
                            if AppliedBuff[eff] > 0 {
                                AddBuffToUnit(victim, source, BuffId[AppliedBuff[eff]][1], level)
                            }
                    }
            }
    }
//============================================================================
    
endlibrary
Top