Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
Lua
Тип:
Наработка
Версия Warcraft:
1.32
Решил доработать существующий BonusMod на Lua ссылка
Автор недоработал до конца, поэтому что-то не работает неправильно или совсем не работает. Пример, функция UnitGetBonus работала неправильно. Где-то в условиях неправильно работает итд.
Улучшения:
  • Увеличено размер с 4096 до 131072. Можно изменять бонусы +- 131072 Абилки скопированы из Jass Custom Stat System v1.5g (CCS), который является абсолютной копией.
  • добавлен параметр скорости атаки. Эта модификация атаки и раньше существовала в других системах, но теперь можно вычислить и базовую скорость атаки. Путем метода расчета можно подсчитать текущую AS. ссылка Очень важный параметр близзард забыли добавить. Хорошо, что есть attack cooldawn
  • юнит умирал от отрицательного параметра силы/запаса хп. Исправлен баг.
  • добавлена возможность изменять базовые характеристики. В рефордже открыты некоторые нативки по чтению / изменению характеристик базовых юнита. Однако, работают они не так как хотелось бы. Обычно суммарное значение какого-то параметра может быть из несколько составляющих: базовый (стартовый в ро), бонус (от предметов и абилок), и значения от атрмбутов героя (базовые/бонусные). А нативки у каждого параметра работают по-разному: пример функция armor изменяет общий, у атаки в расчете исключен бонус от предметов.
Типы праметров (модификаторов):
  • 1 Сила
  • 2 Ловкость
  • 3 Интеллект
  • 4 Урон
  • 5 Броня
  • 6 Регенерация здоровья
  • 7 Регенерация маны
  • 8 Модификатор видимости
  • 9 скорость атаки
  • 10 макс запас здоровья
  • 11 макс запас маны
  • 12 скорость передваижение (только базовый параметр изменять можно)
  • 13 дистанция получения приказа
В рефордже добавлено много всяких функции. Есть нативки, которые предоставляют прямой доступ к данным. А также существуют нативки для работы с филдами (полями) => чтение и изменение данных полей. Однако, для большинства полей можно только прочитать, а вот изменить практически нельзя (кроме регена хп и маны и др). Ничего просто не изменится. Безопасный способ использовать нативки с приставкой Blz
нативки рефорджа (не все)
native GetUnitFacing takes unit whichUnit returns real
native SetUnitFacing takes unit whichUnit, real facingAngle returns nothing

native GetUnitMoveSpeed takes unit whichUnit returns real
native GetUnitDefaultMoveSpeed takes unit whichUnit returns real
native SetUnitMoveSpeed takes unit whichUnit, real newSpeed returns nothing

native GetUnitAcquireRange takes unit whichUnit returns real
native GetUnitDefaultAcquireRange takes unit whichUnit returns real
native SetUnitAcquireRange takes unit whichUnit, real newAcquireRange returns nothing

native GetUnitTurnSpeed takes unit whichUnit returns real
native GetUnitDefaultTurnSpeed takes unit whichUnit returns real
native SetUnitTurnSpeed takes unit whichUnit, real newTurnSpeed returns nothing

function GetUnitPropWindowBJ takes unit whichUnit returns real
    return GetUnitPropWindow(whichUnit) * bj_RADTODEG
endfunction
function GetUnitDefaultPropWindowBJ takes unit whichUnit returns real
    return GetUnitDefaultPropWindow(whichUnit)
endfunction
native SetUnitPropWindow takes unit whichUnit, real newPropWindowAngle returns nothing


native GetUnitFlyHeight takes unit whichUnit returns real
native GetUnitDefaultFlyHeight takes unit whichUnit returns real
native SetUnitFlyHeight takes unit whichUnit, real newHeight, real rate returns nothing

native BlzGetLocalUnitZ takes unit whichUnit returns real
native BlzGetUnitZ takes unit whichUnit returns real


native BlzGetUnitArmor takes unit whichUnit returns real --считывает базовый+бонус
native BlzSetUnitArmor takes unit whichUnit, real armorAmount returns nothing

native BlzGetUnitBaseDamage takes unit whichUnit, integer weaponIndex returns integer
native BlzGetUnitDiceNumber takes unit whichUnit, integer weaponIndex returns integer
native BlzGetUnitDiceSides takes unit whichUnit, integer weaponIndex returns integer
native BlzSetUnitBaseDamage takes unit whichUnit, integer baseDamage, integer weaponIndex returns nothing
native BlzSetUnitDiceNumber takes unit whichUnit, integer diceNumber, integer weaponIndex returns nothing
native BlzSetUnitDiceSides takes unit whichUnit, integer diceSides, integer weaponIndex returns nothing

native BlzGetUnitAttackCooldown takes unit whichUnit, integer weaponIndex returns real
native BlzSetUnitAttackCooldown takes unit whichUnit, real cooldown, integer weaponIndex returns nothing

native BlzGetUnitMaxHP takes unit whichUnit returns integer
native BlzSetUnitMaxHP takes unit whichUnit, integer hp returns nothing

native BlzGetUnitMaxMana takes unit whichUnit returns integer
native BlzSetUnitMaxMana takes unit whichUnit, integer mana returns nothing

native BlzUnitHideAbility takes unit whichUnit, integer abilId, boolean flag returns nothing

native BlzGetUnitAbilityManaCost takes unit whichUnit, integer abilId, integer level returns integer
native BlzSetUnitAbilityManaCost takes unit whichUnit, integer abilId, integer level, integer manaCost returns nothing

native BlzGetUnitAbilityCooldown takes unit whichUnit, integer abilId, integer level returns real
native BlzGetUnitAbilityCooldownRemaining takes unit whichUnit, integer abilId returns real
native BlzSetUnitAbilityCooldown takes unit whichUnit, integer abilId, integer level, real cooldown returns nothing

native BlzUnitHideAbility takes unit whichUnit, integer abilId, boolean flag returns nothing
native BlzUnitDisableAbility takes unit whichUnit, integer abilId, boolean flag, boolean hideUI returns nothing

UNIT_RF_CAST_BACK_SWING = ConvertUnitRealField(FourCC('ucbs'))	
UNIT_RF_CAST_POINT = ConvertUnitRealField(FourCC('ucpt'))
BlzGetUnitRealField(GetTriggerUnit(), UNIT_RF_CAST_BACK_SWING)
BlzGetUnitRealField(GetTriggerUnit(), UNIT_RF_CAST_POINT)
некоторые параметры уже есть в нативках рефорджа. Правда, они либо выдают/изменяют общий параметр (базовый+бонус) или только базовый. Можно только подсчитать, но для точности подсчета некоторых параметров рекомендуется делать заклинания, где есть баффы/дебаффы, полностью кастомные.
код BonusMod
do
local POWERS   = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072 }
local MAX, MIN = POWERS[#POWERS], -POWERS[#POWERS]

local ABILITY  = {
	--STR: 1 [1-18]
	FourCC('ZxF0'), -- +1
	FourCC('ZxF1'), -- +2
	FourCC('ZxF2'), -- +4
	FourCC('ZxF3'), -- +8
	FourCC('ZxF4'), -- +16
	FourCC('ZxF5'), -- +32
	FourCC('ZxF6'), -- +64
	FourCC('ZxF7'), -- +128
	FourCC('ZxF8'), -- +256
	FourCC('ZxF9'), -- +512
	FourCC('ZxFa'), -- +1024
	FourCC('ZxFb'), -- +2048
	FourCC('ZxFc'), -- +4096
    FourCC('ZxFd'), -- +8192
    FourCC('ZxFe'), -- +16384
    FourCC('ZxFf'), -- +32768
    FourCC('ZxFg'), -- +65536
    FourCC('ZxFh'), -- -131072
    
	-- AGI 2 [18-36]
	FourCC('ZxG0'), -- +1
	FourCC('ZxG1'), -- +2
	FourCC('ZxG2'), -- +4
	FourCC('ZxG3'), -- +8
	FourCC('ZxG4'), -- +16
	FourCC('ZxG5'), -- +32
	FourCC('ZxG6'), -- +64
	FourCC('ZxG7'), -- +128
	FourCC('ZxG8'), -- +256
	FourCC('ZxG9'), -- +512
	FourCC('ZxGa'), -- +1024
	FourCC('ZxGb'), -- +2048
    FourCC('ZxGc'), -- +4096
    FourCC('ZxGd'), -- +8192
    FourCC('ZxGe'), -- +16384
    FourCC('ZxGf'), -- +32768
    FourCC('ZxGg'), -- +65536
    FourCC('ZxGh'), -- -131072
    
    
	-- INT 3 [36-54]
	FourCC('ZxH0'), -- +1
	FourCC('ZxH1'), -- +2
	FourCC('ZxH2'), -- +4
	FourCC('ZxH3'), -- +8
	FourCC('ZxH4'), -- +16
	FourCC('ZxH5'), -- +32
	FourCC('ZxH6'), -- +64
	FourCC('ZxH7'), -- +128
	FourCC('ZxH8'), -- +256
	FourCC('ZxH9'), -- +512
	FourCC('ZxHa'), -- +1024
	FourCC('ZxHb'), -- +2048
	FourCC('ZxHc'), -- +4096
    FourCC('ZxHd'), -- +8192
    FourCC('ZxHe'), -- +16384
    FourCC('ZxHf'), -- +32768
    FourCC('ZxHg'), -- +65536
    FourCC('ZxHh'), -- -131072
    
	-- DAMAGE 4 [54-72]
	FourCC('ZxB0'), -- +1
	FourCC('ZxB1'), -- +2
	FourCC('ZxB2'), -- +4
	FourCC('ZxB3'), -- +8
	FourCC('ZxB4'), -- +16
	FourCC('ZxB5'), -- +32
	FourCC('ZxB6'), -- +64
	FourCC('ZxB7'), -- +128
	FourCC('ZxB8'), -- +256
	FourCC('ZxB9'), -- +512
	FourCC('ZxBa'), -- +1024
	FourCC('ZxBb'), -- +2048
    FourCC('ZxBc'), -- +4096
    FourCC('ZxBd'), -- +8192
    FourCC('ZxBe'), -- +16384
    FourCC('ZxBf'), -- +32768
    FourCC('ZxBg'), -- +65536
    FourCC('ZxBh'), -- -131072
    
	-- ARMOR 5 [72-90]
	FourCC('ZxA0'), -- +1
	FourCC('ZxA1'), -- +2
	FourCC('ZxA2'), -- +4
	FourCC('ZxA3'), -- +8
	FourCC('ZxA4'), -- +16
	FourCC('ZxA5'), -- +32
	FourCC('ZxA6'), -- +64
	FourCC('ZxA7'), -- +128
	FourCC('ZxA8'), -- +256
	FourCC('ZxA9'), -- +512
	FourCC('ZxAa'), -- +1024
	FourCC('ZxAb'), -- +2048
    FourCC('ZxAc'), -- +4096
    FourCC('ZxAd'), -- +8192
    FourCC('ZxAe'), -- +16384
    FourCC('ZxAf'), -- +32768
    FourCC('ZxAg'), -- +65536
    FourCC('ZxAh'), -- -131072
    
	-- regen HP 6 [90-108]
	FourCC('ZxJ0'), -- +1
	FourCC('ZxJ1'), -- +2
	FourCC('ZxJ2'), -- +4
	FourCC('ZxJ3'), -- +8
	FourCC('ZxJ4'), -- +16
	FourCC('ZxJ5'), -- +32
	FourCC('ZxJ6'), -- +64
	FourCC('ZxJ7'), -- +128
	FourCC('ZxJ8'), -- +256
	FourCC('ZxJ9'), -- +512
	FourCC('ZxJa'), -- +1024
	FourCC('ZxJb'), -- +2048
    FourCC('ZxJc'), -- +4096
    FourCC('ZxJd'), -- +8192
    FourCC('ZxJe'), -- +16384
    FourCC('ZxJf'), -- +32768
    FourCC('ZxJg'), -- +65536
    FourCC('ZxJh'), -- -131072
	-- regen MP 7 [108-126]
	FourCC('ZxK0'), -- +1
	FourCC('ZxK1'), -- +2
	FourCC('ZxK2'), -- +4
	FourCC('ZxK3'), -- +8
	FourCC('ZxK4'), -- +16
	FourCC('ZxK5'), -- +32
	FourCC('ZxK6'), -- +64
	FourCC('ZxK7'), -- +128
	FourCC('ZxK8'), -- +256
	FourCC('ZxK9'), -- +512
	FourCC('ZxKa'), -- +1024
	FourCC('ZxKb'), -- +2048
    FourCC('ZxKc'), -- +4096
    FourCC('ZxKd'), -- +8192
    FourCC('ZxKe'), -- +16384
    FourCC('ZxKf'), -- +32768
    FourCC('ZxKg'), -- +65536
    FourCC('ZxKh'), -- -131072
	-- SIGHT 8 [126-144]
	FourCC('ZxC0'), -- +1
	FourCC('ZxC1'), -- +2
	FourCC('ZxC2'), -- +4
	FourCC('ZxC3'), -- +8
	FourCC('ZxC4'), -- +16
	FourCC('ZxC5'), -- +32
	FourCC('ZxC6'), -- +64
	FourCC('ZxC7'), -- +128
	FourCC('ZxC8'), -- +256
	FourCC('ZxC9'), -- +512
	FourCC('ZxCa'), -- +1024
	FourCC('ZxCb'), -- +2048
    FourCC('ZxCc'), -- +4096
    FourCC('ZxCd'), -- +8192
    FourCC('ZxCe'), -- +16384
    FourCC('ZxCf'), -- +32768
    FourCC('ZxCg'), -- +65536
    FourCC('ZxCh'), -- -131072
    -- AttackSpeed 9 [144-162]
	FourCC('ZxI0'), -- +1
	FourCC('ZxI1'), -- +2
	FourCC('ZxI2'), -- +4
	FourCC('ZxI3'), -- +8
	FourCC('ZxI4'), -- +16
	FourCC('ZxI5'), -- +32
	FourCC('ZxI6'), -- +64
	FourCC('ZxI7'), -- +128
	FourCC('ZxI8'), -- +256
	FourCC('ZxI9'), -- +512
	FourCC('ZxIa'), -- +1024
	FourCC('ZxIb'), -- +2048
    FourCC('ZxIc'), -- +4096
    FourCC('ZxId'), -- +8192
    FourCC('ZxIe'), -- +16384
    FourCC('ZxIf'), -- +32768
    FourCC('ZxIg'), -- +65536
    FourCC('ZxIh'), -- -131072
    
    -- Max Life 10 [162-180]
	FourCC('ZxE0'), -- +1
	FourCC('ZxE1'), -- +2
	FourCC('ZxE2'), -- +4
	FourCC('ZxE3'), -- +8
	FourCC('ZxE4'), -- +16
	FourCC('ZxE5'), -- +32
	FourCC('ZxE6'), -- +64
	FourCC('ZxE7'), -- +128
	FourCC('ZxE8'), -- +256
	FourCC('ZxE9'), -- +512
	FourCC('ZxEa'), -- +1024
	FourCC('ZxEb'), -- +2048
    FourCC('ZxEc'), -- +4096
    FourCC('ZxEd'), -- +8192
    FourCC('ZxEe'), -- +16384
    FourCC('ZxEf'), -- +32768
    FourCC('ZxEg'), -- +65536
    FourCC('ZxEh'), -- -131072
    
    -- Max Mana 11 [180-198]
	FourCC('ZxD0'), -- +1
	FourCC('ZxD1'), -- +2
	FourCC('ZxD2'), -- +4
	FourCC('ZxD3'), -- +8
	FourCC('ZxD4'), -- +16
	FourCC('ZxD5'), -- +32
	FourCC('ZxD6'), -- +64
	FourCC('ZxD7'), -- +128
	FourCC('ZxD8'), -- +256
	FourCC('ZxD9'), -- +512
	FourCC('ZxDa'), -- +1024
	FourCC('ZxDb'), -- +2048
    FourCC('ZxDc'), -- +4096
    FourCC('ZxDd'), -- +8192
    FourCC('ZxDe'), -- +16384
    FourCC('ZxDf'), -- +32768
    FourCC('ZxDg'), -- +65536
    FourCC('ZxDh') -- -131072
}

local TYPES = #ABILITY / #POWERS

---@param target unit
---@param mod integer
function UnitClearBonus (target, mod)
	if type(mod) ~= 'number' or mod < 1 or mod > TYPES then
		return print('UnitClearBonus: Invalid mod', mod)
    elseif GetUnitTypeId (target) == 0 or IsUnitType (target, UNIT_TYPE_DEAD) then
        return print('UnitClearBonus: Unit is dead or does not exist')
	end
	
	for i = 1, #POWERS do
		UnitRemoveAbility(target, ABILITY[(mod - 1) * #POWERS + i])
	end
end

---@param target unit
---@param mod integer
---@param ammount integer
---@return boolean
function UnitSetBonus (target, mod, ammount)
	if type(mod) ~= 'number' or mod < 1 or mod > TYPES then
		print('UnitSetBonus: Invalid mod', mod)
		return false
	elseif type(ammount) ~= 'number' or ammount < MIN or ammount > MAX then
		print('UnitSetBonus: Bonus too high or low', ammount)
		return false
    elseif GetUnitTypeId (target) == 0 or IsUnitType (target, UNIT_TYPE_DEAD) then
        print('UnitSetBonus: Unit is dead or does not exist')
		return false
	end
    
    
    if mod > 0 and mod < 4 then
        if not IsUnitType(target, UNIT_TYPE_HERO) then
            print('UnitSetBonus: you cant give the ability to a non-hero')
            return false
        end
    elseif mod == 9 then
        
        --[[
        local agility = GetUnitAgilityBonusIAS(target)*100

        if ammount+agility > 400 then
            ammount = 400-agility
            if ammount < 0 then
                ammount = 0
            end
            elseif ammount+agility < -80 then
            ammount = -80-agility
            if ammount > 0 then
                ammount = 0
            end
        end
        ]]
    end
    
    
    
    
	local ability 
	if ammount < 0 then
		ammount = MAX + ammount
		
        for i = #POWERS - 1, 1, -1 do
            ability = ABILITY[(mod - 1) * #POWERS + i]
            if ammount >= POWERS[i] then
                UnitAddAbility(target, ability)
                UnitMakeAbilityPermanent(target, true, ability)
                ammount = ammount - POWERS[i]
            else
                UnitRemoveAbility(target, ability)
            end
        end
        
        ability = ABILITY[(mod - 1) * #POWERS + #POWERS]
        UnitAddAbility(target, ability)
		UnitMakeAbilityPermanent(target, true, ability)
	else
        ability = ABILITY[(mod - 1) * #POWERS + #POWERS]
		UnitRemoveAbility(target, ability)
        
        for i = #POWERS - 1, 1, -1 do
            ability = ABILITY[(mod - 1) * #POWERS + i]
            if ammount >= POWERS[i] then
                UnitAddAbility(target, ability)
                UnitMakeAbilityPermanent(target, true, ability)
                ammount = ammount - POWERS[i]
            else
                UnitRemoveAbility(target, ability)
            end
        end
	end
	return true
end

---@param target unit
---@param mod integer
---@return integer
function UnitGetBonus (target, mod)
    local ammount = 0
	
	if type(mod) ~= 'number' or mod < 1 or mod > TYPES then
		print('UnitGetBonus: Invalid mod', mod)
        return 0
    elseif GetUnitTypeId (target) == 0 or IsUnitType (target, UNIT_TYPE_DEAD) then
        print('UnitGetBonus: Unit is dead or does not exist')
        return 0
	end
    
	if GetUnitAbilityLevel(target, ABILITY[(mod - 1) * #POWERS + #POWERS]) > 0 then
		ammount = MIN
	end
	
	for i = 1, #POWERS-1 do
        if GetUnitAbilityLevel(target, ABILITY[((mod - 1) * #POWERS) + i]) > 0 then
            ammount = ammount + POWERS[i]
		end
	end
    return ammount

end

---@param target unit
---@param mod integer
---@param ammount integer
---@return boolean
function UnitAddBonus (target, mod, ammount)
    return UnitSetBonus(target, mod,UnitGetBonus(target, mod)+ammount)
end
end
функции
do
	local InitGlobalsOrigin = InitGlobals
	function InitGlobals()
		InitGlobalsOrigin()
        
        --константы
        NeedHeroXP = 200
        NeedHeroXPFormulaA = 1.00
        NeedHeroXPFormulaB = 100
        NeedHeroXPFormulaC = 0	
        AttackSpeedBonusPerAgilityPoint = 0.02
        DefenseBonusPerAgilityPoint = 0.3
        DefenseBaseValue = -2 --for Agility
        HitPointBonusPerStrength = 25
        RegenHpBonusPerStrength = 0.05
        ManaPointBonusPerInt = 15
        RegenManaBonusPerInt = 0.05
        Multiplier = 0.060 --for damage and armor
        UnitSpeedMax = 400.0
        UnitSpeedMin = 150.0
        BuildingSpeedMax = 400.0
        BuildingSpeedMin = 25.0

--основные характеристики героя ============
        --основной атрибут героя (1-str, 3-agi, 2-int). влияет на атаку
        function GetHeroPrimaryAttribute(hero)
            return BlzGetUnitIntegerField(hero, UNIT_IF_PRIMARY_ATTRIBUTE)
        end
        function SetHeroPrimaryAttribute(hero, value) --установка не работает
            BlzSetUnitIntegerField( hero, UNIT_IF_PRIMARY_ATTRIBUTE, value)
        end
        
        function GetHeroStrPerLevel(hero) 
            return BlzGetUnitRealField(hero, UNIT_RF_STRENGTH_PER_LEVEL)
        end
        function GetHeroAgiPerLevel(hero) 
            return BlzGetUnitRealField(hero, UNIT_RF_AGILITY_PER_LEVEL)
        end
        function GetHeroIntPerLevel(hero) 
            return BlzGetUnitRealField(hero, UNIT_RF_INTELLIGENCE_PER_LEVEL)
        end
        
        --стартовые характеристики на 1-ом уровне
        function GetBasicParamStr(u)
            return math.ceil(GetHeroStr_base(u)-(GetHeroStrPerLevel(u)*(GetHeroLevel(u)-1)))
        end
        function GetBasicParamAgi(u)
            return math.ceil(GetHeroAgi_base(u)-(GetHeroAgiPerLevel(u)*(GetHeroLevel(u)-1)))
        end
        function GetBasicParamInt(u)
            return math.ceil(GetHeroInt_base(u)-(GetHeroIntPerLevel(u)*(GetHeroLevel(u)-1)))
        end
        
        
        --общие параметры атрибутов: базовый+бонус (бонус можно исключить)
        function GetHeroAttributeStr(hero, includeBonuses)
            return GetHeroStr(hero, includeBonuses)
        end
        function GetHeroAttributeAgi(hero, includeBonuses)
            return GetHeroAgi(hero, includeBonuses)
        end
        function GetHeroAttributeInt(hero, includeBonuses)
            return GetHeroInt(hero, includeBonuses)
        end
        
        --базовые атрибуты героя
        function GetHeroStr_base(hero)
            return BlzGetUnitIntegerField(hero, UNIT_IF_STRENGTH)
        end
        function GetHeroAgi_base(hero)
            return BlzGetUnitIntegerField(hero, UNIT_IF_AGILITY)
        end
        function GetHeroInt_base(hero)
            return BlzGetUnitIntegerField(hero, UNIT_IF_INTELLIGENCE)
        end
        --бонусные атрибуты героя
        function GetHeroStr_bonus(hero)
            return BlzGetUnitIntegerField(hero, UNIT_IF_STRENGTH_WITH_BONUS)-GetHeroStr_base(hero)
        end
        function GetHeroAgi_bonus(hero)
            return BlzGetUnitIntegerField(hero, UNIT_IF_AGILITY_WITH_BONUS)-GetHeroAgi_base(hero)
        end
        function GetHeroInt_bonus(hero)
            return BlzGetUnitIntegerField(hero, UNIT_IF_INTELLIGENCE_WITH_BONUS)-GetHeroInt_base(hero)
        end
        
        --установить базовые (белые) атрибуты героя
        function SetHeroBaseStr(hero, value)
            SetHeroStr(hero, value, true)
        end
        function SetHeroBaseAgi(hero, value)
            SetHeroAgi(hero, value, true)
        end
        function SetHeroBaseInt(hero, value)
            SetHeroInt(hero, value, true)
        end
        --установить бонусные (зеленые) атрибуты героя
        function SetHeroBonusStr(hero, value)
            UnitSetBonus (hero, 1, value)
        end
        function SetHeroBonusAgi(hero, value)
            UnitSetBonus (hero, 2, value)
        end
        function SetHeroBonusInt(hero, value)
            UnitSetBonus (hero, 3, value)
        end
        
        --добавить бонусные (зеленые) атрибуты героя
        function AddHeroBonusStr(hero, value)
            UnitAddBonus (target, 1, ammount)
        end
        function AddHeroBonusAgi(hero, value)
            UnitAddBonus (target, 2, ammount)
        end
        function AddHeroBonusInt(hero, value)
            UnitAddBonus (target, 3, ammount)
        end
        
        --основной атрибут (включая бонус)
        function GetHeroGeneralPrimaryAttribute(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                if GetHeroPrimaryAttribute(hero) == 1 then --str
                    return GetHeroAttributeStr(hero, true)
                elseif GetHeroPrimaryAttribute(hero) == 2 then --int
                    return GetHeroAttributeInt(hero, true)
                elseif GetHeroPrimaryAttribute(hero) == 3 then --agi
                    return GetHeroAttributeAgi(hero, true)
                end
            end
        end
        --базовый атрибут
        function GetHeroBasePrimaryAttribute(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                if GetHeroPrimaryAttribute(hero) == 1 then --str
                    return GetHeroAttributeStr(hero, false)
                elseif GetHeroPrimaryAttribute(hero) == 2 then --int
                    return GetHeroAttributeInt(hero, false)
                elseif GetHeroPrimaryAttribute(hero) == 3 then --agi
                    return GetHeroAttributeAgi(hero, false)
                end
            end
        end
        --бонусный атрибут
        function GetHeroBonusPrimaryAttribute(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                if GetHeroPrimaryAttribute(hero) == 1 then --str
                    return GetHeroStr_bonus(hero)
                elseif GetHeroPrimaryAttribute(hero) == 2 then --int
                    return GetHeroInt_bonus(hero)
                elseif GetHeroPrimaryAttribute(hero) == 3 then --agi
                    return GetHeroAgi_bonus(hero)
                end
            end
        end
        
--урон ========================

        --bonus damage от абилок-когтей
        function UnitGetBonusDamage(unit)
            return UnitGetBonus(unit, 4)
        end
        function UnitSetBonusDamage(unit,value)
            UnitSetBonus(unit, 4,value)
        end

        --суммарный bonus damage (от осного атрибута+от когтей)
        function GetUnitBonusDamage(unit)
            local bonus = 0
            if IsUnitType(unit, UNIT_TYPE_HERO) then
                if GetHeroPrimaryAttribute(unit) == 1 then --str
                    bonus = GetHeroStr_bonus(unit)
                elseif GetHeroPrimaryAttribute(unit) == 2 then --int
                    bonus = GetHeroInt_bonus(unit)
                elseif GetHeroPrimaryAttribute(unit) == 3 then --agi
                    bonus = GetHeroAgi_bonus(unit)
                end
            end
        
            --bonus damage от основного атрибута + bonus damage от когтей
            return UnitGetBonusDamage(unit)+ bonus
        end
        
        
        --общий базовый урон с учетом базового атрибута героя
        --бонус урона от предметов в функции BlzGetUnitBaseDamage не учитывается, поэтому его в расчетах нет
        function GetUnitBaseDamage(unit, index)
            local base = 0
            local bonus = 0
            if IsUnitType(unit, UNIT_TYPE_HERO) then
                if GetHeroPrimaryAttribute(unit) == 1 then --str
                    bonus = GetHeroStr_bonus(unit)
                elseif GetHeroPrimaryAttribute(unit) == 2 then --int
                    bonus = GetHeroInt_bonus(unit)
                elseif GetHeroPrimaryAttribute(unit) == 3 then --agi
                    bonus = GetHeroAgi_bonus(unit)
                end
            end
        
        
            return(BlzGetUnitBaseDamage(unit,index)-bonus)
        end
        
        --изначальный урон (без учета бонусного атрибута)
        --короче, это чистый урон без основного атрибута героя
        --для обычных (не-героев) эта функция бесполезна, тк равнозначна GetUnitBaseDamage
        function GetUnitBasicDamage(unit, index)
            if IsUnitType(unit, UNIT_TYPE_HERO) then
                return GetUnitBaseDamage(unit, index)-GetHeroBasePrimaryAttribute(unit)
            else
                return GetUnitBaseDamage(unit, index)
            end
        end
        
        function GetUnitMinDamage(unit, index)
            return (GetUnitBaseDamage(unit,index)+BlzGetUnitDiceNumber(unit,index))
        end
        
        function GetUnitMaxDamage(unit, index)
            return (GetUnitBaseDamage(unit,index)+BlzGetUnitDiceNumber(unit,index)*BlzGetUnitDiceSides(unit,index))
        end
           
--скорость атаки =====================
        --BAS - базовая скорость атаки, показывает кол-во ударов в сек
        function GetUnitBaseAttackSpeed(unit, index)
            if BlzGetUnitAttackCooldown(unit, index) ~= 0 then
                return 1/BlzGetUnitAttackCooldown(unit, index)
            else
                return 0
            end
        end
        
        --IAS - показывает %-ый бонус от ловкости героя
        function GetUnitAgilityBonusIAS(unit)
            if IsUnitType(unit, UNIT_TYPE_HERO) then
                return (GetHeroAttributeAgi(unit, true)*AttackSpeedBonusPerAgilityPoint) --0.02% бонуса AS за каждую единицу ловкости
            else
                return 0
            end
        end
        
        --IAS - показывает % процентное содержание AS
        function GetUnitBaseIAS(unit)
            return 1.00 --изначально AS равна 1.00 (100%)
        end
        
        
        --bonus IAS - показывает процент AS от абилок
        --делим на 100 тк результат из BonusMod выдают в виде целых чисел
        function GetUnitBonusIAS(unit)
            return (UnitGetBonus (unit, 9) / 100)
        end
        function SetUnitBonusIAS(unit,value)
            return (UnitSetBonus (unit, 9, R2I(value*100)))
        end
        
        --общий бонус. лимитирован от -80% до 400%
        function GetGeneralUnitBonusIAS(unit)
            local bonus = GetUnitAgilityBonusIAS(unit) + GetUnitBonusIAS(unit)
            
            if bonus > 4.00 then
                return 4.00
            elseif bonus < -0.80 then
                return -0.80
            end
            
            return bonus
        end
        
        --показывает общий суммарный IAS в %
        function GetUnitIncreaseAttackSpeed(unit, includeBonuses)
            if includeBonuses then
                return GetUnitBaseIAS(unit) + GetGeneralUnitBonusIAS(unit)
            else
                return GetUnitBaseIAS(unit) 
            end
        end
        
        --текущий AS выдает кол-во ударов в сек
        function GetUnitCurrentAttackSpeed(unit, index)
            return GetUnitBaseAttackSpeed(unit, index) * GetUnitIncreaseAttackSpeed(unit, true)
        end
        
        --текущее время задержки для атаки
        function GetUnitCurrentAttackTime(unit, index)
            if GetUnitIncreaseAttackSpeed(unit, true) ~= 0 then
                return BlzGetUnitAttackCooldown(unit, index) / GetUnitIncreaseAttackSpeed(unit, true)
            else
                return 0
            end
        end        
           
--ARMOR ==============================

        --base armor от base (белой) agility
        function GetHeroBaseArmor(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return (GetHeroAttributeAgi(hero,false)*DefenseBonusPerAgilityPoint)+DefenseBaseValue
            else
                return 0
            end
        end
        
        --bonus armor от bonus (зеленой) agility
        function GetHeroBonusArmor(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return GetHeroAgi_bonus(hero)*DefenseBonusPerAgilityPoint
            else
                return 0
            end
        end
        
        --bonus armor от способностей
        function UnitGetBonusArmor(unit)
            return UnitGetBonus (unit, 5)
        end
        function UnitSetBonusArmor(unit,value)
            return UnitSetBonus (unit, 5, value)
        end
        
        --суммарный бонус защиты
        function GetUnitBonusArmor(unit)
            return UnitGetBonusArmor(unit)+GetHeroBonusArmor(unit)
        end

        --суммарная базовая защита
        function GetUnitBaseArmor(unit)
            return BlzGetUnitArmor(unit)-GetUnitBonusArmor(unit)
        end
        --изначальная базовая защита (без учета ловкости)
        --дроби базовой защиты пришлось отсекать
        --из-за ловкости значения могут не округляться до целых
        --пример 28, а получилось 27.99. базовый параметр при расчетах получается не 0, а -0.11
        function GetBasicArmor(unit)
            local basic = GetUnitBaseArmor(unit)-GetHeroBaseArmor(unit)
            
            if basic>0 then
                return math.floor(basic)
            elseif basic<0 then
                return math.ceil(basic)
            else
                return basic
            end
            
        end
--DamageReduction =======================
        --формула снижения армора
        --https://xgm.guru/p/wc3/get-unit-armor


        function GetDamageReduction(unit)
            local armor = BlzGetUnitArmor(unit)
            local reduction = 0
          
            if armor>0 then
                reduction = Multiplier * armor / (1 + Multiplier * armor)
            elseif armor<0 then
                reduction = (1 - Multiplier) ^ (-armor) - 1
            end
            
            return reduction
        end
     
--HP и MANA =====================     
         function SetUnitHP(unit,value)
            SetUnitState(unit, UNIT_STATE_LIFE, RMaxBJ(0,value))
        end
        function SetUnitMana(unit,value)
            SetUnitState(unit, UNIT_STATE_MANA, RMaxBJ(0,value))
        end    

--MAX HP и MAX MANA =============  
        function GetHeroBaseMaxHP(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return GetHeroStr(hero, true)*HitPointBonusPerStrength
            else
                return 0
            end
        end
        function GetHeroBaseMaxMana(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return GetHeroInt(hero, true)*ManaPointBonusPerInt
            else
                return 0
            end
        end
        
        
        function GetUnitBonusMaxHP(unit)
            return UnitGetBonus (unit, 10) 
        end
        function GetUnitBaseMaxHP(unit)
            return BlzGetUnitMaxHP(unit)-(GetHeroBaseMaxHP(unit)+GetUnitBonusMaxHP(unit))
        end
        

        function GetUnitBonusMaxMana(unit)
            return UnitGetBonus (unit, 11) 
        end
        function GetUnitBaseMaxMana(unit)
            return BlzGetUnitMaxMana(unit)-(GetHeroBaseMaxMana(unit)+GetUnitBonusMaxMana(unit))
        end

-- regen hp и regen mana ==================

        --bonus regen hp/sec
        function GetUnitBonusRegenHP(unit)
            return UnitGetBonus (unit, 6)
        end
        --bonus % увеличение mana regen от base regen
        function GetUnitBonusRegenMana(unit)
            return UnitGetBonus (unit, 7)
        end
        
        --bonus regen hp/sec
        function GetUnitBonusRegenHP(unit)
            return UnitGetBonus (unit, 6)
        end
        
        --bonus regen hp/sec от strength
        function GetHeroRegenHP(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return GetHeroStr(hero, true)*RegenHpBonusPerStrength
            else
                return 0
            end
        end
        --base regen hp/sec
        function GetUnitBaseRegenHP(unit)
            return BlzGetUnitRealField(unit, UNIT_RF_HIT_POINTS_REGENERATION_RATE)
        end
        function SetUnitBaseRegenHP(unit, value) 
            BlzSetUnitRealFieldBJ( unit, UNIT_RF_HIT_POINTS_REGENERATION_RATE, value )
        end
        --общий бонус регена (полезен для героев)
        function GetUnitGeneralBonusRegenHP(unit)
            return GetHeroRegenHP(unit)+GetUnitBonusRegenHP(unit)
        end
        --общий regen hp/sec
        function GetUnitRegenHP(unit)
            return GetUnitBaseRegenHP(unit)+GetUnitGeneralBonusRegenHP(unit)
        end
        
        --procent от mana regen
        function GetUnitBonusProcentRegenMana(unit)
            return UnitGetBonus (unit, 7)/100
        end
        function SetUnitBonusProcentRegenMana(unit,value)
            return UnitGetBonus (unit, 7,R2I(value*100))
        end
        
        --regen mana/sec от intellect
        function GetHeroRegenMana(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return GetHeroInt(hero, true)*RegenManaBonusPerInt
            else
                return 0
            end
        end
        
        --base regen mana/sec
        function GetUnitBaseRegenMana(unit)
            return BlzGetUnitRealField(unit, UNIT_RF_MANA_REGENERATION)
        end
        function SetUnitBaseRegenMana(unit, value)
            return BlzSetUnitRealField( unit, UNIT_RF_MANA_REGENERATION, value )
        end
        
        function GetUnitBonusRegenMana(unit)
            return (GetHeroRegenMana(unit)+GetUnitBaseRegenMana(unit))*GetUnitBonusProcentRegenMana(unit)
        end
        
        --общий бонус регена (полезен для героев)
        function GetUnitGeneralBonusRegenMana(unit)
            return GetHeroRegenMana(unit)+GetUnitBonusRegenMana(unit)
        end
        
        --общий реген маны
        function GetUnitRegenMana(unit)
            return GetUnitBaseRegenMana(unit)+GetUnitGeneralBonusRegenMana(unit)
        end
        
--check ATTACK =================
        
        function IsAttackUnitEnabled(unit,index)
            return BlzGetUnitWeaponBooleanField(unit, UNIT_WEAPON_BF_ATTACKS_ENABLED,index)
        end
        
        -- 0 - normal (skills), 1 - melee, 2 - pierce, 3 - siege, 4 - magic,5 - chaos,6 - hero
        function GetUnitAttackType(unit,index)
            return BlzGetUnitWeaponIntegerField(unit, UNIT_WEAPON_IF_ATTACK_ATTACK_TYPE, index)
        end
        
-- check type defense ==============
        function GetUnitDefenseType(unit)
            return BlzGetUnitIntegerField(unit, UNIT_IF_DEFENSE_TYPE)
        end

-- AcquisitionRange ===================
        function GetUnitAcquisitionRange(unit)
            return BlzGetUnitRealField(unit, UNIT_RF_ACQUISITION_RANGE)
        end
        function SetUnitAcquisitionRange(unit,value)
            return BlzSetUnitRealField(unit, UNIT_RF_ACQUISITION_RANGE,value)
        end
        
        
-- radius sight =====================
        function GetUnitSightRadius(unit)
            return BlzGetUnitRealField(unit, UNIT_RF_SIGHT_RADIUS)
        end
        function SetUnitSightRadius(unit, value)
            return BlzSetUnitRealField( unit, UNIT_RF_SIGHT_RADIUS, value )
        end
        
        
        function GetUnitBonusSightRadius(unit)
            return UnitGetBonus (unit, 8)
        end
        
        function SetUnitBonusSightRadius(unit,value)
            return UnitSetBonus (unit, 8,value)
        end
        
--макс опыт ====================================
        function GetHeroMaxXP(hero)
            local level = GetUnitLevel(hero)
            local need = 0
            
            for i=1, level do
                need = need * NeedHeroXPFormulaA + NeedHeroXPFormulaB * (i+1) + NeedHeroXPFormulaC
            end
            return need
        end
        
    end
end

список функции

характеристики героя
модификаторы атрибута можно вычислить разными способами. Достаточно нативки GetHeroStr/GetHeroAgi/GetHeroInt из варика 1.26. Они еще актуальны. Но я как-то эксперементировал, и проверял на что влияют поля (филды). И как-то у меня по своему получилосб. Короче, что там, что здесь - разницы никакой. Поэтому я не стал прибегать к не нужной проверки UnitGetBonus из BonusMod, где циклом чекает. Не нужно.
определение основного атрибута
--основной атрибут героя (1-str, 3-agi, 2-int). влияет на атаку
function GetHeroPrimaryAttribute(hero)
    return BlzGetUnitIntegerField(hero, UNIT_IF_PRIMARY_ATTRIBUTE)
end
--установка не работает
function SetHeroPrimaryAttribute(hero, value)
    BlzSetUnitIntegerField( hero, UNIT_IF_PRIMARY_ATTRIBUTE, value)
end
определение начисления очков атрибута за каждый уровень
function GetHeroStrPerLevel(hero) 
	return BlzGetUnitRealField(hero, UNIT_RF_STRENGTH_PER_LEVEL)
end
function GetHeroAgiPerLevel(hero) 
	return BlzGetUnitRealField(hero, UNIT_RF_AGILITY_PER_LEVEL)
end
function GetHeroIntPerLevel(hero) 
	return BlzGetUnitRealField(hero, UNIT_RF_INTELLIGENCE_PER_LEVEL)
end
определение: общие параметры атрибутов (дефолтные нативки)
--общие параметры атрибутов: базовый+бонус (бонус можно исключить)
function GetHeroAttributeStr(hero, includeBonuses)
	return GetHeroStr(hero, includeBonuses)
end
function GetHeroAttributeAgi(hero, includeBonuses)
    return GetHeroAgi(hero, includeBonuses)
end
function GetHeroAttributeInt(hero, includeBonuses)
	return GetHeroInt(hero, includeBonuses)
end
определение: базовые атрибуты героя (белые атрибуты)
--базовые атрибуты героя
function GetHeroStr_base(hero)
	return BlzGetUnitIntegerField(hero, UNIT_IF_STRENGTH)
end
function GetHeroAgi_base(hero)
	return BlzGetUnitIntegerField(hero, UNIT_IF_AGILITY)
end
function GetHeroInt_base(hero)
	return BlzGetUnitIntegerField(hero, UNIT_IF_INTELLIGENCE)
end
определение: бонусные атрибуты (зеленые атрибуты)
--бонусные атрибуты героя
function GetHeroStr_bonus(hero)
	return BlzGetUnitIntegerField(hero, UNIT_IF_STRENGTH_WITH_BONUS)-GetHeroStr_base(hero)
end
function GetHeroAgi_bonus(hero)
	return BlzGetUnitIntegerField(hero, UNIT_IF_AGILITY_WITH_BONUS)-GetHeroAgi_base(hero)
end
function GetHeroInt_bonus(hero)
	return BlzGetUnitIntegerField(hero, UNIT_IF_INTELLIGENCE_WITH_BONUS) - GetHeroInt_base(hero)
end
дополнительные базовые аттрибуты (наскока изменили от дефолта)
поскольку нативок и филдов не обнаружил. и никак не достать. а бесполезную бд вручную делать не хочется. решил написать код заполнения бд при создании юнита. Это сделано специально, для сброса параметров. при создании юнита система записывает стартовые базовые параметры. В игре могу изменять базовые параметры, но и также сбросить. Ну по идее это мб и бесполезной штукой.
заметка: система фиксирует не только при создании юнитов, но и регистрирует тех, что на карте. И не все герои изначально имеют стартовые характеристики, поскольку они уже возросли. Поэтому расчет идет от уровня.
короче, в чем суть этих стартовых функции? в редакторе вы можете поставить героя на карту. Задать уровень герою, у него за каждый уровень соответственно возрастают характеристики. Также, можно и изменить базовые уровни на любой другой прям в редакторе. Но вот наскока изменили это значение можно подсчитать и записать как basic
--GetBasicParam показывает насколько изменилась базовая характеристика по стравнению с дефолтом
function GetBasicParamStr(u)
    return math.ceil(GetHeroStr_base(u)-(GetHeroStrPerLevel(u)*(GetHeroLevel(u)-1)))
end
function GetBasicParamAgi(u)
    return math.ceil(GetHeroAgi_base(u)-(GetHeroAgiPerLevel(u)*(GetHeroLevel(u)-1)))
end
function GetBasicParamInt(u)
    return math.ceil(GetHeroInt_base(u)-(GetHeroIntPerLevel(u)*(GetHeroLevel(u)-1)))
end
основной атрибут
основной атрибут помогает отобразить кол-во атаки. Ведь у героев вся атака строится на основном атрибуте
у меня три функции определения урона: общий, базовый, бонус. Поскольку нужно бывает нужно учитывать только базовый/бонусный урон/или исключить бонусный и др
общий атрибут
--основной атрибут (включая бонус)
function GetHeroGeneralPrimaryAttribute(hero)
    if IsUnitType(hero, UNIT_TYPE_HERO) then
        if GetHeroPrimaryAttribute(hero) == 1 then --str
            return GetHeroAttributeStr(hero, true)
        elseif GetHeroPrimaryAttribute(hero) == 2 then --int
            return GetHeroAttributeInt(hero, true)
        elseif GetHeroPrimaryAttribute(hero) == 3 then --agi
            return GetHeroAttributeAgi(hero, true)
        end
    end
end
базовый основной атрибут
--базовый атрибут
function GetHeroBasePrimaryAttribute(hero)
    if IsUnitType(hero, UNIT_TYPE_HERO) then
        if GetHeroPrimaryAttribute(hero) == 1 then --str
			return GetHeroAttributeStr(hero, false)
        elseif GetHeroPrimaryAttribute(hero) == 2 then --int
            return GetHeroAttributeInt(hero, false)
        elseif GetHeroPrimaryAttribute(hero) == 3 then --agi
            return GetHeroAttributeAgi(hero, false)
        end
    end
end
бонусной основной атрибут
--бонусный атрибут
function GetHeroBonusPrimaryAttribute(hero)
    if IsUnitType(hero, UNIT_TYPE_HERO) then
        if GetHeroPrimaryAttribute(hero) == 1 then --str
            return GetHeroStr_bonus(hero)
        elseif GetHeroPrimaryAttribute(hero) == 2 then --int
            return GetHeroInt_bonus(hero)
        elseif GetHeroPrimaryAttribute(hero) == 3 then --agi
            return GetHeroAgi_bonus(hero)
        end
    end
end
Теперь введем функции на установку параметров. Изначально в варике доступны SetHeroStr/SetHeroAgi/SetHeroInt. Но они меняют только базовые параметры. А вот бонусы придеться добавлять через UnitSetBonus
изменение базовых атрибутов (белых атрибутов)
--установить базовые (белые) атрибуты героя
function SetHeroBaseStr(hero, value)
	SetHeroStr(hero, value, true)
end
function SetHeroBaseAgi(hero, value)
	SetHeroAgi(hero, value, true)
end
function SetHeroBaseInt(hero, value)
	SetHeroInt(hero, value, true)
end
изменение бонусных атрибутов (зеленых атрибутов)
--установить бонусные (зеленые) атрибуты героя
function SetHeroBonusStr(hero, value)
	UnitSetBonus (hero, 1, value)
end
function SetHeroBonusAgi(hero, value)
	UnitSetBonus (hero, 2, value)
end
function SetHeroBonusInt(hero, value)
	UnitSetBonus (hero, 3, value)
end
добавить бонусные атрибуты
короче, функции на добавлении очков модификаторов из BonusMod
--добавить бонусные (зеленые) атрибуты героя
function AddHeroBonusStr(hero, value)
	UnitAddBonus (target, 1, ammount)
end
function AddHeroBonusAgi(hero, value)
	UnitAddBonus (target, 2, ammount)
end
function AddHeroBonusInt(hero, value)
	UnitAddBonus (target, 3, ammount)
end
включена/выключена атака
Перво-наперво нужно проверять есть ли у юнита атака вообще. Это можно сделать с помощью проверки GetUnitAbilityLevel(unit, FourCC('Aatk'))>0
function IsAttackUnitEnabled(unit,index)
	return BlzGetUnitWeaponBooleanField(unit, UNIT_WEAPON_BF_ATTACKS_ENABLED,index)
end
урон
в рефордже уже существуют новые нативки для урона
native BlzGetUnitBaseDamage takes unit whichUnit, integer weaponIndex returns integer
native BlzGetUnitDiceNumber takes unit whichUnit, integer weaponIndex returns integer
native BlzGetUnitDiceSides takes unit whichUnit, integer weaponIndex returns integer
native BlzSetUnitBaseDamage takes unit whichUnit, integer baseDamage, integer weaponIndex returns nothing
native BlzSetUnitDiceNumber takes unit whichUnit, integer diceNumber, integer weaponIndex returns nothing
native BlzSetUnitDiceSides takes unit whichUnit, integer diceSides, integer weaponIndex returns nothing
определение: суммарный базовый урон (базовый урон + основной атрибут)
BlzGetUnitBaseDamage определяет суммарный урон (урон из ро + урон от основного базового атрибута). из основного атрибута героя BlzGetUnitBaseDamage учитывает даже бонусный атрибут. Бонусный атрибут прибавляется к бонусному урону, поэтому нас интересует только базовый основной атрибут героя
заметка: BlzGetUnitBaseDamage почему-то не учитывает бонусы урона от предметов. Но зато учитывает урон от основного атрибута, или бонус тоже от основного атрибута.
--общий базовый урон с учетом базового атрибута героя
--бонус урона от предметов в функции BlzGetUnitBaseDamage не учитывается, поэтому его в расчетах нет
function GetUnitBaseDamage(unit, index)
	local base = 0
	local bonus = 0
	if IsUnitType(unit, UNIT_TYPE_HERO) then
		if GetHeroPrimaryAttribute(unit) == 1 then --str
			bonus = GetHeroStr_bonus(unit)
		elseif GetHeroPrimaryAttribute(unit) == 2 then --int
			bonus = GetHeroInt_bonus(unit)
		elseif GetHeroPrimaryAttribute(unit) == 3 then --agi
			bonus = GetHeroAgi_bonus(unit)
		end
	end
        
        
	return(BlzGetUnitBaseDamage(unit,index)-bonus)
end
бонусный урон
тут функции работают с очкамит модификатора-4 из BonusMod, т.е. из предметов
--bonus damage от абилок-когтей
function UnitGetBonusDamage(unit)
	return UnitGetBonus(unit, 4)
end
function UnitSetBonusDamage(unit,value)
	UnitSetBonus(unit, 4,value)
end
суммарный бонусный урон (бонусный урон + бонус от основного атрибута)
--суммарный bonus damage (от осного атрибута+от когтей)
function GetUnitBonusDamage(unit)
    local bonus = 0
    if IsUnitType(unit, UNIT_TYPE_HERO) then
        if GetHeroPrimaryAttribute(unit) == 1 then --str
            bonus = GetHeroStr_bonus(unit)
        elseif GetHeroPrimaryAttribute(unit) == 2 then --int
            bonus = GetHeroInt_bonus(unit)
        elseif GetHeroPrimaryAttribute(unit) == 3 then --agi
            bonus = GetHeroAgi_bonus(unit)
        end
    end
        
    --bonus damage от основного атрибута + bonus damage от когтей
    return UnitGetBonusDamage(unit)+ bonus
end
Min and Max damage
Вычисляются по такой формуле
Min = Damage Base + Number of Dice (количество костей)
Max = Damage Base + Number of Dice * Sides per Die (кол-во костей*урона с каждой кости)
function GetUnitMinDamage(unit, index)
	return (GetUnitBaseDamage(unit,index) + BlzGetUnitDiceNumber(unit,index))
end
        
function GetUnitMaxDamage(unit, index)
    return (GetUnitBaseDamage(unit,index) + BlzGetUnitDiceNumber(unit,index) * BlzGetUnitDiceSides(unit,index))
 end
защита
в рефордже уже есть две нативки для работы с защитой. Однако, оно выдает инфу или изменяет общий armor. Никак не подразделяет на базовую и бонус
--считывает базовый+бонус
native BlzGetUnitArmor takes unit whichUnit returns real 
native BlzSetUnitArmor takes unit whichUnit, real armorAmount returns nothing
базовая защита от базовой ловкости
--константы
DefenseBonusPerAgilityPoint = 0.3
DefenseBaseValue = -2 --for Agility

--base armor от base (белой) agility
function GetHeroBaseArmor(hero)
	if IsUnitType(hero, UNIT_TYPE_HERO) then
		return (GetHeroAttributeAgi(hero,false) * DefenseBonusPerAgilityPoint) + DefenseBaseValue
	else
		return 0
	end
end
бонусная защита от бонусной ловкости
--bonus armor от bonus (зеленой) agility
function GetHeroBonusArmor(hero)
	if IsUnitType(hero, UNIT_TYPE_HERO) then
		return GetHeroAgi_bonus(hero) * DefenseBonusPerAgilityPoint
	else
		return 0
	end
end
бонус защиты от модификатора-5 из BonusMod
--bonus armor от способностей
function UnitGetBonusArmor(unit)
	return UnitGetBonus (unit, 5)
end
function UnitSetBonusArmor(unit,value)
	return UnitSetBonus (unit, 5, value)
end
суммарный бонус защиты
--суммарный бонус защиты
function GetUnitBonusArmor(unit)
	return UnitGetBonusArmor(unit)+GetHeroBonusArmor(unit)
end
суммарная базовая защита
напомню, что BlzGetUnitArmor учитывает общую защиту. и не подразделяет на базовую и бонусную защиту.
--суммарная базовая защита
function GetUnitBaseArmor(unit)
	return BlzGetUnitArmor(unit)-GetUnitBonusArmor(unit)
end
изначальная базовая защита
--изначальная базовая защита (без учета ловкости)
--дроби базовой защиты пришлось отсекать
--из-за ловкости значения могут не округляться до целых
--пример 28, а получилось 27.99. базовый параметр при расчетах получается не 0, а -0.11
function GetBasicArmor(unit)
	local basic = GetUnitBaseArmor(unit)-GetHeroBaseArmor(unit)
				
	if basic>0 then
		return math.floor(basic)
	elseif basic<0 then
		return math.ceil(basic)
	else
		return basic
	end
            
end
снижение брони
в подсказках часто вижу описание об этом.
Снижение полученного урона за единицу брони:
Damage Reduction = Multiplier * Armor / (1 + Multiplier * Armor);
где Multiplier - это значение из Gameplay Constants - Combat - Armor Damage Reduction Multiplier, по умолчанию равное 0.06
Пришлось повозиться с этой штукой. Эта формула работает только при положительном armor. При отрицательном armor там какая то другая формула. И еще ограничение выпирается до ?1% судя по инфе интерфейса, но так ли не знаю.
--формула снижения армора
--https://xgm.guru/p/wc3/get-unit-armor

function GetDamageReduction(unit)
    local armor = BlzGetUnitArmor(unit)
    local reduction = 0
          
    if armor>0 then
        reduction = Multiplier * armor / (1 + Multiplier * armor)
    elseif armor<0 then
        reduction = (1 - Multiplier) ^ (-armor) - 1
    end
            
    return reduction
end
регенерация здоровья
базовая регенерация здоровья
можно определить базовый реген. и даже изменить его без проблем с помощью поля (филда).
--base regen hp/sec
function GetUnitBaseRegenHP(unit)
	return BlzGetUnitRealField(unit, UNIT_RF_HIT_POINTS_REGENERATION_RATE)
end
function SetUnitBaseRegenHP(unit, value) 
	BlzSetUnitRealFieldBJ( unit, UNIT_RF_HIT_POINTS_REGENERATION_RATE, value )
end
бонусная регенерация здоровья от модификатора-6 из BonusMod
--bonus regen hp/sec
function GetUnitBonusRegenHP(unit)
	return UnitGetBonus (unit, 6)
end
function SetUnitBonusRegenHP(unit, value)
	return UnitSetBonus (unit, 6, value)
end
регенерация от силы
--константа
RegenHpBonusPerStrength = 0.05

--regen hp/sec от strength
function GetHeroRegenHP(hero)
	if IsUnitType(hero, UNIT_TYPE_HERO) then
		return GetHeroStr(hero, true)*RegenHpBonusPerStrength
	else
		return 0
	end
end
ОБЩИЙ РЕГЕН
--общий regen hp/sec
function GetUnitGeneralBonusRegenHP(unit)
	return GetUnitBaseRegenHP(unit) + GetHeroRegenHP(unit) + GetUnitBonusRegenHP(unit)
end
регенерация маны
базовая регенерация маны
тоже как и в здоровье можно менять с помощью поля (филда)
--base regen mana/sec
function GetUnitBaseRegenMana(unit)
	return BlzGetUnitRealField(unit, UNIT_RF_MANA_REGENERATION)
end
function SetUnitBaseRegenMana(unit, value)
	return BlzSetUnitRealField( unit, UNIT_RF_MANA_REGENERATION, value )
end
бонусная регенерация от интеллекта
--константа
RegenManaBonusPerInt = 0.05

--regen mana/sec от intellect
function GetHeroRegenMana(hero)
	if IsUnitType(hero, UNIT_TYPE_HERO) then
		return GetHeroInt(hero, true)*RegenManaBonusPerInt
	else
		return 0
	end
end
процентное увеличение регенерации от маски соби
тут модификатор-7 работает на абилках из маски соби
--procent от mana regen
function GetUnitBonusProcentRegenMana(unit)
	return UnitGetBonus (unit, 7)/100 --возвращает целые
end
function SetUnitBonusProcentRegenMana(unit,value)
	return UnitGetBonus (unit, 7,R2I(value*100))
end
function GetUnitBonusRegenMana(unit)
	return (GetHeroRegenMana(unit) + GetUnitBaseRegenMana(unit)) * GetUnitBonusProcentRegenMana(unit)
end
общая регенерация маны
--общий бонус регена (полезен для героев)
function GetUnitGeneralBonusRegenMana(unit)
    return GetHeroRegenMana(unit)+GetUnitBonusRegenMana(unit)
end
--общий реген маны
function GetUnitRegenMana(unit)
    return GetUnitBaseRegenMana(unit)+GetUnitGeneralBonusRegenMana(unit)
end
радиус обзора
радиус обзора меняется хорошо через нативку филда
function GetUnitSightRadius(unit)
    return BlzGetUnitRealField(unit, UNIT_RF_SIGHT_RADIUS)
end
function SetUnitSightRadius(unit, value)
    return BlzSetUnitRealField( unit, UNIT_RF_SIGHT_RADIUS, value )
end
function GetUnitBonusSightRadius(unit)
    return UnitGetBonus (unit, 8)
end
function SetUnitBonusSightRadius(unit,value)
    return UnitSetBonus (unit, 8,value)
end
радиус получения атаки
function GetUnitAcquisitionRange(unit)
    return BlzGetUnitRealField(unit, UNIT_RF_ACQUISITION_RANGE)
end
function SetUnitAcquisitionRange(unit,value)
    return BlzSetUnitRealField(unit, UNIT_RF_ACQUISITION_RANGE,value)
end
оказывается в редакторе уже существовали нативки. просто нигде у меня не находили свое применение
native GetUnitAcquireRange takes unit whichUnit returns real
native GetUnitDefaultAcquireRange takes unit whichUnit returns real
native SetUnitAcquireRange takes unit whichUnit, real newAcquireRange returns nothing
скорость атаки
в рефордже ввели только нативку по определению/изменению базового времени задержки между атаками. И больше ничего нет. Только от этого можно отталкиваться.
native BlzGetUnitAttackCooldown takes unit whichUnit, integer weaponIndex returns real
native BlzSetUnitAttackCooldown takes unit whichUnit, real cooldown, integer weaponIndex returns nothing
пришлось вычислять. ранее, я не знал как, пока сам не прочитал. вернее, я и раньше знал, но боялся ошибиться в точности, поэтому не брался.
теория
Скорость атаки - это показатель ударов в секунду, или как часто взмахивает оружием ваш герой. Скорость атаки зависит от ловкости, аур, артефактов, скилов. Чем быстрее скорость атаки тем больше урона в определенное время наносит урона герой.
Для вывода формулы будут использованы некоторые понятия:
AS - attack speed - Скорость атаки, кол-во ударов в сек
BAS - basic attack speed - Базовая скорость атаки, кол-во ударов в сек
IAS - increase attack speed дополнительный процент. Складывается из ловкости героя и бонусов скорости атаки. Не может быть выше 400 или ниже -80. Изначально скорость не измерялась в процентах, но так пошло в варкрафте. Понижение и увеличение скорости осуществляется с помощью модификаторов-способностей. А еще дополнительно от ловкости через константы. Изначальная скорость юнитов равно 1.00 (100%). Максимум бонусом можно задать 4.00 (400%). Это в сумме: изначальная + бонусная = 100+400 = 500%. В варкрафте в максимум упирается в в этот потолок, это 5 ударов в сек. больше никак не сделать. ниже 100% нормы - уже скорость идет на понижение. самый минимальный предел = 20%. Ниже 20% никак нельзя поставить.
Складывается из ловкости героя и бонусов скорости атаки. Не может быть выше 400 или ниже -80.
  • 0.20 = -80% IAS <= самый минимальный результат. ниже этого нельзя поставить.
  • 1.00 = 0% IAS <= изначальную скорость принята считать за 1.00 (100%)
  • 2.00 = 100% IAS <= при увеличении AS на 1.00 (100%), скорость увеличилась 2.00
Delay - Базовая задержка между ударами, сек. По-другому, Delay называют базовое время атаки Base attack time, BAT. или AttackCooldown. Можно проверить таймером от замаха до замаха - это будет считаться временем. Начало замаха означает начала атаки.
Time - время задержки после добавления модификации бонусов, сек. Этот параметр добавил специально, чтобы смотреть как меняется время задержки между атаками после добавления модификаторов.
Изначально в механике игры заложен параметр задержка между ударами - Delay, а не скорость атаки.
У подавляющего большинства героев из доты Delay равен 1.7 сек, за исключением:
Magina - The Anti-Mage (Антимаг) – 1.45 сек.
Shandelzare Silkwood - The Vengeful Spirit (Венга) – 1.77 сек.
Balanar - The Night Stalker (Сталкер) – 1.8 сек.
Terrorblade - The Soul Keeper (Террорблейд) – 1.5 сек.
Чтобы рассчитать скорость атаки - AS, нам необходимо знать BAS и IAS героя:
Чтобы вычислить базовую скорость атаки (BAS), нужно количество выстрелов (ударов) разделить на время, за которое они произведены. За основу мы берем единицу, т.е. один удар, которым совершаем атаку за определенное время. То есть мы должны 1 разделить на Delay, так как пауза между выстрелами (ударами) равна 1.7 сек., отсюда: BAS =1/Delay=1/1.7 ≈ 0.6 выстрелов в секунду. Для вышеуказанных героев с отличающимися задержками от стандартной, все рассчитывается точно так же по формуле BAS =1/Delay.
IAS - дополнительный процент – процент увеличения скорости атаки, равен сумме процентов от ловкости, артефактов, умений, наложенных заклинаний и аур.
Измеряется IAS в % и подразделяется как бы на 2е группы:
  • IAS от ловкости. Каждая единица ловкости увеличивает IAS на 1%. (Например, у героя ловкость равна 24, тогда IAS от ловкости = 24*1%=24%). (0.01) 1% взят из констант доты. В варкрафте значение это мб другим, оно равно 0.02 за каждую ловкость
  • IAS от артефактов, умений, наложенных заклинаний и аур. Сразу указан в % и не тр***ет дополнительных расчетов. Все IAS складываются между собой. (Например, IAS от ловкости = 30%, IAS от Power treads = 30%, следовательно, общий (суммарный) IAS (Σ IAS)) = 60%
Получается вот такая формула подсчета скорости:
AS = BAS* (1 + Σ IAS)=1/Delay*(1 + Σ IAS)
Примеры:
Silencer с ловкостью в 20 ед., тогда:
Σ IAS = 20 * 1% = 20%,
AS = 0.6 * (1+ 20%) ≈ 0,7 выстрелов (ударов) в секунду
Time = Delay / (1+ 20%) = 1.7 / 1.2 % = 1.4 сек - задержка между ударами
Axe с Power treads и MKB, ловкость = 35, тогда:
Σ IAS = 35 * 1% + 30% + 15% = 80%,
AS = 0.6* (1+80%) ≈ 1.1 выстрел (удар) в секунду
Time = Delay / (1+80%) = 1.7 / 1.8 % = 0.94 сек - задержка между ударами
базовый IAS
изначально равно 100%
--IAS - показывает % процентное содержание AS
function GetUnitBaseIAS(unit)
	return 1.00 --изначально AS равна 1.00 (100%)
end
базовая скорость AS (при base IAS = 100%)
тут base AS=1/ base BAT
--BAS - базовая скорость атаки, показывает кол-во ударов в сек
function GetUnitBaseAttackSpeed(unit, index)
    if BlzGetUnitAttackCooldown(unit, index) ~= 0 then
        return 1/BlzGetUnitAttackCooldown(unit, index)
    else
        return 0
    end
end
bonus IAS от ловкости
--константа
AttackSpeedBonusPerAgilityPoint = 0.02

--IAS - показывает %-ый бонус от ловкости героя
function GetUnitAgilityBonusIAS(unit)
	if IsUnitType(unit, UNIT_TYPE_HERO) then
		return (GetHeroAttributeAgi(unit, true) * AttackSpeedBonusPerAgilityPoint) --0.02% бонуса AS за каждую единицу ловкости
	else
		return 0
	end
end
IAS от модификатора-9 из BonusMod
--bonus IAS - показывает процент AS от абилок
--делим на 100 тк результат из BonusMod выдают в виде целых чисел
function GetUnitBonusIAS(unit)
	return (UnitGetBonus (unit, 9) / 100)
end
function SetUnitBonusIAS(unit,value)
	return (UnitSetBonus (unit, 9, R2I(value*100)))
end
общий бонусный IAS (значение этого параметра ограничены от -0.80 до 4.00)
--общий бонус. лимитирован от -80% до 400%
function GetGeneralUnitBonusIAS(unit)
	local bonus = GetUnitAgilityBonusIAS(unit) + GetUnitBonusIAS(unit)
            
	if bonus > 4.00 then
		return 4.00
	elseif bonus < -0.80 then
		return -0.80
	end
            
	return bonus
end
суммарный IAS (base+bonus)
--показывает общий суммарный IAS в %
function GetUnitIncreaseAttackSpeed(unit, includeBonuses)
	if includeBonuses then
		return GetUnitBaseIAS(unit) + GetGeneralUnitBonusIAS(unit)
	else
		return GetUnitBaseIAS(unit) 
	end
end
AS
--AS выдает кол-во ударов в сек
function GetUnitCurrentAttackSpeed(unit, index)
	return GetUnitBaseAttackSpeed(unit, index) * GetUnitIncreaseAttackSpeed(unit, true)
end
AttackTime
--время задержки для атаки
function GetUnitCurrentAttackTime(unit, index)
    if GetUnitIncreaseAttackSpeed(unit, true) ~= 0 then
        return BlzGetUnitAttackCooldown(unit, index) / GetUnitIncreaseAttackSpeed(unit, true)
    else
        return 0
    end
end
хп/мана
function SetUnitHP(unit,value)
	SetUnitState(unit, UNIT_STATE_LIFE, RMaxBJ(0,value))
end
function SetUnitMana(unit,value)
	SetUnitState(unit, UNIT_STATE_MANA, RMaxBJ(0,value))
end
макс хп/макс мана
тут в рефордже завезли новые функции на определение/изменение макс запасов хп и маны. так что сами решайте. Можете использовать модификаторы-10 и 11 из BonusMod или этими нативками.
native BlzGetUnitMaxHP takes unit whichUnit returns integer
native BlzSetUnitMaxHP takes unit whichUnit, integer hp returns nothing

native BlzGetUnitMaxMana takes unit whichUnit returns integer
native BlzSetUnitMaxMana takes unit whichUnit, integer mana returns nothing

        function GetHeroBaseMaxHP(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return GetHeroStr(hero, true)*HitPointBonusPerStrength
            else
                return 0
            end
        end
        function GetHeroBaseMaxMana(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return GetHeroInt(hero, true)*ManaPointBonusPerInt
            else
                return 0
            end
        end

function GetUnitBonusMaxHP(unit)
    return UnitGetBonus (unit, 10) 
end
function GetUnitBaseMaxHP(unit)
    return BlzGetUnitMaxHP(unit)-(GetHeroBaseMaxHP(unit)+GetUnitBonusMaxHP(unit))
end
        
function GetUnitBonusMaxMana(unit)
    return UnitGetBonus (unit, 11) 
end
function GetUnitBaseMaxMana(unit)
    return BlzGetUnitMaxMana(unit)-(GetHeroBaseMaxMana(unit)+GetUnitBonusMaxMana(unit))
end
уровни апгрейдов урона/брони
можно вычислить с помощью фреймов
BlzGetFrameByName("InfoPanelIconLevel",0) - 1 атака
BlzGetFrameByName("InfoPanelIconLevel",1) - 2 атака
BlzGetFrameByName("InfoPanelIconLevel",2) - броня
--пример
if BlzFrameGetText(BlzGetFrameByName("InfoPanelIconLevel",0)))>0 then

end
как определить уровень апгрейда атаки/защиты
такой нативки в рефе к сожалению нет. и филдов тоже не прилагается (искал, но такая информация не является характеристикой юнита, а скорее игрока). Только или костыльным способом или через бд
прочесть из фрейма
можно прочесть из фреймов. Когда вы выделяете юнита, то можете прочесть уровень.
Раньше так я думал, что проще всего для отображения всех данных BonusMode, проверяя работу созданных мной кастомных функции. Честно, апгрейды атаки/защиты ни на что не влияли. Просто показать эффект решил. Хотелось найти идеального и безопасного решения, но так и не нашел тогда. И чтение инфы с фрейма не точная, у вас должен быть видим
Заметка: обращение к данным фрейма не всегда безопасно: там может быть ничего не указано (пример, если выбрать героя, то у него не указаны апгрейды атаки, как у пехотинца), либо фрейм SimpleInfoPanelUnitDetail не видим (достаточно выделить несколько юнитов, и панель SimpleInfoPanelUnitDetail с дочерними фреймами станет невидимым => ничего оттуда не получишь. При выделении несколько юнитов, например, у вас отображается другая панель => групповая, и одиночная панель SimpleInfoPanelUnitDetail будет скрыта ).
Еще помните, что это дочерние фреймы SimpleInfoPanelUnitDetail являются не полноценными simpleframes, т.е. простыми строками string. Игра не любит, если вы используете ниже перечисленнные natives на строках(String) /текстурах(Texture), игра вылетает:
BlzFrameSetVisible
BlzFrameIsVisible
BlzFrameSetAlpha
BlzFrameSetLevel​
Но зато вы можете получить string с помощью BlzFrameGetText(frame), если есть что прочесть. Но перед этим лучше проверяйте видим ли родитель SimpleInfoPanelUnitDetail. А еще проверить, что в строке есть какая-то запись. Но в основном это не всегда можно получать так информацию.
local syncTrigger_techArmor = CreateTrigger()
for int = 0, bj_MAX_PLAYERS - 1 do
	BlzTriggerRegisterPlayerSyncEvent(syncTrigger_techArmor, Player(int), "IsCursorMouseInGameZone", false)
end
TriggerAddAction(syncTrigger_techArmor, function()
	local str = BlzGetTriggerSyncPrefix()
	local n = BlzGetTriggerSyncData()
	local length_str = #str
	local start_pos, end_pos = str:find('tech_armor_')
	local substring = string.sub(str, end_pos+1)
	
	print('level tech armor: '..substring..' у игрока-'..n)
	
	n = tonumber(n)
	local tech_lv_armor = tonumber(substring)
	
	if tech_lv_armor>0 then
		--иконка улучшения
		infopanel[n].tech_level_armor=tech_lv_armor
		--иконка типа армора
		infopanel[n].icon_armor = ARMOR_ICON_WITH_UPGRAID[infopanel[n].type_armor]            
		
		if GetLocalPlayer()==Player(n) then
			--изменяем текстуру
			BlzFrameSetTexture(infopanel[n].TextureArmor, infopanel[n].icon_armor,0, true)
			--обновляем tech
			BlzFrameSetText(infopanel[n].TechArmor, infopanel[n].tech_level_armor)
			BlzFrameSetVisible(infopanel[n].TechArmor, true)
		end
	else
		infopanel[n].tech_level_armor=0
		infopanel[n].icon_armor = ARMOR_ICON[infopanel[n].type_armor]
		if GetLocalPlayer()==Player(n) then
			--изменяем текстуру
			BlzFrameSetTexture(TextureArmor,infopanel[n].icon_armor,0, true)
			--обновляем tech
			BlzFrameSetVisible(infopanel[n].TechArmor, false)
		end
	end

end)

if BlzFrameIsVisible(BlzGetFrameByName("SimpleInfoPanelUnitDetail",0)) then
	local tech_lv_armor = BlzFrameGetText(BlzGetFrameByName("InfoPanelIconLevel",2))
	if tech_lv_armor then
		tech_lv_armor = tonumber(tech_lv_armor)
		--в луа проще проверять по типу. тк пустая строка "" и nil => есть отличия.
		if type(tech_lv_armor)=='number' then
			print(tostring('tech lv armor: '..tech_lv_armor))
			if tech_lv_armor>0 then
				BlzSendSyncData("tech_armor_"..tech_lv_armor, n)
			end
		end
	end
end
бд
Второй способ это создать бд. Как правило, в механики игры любая технология привязана к игроку. Если изучает красный, все апгрейды будут на юнитах красного игрока действовать. А если передать эти войска синему игроку, который не изучал технологии, то апгрейды с войск сбрасываются.
проще привязать апгрейды игрока к конкретным типам юнитов.
код-1 динамичная бд
do
    local real = MarkGameStarted
    function MarkGameStarted()
    real()

	LEVEL_TECH_DAMAGE_OF_UNIT = {}
	LEVEL_TECH_ARMOR_OF_UNIT = {}

	for a=1,12 do
		LEVEL_TECH_DAMAGE_OF_UNIT[a] = {}
		LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hfoo')]=0
		LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hrif')]=0
		LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hmtm')]=0
		LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hkni')]=0
		LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hgry')]=0
		LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('ufro')]=0
		LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('emtg')]=0

		LEVEL_TECH_ARMOR_OF_UNIT[a] = {}
		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hfoo')]=0
		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hrif')]=0
		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hmtm')]=0
		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hkni')]=0
		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hgry')]=0
		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('ufro')]=0
		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('emtg')]=0

		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hbla')]=0
		LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hhou')]=0
	end

	trigger_player_research_finish = CreateTrigger()
	TriggerAddAction( trigger_player_research_finish, function()
		local techid = GetResearched()
		local current_lv_tech = GetPlayerTechCount(GetTriggerPlayer(), techid, true)
		local max_lv_tech = GetPlayerTechMaxAllowed(GetTriggerPlayer(), techid)
		if techid == FourCC('Rhme') then --железные мечи
			LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hfoo')]=current_lv_tech
			LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hkni')]=current_lv_tech
			LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hgry')]=current_lv_tech
		elseif techid == FourCC('Rhra') then --черный порох
			LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hrif')]=current_lv_tech
			LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('hmtm')]=current_lv_tech
		elseif techid == FourCC('Rhar') then --железные щиты
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hfoo')]=current_lv_tech
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hkni')]=current_lv_tech
		elseif techid == FourCC('Rhla') then --поклепанная кожа
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hrif')]=current_lv_tech
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hmtm')]=current_lv_tech
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hgry')]=current_lv_tech
		elseif techid == FourCC('Rhac') then --каменная укладка
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hbla')]=current_lv_tech
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('hhou')]=current_lv_tech
		elseif techid == FourCC('Resw') then --сила леса
			LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('emtg')]=current_lv_tech
		elseif techid == FourCC('Rerh') then --прочные шкуры
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('emtg')]=current_lv_tech
		elseif techid == FourCC('Rura') then --атака чудовищ
			LEVEL_TECH_DAMAGE_OF_UNIT[a][FourCC('ufro')]=current_lv_tech
		elseif techid == FourCC('Rucr') then --броня чудовищ
			LEVEL_TECH_ARMOR_OF_UNIT[a][FourCC('ufro')]=current_lv_tech
		end
	end)
	end
end
код-2
или досточно знать на каких юнитов действует апгрейд. Узнаете какая технология улучшит ту или ную характеристику. Пример, урон пехотинца улучшается после изучения железных мечей в кузнице. Можно просто заполнить бд на каждую характеристику. И потом по current_lv_tech = GetPlayerTechCount(GetTriggerPlayer(), techid, true) узнать уровень
TECH_DAMAGE_OF_UNIT = {}
TECH_ARMOR_OF_UNIT = {}

TECH_DAMAGE_OF_UNIT[FourCC('hfoo')]='Rhme' --железные мечи
TECH_DAMAGE_OF_UNIT[FourCC('hkni')]='Rhme'
TECH_DAMAGE_OF_UNIT[FourCC('hgry')]='Rhme'	
TECH_DAMAGE_OF_UNIT[FourCC('hrif')]='Rhra' --черный порох
TECH_DAMAGE_OF_UNIT[FourCC('hmtm')]='Rhra'

TECH_DAMAGE_OF_UNIT[FourCC('ufro')]='Rura' --атака чудовищ
TECH_DAMAGE_OF_UNIT[FourCC('emtg')]='Resw' --сила леса

TECH_ARMOR_OF_UNIT[FourCC('hfoo')]='Rhar' --железные щиты
TECH_ARMOR_OF_UNIT[FourCC('hkni')]='Rhar'
TECH_ARMOR_OF_UNIT[FourCC('hrif')]='Rhla' --поклепанная кожа
TECH_ARMOR_OF_UNIT[FourCC('hmtm')]='Rhla'
TECH_ARMOR_OF_UNIT[FourCC('hgry')]='Rhla'

TECH_ARMOR_OF_UNIT[FourCC('ufro')]='Rucr' --броня чудовищ
TECH_ARMOR_OF_UNIT[FourCC('emtg')]='Rerh' --прочные шкуры

TECH_ARMOR_OF_UNIT[FourCC('hbla')]='Rhac' --каменная укладка
TECH_ARMOR_OF_UNIT[FourCC('hhou')]='Rhac'
тип атаки
-- 0 - normal (skills), 1 - melee, 2 - pierce, 3 - siege, 4 - magic,5 - chaos,6 - hero
function GetUnitAttackType(unit,index)
	return BlzGetUnitWeaponIntegerField(unit, UNIT_WEAPON_IF_ATTACK_ATTACK_TYPE, index)
end
тип защиты
типы защиты
  • 0 - small (легкая)
  • 1 - medium (средняя)
  • 2 - large (тяжелая)
  • 3 - fort (укрепленная)
  • 4 norm
  • 5 - hero
  • 6 - divine
  • 7 - None (без брони)
--  defense type
DEFENSE_TYPE_LIGHT = ConvertDefenseType(0)	
DEFENSE_TYPE_MEDIUM = ConvertDefenseType(1)	
DEFENSE_TYPE_LARGE = ConvertDefenseType(2)	
DEFENSE_TYPE_FORT = ConvertDefenseType(3)	
DEFENSE_TYPE_NORMAL = ConvertDefenseType(4)	
DEFENSE_TYPE_HERO = ConvertDefenseType(5)	
DEFENSE_TYPE_DIVINE = ConvertDefenseType(6)	
DEFENSE_TYPE_NONE = ConvertDefenseType(7)	
function GetUnitDefenseType(unit)
	return BlzGetUnitIntegerField(unit, UNIT_IF_DEFENSE_TYPE)
end
макс требуемый опыт для повышения уровня
--константы
	NeedHeroXP = 200
	NeedHeroXPFormulaA = 1.00
	NeedHeroXPFormulaB = 100
	NeedHeroXPFormulaC = 0	
	        --макс опыт
function GetHeroMaxXP(hero)
	local level = GetUnitLevel(hero)
	local need = 0
            
	for i=1, level do
		need = need * NeedHeroXPFormulaA + NeedHeroXPFormulaB * (i+1) + NeedHeroXPFormulaC
	end
	return need
 end

Базовые параметры

функции для табличных параметров
были созданы отдельный custom cript, где осуществляется работа полностью с basic и base параметрами. Может быть это бесполезно, но сделан как пример, в base записываются базовые параметры. Изначально только их можно и было использовать. У каждого юнита по каждому параметру (сила, ловкость, интеллект, урон, защита и пр) была своя таблица base, с помощью которой можно было изменять, либо узнавать текущий базовый параметр.
Несмотря на то, что многие параметры итак можно узнать нативным способом, через нативки. Но не у всех, конечно. Некоторые параметры требуют более точного ответа. Хотя я не могу вспомнить зачем, но зачем то я это сделал. Видать мне очень не давало покоя.
В дальнейшем нужно было еще добавить в качестве примера кнопку сброса. Я думал, что круто сбросить параметр к изначальному значению. И в результате появилась, еще одна группа таблиц basic на каждый параметр. Это изначальные значения каждого параметра, заданного в редакторе объектов. Пример, если задать юниту в ро +2 базовая защиты, при создании у него будет изначально +2 базового армора. Я не знал, как вычислить, тк таких нативок нет в рефе. Или они не могут читать данные с ро. не все филды есть, или не работают. Этот армор можно будет изменить в игре через триггеры, тогда как вернуть как было?
Самое простое это забивать бд для каждого юнита каждую характеристику. Это вообще труд. Хотел подобрать набор api функции. придумать адекватную систему для пользователя, чтобы ему не нужно было ничего забивать в BonusMode. Хитрым способом мной был придуман способ: при появлении нового созданного юнита на карте сразу же записываем его характеристики, потом они возможно динамично изменяется игрой.
В результате этого весь расчет идет от basic. Есть зависимость. Теперь, base означает насколько изменилась число по сравнению с basic. Если значение value увеличивается, то прибавляем к base. Если значение value уменьшается, то убавляем base.
Можно add/sub => base param = basic + (base+value)
То есть базовый параметр, это сумма base и basic. base изначально равен 0, но если параметр хоть как-то менялся, то он будет не равно ноль.
get => base param = base + basic
Совсем по-другому будет установить значение set, в отличии от add/sub. Но там другая формула:
base = value-basic
Пример:
basic = 20
установить base 30
base = 30-20 = 10
Пример:
basic = 10
установить base 15
base = 10-15 = -5
полная формула: base param = basic + (value-basic)
полный код
do
	local InitGlobalsOrigin = InitGlobals
	function InitGlobals()
		InitGlobalsOrigin()
    
        param = {}
		--base означает насколько изменилась число по сравнению с basic.
        param.base = {}
        param.base.str = {} --hero attribute 1-3
        param.base.agi = {}
        param.base.int = {}
        param.base.dmg1 = {} --dmg 4
        param.base.dmg2 = {}
        param.base.arm = {} --armor 5
        param.base.regenhp = {} --regeneration hp 6
        param.base.regenmana = {} --regeneration mana 7
        param.base.sight = {} --sight 8
        param.base.bat1 = {}
        param.base.bat2 = {}

        param.base.maxhp = {} -- max life 10
        param.base.maxmana = {} -- max mana 11
        param.base.move = {} -- move speed 12
        param.base.acquisition = {} 
        
        --basic - стартовые параметры (нужны для сброса) 
        --поскольку не ко всем полям бд можножно получить, то заводим эти basic. При создании юнита высчитываем изначальный параметр
        
        param.basic = {}
        param.basic.str = {} --hero attribute 1-3
        param.basic.agi = {}
        param.basic.int = {}
        param.basic.dmg1 = {}
        param.basic.dmg2 = {}
        param.basic.arm = {}
        param.basic.regenhp = {}
        param.basic.regenmana = {}
        param.basic.bat1 = {}
        param.basic.bat2 = {}
        param.basic.maxhp = {}
        param.basic.maxmana = {}
        param.basic.sight = {}
        param.basic.move = {}
        param.basic.acquisition = {} 
        

		--эти три функции атрибута нужны, чтобы сбросить базовый параметр
		--суммарная расчетная базовая сила за каждый уровень
		--param.basic.str записан дополнительный атрибут GetBaseParamStr(u), если он есть
        function GetBaseParamStr(u)
            local h = GetHandleId(u)
            if IsUnitType(u, UNIT_TYPE_HERO) then
                return param.basic.str[h]+GetHeroStrPerLevel(u)*(GetHeroLevel(u)-1)
            else
                return 0
            end
        end
		--суммарная расчетная базовая ловкость за каждый уровень
		--param.basic.agi записан дополнительный атрибут GetBaseParamAgi(u), если он есть
        function GetBaseParamAgi(u)
            local h = GetHandleId(u)
            if IsUnitType(u, UNIT_TYPE_HERO) then
                return param.basic.agi[h]+GetHeroAgiPerLevel(u)*(GetHeroLevel(u)-1)
            else
                return 0
            end
        end
		--суммарный базовый расчетный интеллект за каждый уровень
		--param.basic.int записан дополнительный атрибут GetBaseParamInt(u), если он есть
        function GetBaseParamInt(u)
            local h = GetHandleId(u)
            if IsUnitType(u, UNIT_TYPE_HERO) then
                return param.basic.int[h]+GetHeroIntPerLevel(u)*(GetHeroLevel(u)-1)
            else
                return 0
            end
        end
        
        --базовый армор от суммарной расчетной базовой ловкости за каждый уровень
        function GetHeroBaseParamArmor(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                return (GetBaseParamAgi(hero)*DefenseBonusPerAgilityPoint)+DefenseBaseValue
            else
                return 0
            end
        end
		--основной базовый аттрибут. тут расчеты каждого атрибута берутся за каждый уровень
        function GetHeroBaseParamPrimaryAttribute(hero)
            if IsUnitType(hero, UNIT_TYPE_HERO) then
                if GetHeroPrimaryAttribute(hero) == 1 then --str
                    return GetBaseParamStr(hero)
                elseif GetHeroPrimaryAttribute(hero) == 2 then --int
                    return GetBaseParamInt(hero)
                elseif GetHeroPrimaryAttribute(hero) == 3 then --agi
                    return GetBaseParamAgi(hero)
                end
            else
				return 0
            end
        end
		--базовый урон: урон из ро + основный аттрибут. Внимание: апгрейды не учел в param.basic.dmg1 или param.basic.dmg2. Но нужно их тоже засчитать
        function GetUnitBasicParamDamage(unit,index)
            local h = GetHandleId(unit)
            if index == 0 then
                return GetHeroBaseParamPrimaryAttribute(unit)+param.basic.dmg1[h]
            elseif index == 1 then
                return GetHeroBaseParamPrimaryAttribute(unit)+param.basic.dmg2[h]
            else
                return 0
            end
        end
		--суммарный basic армор: базовый армор от ловкости +армор из ро. Внимание: апгрейды не учел в param.basic.arm. Но нужно их тоже засчитать 
        function GetUnitBasicParamArmor(unit)
            local h = GetHandleId(unit)
            return GetHeroBaseParamArmor(unit)+param.basic.arm[h]
        end
		--базовая аремя атаки юнита изначальная
        function GetUnitBasicParamBAT(unit,index)
            local h = GetHandleId(unit)
            if index == 0 then
                return param.basic.bat1[h]
            elseif index == 1 then
                return param.basic.bat2[h]
            else
                return 0
            end
        end
        --базовая скорость атаки юнита изначальная
        function GetUnitBasicParamAS(unit, index)
            local cooldawn = 0
            local h = GetHandleId(unit)
            if index == 0 then
                cooldawn = param.basic.bat1[h]
            elseif index == 1 then
                cooldawn = param.basic.bat2[h]
            end
            if cooldawn ~= 0 then
                return 1/cooldawn
            else
                return 0
            end
        end
        
        --регистрируем на карте имеющих юнитов
        local group_param = CreateGroup()
        TimerStart(CreateTimer(),0.03,false,function()
            GroupEnumUnitsInRect(group_param, bj_mapInitialPlayableArea, nil)
            ForGroup(group_param,function()
                local u = GetEnumUnit()
                local h = GetHandleId(u)
                if IsUnitType(u, UNIT_TYPE_HERO) then
                    param.basic.str[h] = GetBasicParamStr(u)
                    param.basic.agi[h] = GetBasicParamAgi(u)
                    param.basic.int[h] = GetBasicParamInt(u)
                    print(param.basic.str[h])
                end
                param.basic.dmg1[h]=GetUnitBasicDamage(u,0)
                param.basic.dmg2[h]=GetUnitBasicDamage(u,1)
                param.basic.arm[h]=GetBasicArmor(u)
                param.basic.regenhp[h]= GetUnitBaseRegenHP(u)
                param.basic.regenmana[h]= GetUnitBaseRegenMana(u)
                param.basic.bat1[h]=BlzGetUnitAttackCooldown(u,0)
                param.basic.bat2[h]=BlzGetUnitAttackCooldown(u,1)
                param.basic.maxhp[h]=GetUnitBaseMaxHP(u)
                param.basic.maxmana[h]=GetUnitBaseMaxMana(u)
                param.basic.move[h]=GetUnitDefaultMoveSpeed(u)
                param.basic.sight[h] = GetUnitSightRadius(u)
                param.basic.acquisition[h]=GetUnitAcquisitionRange(u)
                
                --эти динамичные базовые параметры, которые можно изменить
                --показывают сколько вы хотите добавить base очков параметра
                param.base.str[h]=0
                param.base.agi[h]=0
                param.base.int[h]=0
                param.base.dmg1[h]=0
                param.base.dmg2[h]=0
                param.base.arm[h]=0
                param.base.regenhp[h] = 0
                param.base.regenmana[h] = 0
                param.base.bat1[h] = 0
                param.base.bat2[h] = 0
                param.base.sight[h] = 0
                param.base.maxhp[h] = 0
                param.base.maxmana[h] = 0
                param.base.move[h] = 0 
                param.base.acquisition[h]=0
            end)
            
            print("кол-во юнитов на карте: "..BlzGroupGetSize(general_group))
            DestroyTimer(GetExpiredTimer())
        end)

        --регистрируем триггер на появление юнитов
        local trigger = CreateTrigger() --триггер добавления юнитов
        TriggerRegisterEnterRectSimple( trigger, bj_mapInitialPlayableArea )
        TriggerAddCondition(trigger, Condition( function()
            return not IsUnitInGroup(GetTriggerUnit(), group_param)
        end) )
        TriggerAddAction(trigger,function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            if IsUnitType(u, UNIT_TYPE_HERO) then
                param.basic.str[h] = GetBasicParamStr(u)
                param.basic.agi[h] = GetBasicParamAgi(u)
                param.basic.int[h] = GetBasicParamInt(u)
            end
            param.basic.dmg1[h]=GetUnitBasicDamage(u,0)
            param.basic.dmg2[h]=GetUnitBasicDamage(u,1)
            param.basic.arm[h]=GetBasicArmor(u)
            param.basic.regenhp[h]= GetUnitBaseRegenHP(u)
            param.basic.regenmana[h]= GetUnitBaseRegenMana(u)
            param.basic.bat1[h]=BlzGetUnitAttackCooldown(u,0)
            param.basic.bat2[h]=BlzGetUnitAttackCooldown(u,1)
            param.basic.maxhp[h]=GetUnitBaseMaxHP(u)
            param.basic.maxmana[h]=GetUnitBaseMaxMana(u)
            param.basic.move[h]=GetUnitDefaultMoveSpeed(u)
            param.basic.sight[h] = GetUnitSightRadius(u)
            param.basic.acquisition[h]=GetUnitAcquisitionRange(u)
            
            
            --эти динамичные базовые параметры, которые можно изменить
            --инициируем бд для созданного
            param.base.str[h]=0
            param.base.agi[h]=0
            param.base.int[h]=0
            param.base.dmg1[h]=0
            param.base.dmg2[h]=0
            param.base.arm[h]=0
            param.base.regenhp[h] = 0
            param.base.regenmana[h] = 0
            param.base.bat1[h] = 0
            param.base.bat2[h] = 0
            param.base.sight[h] = 0
            param.base.maxhp[h] = 0
            param.base.maxmana[h] = 0
            param.base.move[h] = 0 
            param.base.acquisition[h]=0
            
            GroupAddUnit(group_param,u)
            
        end)
        
        --это функция добавления была создана для ввода базового модификатора в чат
        --index атаки моэно не прописывать, пример: UnitAddBase(unit,mod,value)
        function UnitAddBase(unit,mod,value,index)
            if type(mod) ~= 'number' or type(value) ~= 'number' then
                return false
            elseif (mod == 4 or mod == 9) and type(index) ~= 'number' then
                return false
            elseif GetUnitTypeId (unit) == 0 or IsUnitType (unit, UNIT_TYPE_DEAD) then
                return false
            elseif mod > 0 and mod < 4 then
                if not IsUnitType(unit, UNIT_TYPE_HERO) then
                    print('UnitSetBonus: you cant give the ability to a non-hero')
                    return false
                end
            end
            
            local h = GetHandleId(unit)
            if mod == 1 then
                param.base.str[h]=param.base.str[h]+value
                SetHeroBaseStr(unit, R2I(RoundEx(GetBaseParamStr(unit)+param.base.str[h])))
            elseif mod == 2 then
                param.base.agi[h]=param.base.agi[h]+value
                SetHeroBaseAgi(unit, R2I(RoundEx(GetBaseParamAgi(unit)+param.base.agi[h])))
            elseif mod == 3 then
                param.base.int[h]=param.base.int[h]+value
                SetHeroBaseInt(unit, R2I(RoundEx(GetBaseParamInt(unit)+param.base.int[h])))
            elseif mod == 4 then
                if index == 0 then
                    param.base.dmg1[h]=param.base.dmg1[h]+value
                    BlzSetUnitBaseDamage(unit,R2I(RoundEx(GetUnitBasicParamDamage(unit,index)+param.base.dmg1[h])),index)
                elseif index == 1 then
                    param.base.dmg2[h]=param.base.dmg2[h]+value
                    BlzSetUnitBaseDamage(unit,R2I(RoundEx(GetUnitBasicParamDamage(unit,index)+param.base.dmg2[h])),index)
                end
            elseif mod == 5 then
                param.base.arm[h]=param.base.arm[h]+value
                BlzSetUnitArmor(unit, GetUnitBasicParamArmor(unit)+param.base.arm[h])
            elseif mod == 6 then
                param.base.regenhp[h]=param.base.regenhp[h]+value
                SetUnitBaseRegenHP(unit, param.basic.regenhp[h]+param.base.regenhp[h])
            elseif mod == 7 then
                param.base.regenmana[h]=param.base.regenmana[h]+value
                SetUnitBaseRegenMana(unit, param.basic.regenmana[h]+param.base.regenmana[h])           
            elseif mod == 8 then
                param.basic.sight[h] = param.basic.sight[h]+value
                SetUnitSightRadius(unit,param.basic.sight[h]+param.base.sight[h])
            elseif mod == 9 then
                if index == 0 then
                    param.base.bat1[h] = param.base.bat1[h] + value
                    BlzSetUnitAttackCooldown(unit,param.basic.bat1[h]+param.base.bat1[h],index)
                elseif index == 1 then
                    param.base.bat2[h] = param.base.bat2[h] + value
                    BlzSetUnitAttackCooldown(unit,param.basic.bat2[h]+param.base.bat2[h],index)
                end
            elseif mod == 10 then
                param.base.maxhp[h]= param.base.maxhp[h]+value
                BlzSetUnitMaxHP(unit,R2I(RoundEx(GetHeroBaseMaxHP(unit)+param.basic.maxhp[h]+param.base.maxhp[h])))
            elseif mod == 11 then   
                param.base.maxmana[h]= param.base.maxmana[h]+value
                BlzSetUnitMaxMana(unit,R2I(RoundEx(GetHeroBaseMaxMana(unit)+param.basic.maxmana[h]+param.base.maxmana[h])))
            elseif mod == 12 then 
                param.base.move[h] = param.base.move[h] + value
                SetUnitMoveSpeed(unit,param.basic.move[h]+param.base.move[h])
            elseif mod == 13 then 
                param.base.acquisition[h]=param.base.acquisition[h] + value
                SetUnitAcquisitionRange(unit,param.basic.acquisition[h]+param.base.acquisition[h])

            end
            
        end
        
        
        --эта функция была добавления для задания параметра через чат
        --index атаки моэно не прописывать, пример: UnitSetBase(unit,mod,value) base = value-basic
        function UnitSetBase(unit,mod,value,index)
            if type(mod) ~= 'number' or type(value) ~= 'number' then
                return false
            elseif (mod == 4 or mod == 9) and type(index) ~= 'number' then
                return false
            elseif GetUnitTypeId (unit) == 0 or IsUnitType (unit, UNIT_TYPE_DEAD) then
                return false
            elseif mod > 0 and mod < 4 then
                if not IsUnitType(unit, UNIT_TYPE_HERO) then
                    print('UnitSetBonus: you cant give the ability to a non-hero')
                    return false
                end
            end
            
            local h = GetHandleId(unit)
            if mod == 1 then
                param.base.str[h]=value-GetBaseParamStr(unit)
                SetHeroBaseStr(unit,R2I(RoundEx(GetBaseParamStr(unit)+param.base.str[h])))
            elseif mod == 2 then
                param.base.agi[h]=value-GetBaseParamAgi(unit)
                SetHeroBaseAgi(unit,R2I(RoundEx(GetBaseParamAgi(unit)+param.base.agi[h])))
            elseif mod == 3 then
                param.base.int[h]=value-GetBaseParamInt(unit)
                SetHeroBaseInt(unit,R2I(RoundEx(GetBaseParamInt(unit)+param.base.int[h])))
            elseif mod == 4 then
                if index == 0 then
                    param.base.dmg1[h]=R2I(RoundEx(value-GetUnitBasicParamDamage(unit,index)))
                    BlzSetUnitBaseDamage(unit,R2I(RoundEx(GetUnitBasicParamDamage(unit,index)+param.base.dmg1[h])),index)
                elseif index == 1 then
                    param.base.dmg2[h]=R2I(RoundEx(value-GetUnitBasicParamDamage(unit,index)))
                    BlzSetUnitBaseDamage(unit,R2I(RoundEx(GetUnitBasicParamDamage(unit,index)+param.base.dmg2[h])),index)
                end
            elseif mod == 5 then
                param.base.arm[h]=R2I(RoundEx(value-GetUnitBasicParamArmor(unit)))
                BlzSetUnitArmor(unit,param.base.arm[h]+GetUnitBasicParamArmor(unit))
            elseif mod == 6 then
                param.base.regenhp[h]=R2I(RoundEx(value-param.basic.regenhp[h]))
                SetUnitBaseRegenHP(unit, param.base.regenhp[h]+-param.basic.regenhp[h])
            elseif mod == 7 then
                param.base.regenmana[h]=R2I(RoundEx(value-param.basic.regenmana[h]))
                SetUnitBaseRegenMana(unit, param.base.regenmana[h]+param.basic.regenmana[h])           
            elseif mod == 8 then
                param.base.sight[h]=R2I(RoundEx(value-param.basic.sight[h]))
                SetUnitSightRadius(unit,param.base.sight[h]+param.basic.sight[h])
            elseif mod == 9 then
                if index == 0 then
                    param.base.bat1[h]=R2I(RoundEx(value-param.basic.bat1[h]))
                    BlzSetUnitAttackCooldown(unit,param.base.bat1[h]+param.basic.bat1[h],index)
                elseif index == 1 then
                    param.base.bat2[h]=R2I(RoundEx(value-param.basic.bat2[h]))
                    BlzSetUnitAttackCooldown(unit,param.base.bat2[h]+param.basic.bat2[h],index)
                end
            elseif mod == 10 then
                param.base.maxhp[h]=R2I(RoundEx(value-param.basic.maxhp[h])) --требуется проверка, пока неизвестно как работает, возможна нужно с GetHeroBaseMaxHP(unit)
                BlzSetUnitMaxHP(unit,R2I(RoundEx(param.base.maxhp[h]+param.basic.maxhp[h])))
            elseif mod == 11 then   
                param.base.maxmana[h]=R2I(RoundEx(value-param.basic.maxmana[h])) --требуется проверка, пока неизвестно как работает, возможна нужно с GetHeroBaseMaxMana(unit)
                BlzSetUnitMaxMana(unit,R2I(RoundEx(param.base.maxmana[h]+param.basic.maxmana[h])))
            elseif mod == 12 then 
                param.base.move[h]=value-param.basic.move[h] --требуется проверка
                SetUnitMoveSpeed(unit,param.base.move[h]+param.basic.move[h])
            elseif mod == 13 then 
                param.base.acquisition[h]=value-param.basic.acquisition[h]
                SetUnitAcquisitionRange(unit,param.base.acquisition[h]+param.basic.acquisition[h])
            end            
        end
        --эта функция была добавления для задания параметра через чат
        --index атаки моэно не прописывать, пример: UnitClearBase(unit,mod)
        function UnitClearBase(unit,mod,index)
            
    
            if type(mod) ~= 'number' then
                return false
            elseif (mod == 4 or mod == 9) and type(index) ~= 'number' then
                return false
            elseif GetUnitTypeId (unit) == 0 or IsUnitType (unit, UNIT_TYPE_DEAD) then
                return false
            elseif mod > 0 and mod < 4 then
                if not IsUnitType(unit, UNIT_TYPE_HERO) then
                    print('UnitSetBonus: you cant give the ability to a non-hero')
                    return false
                end
            end
            
            
            local h = GetHandleId(unit)
            if mod == 1 then
                param.base.str[h]=0
                SetHeroBaseStr(unit, R2I(RoundEx(GetBaseParamStr(unit)+param.base.str[h])))
            elseif mod == 2 then
                param.base.agi[h]=0
                SetHeroBaseAgi(unit, R2I(RoundEx(GetBaseParamAgi(unit)+param.base.agi[h])))
            elseif mod == 3 then
                param.base.int[h]=0
                SetHeroBaseInt(unit, R2I(RoundEx(GetBaseParamInt(unit)+param.base.int[h])))
            elseif mod == 4 then
                if index == 0 then
                    param.base.dmg1[h]=0
                    BlzSetUnitBaseDamage(unit,R2I(RoundEx(GetUnitBasicParamDamage(unit,index)+param.base.dmg1[h])),index)
                elseif index == 1 then
                    param.base.dmg2[h]=0
                    BlzSetUnitBaseDamage(unit,R2I(RoundEx(GetUnitBasicParamDamage(unit,index)+param.base.dmg2[h])),index)
                end
            elseif mod == 5 then
                param.base.arm[h]=0
                BlzSetUnitArmor(unit, GetUnitBasicParamArmor(unit)+param.base.arm[h])
            elseif mod == 6 then
                param.base.regenhp[h]=0
                SetUnitBaseRegenHP(unit, param.basic.regenhp[h]+param.base.regenhp[h])
            elseif mod == 7 then
                param.base.regenmana[h]=0
                SetUnitBaseRegenMana(unit, param.basic.regenmana[h]+param.base.regenmana[h])           
            elseif mod == 8 then
                param.basic.sight[h] = 0
                SetUnitSightRadius(unit,param.basic.sight[h]+param.base.sight[h])
            elseif mod == 9 then
                if index == 0 then
                    param.base.bat1[h] = 0
                    BlzSetUnitAttackCooldown(unit,param.basic.bat1[h]+param.base.bat1[h],index)
                elseif index == 1 then
                    param.base.bat2[h] = 0
                    BlzSetUnitAttackCooldown(unit,param.basic.bat2[h]+param.base.bat2[h],index)
                end
            elseif mod == 10 then
                param.base.maxhp[h]= 0
                BlzSetUnitMaxHP(unit,R2I(RoundEx(GetHeroBaseMaxHP(unit)+param.basic.maxhp[h]+param.base.maxhp[h])))
            elseif mod == 11 then   
                param.base.maxmana[h]= 0
                BlzSetUnitMaxMana(unit,R2I(RoundEx(GetHeroBaseMaxMana(unit)+param.basic.maxmana[h]+param.base.maxmana[h])))
            elseif mod == 12 then 
                param.base.move[h] = 0
                SetUnitMoveSpeed(unit,param.basic.move[h]+param.base.move[h])
            elseif mod == 13 then 
                param.base.acquisition[h]=0
                SetUnitAcquisitionRange(unit,param.basic.acquisition[h]+param.base.acquisition[h])
            end
        end
    end
end
Добавлена возможность прокручивать или уставливать значения прямо в фреймах. Ибо в чатах неудобно всегда тестить.
Заметки:
  • скорость атаки. тут теоритически высчитывается. мы можешь узнать дефолтную attack cooldawn. В игре изначально предоставлена базовая attack cooldawn, и только базовая attack cooldawn, и больше ничего нет. И с помощью нее можно вычислить базовую скорость. Но нужно вам знать %, короче наскока изменяется эти базовые attack cooldawn, attack speed. По идее можно вообще обойтись без абилок перчаток, храните инфу в таблицах. изменяем саму attack cooldawn.
  • для изменения задержки между ударами таймером - рекомендуется кого-нибудь ударить. На карту я поставил специально ферму с регеном и хп, так сказать грушу для битья
  • поставил кузницу, чтобы изменять уровень апгрейда атаки/защиты. на пехотинце тестировалось. отследить можно, берем инфу из фрейма. но в фреймах я не доделал, кому надо - отвечу.
  • положил на карту сферы, дабы посмотреть включена/выключена атака. Это похоже работает только у горного гиганта, когда дерево вырывает
  • мана реген. модификатора регена маны работает с помощью абилки маски соби. там процентное содержание выдает. процент умножает на общий реген маны. И работает не так как надо. И еще она не работает у обычных юнитов.
Обновление:
  • исправлены ошибки в расчетах.
  • поработал немного над оформлением фреймов
  • добавлена возможность изменять базовые параметры.
Планы:
  • продолжить улучшать +много идеи. Хочу реализовать показ данных фрейма при наводке мыши на вражеского юнита: скока возможного урона, может ли атаковать, сильный/слабый юнит. А еще хочу потестить свою агро-систему с отображением радиуса.
  • бонус от абилки мана-реген маски соби не работает. тут надо включать другие бонусы, поэтому это не реально посчитать точное.
`
ОЖИДАНИЕ РЕКЛАМЫ...
0
27
2 года назад
Отредактирован MpW
0
повторяющие действие. пример бонус на макс хп можно изменить прямой нативкой. или реген тоже можно изменять.
а вот сила/ловкость/интеллект, защита/урон и др => им трудно добавить бонус, тк нативки изменяют только базовый или общий, т.е. белый параметр. нету подразделения четкого. это тогда нужно изменять сам интерфейс. в принципе не сложно добавить зеленку в интерфейс, а все данных в таблицах подразделять: бонус/базовый. Но это уже в след версии. Здесь бонусы добавляются через абилки степени двойки
1
32
2 года назад
1
Мощно
0
27
2 года назад
Отредактирован MpW
0
бонус мана реген через абилку маски соби может не работать у не-героев, только у героев. тестил еще в мемхаке. так что лучше напрямую изменять базовый мана реген, а данных хранить в таблицах
--base regen mana/sec
        function GetUnitBaseRegenMana(unit)
            return BlzGetUnitRealField(unit, UNIT_RF_MANA_REGENERATION)
        end
        function SetUnitBaseRegenMana(unit, value)
            return BlzSetUnitRealField( unit, UNIT_RF_MANA_REGENERATION, value )
        end
0
32
2 года назад
0
а с мана регеном я помню кажется, потому соби маски повышают реген в процентах от базового коээфициента, а его нет у некоторых юнитов надо что-то в ро поставить, или же делать на основа ауры, которая повышает мана реген числом. А у героев есть как бы базовый коэффициент

Предыдущий бонус мод слизан с хайвовского на джасе, и самое главное - перенос, нужна инструкция по переносу бонус мода НЕ в пустую карту а в готовую карту.
Я вроде где-то расписывал это но не помню, но могу сказать что это точно работает
0
27
2 года назад
Отредактирован MpW
0
Bergi,
Предмет: регенерация маны 'AIrm'/Предмет: регенерация маны (малый) 'AIrn' - каждую секунду процентно восстанавливает ману. Процент идет от базового регена + от регена интеллекта героя + другие бонусные регенерации типа чародейская ауры или аура фонтана магии. Эта регенерация работает только у героя, у обычных юнитов что-то не хочет идти.
формула
MANA_REGEN_SobiMask =((base_mana_regen + mana_regen_Intellect + другие бонусы типа чародейской ауры)*p) - реген от одной абилки. Если вообще нет никакого регена (реген != 0, главное чтоб был хотя бы один реген), то не будет работать реген и от маски. теперь даже отрицательный реген может получится, если указано отрицательное значение коэффициента. ВНИМАНИЕ: в этой формуле MANA_REGEN_SobiMask не учитывается реген от других соби масок, если у героя их несколько. Учитывают базовый реген, реген от инты +другие регены
MANA_REGEN_Common = mana_regen_Intellect + MANA_REGEN_SobiMask + другие бонусы типа чародейской ауры - общий реген (так как у героя работает только реген от инты и от других бонусов, а вот базовый реген не учитывается. Так как базовый реген не работает на герое)
MANA_REGEN_Common = mana_regen_Intellect + MANA_REGEN_SobiMask1 + MANA_REGEN_SobiMask2 + другие бонусы типа чародейской ауры - общий реген ((если абилок от маски соби несколько, они суммируются вот так)
Какие бонусы есть в игре? Это пассивки (чародейская аура, аура фонтана, маска соби не учитывается), активных заклинании с постепенным восстановлением не много (рев, леденящий крик, омоложение не учитывается,
base_mana_regen - базовый реген, который указан в РО юнита "Характеристики - Восстановление маны". Работает только у обычных юнитов, тестировал этот момент у героя. У героя показывает реген от интеллекта (базовый не работает у героя), но когда он одевает маску соби учитывается базовый реген. Благодаря базовому регену, можно сделать героя с уникальным регеном.
mana_regen_Intellect = Intellect * k - реген от интеллекта (где Intellect - кол-во интеллекта героя, k - константа "Характеристики героя: увеличение скорости восстановления за единицу разума", которая за каждую единицу маны восстанавливает заданное число)
p - процент от абилки
0
32
2 года назад
0
Я вообще против таких штук как реген в бонус моде, потому что что реген, это по факту "полученное лечение самого себя" и не плохо бы его контролировать триггерно а не через РО, например его можно будет подсчитать если это важная стата, можно будет сделать предмет - усиливает реген в 2 раза, можно будет делать запрет регена без костылей при появлении новых источников регена, это всё банально проще, когда ты это сделал и котролиш. Поэтому это всё не важно как по мне
0
27
2 года назад
0
ээх.. ладно. придется исправлять атаку. заметил ошибку с атакой, когда добавляю основной атрибут. что-то ломается
0
27
2 года назад
Отредактирован MpW
0
Вышла новая версия!
Обновление с 2.5 до 2.8:
  • переделка BonusMode, исправлены некоторые ошибки, удобства при копировании. некоторые фреймы и система переплетены были в одно, мешает. а еще при копировании всей системы фреймы ломаются или переставали работать. теперь фреймы можно не копировать. интерфейс это не важная часть, это прежде всего для проверки работы системы.
  • некоторые данные неправильно показывали.
  • исправлены ошибки при сэйв/лоаде, из-за фреймов вылетала игра при загрузке. пришлось пересоздавать данные. это большая работа.
  • исправлен десихрон при мультиплеере, тестил, вроде все норм.
  • добавлено отображение collision, pathing здании и декорации, а также acquisition range (радиус получения атаки).
  • была идея добавить проверку наскока юнит слаб/сильный. добавил доп окно при наведении мыши на юнита. В окне отображается выбранный юнит и выделенная цель. Не до конца доработано, тк нужно еще много чего добавить и проверить окно на десихрон и сэйв/лоад
Чтобы оставить комментарий, пожалуйста, войдите на сайт.