Добавлен , опубликован

спецэффект

спецэффект
effecttype t
--"Графика - Эффект (EffectArt)"
EFFECT_TYPE_EFFECT = ConvertEffectType(0)
--"Графика - Цель (TargetArt)"
EFFECT_TYPE_TARGET = ConvertEffectType(1)
--"Графика - Маг (CasterArt)"
EFFECT_TYPE_CASTER = ConvertEffectType(2)
--"Графика - Особые (SpecialArt)"
EFFECT_TYPE_SPECIAL = ConvertEffectType(3)
--"Графика - Область воздействия (AreaEffectArt)"
EFFECT_TYPE_AREA_EFFECT = ConvertEffectType(4)
--"Графика - Анимация дистанционной атаки (MissileArt)"
EFFECT_TYPE_MISSILE = ConvertEffectType(5)
--"Графика - Эффекты молнии (LightningEffect)"
EFFECT_TYPE_LIGHTNING = ConvertEffectType(6)
GetAbilityEffectById и GetAbilityEffect
GetAbilityEffectById. Получить строку эффекта (путь). GetAbilityEffectById, которая может извлекать строки из полей спецэффектов любой абилки (ability) в редакторе объектов.
  • abilityId - ид абилки
  • t effecttype - строка абилки. У абилки оч много разных эффектов: на кастера, на мага, на цель, снаряды итд. Здесь можно выбрать из какой строки абилки хотите изъять
  • index - индекс, номер эффекта в строке. номер эффекта в поле, который вы хотите извлечь, начиная с 0. Кому не понятно, что за индекс. В одном поле можно задать несколько эффектов, и вам будет предложен выбор, какой из этих эффектов выбирать.
---@param abilityId integer
---@param t effecttype
---@param index integer
---@return string
function GetAbilityEffectById(abilityId, t, index) end	-- (native)
GetAbilityEffect полагаю, что должна давать тот же результат, что и GetAbilityEffectById. У нее вместо abilityId указан abilityString.
  • abilityString - неизвестный параметр, что означает неизвестно. Как-то должны здесь указать на способность, тк уже есть указать на строку t effecttype. Именные способности плохо работают, тем более в редакторе можно несколько таких одноименных восоздать. Возможно, есть в редакторе список дефолтных, как у юнитов. Или может быть это строковый указать на равкод.
строку ввести, типа "ahea"/"<ahea,atat>"/"<ahea,TargetArt>". Короче, ничего не работает из этого. Даже в гуи меню нет такой нативки.
---@param abilityString string
---@param t effecttype
---@param index integer
---@return string
function GetAbilityEffect(abilityString, t, index) end	-- (native)
создать спеэффект
Примечательно, что для создания у эффекта много нативок.
Примечание: зависит от модели, при создании может проигрывать в начале не нужные анимации. Поэтому рекомендуется либо отредактировать модель, или создать в углу карты эффект и только потом поместить.
Указывают путь модели modelName
создать спецэффект в точке.
native AddSpecialEffect takes string modelName, real x, real y returns effect
native AddSpecialEffectLoc takes string modelName, location where returns effect
AddSpecialEffectTarget - создать и привязать созданный эффект на цели targetWidget. Аттачим модель на цель. У модели несколько аттачей.
native AddSpecialEffectTarget takes string modelName, widget targetWidget, string attachPointName returns effect
AddSpellEffectTarget - создать и привязать созданный эффект на цели targetWidget. Аттачим модель на цель. Отличие от первой AddSpecialEffectTarget в том, что прописываем в строку effecttype t модель. effecttype t не только к абилкам применима, но и наверное к строкам юнита. Хотя, вызывает сомнения, не понятный параметр. Это поле применимо к атаке "Графика - Анимация дистанционной атаки (MissileArt)", больше у юнитов не видел полей. (не проверено)
native AddSpellEffectTarget takes string modelName, effecttype t, widget targetWidget, string attachPoint returns effect
Указывают модель из строчки абилки effecttype t
создаем в точке
native AddSpellEffectById takes integer abilityId, effecttype t,real x, real y returns effect
native AddSpellEffectByIdLoc takes integer abilityId, effecttype t,location where returns effect
Аттачим модель на цель
native AddSpellEffectTargetById takes integer abilityId, effecttype t, widget targetWidget, string attachPoint returns effect
Указывают модель из строчки абилки abilityString
создать эффект в точке. совершенно не рабочие абилки, тк неизвестно, что нужно указывать в качестве параметра abilityString.
native AddSpellEffect takes string abilityString, effecttype t, real x, real y returns effect
native AddSpellEffectLoc takes string abilityString, effecttype t,location where returns effect
уничтожить спецэффект
Удаляет из игры спецэффект. Но перед удалением эффекта игра проигрывает анимацию уничтожения эффекта. Например, взрывается или исчезает и так далее. Остаются эффекты взрывов на земле итд. Чтобы я не делал:
-прятал альфа-каналом
-скрывал размер scale в ноль
идея только сместить в угол и там взорвать эффект. ссылка
native DestroyEffect takes effect whichEffect returns nothing
get coords x,y,z
локально отображает данные эффекта, мб вызывать десинки. хранить коорды в глобалках
native BlzGetLocalSpecialEffectX takes effect whichEffect returns real
native BlzGetLocalSpecialEffectY takes effect whichEffect returns real
native BlzGetLocalSpecialEffectZ takes effect whichEffect returns real
задаем положение эффекта x,y,z
Тут итак все понятно. насчет BlzSetSpecialEffectHeight не уверен, является ли это z, или как отдельный параметр высоты.
native BlzSetSpecialEffectHeight takes effect whichEffect, real height returns nothing
native BlzSetSpecialEffectPosition takes effect whichEffect, real x, real y, real z returns nothing
native BlzSetSpecialEffectPositionLoc takes effect whichEffect, location loc returns nothing
native BlzSetSpecialEffectX takes effect whichEffect, real x returns nothing
native BlzSetSpecialEffectY takes effect whichEffect, real x returns nothing
native BlzSetSpecialEffectZ takes effect whichEffect, real x returns nothing
задаем прозрачность цвет
native BlzSetSpecialEffectAlpha takes effect whichEffect, integer alpha returns nothing
native BlzSetSpecialEffectColor takes effect whichEffect, integer r, integer g, integer b returns nothing
native BlzSetSpecialEffectColorByPlayer takes effect whichEffect, player whichPlayer returns nothing
проигрывает анимацию
function BlzPlaySpecialEffect takes effect whichEffect, animtype whichAnim returns nothing
function BlzPlaySpecialEffectWithTimeScale takes effect whichEffect, animtype whichAnim, real timeScale returns nothing
    constant animtype           ANIM_TYPE_BIRTH                 = ConvertAnimType(0)
    constant animtype           ANIM_TYPE_DEATH                 = ConvertAnimType(1)
    constant animtype           ANIM_TYPE_DECAY                 = ConvertAnimType(2)
    constant animtype           ANIM_TYPE_DISSIPATE             = ConvertAnimType(3)
    constant animtype           ANIM_TYPE_STAND                 = ConvertAnimType(4)
    constant animtype           ANIM_TYPE_WALK                  = ConvertAnimType(5)
    constant animtype           ANIM_TYPE_ATTACK                = ConvertAnimType(6)
    constant animtype           ANIM_TYPE_MORPH                 = ConvertAnimType(7)
    constant animtype           ANIM_TYPE_SLEEP                 = ConvertAnimType(8)
    constant animtype           ANIM_TYPE_SPELL                 = ConvertAnimType(9)
    constant animtype           ANIM_TYPE_PORTRAIT              = ConvertAnimType(10)
что это за анимация можно по нативке определить
---@param whichAnim animtype
---@return string
function BlzGetAnimName(whichAnim) end	-- (native)
SubAnimation
function BlzSpecialEffectAddSubAnimation takes effect whichEffect, subanimtype whichSubAnim returns nothing
function BlzSpecialEffectClearSubAnimations takes effect whichEffect returns nothing
function BlzSpecialEffectRemoveSubAnimation takes effect whichEffect, subanimtype whichSubAnim returns nothing
    constant subanimtype        SUBANIM_TYPE_ROOTED             = ConvertSubAnimType(11)
    constant subanimtype        SUBANIM_TYPE_ALTERNATE_EX       = ConvertSubAnimType(12)
    constant subanimtype        SUBANIM_TYPE_LOOPING            = ConvertSubAnimType(13)
    constant subanimtype        SUBANIM_TYPE_SLAM               = ConvertSubAnimType(14)
    constant subanimtype        SUBANIM_TYPE_THROW              = ConvertSubAnimType(15)
    constant subanimtype        SUBANIM_TYPE_SPIKED             = ConvertSubAnimType(16)
    constant subanimtype        SUBANIM_TYPE_FAST               = ConvertSubAnimType(17)
    constant subanimtype        SUBANIM_TYPE_SPIN               = ConvertSubAnimType(18)
    constant subanimtype        SUBANIM_TYPE_READY              = ConvertSubAnimType(19)
    constant subanimtype        SUBANIM_TYPE_CHANNEL            = ConvertSubAnimType(20)
    constant subanimtype        SUBANIM_TYPE_DEFEND             = ConvertSubAnimType(21)
    constant subanimtype        SUBANIM_TYPE_VICTORY            = ConvertSubAnimType(22)
    constant subanimtype        SUBANIM_TYPE_TURN               = ConvertSubAnimType(23)
    constant subanimtype        SUBANIM_TYPE_LEFT               = ConvertSubAnimType(24)
    constant subanimtype        SUBANIM_TYPE_RIGHT              = ConvertSubAnimType(25)
    constant subanimtype        SUBANIM_TYPE_FIRE               = ConvertSubAnimType(26)
    constant subanimtype        SUBANIM_TYPE_FLESH              = ConvertSubAnimType(27)
    constant subanimtype        SUBANIM_TYPE_HIT                = ConvertSubAnimType(28)
    constant subanimtype        SUBANIM_TYPE_WOUNDED            = ConvertSubAnimType(29)
    constant subanimtype        SUBANIM_TYPE_LIGHT              = ConvertSubAnimType(30)
    constant subanimtype        SUBANIM_TYPE_MODERATE           = ConvertSubAnimType(31)
    constant subanimtype        SUBANIM_TYPE_SEVERE             = ConvertSubAnimType(32)
    constant subanimtype        SUBANIM_TYPE_CRITICAL           = ConvertSubAnimType(33)
    constant subanimtype        SUBANIM_TYPE_COMPLETE           = ConvertSubAnimType(34)
    constant subanimtype        SUBANIM_TYPE_GOLD               = ConvertSubAnimType(35)
    constant subanimtype        SUBANIM_TYPE_LUMBER             = ConvertSubAnimType(36)
    constant subanimtype        SUBANIM_TYPE_WORK               = ConvertSubAnimType(37)
    constant subanimtype        SUBANIM_TYPE_TALK               = ConvertSubAnimType(38)
    constant subanimtype        SUBANIM_TYPE_FIRST              = ConvertSubAnimType(39)
    constant subanimtype        SUBANIM_TYPE_SECOND             = ConvertSubAnimType(40)
    constant subanimtype        SUBANIM_TYPE_THIRD              = ConvertSubAnimType(41)
    constant subanimtype        SUBANIM_TYPE_FOURTH             = ConvertSubAnimType(42)
    constant subanimtype        SUBANIM_TYPE_FIFTH              = ConvertSubAnimType(43)
    constant subanimtype        SUBANIM_TYPE_ONE                = ConvertSubAnimType(44)
    constant subanimtype        SUBANIM_TYPE_TWO                = ConvertSubAnimType(45)
    constant subanimtype        SUBANIM_TYPE_THREE              = ConvertSubAnimType(46)
    constant subanimtype        SUBANIM_TYPE_FOUR               = ConvertSubAnimType(47)
    constant subanimtype        SUBANIM_TYPE_FIVE               = ConvertSubAnimType(48)
    constant subanimtype        SUBANIM_TYPE_SMALL              = ConvertSubAnimType(49)
    constant subanimtype        SUBANIM_TYPE_MEDIUM             = ConvertSubAnimType(50)
    constant subanimtype        SUBANIM_TYPE_LARGE              = ConvertSubAnimType(51)
    constant subanimtype        SUBANIM_TYPE_UPGRADE            = ConvertSubAnimType(52)
    constant subanimtype        SUBANIM_TYPE_DRAIN              = ConvertSubAnimType(53)
    constant subanimtype        SUBANIM_TYPE_FILL               = ConvertSubAnimType(54)
    constant subanimtype        SUBANIM_TYPE_CHAINLIGHTNING     = ConvertSubAnimType(55)
    constant subanimtype        SUBANIM_TYPE_EATTREE            = ConvertSubAnimType(56)
    constant subanimtype        SUBANIM_TYPE_PUKE               = ConvertSubAnimType(57)
    constant subanimtype        SUBANIM_TYPE_FLAIL              = ConvertSubAnimType(58)
    constant subanimtype        SUBANIM_TYPE_OFF                = ConvertSubAnimType(59)
    constant subanimtype        SUBANIM_TYPE_SWIM               = ConvertSubAnimType(60)
    constant subanimtype        SUBANIM_TYPE_ENTANGLE           = ConvertSubAnimType(61)
    constant subanimtype        SUBANIM_TYPE_BERSERK            = ConvertSubAnimType(62)
вращаем модель по roll,yaw,pitch
переводим градусы в радианы math.rad(value)
native BlzSetSpecialEffectOrientation takes effect whichEffect, real yaw, real pitch, real roll returns nothing
native BlzSetSpecialEffectPitch takes effect whichEffect, real pitch returns nothing
native BlzSetSpecialEffectRoll takes effect whichEffect, real roll returns nothing
native BlzSetSpecialEffectYaw takes effect whichEffect, real yaw returns nothing
scale
изменить размер модели спецэффекта. если там частицы, то офк не увеличит. По дефолту размер у всех моделей в варкрафте по умолчанию задан как 1.00. Изредко можно увидеть не 1.00. Если у вас нестандартная модель, у которой размеры могут быть слишком большими или маленькими, иногда для декорации/итема, или юнита приходится в ро уравношенивать скейлом. У них есть для этого специальное поле. Для модели спецэффекта не существует такого поля, оно по умолчанию создается как 1.00. Какие размеры модели в редакторе модели были заданы, такие и будет отображены
native BlzSetSpecialEffectScale takes effect whichEffect, real scale returns nothing
узнать тек размер модели спецэффекта
---@param whichEffect effect
---@return real
function BlzGetSpecialEffectScale(whichEffect) end	-- (native)
задать размеры матрицы модели в 3 плоскостях. Вы можете модель растягивать вертикально или горизонтально, а высоту. Или одновременно все вместе.
---@param whichEffect effect
---@param x real
---@param y real
---@param z real
---@return nothing
function BlzSetSpecialEffectMatrixScale(whichEffect, x, y, z) end	-- (native)
сбросить размеры матрицы модели спецэффекта. т.е. возвращает дефолтный размер = 1.00
---@param whichEffect effect
---@return nothing
function BlzResetSpecialEffectMatrix(whichEffect) end	-- (native)
скорость воспроизведения анимации (ускорить/замедлить анимацию модели спецээфекта)
function BlzSetSpecialEffectTimeScale takes effect whichEffect, real timeScale returns nothing
native BlzSetSpecialEffectTimeScaletakes effect whichEffect, real timeScale returns nothing
время жизни таймера?
native BlzSetSpecialEffectTime takes effect whichEffect, real time returns nothing

юниты

cooldawn of ability
reset
сброс кд всех абилок/итемов
native UnitResetCooldown takes unit whichUnit returns nothing
set
установить кд абилке
native BlzSetUnitAbilityCooldown takes unit whichUnit, integer abilId, integer level, real cooldown returns nothing
еще можно попробоват запустить через филд. Аналогично, выше перечисленному
functiom SetUnitAbilityCooldown(un,abilId,level,cd)
	local abil = BlzGetUnitAbility(un,id)
	BlzSetAbilityRealLevelFieldBJ(abil, ABILITY_RLF_COOLDOWN,level,cd)
end
запустить start cd
function BlzStartUnitAbilityCooldown takes unit whichUnit, integer abilCode, real cooldown returns nothing

--вместо abilCode указываем одну из 3
ability = BlzGetUnitAbility(un,id)
ability = BlzGetItemAbilityByIndex(item, index) 
ability = BlzGetItemAbility(item,id)
завершить end cd
завершить кд абилки юнита
native BlzEndUnitAbilityCooldown takes unit whichUnit, integer abilCode returns nothing

--вместо abilCode указываем одну из 3
ability = BlzGetUnitAbility(un,id)
ability = BlzGetItemAbilityByIndex(item, index) 
ability = BlzGetItemAbility(item,id)
получить тек время кд юнита
native BlzGetUnitAbilityCooldownRemaining takes unit whichUnit, integer abilId returns real
получить базовое кд юнита
native BlzGetUnitAbilityCooldown takes unit whichUnit, integer abilId, integer level returns real
получить кд юнита (custom func)
не проверялась
function GetUnitAbilityCooldown(un,abilId,level)
	local abil = BlzGetUnitAbility(un,id)
	return BlzGetAbilityRealLevelField(abil, ABILITY_RLF_COOLDOWN,level)
end
получить кд абилки
наверное это берут из базы данных абилки. Но чем они обе отличаются, мне не ясно
--возращает кд ???
native BlzGetAbilityCooldowntakes integer abilId, integer level returns real
function BlzGetAbilityCooldown takes integer abilId, integer level returns real
CastRange of ability
Мксимальная дистанцмя наведения абилки. Обычно у большинство таргетных абил указан радиус, если CastRange>0, то абилка является наводящей. Позволяет узнать есть ли у абилки прицел.
--id - равкод абилки, level - уровень абидки (нумерация от нуля) 
function GetCastRangeAbility(un,id,level)
    local ability = BlzGetUnitAbility(un,id)
    return BlzGetAbilityRealLevelField(ability, ABILITY_RLF_CAST_RANGE, level)
end

--index это номер абилки в итеме (нумеруют от нуля)
--как правило, в первом слоте занимают активные абилки, а следом идут пассивки
function GetCastRangeItem(item,index,level)
    local ability = BlzGetItemAbilityByIndex(item, index) 
    return BlzGetAbilityRealLevelField(ability, ABILITY_RLF_CAST_RANGE, level)
end

--id это указанный равкод абилки в итеме (нумеруют от нуля)
function GetCastRangeItemId(item,id,level)
    local ability = BlzGetItemAbility(item,id)
    return BlzGetAbilityRealLevelField(ability, ABILITY_RLF_CAST_RANGE, level)
end
установить дальность каста. (не проверено)
function SetCastRangeAbility(un,id,level,range)
    local ability = BlzGetUnitAbility(un,id)
    return BlzSetAbilityRealLevelFieldBJ(ability, ABILITY_RLF_CAST_RANGE, level,range)
end
ManaCost of ability
получить ManaCost из бд
function BlzGetAbilityManaCost takes integer abilId, integer level returns integer
native BlzGetAbilityManaCosttakes integer abilId, integer level returns integer
получить ManaCost юнита
native BlzGetUnitAbilityManaCost takes unit whichUnit, integer abilId, integer level returns integer
установить ManaCost юниту
function BlzSetUnitAbilityManaCost takes unit whichUnit, integer abilId, integer level, integer manaCost returns nothing
сокрытие кнопок юнита
В рефордже перестают адекватно работать сокрытие через импорт, или ро работает 0,-11 (но не всегда). Я уже не помню, что там. Помню, что я другое решение нашел - через нативку.
Можно спрятать этими нативками в рефе. Однако, они тоже не всегда адекватно работают. Можно спрятать на совсем, и обратно не хотят отображаться. У меня было так, что никак не хотела кнопка обратно отображаться. Мб дело в моих кривых руках. чисто спрятать и показать => работает
native BlzUnitHideAbility takes unit whichUnit, integer abilId, boolean flag returns nothing
или это. выключать их мб и не стоит, но вот второй параметр отвечает за сокрытие. Но работает и багуется также.
function BlzUnitDisableAbility takes unit whichUnit, integer abilId, boolean flag, boolean hideUI returns nothing
native BlzUnitDisableAbilitytakes unit whichUnit, integer abilId, boolean flag, boolean hideUI returns nothing
Единственный нормальный способ сокрытия:
BlzUnitDisableAbility(u,id2,false,hideUI) => флаг hideUI меняешь, а первый не трогаем
проверка на смерть юнита
это бывает полезно отсекать мертвых, дабы не вспоминает и лишний раз не открывать долбанный редактор.
    function IsDead takes unit u returns boolean
        return GetWidgetLife(u) < 0.405 or IsUnitType(u,UNIT_TYPE_DEAD)
    endfunction
	function IsUnitDead takes unit u returns boolean 
		return IsUnitType( u, UNIT_TYPE_DEAD ) or GetUnitTypeId( u ) < 1
	endfunction
Взят из Ai скрипта, нужно будет инициировать в шапке
native UnitAlive            takes unitid                               returns boolean
Можно проверять смерть юнита через кол-во здоровья, меньше 0.405 означает, что юнит мертв.
Также классификация UNIT_TYPE_DEAD показывает, что юнит труп/мертв (иногда полезно при реинкарнации).
И еще проверять тип, если юнит удалился из игры после разложения, вам выдадут GetUnitTypeId( u )==0
тип передвижения
типы
--  Move Type
MOVE_TYPE_UNKNOWN = ConvertMoveType(0)	--неизвестный	
MOVE_TYPE_FOOT = ConvertMoveType(1)	--пеший (наземный)
MOVE_TYPE_FLY = ConvertMoveType(2)	--летающий	
MOVE_TYPE_HORSE = ConvertMoveType(4)	--конный (наземный)
MOVE_TYPE_HOVER = ConvertMoveType(8)	--парящий (наземный)	
MOVE_TYPE_FLOAT = ConvertMoveType(16)	--плавающий (наземный)	
MOVE_TYPE_AMPHIBIOUS = ConvertMoveType(32)	--амфибия (наземный)	
MOVE_TYPE_UNBUILDABLE = ConvertMoveType(64)	--	
function GetUnitMovementType(unit)
	return BlzGetUnitIntegerField(unit, UNIT_IF_MOVE_TYPE)
end
мгновенно повернуть юнита
facingAngle выражен в градусах 0-360
function BlzSetUnitFacingEx(whichUnit, facingAngle) end
повернуть здание
Нельзя просто повернуть нативно SetUnitFacing(u, angle) или BlzSetUnitFacingEx(u, angle). Это работает только у обычных юнитов. Нужно еще позицию установить SetUnitPosition, чтобы здание развернулось.
Однако, здание может сместиться с первоначальной позиции из-за SetUnitPosition, тк нативка делает перасчеты коллизии. Если короче рядом есть юниты, то оно сдвинется. Ибо не может занять зону из-за учёта коллизий. Возможно рекомендуется у здания убрать карту путей, тк собственная карта путей мешает, и здание сдвигается.
благодарности Unryze, JackFastGame
мгновенный поворот:
--angle выражен в градусах 0-360. 
function SetBuildingFacing(u, angle)
    BlzSetUnitFacingEx(u, angle)
	SetUnitPosition(u, GetUnitX(u), GetUnitY(u))
end
поворот (не мгновенный):
function SetBuildingFacing(u, angle)
    local currentUnitFacing = GetUnitFacing(u)
	
    local t = CreateTimer()
    local DIVERGENCE = 1.0
	
    angle = math.fmod(angle,360)
	
	TimerStart(t, 0.01, true, function()
		local currentUnitFacing = GetUnitFacing(u)
		SetUnitPosition(u, GetUnitX(u), GetUnitY(u))
		SetUnitFacing(u, angle)
		if (currentUnitFacing <= angle-DIVERGENCE or currentUnitFacing >= angle+DIVERGENCE) == false then
			DestroyTimer(t)
		end
	end)
end
кол-во ударов
--сколько ударов нанесет юнит за заданное время
--возможно надо будет еще учесть скорость анимации атаки - обратного броска http://blog.d1stats.ru/blog/dm/65.html
function NumberOfStrikes(unit,index,time)
    return GetUnitCurrentAttackSpeed(unit, index)*time
end
если юнит не может двигаться
код не очень хорош, тк требует много проверок. проверяет и скорость, и стан, и наличие всяких баффов (последнее не очень хорошая вещь, тк это на дефолтные баффы распространяется). И далеко не на всё расчитано
        function GetUnitDefenseType(unit)
            return BlzGetUnitIntegerField(unit, UNIT_IF_DEFENSE_TYPE)
        end 
        
        --если юнит не может двигаться
        function UnitInMove(u)
            --если юнит имеет нулевую скорость
            local b1 = GetUnitMoveSpeed(u)<=0
            --если юнит нет абилки перемещения
            local b2 = not UnitHasBuffBJ(u,FourCC('Amov'))
            --если юнит застанен 
            local b3 = GetUnitCurrentOrder(u)==851973 or IsUnitType(u, UNIT_TYPE_STUNNED) --stunned
            
            --если заморожен ледяной атакой (обездвижен)
            local b4 = UnitHasBuffBJ(u,FourCC('Bfrz')) or UnitHasBuffBJ(u,FourCC('Bfre')) 
            --если юнит спит
            local b5 = IsUnitType(u, UNIT_TYPE_SLEEPING) or UnitCanSleepPerm(u)
            --если юнит оплетен корнями
            local b6 = UnitHasBuffBJ(u,FourCC('BEer'))
            --если древо сидит, имеет
            local b7 = IsUnitType(u, UNIT_TYPE_ANCIENT) and (not GetUnitDefenseType(u)==2)
            --если юнит пойман огненным лассо
            local b8 = UnitHasBuffBJ(u,FourCC('Bmlt')) --Bmlc,Bmlt 
            --если юнит пойман сеткой навыком Ловчий
            local b9 = UnitHasBuffBJ(u,FourCC('Bena')) or UnitHasBuffBJ(u,FourCC('Beng')) 
            
            return b1 or b2 or b3 or b4 or b5 or b6 or b7 or b8 or b9
        end

Группа

группа
я все функции не стал добавлять. добавлю те, которыми редко пользуюсь
интересные результаты
добавляет/убирает юнита. также можно группу совсем почистить
native GroupAddUnit takes group whichGroup, unit whichUnit returns nothing
native GroupClear takes group whichGroup returns nothing
native GroupRemoveUnit takes group whichGroup, unit whichUnit returns nothing
размер группы, возвращает кол-во юнитов в группе
function BlzGroupGetSize takes group whichGroup returns integer
возвращает юнита по номеру в группе. Каждый юнит имеет свой номер в группе. Удобно таким образом перебирать юнитов по номеру циклом.
function BlzGroupUnitAt takes group whichGroup, integer index returns unit
и еще две функции. Одна убирает юнитов из одной группы, другая наоборот, добавляет юнитов в группу.
function BlzGroupRemoveGroupFast takes group whichGroup, group removeGroup returns integer
function BlzGroupAddGroupFast takes group whichGroup, group addGroup returns integer
свои самодельные функции группы
кол-во живых юнитов указанного типа игрока на карте
например может пригодится для требовании
        function BlzCountLivingPlayerUnitsOfTypeId(unitId, whichPlayer)
            local g = CreateGroup()
            GroupEnumUnitsOfPlayer(g, whichPlayer, Condition(function()
               return GetUnitTypeId(GetFilterUnit())==unitId and not IsUnitType( GetFilterUnit(), UNIT_TYPE_DEAD ) 
            end))
           local Count = BlzGroupGetSize (g)
            DestroyGroup(g)

            return Count
        end
или код, который проверяет кол-во построенных здании на карте
do 
	local InitGlobalsOrigin = InitGlobals
	function InitGlobals()
		InitGlobalsOrigin()

        local group_construct = CreateGroup()

        local start_construction = CreateTrigger()
        TriggerRegisterAnyUnitEventBJ( start_construction, EVENT_PLAYER_UNIT_CONSTRUCT_START )
        TriggerRegisterAnyUnitEventBJ( start_construction, EVENT_PLAYER_UNIT_UPGRADE_START )
        TriggerAddAction( start_construction, function()
            GroupAddUnit(group_construct, GetTriggerUnit())
        end)

        local end_construction = CreateTrigger()
        TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
        TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL )
        TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_UPGRADE_CANCEL )
        TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_UPGRADE_FINISH )
        TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_DEATH )
        TriggerAddAction( end_construction, function()
            GroupRemoveUnit(group_construct, GetTriggerUnit())
        end)



        function BlzCountLivingPlayerUnitsOfTypeId(unitId, whichPlayer)
            local g = CreateGroup()
            GroupEnumUnitsOfPlayer(g, whichPlayer, Condition(function()
            return GetUnitTypeId(GetFilterUnit())==unitId and (not IsUnitType( GetFilterUnit(), UNIT_TYPE_DEAD )) and (not IsUnitInGroup(GetFilterUnit(),group_construct))
            end))
            local Count = BlzGroupGetSize(g)
            DestroyGroup(g)

            return Count
        end
        
        TimerStart(CreateTimer(),1.00,true,function()
            print('тик')
            local count = BlzCountLivingPlayerUnitsOfTypeId(FourCC('hhou'), Player(0))
            print(tostring(count))
        end)
    end
end
здание построено или нет
по условию IsUnitInGroup(u,group_construct) можно проверить строится ли оно, или нет
local group_construct = CreateGroup()

local start_construction = CreateTrigger()
TriggerRegisterAnyUnitEventBJ( start_construction, EVENT_PLAYER_UNIT_CONSTRUCT_START )
TriggerRegisterAnyUnitEventBJ( start_construction, EVENT_PLAYER_UNIT_UPGRADE_START )
TriggerAddAction( start_construction, function()
	GroupAddUnit(group_construct, GetTriggerUnit())
end)

local end_construction = CreateTrigger()
TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL )
TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_UPGRADE_CANCEL )
TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_UPGRADE_FINISH )
TriggerRegisterAnyUnitEventBJ( end_construction, EVENT_PLAYER_UNIT_DEATH )
TriggerAddAction( end_construction, function()
	GroupRemoveUnit(group_construct, GetTriggerUnit())
end)

Events, debugs, и их разборы

события каста
для тех, кто забыл
Begins channeling an ability (Начинает работать способность)
это начало работы абилки. В этот момент запускается CastTime (задержка способности). У большинства способностей оно равно ноль, что означает отсутствие задержки. И кажется, что EVENT_PLAYER_UNIT_SPELL_CHANNEL и EVENT_PLAYER_UNIT_SPELL_CAST одинаковые события. В русских гуи перевели как "начинает направлять способность", channeling ведь, по факту это кривой перевод. И константа цели не отображает. событие работает даже у не-таргетных абил.
В этот момент еще запускается кд. Однако, насчет перезарядки, не у всех заклинании она сразу запускается. У Channel-заклинании оно сразу запускается
EVENT_PLAYER_UNIT_SPELL_CHANNEL
Begins casting of ability (Начинает применять способность) - Начинается каст абилки. В это время кастер начинает проигрывать анимацию каста. У всех юнитов прописан - Cast Point. Сколько секунд проигрывает анимацию. Дело в том, что у разных моделей юнитов разные анимации, и разное время каста. пример Если этого не было, сразу перешли к следующему.
EVENT_PLAYER_UNIT_SPELL_CAST
Start the effect of an ability (Приводит способность в действие). В этот момент времени проигрываются эффекты магии: кастер как маг получается различные эффекты, какие указаны в способности: пример над головой свечения, или небо светится итд. Если это заклинание таргетное, то заклинание может выпускать снаряды. Доступны костанты цели: точка или юнит. Если быть короче, в это время на цель накладывается эффект или выпускаются снаряды. Скорость снаряда указана в абилках. Тут разные способности, и у каждого различное действие У молота бурь пример запускается полет снаряда, и только после того как долетит молот до цели, цель получает урон .Пример в буране начинается падение сосулек итд. Еще самое важное, что в этот момент у юнита и игрока забирают требуемые ресурсы (мана, золото, дерево итд), проходит под требования.
EVENT_PLAYER_UNIT_SPELL_EFFECT
Finished casting an ability (Завершает применение способности) - Заканчивает каст абилки.
Все заклинания разные, и могут по разному заканчиваться. Этот момент предвищает, что юнит закончил анимацию.
Пример, молот бурь. Как только юнит запустил молот (в этот момент снаряд еще не нанес никакого урона, кастер их только-только отправил до цели, снаряд еще летит), кастер тут же опускает руки - проигрывает анимацию обратного хода
Пример, свет паладина. Как только юнит нацелился на цель (в этот момент начинается проигрывает эффект свечения, якобы исцеления или очищения светом нежити, и происходит урон), кастер тут же опускает руки - проигрывает анимацию обратного хода
Пример, буран имеет channeling-внимацию. Когда запускаешь длительный каст и падение сосулек. После того как завершает проигрывать channeling-анимацию, кастер проигрывает опускание рук - анимацию обратного хода.
Finished casting an ability показывает, что кастер завершил махание рук. пример
EVENT_PLAYER_UNIT_SPELL_FINISH
Stop casting an ability (Прекращает применение способности)
Отменяет каст абилки. (Сбивают как пример). Каст можно прервать. Часто это можно ассоциировать с бураном, который проигрывает channeling-анимацию. И когда игрок отдает новый приказ, кастер прерывает каст. Также кастер можно сбить, пример накинуть стан, и маг останется обездвиженным. Прерывает не работает на мгновенных заклинаниях, и таких очень много 80-90%.
У не channel-заклинании вроде бурана (мгновенных) после события "приводит в действие" проигрывается анимация обратного хода, которую можно перебить отдачей юниту приказа сразу же после завершения каста, тогда юнит не поспевает завершить полностью анимацию. В тот момент проигрывается событие завершения каста.
EVENT_PLAYER_UNIT_SPELL_ENDCAST
код
do
    local real = MarkGameStarted
    function MarkGameStarted()
    real()

        TriggerCast = CreateTrigger()
		TriggerRegisterPlayerUnitEventSimple( TriggerCast, Player(0), EVENT_PLAYER_UNIT_SPELL_CHANNEL  )
		TriggerRegisterPlayerUnitEventSimple( TriggerCast, Player(0), EVENT_PLAYER_UNIT_SPELL_CAST  )
		TriggerRegisterPlayerUnitEventSimple( TriggerCast, Player(0), EVENT_PLAYER_UNIT_SPELL_EFFECT  )
        TriggerRegisterPlayerUnitEventSimple( TriggerCast, Player(0), EVENT_PLAYER_UNIT_SPELL_ENDCAST )
        TriggerRegisterPlayerUnitEventSimple( TriggerCast, Player(0), EVENT_PLAYER_UNIT_SPELL_FINISH  )
        
        TriggerAddAction( TriggerCast, function()
            local n = GetPlayerId(GetTriggerPlayer())
            local u = GetTriggerUnit()
			local h = GetHandleId(u)
			
			local id_ability = GetSpellAbilityId()
			local eventId = GetTriggerEventId()
			
			local lv = GetUnitAbilityLevel(u,lv)
			local cd = BlzGetUnitAbilityCooldownRemaining(u,id_ability)
			
            if eventId==EVENT_PLAYER_UNIT_SPELL_CHANNEL then
				print('у юнита '..GetUnitName(GetTriggerUnit())..' начинает работать '..GetObjectName(id_ability)..', cd: '..tostring(cd) )
			elseif eventId==EVENT_PLAYER_UNIT_SPELL_CAST then
				print('юнит '..GetUnitName(GetTriggerUnit())..' начинает кастовать '..GetObjectName(id_ability)..', cd: '..tostring(cd) )
			elseif eventId==EVENT_PLAYER_UNIT_SPELL_EFFECT then
				print('юнит '..GetUnitName(GetTriggerUnit())..' приводит способность в действие '..GetObjectName(id_ability)..', cd: '..tostring(cd) )
            if eventId==EVENT_PLAYER_UNIT_SPELL_ENDCAST then
                print('юнит '..GetUnitName(GetTriggerUnit())..' прерывает способность '..GetObjectName(id_ability)..', cd: '..tostring(cd) )
            elseif eventId==EVENT_PLAYER_UNIT_SPELL_FINISH then
                print('юнит '..GetUnitName(GetTriggerUnit())..' завершает способность '..GetObjectName(id_ability)..', cd: '..tostring(cd) )
            end
		end
	end
end
приказы
ид приказ и его название
constant native GetIssuedOrderId takes nothing returns integer
его строковое название приказа можно получить
constant native OrderId2String takes integer orderId returns string
пример
OrderId2String(GetIssuedOrderId())
Однако, не все приказы имеют строковые название. Также, некоторые отдачи приказов, например при строительстве, имеют в качестве ид-приказа ид-здания. И чтобы удостовериться в этом, как правило, равкод больше чем 860000
константы и события приказа
constant native GetOrderedUnit takes nothing returns unit
constant native GetOrderPointLoc takes nothing returns location
constant native GetOrderPointX takes nothing returns real
constant native GetOrderPointY takes nothing returns real
constant native GetOrderTarget takes nothing returns widget
constant native GetOrderTargetDestructable takes nothing returns destructable
constant native GetOrderTargetItem takes nothing returns item
constant native GetOrderTargetUnit takes nothing returns unit
и события
EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER
EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER
EVENT_PLAYER_UNIT_ISSUED_ORDER
EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER
код дебага
do
    local real = MarkGameStarted
    function MarkGameStarted()
    real()


        TriggerOrder  = CreateTrigger()
        TriggerRegisterPlayerUnitEventSimple( TriggerOrder , Player(0), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
        TriggerRegisterPlayerUnitEventSimple( TriggerOrder , Player(0), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
        TriggerRegisterPlayerUnitEventSimple( TriggerOrder , Player(0), EVENT_PLAYER_UNIT_ISSUED_ORDER ) --EVENT_PLAYER_UNIT_ISSUED_ORDER
        TriggerRegisterPlayerUnitEventSimple( TriggerOrder , Player(0), EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER )
        TriggerAddAction( TriggerOrder , function()
            local n = GetPlayerId(GetTriggerPlayer())
            local h = GetHandleId(GetTriggerUnit())
            local eventId = GetTriggerEventId()
            local idorder = GetIssuedOrderId()
            
            if eventId==EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER then
                local x,y = GetOrderPointX(),GetOrderPointY()
				
				
				if idorder>86000 then
					print(GetUnitName(GetTriggerUnit())..' получает приказ '..OrderId2String(idorder)..' ('..idorder..') в точку ('..x..','..y..')')
				else
					print(GetUnitName(GetTriggerUnit())..' получает приказ строить '..GetObjectName(idorder)..' ('..idorder..') в точку ('..x..','..y..')')
				end
			
			elseif eventId==EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER then
                local target
                local idtarget
                if GetOrderTargetDestructable() ~= nil then
                    target = GetOrderTargetDestructable()
                    idtarget = GetDestructableTypeId(target)
                elseif GetOrderTargetUnit() ~= nil then
                    target = GetOrderTargetUnit()
                    idtarget = GetUnitTypeId(target)
                elseif GetOrderTargetItem() ~= nil then
                    target = GetOrderTargetItem()
                    idtarget = GetItemTypeId(target)
                end
                
				print(GetUnitName(GetTriggerUnit())..' наводит приказом '..OrderId2String(idorder)..' ('..idorder..') в цель: '..GetObjectName(idtarget))
			else
                print(GetUnitName(GetTriggerUnit())..' получает приказ '..OrderId2String(idorder)..' ('..idorder..')')
            end
        end)
		
        print("end init sight deactivation")
    end
end
список приказов
	absorb=852529;
	acidbomb=852662;
	acolyteharvest=852185;
	AImove=851988;
	ambush=852131;
	ancestralspirit=852490;
	ancestralspirittarget=852491;
	animatedead=852217;
	antimagicshell=852186;
	attack=851983;
	attackground=851984;
	attackonce=851985;
	attributemodskill=852576;
	auraunholy=852215;
	auravampiric=852216;
	autodispel=852132;
	autodispeloff=852134;
	autodispelon=852133;
	autoentangle=852505;
	autoentangleinstant=852506;
	autoharvestgold=852021;
	autoharvestlumber=852022;
	avatar=852086;
	avengerform=852531;
	awaken=852466;
	banish=852486;
	barkskin=852135;
	barkskinoff=852137;
	barkskinon=852136;
	battleroar=852099;
	battlestations=852099;
	bearform=852138;
	berserk=852100;
	blackarrow=852577;
	blackarrowoff=852579;
	blackarrowon=852578;
	blight=852187;
	blink=852525;
	blizzard=852089;
	bloodlust=852101;
	bloodlustoff=852103;
	bloodluston=852102;
	board=852043;
	breathoffire=852580;
	breathoffrost=852560;
	build=851994;
	burrow=852533;
	cannibalize=852188;
	carrionscarabs=852551;
	carrionscarabsinstant=852554;
	carrionscarabsoff=852553;
	carrionscarabson=852552;
	carrionswarm=852218;
	chainlightning=852119;
	channel=852600;
	charm=852581;
	chemicalrage=852663;
	cloudoffog=852473;
	clusterrockets=852652;
	coldarrows=852244;
	coldarrowstarg=852243;
	controlmagic=852474;
	corporealform=852493;
	corrosivebreath=852140;
	coupleinstant=852508;
	coupletarget=852507;
	creepanimatedead=852246;
	creepdevour=852247;
	creepheal=852248;
	creephealoff=852250;
	creephealon=852249;
	creepthunderbolt=852252;
	creepthunderclap=852253;
	cripple=852189;
	curse=852190;
	curseoff=852192;
	curseon=852191;
	cyclone=852144;
	darkconversion=852228;
	darkportal=852229;
	darkritual=852219;
	darksummoning=852220;
	deathanddecay=852221;
	deathcoil=852222;
	deathpact=852223;
	decouple=852509;
	defend=852055;
	detectaoe=852015;
	detonate=852145;
	devour=852104;
	devourmagic=852536;
	disassociate=852240;
	disenchant=852495;
	dismount=852470;
	dispel=852057;
	divineshield=852090;
	doom=852583;
	drain=852487;
	dreadlordinferno=852224;
	dropitem=852001;
	drunkenhaze=852585;
	earthquake=852121;
	eattree=852146;
	elementalfury=852586;
	ensnare=852106;
	ensnareoff=852108;
	ensnareon=852107;
	entangle=852147;
	entangleinstant=852148;
	entanglingroots=852171;
	etherealform=852496;
	evileye=852105;
	faeriefire=852149;
	faeriefireoff=852151;
	faeriefireon=852150;
	fanofknives=852526;
	farsight=852122;
	fingerofdeath=852230;
	firebolt=852231;
	flamestrike=852488;
	flamingarrows=852174;
	flamingarrowstarg=852173;
	flamingattack=852540;
	flamingattacktarg=852539;
	flare=852060;
	forceboard=852044;
	forceofnature=852176;
	forkedlightning=852586;
	freezingbreath=852195;
	frenzy=852561;
	frenzyoff=852563;
	frenzyon=852562;
	frostarmor=852225;
	frostarmoroff=852459;
	frostarmoron=852458;
	frostnova=852226;
	getitem=851981;
	gold2lumber=852233;
	grabtree=852511;
	harvest=852018;
	heal=852063;
	healingspray=852664;
	healingward=852109;
	healingwave=852501;
	healoff=852065;
	healon=852064;
	hex=852502;
	holdposition=851993;
	holybolt=852092;
	howlofterror=852588;
	humanbuild=851995;
	immolation=852177;
	impale=852555;
	incineratearrow=852670;
	incineratearrowoff=852672;
	incineratearrowon=852671;
	inferno=852232;
	innerfire=852066;
	innerfireoff=852068;
	innerfireon=852067;
	instant=852200;
	invisibility=852069;
	lavamonster=852667;
	lightningshield=852110;
	load=852046;
	loadarcher = 852142;
	loadcorpse=852050;
	loadcorpseinstant=852053;
	locustswarm=852556;
	lumber2gold=852234;
	magicdefense=852478;
	magicleash=852480;
	magicundefense=852479;
	manaburn=852179;
	manaflareoff=852513;
	manaflareon=852512;
	manashieldoff=852590;
	manashieldon=852589;
	massteleport=852093;
	mechanicalcritter=852564;
	metamorphosis=852180;
	militia=852072;
	militiaconvert=852071;
	militiaoff=852073;
	militiaunconvert=852651;
	mindrot=852565;
	mirrorimage=852123;
	monsoon=852591;
	mount=852469;
	mounthippogryph=852143;
	move=851986;
	nagabuild=852467;
	neutraldetectaoe=852023;
	neutralinteract=852566;
	neutralspell=852630;
	nightelfbuild=851997;
	orcbuild=851996;
	parasite=852601;
	parasiteoff=852603;
	parasiteon=852602;
	patrol=851990;
	phaseshift=852514;
	phaseshiftinstant=852517;
	phaseshiftoff=852516;
	phaseshifton=852515;
	phoenixfire=852481;
	phoenixmorph=852482;
	poisonarrows=852255;
	poisonarrowstarg=852254;
	polymorph=852074;
	possession=852196;
	preservation=852568;
	purge=852111;
	rainofchaos=852237;
	rainoffire=852238;
	raisedead=852197;
	raisedeadoff=852199;
	raisedeadon=852198;
	ravenform=852155;
	recharge=852157;
	rechargeoff=852159;
	rechargeon=852158;
	rejuvination=852160;
	renew=852161;
	renewoff=852163;
	renewon=852162;
	repair=852024;
	repairoff=852026;
	repairon=852025;
	replenish=852542;
	replenishlife=852545;
	replenishlifeoff=852547;
	replenishlifeon=852546;
	replenishmana=852548;
	replenishmanaoff=852550;
	replenishmanaon=852549;
	replenishoff=852544;
	replenishon=852543;
	request_hero=852239;
	requestsacrifice=852201;
	restoration=852202;
	restorationoff=852204;
	restorationon=852203;
	resumebuild=851999;
	resumeharvesting=852017;
	resurrection=852094;
	returnresources=852020;
	revenge=852241;
	revive=852039;
	roar=852164;
	robogoblin=852656;
	root=852165;
	sacrifice=852205;
	sanctuary=852569;
	scout=852181;
	selfdestruct=852040;
	selfdestructoff=852042;
	selfdestructon=852041;
	sentinel=852182;
	setrally=851980;
	shadowsight=852570;
	shadowstrike=852527;
	shockwave=852125;
	silence=852592;
	sleep=852227;
	slow=852075;
	slowoff=852077;
	slowon=852076;
	smart=851971;
	soulburn=852668;
	soulpreservation=852242;
	spellshield=852571;
	spellshieldaoe=852572;
	spellsteal=852483;
	spellstealoff=852485;
	spellstealon=852484;
	spies=852235;
	spiritlink=852499;
	spiritofvengeance=852528;
	spirittroll=852573;
	spiritwolf=852126;
	stampede=852593;
	standdown=852113;
	starfall=852183;
	stasistrap=852114;
	steal=852574;
	stomp=852127;
	stoneform=852206;
	stop=851972;
	submerge=852604;
	summonfactory=852658;
	summongrizzly=852594;
	summonphoenix=852489;
	summonquillbeast=852595;
	summonwareagle=852596;
	tankdroppilot=852079;
	tankloadpilot=852080;
	tankpilot=852081;
	taunt=852520;
	thunderbolt=852095;
	thunderclap=852096;
	tornado=852597;
	townbelloff=852083;
	townbellon=852082;
	tranquility=852184;
	transmute=852665;
	unavatar=852087;
	unavengerform=852532;
	unbearform=852139;
	unburrow=852534;
	uncoldarrows=852245;
	uncorporealform=852494;
	undeadbuild=851998;
	undefend=852056;
	undivineshield=852091;
	unetherealform=852497;
	unflamingarrows=852175;
	unflamingattack=852541;
	unholyfrenzy=852209;
	unimmolation=852178;
	unload=852047;
	unloadall=852048;
	unloadallcorpses=852054;
	unloadallinstant=852049;
	unpoisonarrows=852256;
	unravenform=852156;
	unrobogoblin=852657;
	unroot=852166;
	unstableconcoction=852500;
	unstoneform=852207;
	unsubmerge=852605;
	unsummon=852210;
	unwindwalk=852130;
	vengeance=852521;
	vengeanceinstant=852524;
	vengeanceoff=852523;
	vengeanceon=852522;
	volcano=852669;
	voodoo=852503;
	ward=852504;
	waterelemental=852097;
	wateryminion=852598;
	web=852211;
	weboff=852213;
	webon=852212;
	whirlwind=852128;
	windwalk=852129;
	wispharvest=852214;
			
	scrollofspeed=852285;
	cancel=851976;
	moveslot1=852002;
	moveslot2=852003;
	moveslot3=852004;
	moveslot4=852005;
	moveslot5=852006;
	moveslot6=852007;
	useslot1=852008;
	useslot2=852009;
	useslot3=852010;
	useslot4=852011;
	useslot5=852012;
	useslot6=852013;
	skillmenu=852000;
	stunned=851973;
приказ стройки
заставляет юнита строить определенное здание в точке
native IssueBuildOrder takes unit whichPeon, string unitToBuild, real x, real y returns boolean
native IssueBuildOrderById takes unit whichPeon, integer unitId, real x, real y returns boolean
станд приказы
применяет абилки без цели, нанимает (тренирует) войска, улучшает здания и проводит исследования
native IssueImmediateOrder takes unit whichUnit, string order returns boolean
native IssueImmediateOrderById takes unit whichUnit, integer order returns boolean
применяет приказы в точку
native IssuePointOrder takes unit whichUnit, string order, real x, real y returns boolean
native IssuePointOrderById takes unit whichUnit, integer order, real x, real y returns boolean
native IssuePointOrderLoc takes unit whichUnit, string order, location whichLocation returns boolean
native IssuePointOrderByIdLoc takes unit whichUnit, integer order, location whichLocation returns boolean
применяет приказы в цель (в качестве цели могут быть юниты, предметы, декорации - деревья)
native IssueTargetOrder takes unit whichUnit, string order, widget targetWidget returns boolean
native IssueTargetOrderById takes unit whichUnit, integer order, widget targetWidget returns boolean
по дереву и золоту:
"harvest" - добывать ресурсы
"eattree" - съесть дерево
"grabtree" - вырвать дерево
"sentinel" - сторожевая сова
приказы объектов на цель
IssueInstantTargetOrder
ИСПОЛЬЗОВАНИЕ instantTargetWidget на цель targetWidget
native IssueInstantTargetOrder takes unit whichUnit, string order, widget targetWidget, widget instantTargetWidget returns boolean
native IssueInstantTargetOrderById takes unit whichUnit, integer order, widget targetWidget, widget instantTargetWidget returns boolean
Объяснение: на примере IssueInstantTargetOrder, заставляет юнита whichUnit использовать приказ order на targetWidget с помощью instantTargetWidget
Пример: есть приказ на гуи "dropitem" передать targetWidget итем instantTargetWidget или использовать какое-нибудь заклинание предмета на него
order_dropitem = 852001
IssueInstantPointOrder
С таким же успехом можно юзать итем на цель
ИСПОЛЬЗОВАНИЕ instantTargetWidget в точку
native IssueInstantPointOrder takes unit whichUnit, string order, real x, real y, widget instantTargetWidget returns boolean
native IssueInstantPointOrderById takes unit whichUnit, integer order, real x, real y, widget instantTargetWidget returns boolean
Объяснение: на примере IssueInstantPointOrder, заставляет юнита whichUnit использовать приказ order в точку (x,y) или что-то сделать в точке с помощью instantTargetWidget
Пример: к примеру есть приказ на гуи "dropitem" выбросить предмет targetWidget или приказ использовать итем instantTargetWidget в точку
order_dropitem = 852001
юнит передает предмет цели target (можно так и продать в магазин, если магазин будет целью)
852002 to 852007 (moveslot): Эти приказы перемещают указанный предмет в соответствующий слот инвентаря героя, отдавшего приказ. Идентификатор 852002 переместит предмет в первый слот, идентификатор 852003 – во второй и т.д. Можно с помощью IssueInstantTargetOrderById перетащить итем самому себе.
852008 to 852013 (useslot): Заставляют героя, отдавшего приказ, использовать предмет, находящийся в соответствующем слоте инвентаря. Идентификатор 852008 использует предмет в первом слоте, идентификатор 852009 – во втором и т.д.
нативки приказов предметов
Это тоже приказы, но упрощенные варианты с итемами. При отдаче, которых тоже получаем приказы.
UnitDropItemTarget
передать предмет цели. логически именно так и работает. Декорация и итем не могу принимать предметы
native UnitDropItemTarget takes unit whichUnit, item whichItem, widget target returns boolean
UnitDropItemSlot
перемещает предмет в слот (если там был слот занят, то меняет местами). Иногда можно перемещать исчезнутые итемы в слот (например, они невидимы, заставляем их переместить в слот, и становятся видимы).
в рефе UnitDropItemSlot сбивает приказы. По идее перенос мыши предмета из слота в слот не вызывает перебитием приказа
native UnitDropItemSlot takes unit whichUnit, item whichItem, integer slot returns boolean
UnitUseItem
юнит использует предмет
native UnitUseItem takes unit whichUnit, item whichItem returns boolean
UnitUseItemTarget
юзаем предмет в цель (в качестве цели могут быть юнит, итем. декорация)
native UnitUseItemTarget takes unit whichUnit, item whichItem, widget target returns boolean
UnitUseItemPoint
юзаем предмет в точку
native UnitUseItemPoint takes unit whichUnit, item whichItem, real x, real y returns boolean
UnitDropItemPoint
дропают предмет в точку (на землю короче выкидываем)
native UnitDropItemPoint takes unit whichUnit, item whichItem, real x, real y returns boolean
манипуляции с предметами (не приказы)
даем итем (не создаем !!!)
native UnitAddItem takes unit whichUnit, item whichItem returns boolean
создаем итем определенного типа
native UnitAddItemById takes unit whichUnit, integer itemId returns item
UnitAddItemToSlotById - создает итем определенного типа в определенном слоте.
У нативки UnitAddItemToSlotById могут быть баги, один раз что-то не захотела создаваться в первом слоте (0 слот), созданный предмет выпадает под ногами героя. во всех других 1-5 слотах игра создает предметы норм. задумался заменить UnitAddItemById. Думаю, что это частный случаи бага lua. Нужно внутри меин функции создавать
native UnitAddItemToSlotById takes unit whichUnit, integer itemId, integer itemSlot returns boolean
удаляем итем
native UnitRemoveItem takes unit whichUnit, item whichItem returns nothing
удаляем итем с определенного слота
native UnitRemoveItemFromSlot takes unit whichUnit, integer itemSlot returns item
размер инвентаря
native UnitInventorySize takes unit whichUnit returns integer
итем в слоте
native UnitItemInSlot takes unit whichUnit, integer itemSlot returns item
---@param whichItem item
---@param abilCode integer
---@return boolean
function BlzItemRemoveAbility(whichItem, abilCode) end	-- (native)

---@param whichItem item
---@param abilCode integer
---@return boolean
function BlzItemAddAbility(whichItem, abilCode) end	-- (native)

---@param whichItem item
---@param index integer
---@return ability
function BlzGetItemAbilityByIndex(whichItem, index) end	-- (native)
группы
заставляет отряд применять приказ
native GroupImmediateOrder takes group whichGroup, string order returns boolean
native GroupImmediateOrderById takes group whichGroup, integer order returns boolean
отряду приказ в цель
native GroupTargetOrder takes group whichGroup, string order, widget targetWidget returns boolean
native GroupTargetOrderById takes group whichGroup, integer order, widget targetWidget returns boolean
заставляет отряд использовать приказ в точку
native GroupPointOrder takes group whichGroup, string order, real x, real y returns boolean
native GroupPointOrderById takes group whichGroup, integer order, real x, real y returns boolean
native GroupPointOrderLoc takes group whichGroup, string order, location whichLocation returns boolean
native GroupPointOrderByIdLoc takes group whichGroup, integer order, location whichLocation returns boolean
типы цели
пример сылкка
do
    local InitGlobalsOrigin = InitGlobals -- хукаем функцию InitGlobals

	function InitGlobals()
		InitGlobalsOrigin()
        
	function IsFlagSet(flags, pos)
		if pos == nil then
			return false
		else
			return flags >> pos & 1 == 1
		end
	end
		
	pos_unit = {}
	pos_destructible = {}
	classification = {}
	string_class = {}
	pos_destructible[1]=7 --tree
	pos_destructible[2]=8 --wall
	pos_destructible[3]=9 --debris
	pos_destructible[4]=10 --decoration
	pos_destructible[5]=11 --bridge
	
	pos_unit[1]=1 --ground
	pos_unit[2]=2 --air
	pos_unit[3]=3 --structure
	pos_unit[4]=4 --ward
	pos_unit[5]=23 --non-hero 
	pos_unit[6]=22 --hero
	pos_unit[7]=26 --Organic
	pos_unit[8]=27 --Mechanical 
	pos_unit[9]=28 --non-suicidal
	pos_unit[10]=29 --suicidal
	pos_unit[11]=30 --non-ancient
	pos_unit[12]=31 --ancient
	pos_unit[13]=24 --alive
	pos_unit[14]=25 --dead
	pos_unit[15]=20 --Vulnerable 
	pos_unit[16]=21 --Invulnerable
	pos_unit[17]=17 --not self
	pos_unit[18]=12 --self
	pos_unit[19]=14 --friend
	pos_unit[20]=16 --enemy
	
	pos_unit[21]=13 --Player Units
	pos_unit[22]=15 --Neutral => указывают в UNIT CLASSIFICATION

	classification[5] = UNIT_TYPE_HERO
	classification[7] = UNIT_TYPE_MECHANICAL
	classification[9] = UNIT_TYPE_SAPPER
	classification[11] = UNIT_TYPE_ANCIENT
	classification[13] = UNIT_TYPE_DEAD

	string_class[5] = " non-hero: "
	string_class[6] = " hero: "
	string_class[7] = " mechanical: "
	string_class[8] = " organic: "
	string_class[9] = " suicidal: "
	string_class[10] = " non-suicidal: "
	string_class[11] = " non-ancient: "
	string_class[12] = " ancient: "
	string_class[13] = " alive: "
	string_class[14] = " dead: "
	string_class[15] = " vulnerable: "
	string_class[16] = " invulnerable: "
	string_class[17] = " not self: "
	string_class[18] = " self: "
	string_class[19] = " friend: "
	string_class[20] = " non-friend: "
	string_class[21] = " player unit: "
	string_class[22] = " neutral: "
	
	local string_bug = ""
	
	function comp_flags(flags1,flags2,pos)
		local p1 = IsFlagSet(flags1, pos)
		local p2 = IsFlagSet(flags2, pos)		
		
		--условие истино: 2 параметра положительно, или если 2 параметра не указано
		--условие ложно: если 2 параметра не соотвествуют друг другу
		if p1==p2 then
			--если два параметра положительны
			if p1 then
				string_bug = string_bug.."1"
			else
				string_bug = string_bug.."0"
			end
			return true
		else
			string_bug = string_bug.."0"
			return false
		end

	end	
	function comp_bool(flags1,bool,pos)
			
		local p1 = IsFlagSet(flags1, pos_unit[pos])

		if p1 ~= bool and p1 then
			string_bug = string_bug.."|cffff0000"..string_class[pos].."|r".."0"
			return false
		elseif p1 == bool and p1 then
			string_bug = string_bug.."|cff00ff00"..string_class[pos].."|r".."1"
		end
		return true
	end
	function IsUnitFriend(unit,tg)
		return IsUnitAlly(tg, GetOwningPlayer(unit)) and unit~=tg
	end
	function IsItUnitPlayer(unit,tg)
		return GetOwningPlayer(unit)==GetOwningPlayer(tg) and unit~=tg
	end
	function IsItUnitNeutral(unit)
		local flags = BlzGetUnitIntegerField(unit, UNIT_IF_UNIT_CLASSIFICATION)
		return IsFlagSet(flags,8)
	end
	function CheckFieldAbility(unit,field,rawcode,lv)
		local ability = BlzGetUnitAbility(unit, rawcode)
		local param = ConvertAbilityIntegerLevelField(field)
    
		return BlzGetAbilityIntegerLevelField(ability, param, lv)
	end
	
	function flages_target(flags1,flags2,unit,tg,IsItAttack)

		local max = 22 --макс параметров типов цели
		local b = true
		local c = 0
		
		if IsItAttack then
			max = 12
		end
		
		--проверка по типу "или"
		--если один из параметров цели (ground,air,structure,ward) соотвествует атаке.
		--если юнит не может атаковать ни одной из 4 целей
		string_bug = ""
		for a=1,4 do
			if not comp_flags(flags1,flags2,pos_unit[a]) then
				c = c + 1
			end
		end
		
		if c == 4 then
			b = false
			string_bug = "|cffff0000ground,air,structure,ward:|r "..string_bug
		else
			string_bug = "|cff00ff00ground,air,structure,ward:|r "..string_bug			
		end
		
		--далее идет проверка по типу "и"
		for i=5,max,2 do 
			if i < max then
				if not comp_bool(flags1,IsUnitType(tg, classification[i]),i+1) then
					b = false
				end
				if not comp_bool(flags1,not IsUnitType(tg, classification[i]),i) then
					b = false
				end
			end
		end
		
		if IsItAttack then
			if BlzIsUnitInvulnerable(tg) then
				string_bug=string_bug.." |cffff0000invulnerable:|r 0"
				b = false
			end
		else
			--vulnerable/invulnerable
			if not comp_bool(flags1,not BlzIsUnitInvulnerable(tg),15) then
				b = false
			end
			if not comp_bool(flags1,BlzIsUnitInvulnerable(tg),16) then
				b = false
			end
			
			--vulnerable/invulnerable
			if not comp_bool(flags1,not BlzIsUnitInvulnerable(tg),15) then
				b = false
			end
			if not comp_bool(flags1,BlzIsUnitInvulnerable(tg),16) then
				b = false
			end
			--not self/self
			if not comp_bool(flags1,unit~=tg,17) then
				b = false
			end
			if not comp_bool(flags1,unit==tg,18) then
				b = false
			end
			--friend/enemy
			if not comp_bool(flags1,IsUnitFriend(unit,tg),19) then
				b = false
			end
			if not comp_bool(flags1,IsUnitEnemy(tg, GetOwningPlayer(unit)),20) then
				b = false
			end
			--player units
			if not comp_bool(flags1,IsItUnitPlayer(unit,tg),21) then
				b = false
			end
			--neutral
			if not comp_bool(flags1,IsItUnitNeutral(unit),22) then
				b = false
			end
		end
		
		print(string_bug)
				
		return b
	end
	
		
		function IsItPossibleToAttackTheTarget(unit, target)
		
			--если может атаковать
			if GetUnitAbilityLevel(unit,FourCC('Aatk'))>0 and target~=nil then

				local b1 = BlzGetUnitWeaponBooleanField(unit, UNIT_WEAPON_BF_ATTACKS_ENABLED, 0)
				local b2 = BlzGetUnitWeaponBooleanField(unit, UNIT_WEAPON_BF_ATTACKS_ENABLED, 1)
				if b1 then
					local flags_attacker_1 = BlzGetUnitWeaponIntegerField(unit, UNIT_WEAPON_IF_ATTACK_TARGETS_ALLOWED, 0)
					local flags_target = BlzGetUnitIntegerField(target, UNIT_IF_TARGETED_AS)
					--local flags_spelltargetscaster = CheckFieldAbility(unit,FourCC('atar'),FourCC('AHad'),0) --поле таргета абилок не работает, вернет ноль

                    if not flages_target(flags_attacker_1,flags_target,unit,target,true) then
						print("|cffff0000"..GetUnitName(unit).." не может атаковать цель|r")
					else
						print("|cff00ff00"..GetUnitName(unit).." может атаковать цель|r")
                    end
				end
			end
		end
    
		local Hpal = CreateUnit(Player(0),FourCC('Hpal'),0,0,0)
    
		TimerStart(CreateTimer(),1.00,true,function()
			IsItPossibleToAttackTheTarget(Hpal, BlzGetMouseFocusUnit())
		end)
    end
end
Выборка юнитов
Юнита можно выделить не только своего, но и принадлежащему союзнику, нейтральному, вражескому. У вас с другим игроком может даже быть расшарен общий контроль, но есть контроль или нет, система показывает лишь какого юнита/группу выделил.
По правилу выбор определяется приоритетом BlzGetUnitRealField(unit, UNIT_RF_PRIORITY). У героев как правило высокий приоритет.
Порядок расположения иконок юнитов в группе определяется приоритетом. У всех героев самый высокий, имеет одинаковый приоритет для всех героев. Они всегда будут в первом в списке. Но герои как правило между собой тоже имеют порядок расположения, как правило, первый занимает тот герой, который старше или создан раньше остальных. Логичнее было предположить искать его по хендлу GetHandleId(unit). Но такое не рекомендуют, неизвестно как работает хэндл.
Далее, в порядке идут обычные юниты. Они тоже распределены приоритетом. Обычно воины ближнего боя, далее юниты дальнего боя. На самом деле это совсем не так, но расположены для управления в мили-сражении. Порядок разный. Если у некоторый типов юнитов одинаковый приоритет, то первый идет тот у кого тип выше (хотя не точно).
проверка boolean "юнит выделен игроком"
Юнит выбран. проверяем кто выбрал его с помощью перечисленной функцией.
Можно циклом Player(i=1-12) пробежаться, и проверить кем выделен данный юнит.
constant native IsUnitSelected takes unit whichUnit, player whichPlayer returns boolean
пик в группу, которая выделяет всех выбранных игроком
Показывает группу юнитов, которых выделил в данный момент игрок
В механике игры максимум юнитов выделить игрок может 12.
Внимание: нужно вставлять перед этим действием SyncSelections(), синхронизирующий выбор игрока локально.
native GroupEnumUnitsSelected takes group whichGroup, player whichPlayer, boolexpr filter returns nothing
нативка синхронизации выбора. часто ее добавляю в группы. Не смог найти где еще ее применяют. Только для GroupEnumUnitsSelected
раскрыть
native SyncSelections takes nothing returns nothing
можно создать группу и запихать
function GetUnitsSelectedAll(whichPlayer)
    local g = CreateGroup()
    SyncSelections()
    GroupEnumUnitsSelected(g, whichPlayer, null)
    return g
end
событие "юнит выбран игроком"/"юнит не выбран"
есть события выделения, когда игрок выделяет игрока. и снятия выделения, когда юнит перестает быть выделенным. В принципе понятна работа. Как работает выделение группы? тут все просто, игра снимает выделения с одних юнитов, и заново добавляет новых, будь даже те же самые (просто добавить несколько в группу). Можно создать для каждого игрока группу выделения, и фиксировать прибавление/убавления.
Можно записать в один триггер, и с помощью GetTriggerEventId() определять какое событие сработало
TriggerRegisterPlayerUnitEvent( trig, Player( 0 ), EVENT_PLAYER_UNIT_SELECTED, null )
TriggerRegisterPlayerUnitEvent( trig, Player( 0 ), EVENT_PLAYER_UNIT_DESELECTED, null )
к самому юниту можно обратиться как GetTriggerUnit(), игрок GetTriggerPlayer()
регистр для юнита имеет
constant unitevent EVENT_UNIT_DESELECTED = ConvertUnitEvent(58)
constant unitevent EVENT_UNIT_SELECTED = ConvertUnitEvent(57)
GetPlayerSelectable (no idea)
возможно эта проверка показывает выделен ли у игрока кто-либо
native GetPlayerSelectable takes player whichPlayer returns boolean
BlzIsUnitSelectable
native BlzIsUnitSelectable takes unit whichUnit returns boolean
различные действия выбора
очистка выбора
есть действие очистки выбора. удобно, когда не нужно удалять. сразу чистим. Иначе пришлось бы циклом всех юнитов вычищать, а также записать.
native ClearSelection takes nothing returns nothing
есть действия очистки выбора для игрока
function ClearSelectionForPlayer(whichPlayer)
    if (GetLocalPlayer() == whichPlayer) then
        --Use only local code (no net traffic) within this block to avoid desyncs.
        ClearSelection()
    end
end
добавить/убавить юнита игроку
основная нативка, добавляющая юнита игроку
native SelectUnit takes unit whichUnit, boolean flag returns nothing
вариковские нативки добавления юнита
function SelectUnitAdd(whichUnit)
    SelectUnit(whichUnit, true)
end
function SelectUnitRemove(whichUnit)
    SelectUnit(whichUnit, false)
end
есть еще действия выделения одного юнита, правда не локально
function SelectUnitSingle(whichUnit)
    ClearSelection()
    SelectUnit(whichUnit, true)
end
но как обычно нужно указать к какому игроку локально выбор прилепить. А то действия два выше добавляют всем.
((код
--выделить одного юнита для игрока
function SelectUnitForPlayerSingle(whichUnit,whichPlayer)
    if (GetLocalPlayer() == whichPlayer) then
        --Use only local code (no net traffic) within this block to avoid desyncs.
        ClearSelection()
        SelectUnit(whichUnit, true)
    end
end

--добавить юнита из группы выбора игрока
function SelectUnitAddForPlayer(whichUnit,whichPlayer)
    if (GetLocalPlayer() == whichPlayer) then
        --Use only local code (no net traffic) within this block to avoid desyncs.
        SelectUnit(whichUnit, true)
    end
end
--удалить юнита из группы выбора игрока
function SelectUnitRemoveForPlayer(whichUnit,whichPlayer)
    if (GetLocalPlayer() == whichPlayer) then
        --Use only local code (no net traffic) within this block to avoid desyncs.
        SelectUnit(whichUnit, false)
    end
end
))
выделить группу
function SelectGroupBJEnum()
    SelectUnit( GetEnumUnit(), true )
end
function SelectGroupForPlayerBJ(g, whichPlayer)
    if (GetLocalPlayer() == whichPlayer) then
        --Use only local code (no net traffic) within this block to avoid desyncs.
        ClearSelection()
        ForGroup( g, function SelectGroupBJEnum )
    end
end
глобальные параметры селекта
--объекты могут быть выделены/не выделены, круг выбора отображается/не отображается
native EnableSelect takes boolean state, boolean ui returns nothing
--при наведении объекты могут быть выделены/не выделены, визуальные части вроде круга, полоски жизни мана и хп, и подсказки-фреймы над головой
native EnablePreSelect takes boolean state, boolean ui returns nothing
--при drag-select перетаскивании, а точнее выделение юнитов прямоугольной рамкой drag selection. выделяются/не выделяются объекты, включает/отключает визуальную рамку выделения drag selection box
native EnableDragSelect takes boolean state, boolean ui returns nothing
включить/отключить выделение и круг выбора
function BlzIsSelectionEnabled takes nothing returns boolean
function BlzIsSelectionCircleEnabled takes nothing returns boolean
function BlzEnableSelections takes boolean enableSelection, boolean enableSelectionCircle returns nothing
запись группы
по плану этот код создает для каждого игрока свою группу. При выделении несколькиж юнитов он записывает в группу выделенных юнитов. Или наоборот, когда юнит перестает быть выделенным/или выделенный юнит умирает/или сбрасывается каким-то другим образом выделение => удаляет выделенных юнитов из группы.
Это даже будет лучше, поскольку обращение к нативным функциям происходит медленее из-за синха. И некоторые функции пример IsUnitSelected не работают, если игрок выделяет вражеского юнита. Либо через событие или GroupEnumUnitsSelected. Поэтому лукчшим способом будет записать юнита в группу, и проверять на принадлежность к группе игрока. Если юнита в какой-то группе, значит, он выделен этим игроком
есть похожая система, реализованная на фреймах. тут <= тут более точнее, можно переключение фреймов в группе еще определить.

do
    local InitGlobalsOrigin = InitGlobals
    function InitGlobals()
        InitGlobalsOrigin()
	
        
		function HideEnumUnit(u)
			ShowUnit(u, false )
		end
		function ShowEnumUnit(u)
			ShowUnit(u, true )
		end
		
		selectedUnits = {}
		local triggerSelectedUnit = CreateTrigger()
		
		for a=0, 11 do
			TriggerRegisterPlayerUnitEvent( triggerSelectedUnit, Player(a), EVENT_PLAYER_UNIT_SELECTED,   null )
			TriggerRegisterPlayerUnitEvent( triggerSelectedUnit, Player(a), EVENT_PLAYER_UNIT_DESELECTED,   null )
			TriggerRegisterPlayerUnitEvent( triggerSelectedUnit, Player(a), EVENT_PLAYER_UNIT_DEATH,   null )
		end
		TriggerAddAction( triggerSelectedUnit, function()
			local triggerUnit  =  GetTriggerUnit()
			local playerId     =  GetPlayerId(GetTriggerPlayer())

			if ( GetTriggerEventId( ) == EVENT_PLAYER_UNIT_SELECTED ) then

				if ( selectedUnits[ playerId ] == null ) then
					selectedUnits[ playerId ]  =  CreateGroup( )
				end
                GroupAddUnit( selectedUnits[ playerId ], triggerUnit )
                print( "|cff00ff00"..GetUnitName( triggerUnit ).." selected|r" )
			elseif ( GetTriggerEventId( ) == EVENT_PLAYER_UNIT_DESELECTED ) then
				GroupRemoveUnit( selectedUnits[ playerId ], triggerUnit )
				print( "|cffff0000"..GetUnitName( triggerUnit ).." deselected|r" )

			elseif( GetTriggerEventId( ) == EVENT_PLAYER_UNIT_DEATH ) then

            end
        end)
    end
end

системы и наработки

отследить реинкарнацию / воскрешение
источник
При реинкарнации событие смерти не фиксирует, что юнит умер. Абилка блочит event триггера. Есть способ, который нашел с хайва. Интерпретировал и разобрал для себя.
Есть такой способ - с помощью абилки 'Adef' (укрыться щитом). Кресту (трупу) можно отдавать приказ defend/undefend, отслеживать можно:
  • через событие получения приказа с проверкой, что юнит мертв IsUnitType(u, UNIT_TYPE_DEAD).
  • или отдать приказ defend/undefend мертвому юниту IsUnitType(u, UNIT_TYPE_DEAD) => действие приказа вернет true, если приказ выполним. Иначе, вернет false. Реальный труп (не крест) не может получать приказ, вернет false.
Суть велосипеда: Когда юнит умирает, автоматически движком отдается какой то один приказ => вроде "undefend". Убирает щит. При воскрешении юниту движок снова отдает этот же приказ, чтобы при появлении был убран щит. Саму абилу можно заблокировать, чтобы ее было не видно. Кстати, при реинкарнации можно отдавать приказ defend/undefend.
do
	local InitGlobalsOrigin = InitGlobals
	function InitGlobals()
		InitGlobalsOrigin()
        
		--дефект-абилки на основе Adef, благодаря которым можно отслеживать при первом появлении/удалении, реинкарнацию, трансформацию, смерть, спрятан/видим => игра сама отдает приказ undefend юниту. Adef уникальная абилка, которой можно отдавать приказы даже будучи трупом.
        DetectRemoveAbility = FourCC('A002')
        DetectTransformAbility = FourCC('A001')
        
		IsUnitAlive = {} --состояние юнита: жив/мертв. при событии смерти можно зафиксировать смерть юнита. Но с навыком перерождения событие не фиксирует смерть. Мы должны зафиксировать, что юнит умирал уже с событием приказа undefend. IsUnitAlive помогает определить завершение реинкарнации, а также воскрешение. 
        IsUnitReincarnating = {} --состояние реинкарнации. Это штука помогает определить была ли реинкарнация =true, или труп юнита воскресили =false.
        group_reincarnation = CreateGroup()

		--спрятанные заблокированные детект-абилки все равно работают, несмотря ни на что.
        SetPlayerAbilityAvailable(Player(0), DetectRemoveAbility, false)
        SetPlayerAbilityAvailable(Player(0), DetectTransformAbility, false)
                
                
        TimerStart(CreateTimer(),0.00,false,function()
            GroupEnumUnitsInRect(group_reincarnation, bj_mapInitialPlayableArea, nil)
            ForGroup(group_reincarnation,function()
                
                local u = GetEnumUnit()
                local h = GetHandleId(u)
                
                --if not IsUnitType(u, UNIT_TYPE_DEAD) then
                    if not IsUnitAlive[h] then
                        IsUnitAlive[h] = true
                        IsUnitReincarnating[h] = false
                    end
					
					--даем DetectRemoveAbility юниту, и делаем ее пермаментной. т.е. при смерти, или трансформации эта абилка не исчезнет.
                    UnitAddAbility(u, DetectRemoveAbility)
                    UnitMakeAbilityPermanent(u, true, DetectRemoveAbility )
					
					--DetectTransformAbility является не пермаментной, и при трансформации она исчезнет. Если абилка исчезла после трансформации, значит, что произошел морф
                    --UnitAddAbility(u, DetectTransformAbility)
                --end

            end)
            
            print("кол-во юнитов на карте: "..BlzGroupGetSize(group_reincarnation))
            DestroyTimer(GetExpiredTimer())
        end)

        --регистрируем триггер на появление юнитов
        local trigger_unit_enter = CreateTrigger() --триггер добавления юнитов
        TriggerRegisterEnterRectSimple( trigger_unit_enter, bj_mapInitialPlayableArea )
        TriggerAddCondition(trigger_unit_enter, Condition( function()
            return not IsUnitInGroup(GetTriggerUnit(), group_reincarnation)
        end) )
        TriggerAddAction(trigger_unit_enter,function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            --if not IsUnitType(u, UNIT_TYPE_DEAD) then
                if not IsUnitAlive[h] then
                    IsUnitAlive[h] = true
                    IsUnitReincarnating[h] = false
                end
				--даем DetectRemoveAbility юниту, и делаем ее пермаментной. т.е. при смерти, или трансформации эта абилка не исчезнет.
                UnitAddAbility(u, DetectRemoveAbility)
                UnitMakeAbilityPermanent(u, true, DetectRemoveAbility)

				--DetectTransformAbility является не пермаментной, и при трансформации она исчезнет. Если абилка исчезла после трансформации, значит, что произошел морф
                --UnitAddAbility(u, DetectTransformAbility)
            --end
            
        end)

		--этот триггер смерти ни на что не влияет. Просто хочу показать, что при реинкарнации событие смерти не работает
		--однако, если это не реинкарнация, а например, надо для ВОСКРЕШЕНИЯ
        local trigger_death = CreateTrigger()
        TriggerRegisterPlayerUnitEvent(trigger_death, Player(0), EVENT_PLAYER_UNIT_DEATH, nil)
        TriggerAddAction( trigger_death, function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            
            --при наличии абилы реинкарнации, не событие фиксирует смерть 
            IsUnitAlive[h] = false --для воскрешения обозначаем, что юнит мертв
            print('unit dead') 
        end)

        local trigger_order = CreateTrigger()
        TriggerRegisterPlayerUnitEvent(trigger_order, Player(0), EVENT_PLAYER_UNIT_ISSUED_ORDER, nil)
        TriggerAddAction( trigger_order, function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            
            --После смерти у юнита срабатывает приказ undefend от способности Adef, короче должна начаться реинкарнация
            if IsUnitType(u, UNIT_TYPE_DEAD) then
                TimerStart(CreateTimer(), 0.00, false, function()
                    if IsUnitAlive[h] then 
					--фиксируем, что юнит мертв, и что у юнита реинкарнация, дабы потом удалить
                        IsUnitReincarnating[h] = true
                        IsUnitAlive[h] = false
                        print(GetUnitName(u)..' has started reincarnating')
                    end
                end)
            else
				--этот момент показывает конец реинкарнации. короче, игра повторно отдает юниту undefend. Чекаем по IsUnitAlive и IsUnitReincarnating
                if not IsUnitAlive[h] then
                    IsUnitAlive[h] = true
					if IsUnitReincarnating then
	                    IsUnitReincarnating[h] = false
	                    print(GetUnitName(u)..'  has finished reincarnating') --юнит переродился
					else
						print(GetUnitName(u)..'  has come back to life') --юнит воскрешен
					end
                end
            end
        end)
    end
end
отследить трансформацию (морф)
источник
здесь все происходит аналогично реинкарнации. Здесь тоже выдают способность 'Adef' , но с явным отличием => ее не делают пермаментной. После морфа она исчезает.
  1. выдают на старте всем спрятанную абилку
  2. в начале трансформации юнит получает приказ "undefend" как и в реинкарнации.
  3. при морфе юнит меняет модель, и абилка исчезает. Таймером через 0.00 сек выдаем обратно абилку.
do
	local InitGlobalsOrigin = InitGlobals
	function InitGlobals()
		InitGlobalsOrigin()
        
        DetectRemoveAbility = FourCC('A002')
        DetectTransformAbility = FourCC('A001')
        IsUnitTransforming = {}
        group_transform = CreateGroup()

        SetPlayerAbilityAvailable(Player(0), DetectRemoveAbility, false)
        SetPlayerAbilityAvailable(Player(0), DetectTransformAbility, false)
                
        TimerStart(CreateTimer(),0.00,false,function()
            --выделяем всех юнитов на карте в группу, добавляем способность им и параметры
			
			GroupEnumUnitsInRect(group_transform, bj_mapInitialPlayableArea, nil)
            ForGroup(group_transform,function()
                local u = GetEnumUnit()
                local h = GetHandleId(u)
                IsUnitTransforming[h] = false
                UnitAddAbility(u, DetectTransformAbility)
            end)
            
            print("кол-во юнитов на карте: "..BlzGroupGetSize(group_transform))
            DestroyTimer(GetExpiredTimer())
        end)

		--триггер добавления юнитов
        --регистрируем триггер на появление юнитов
        local trigger_unit_enter = CreateTrigger() 
        TriggerRegisterEnterRectSimple( trigger_unit_enter, bj_mapInitialPlayableArea )
        TriggerAddCondition(trigger_unit_enter, Condition( function()
            return not IsUnitInGroup(GetTriggerUnit(), group_transform)
        end) )
        TriggerAddAction(trigger_unit_enter,function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            IsUnitTransforming[h] = false
            UnitAddAbility(u, DetectTransformAbility)
        end)

        local trigger_order = CreateTrigger()
        TriggerRegisterPlayerUnitEvent(trigger_order, Player(0), EVENT_PLAYER_UNIT_ISSUED_ORDER, nil)
        TriggerAddAction( trigger_order, function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            
			--при получении приказа абилка DetectTransformAbility уже удалилась, тк юнит уже трансформировался. она не сохраняется при трансформации
			if GetUnitAbilityLevel(u, DetectTransformAbility) == 0 and (not IsUnitTransforming[h]) then
				IsUnitTransforming[h] = true
				TimerStart(CreateTimer(), 0.00, false, function()
					if IsUnitTransforming[h] then
						local type = GetUnitTypeId(u) --Set this afterward to give the user extra reference
						print('unit transform in '..GetObjectName(type))
						IsUnitTransforming[h] = false
						--Added 21 July 2017 to fix the issue re-adding this ability in the same instant
						UnitAddAbility(u, DetectTransformAbility)
					end
                end)
			end
        end)
    end
end
отследить удаление юнита
как отследить, что юнит удалился с игры. иногда необходимо устранять утечки, удалять данные с мертвого юнита. проще после смерти удалять и чистить, и все это делать вручную. Но вдруг вы расчитываете, что труп можно оживить. Есть специальные абилки, воскрешающие трупы. Поэтому решил пока попробовать удалять данные не после смерти, а после завершения разложения, которое завершается удалением юнита из игры. Но событие разложение юнита фиксирует не полное разложение, а лишь начало.
система оказалось полезной, чтобы чистить наложенные эффекты, images и пр. Ведь после удаления из игры, эти объекты останутся в игре, хоть и не видимы.
источник
короче, это тоже самое, что и с реинкарнацией и трансформацией. Абилка Adef универсальность опять показала. Даже перед удалением юнита игра зачем то отдает юниту приказ
do
	local InitGlobalsOrigin = InitGlobals
	function InitGlobals()
		InitGlobalsOrigin()
        
        DetectRemoveAbility = FourCC('A002')
        DetectTransformAbility = FourCC('A001')
        IsUnitAlive = {}
        IsUnitReincarnating = {}
        group_reincarnation = CreateGroup()

        SetPlayerAbilityAvailable(Player(0), DetectRemoveAbility, false)
        SetPlayerAbilityAvailable(Player(0), DetectTransformAbility, false)
                  
        TimerStart(CreateTimer(),0.00,false,function()
            GroupEnumUnitsInRect(group_reincarnation, bj_mapInitialPlayableArea, nil)
            ForGroup(group_reincarnation,function()
                
                local u = GetEnumUnit()
                local h = GetHandleId(u)
                
                --if not IsUnitType(u, UNIT_TYPE_DEAD) then
                    if not IsUnitAlive[h] then
                        IsUnitAlive[h] = true
                        IsUnitReincarnating[h] = false
                    end
                    UnitAddAbility(u, DetectRemoveAbility)
                    UnitMakeAbilityPermanent(u, true, DetectRemoveAbility)
                    --UnitAddAbility(u, DetectTransformAbility)
                --end

            end)
            
            print("кол-во юнитов на карте: "..BlzGroupGetSize(group_reincarnation))
            DestroyTimer(GetExpiredTimer())
        end)

        --регистрируем триггер на появление юнитов
        local trigger_unit_enter = CreateTrigger() --триггер добавления юнитов
        TriggerRegisterEnterRectSimple( trigger_unit_enter, bj_mapInitialPlayableArea )
        TriggerAddCondition(trigger_unit_enter, Condition( function()
            return not IsUnitInGroup(GetTriggerUnit(), group_reincarnation)
        end) )
        TriggerAddAction(trigger_unit_enter,function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            --if not IsUnitType(u, UNIT_TYPE_DEAD) then
                if not IsUnitAlive[h] then
                    IsUnitAlive[h] = true
                    IsUnitReincarnating[h] = false
                end
                UnitAddAbility(u, DetectRemoveAbility)
                UnitMakeAbilityPermanent(u, true, DetectRemoveAbility)
                --UnitAddAbility(u, DetectTransformAbility)
            --end
            
        end)


        local trigger_death = CreateTrigger()
        TriggerRegisterPlayerUnitEvent(trigger_death, Player(0), EVENT_PLAYER_UNIT_DEATH, nil)
        TriggerAddAction( trigger_death, function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            
            --при наличии абилы реинкарнации, не событие фиксирует смерть 
            IsUnitAlive[h] = false
            print('unit dead')
        end)

        local trigger_order = CreateTrigger()
        TriggerRegisterPlayerUnitEvent(trigger_order, Player(0), EVENT_PLAYER_UNIT_ISSUED_ORDER, nil)
        TriggerAddAction( trigger_order, function()
            local u = GetTriggerUnit()
            local h = GetHandleId(u)
            
			--перед удалением, когда юнит полностью разложился в ничто, игра отдает приказ undefend и абилка DetectRemoveAbility удаляется из игры. lv=0
			if GetUnitAbilityLevel(u, DetectRemoveAbility) == 0 then
				local type = GetUnitTypeId( u )
				local name = GetUnitName(u)
				--print(GetUnitName(u)..' удалится через 0.00 сек')
				TimerStart(CreateTimer(), 0.00, false, function()
					if GetUnitTypeId( u ) < 1 then
						if IsUnitCreated[h] then
							IsUnitCreated[h] = false
							print('юнит '..name..' удалён из игры')
						end
					end
					DestroyTimer(GetExpiredTimer())
				end)
			end
        end)
    end
end
бд цветов игрока
короче завел я такую таблицу цветов для игроков. Можно различные варианты кодировки цветов представлять. хоть тремя числами rgb 0-255, хоть в виде 16-ричный код. Помню, мне приходилось из редактора брать с руки копипастить. В редакторе можно смотреть цвета игроков. Позднее еще приходилось потом в 16-ричную кодировку конвертить.
В данном случае цвета брались в 1.26 патче. Сейчас для рефа требуется обновление, ибо там число игроков, как и цветов возросло от 12 до 24.
--цвета игроков (red,green,blue)
	ColorPlayer_R = {}
	ColorPlayer_G = {}
	ColorPlayer_B = {}
	--цвета игроков
		--красный (Red) PLAYER_COLOR_RED = 0
		ColorPlayer_R[0] = 255.00
		ColorPlayer_G[0] = 3.00
		ColorPlayer_B[0] = 3.00
		--синий (Blue) PLAYER_COLOR_BLUE = 1
		ColorPlayer_R[1] = 0.00
		ColorPlayer_G[1] = 66.00
		ColorPlayer_B[1] = 255.00    
		--голубой (Teal) PLAYER_COLOR_CYAN = 2
		ColorPlayer_R[2] = 28.00
		ColorPlayer_G[2] = 230.00
		ColorPlayer_B[2] = 185.00
		--фиолетовый (Purple) PLAYER_COLOR_PURPLE = 3
		ColorPlayer_R[3] = 84.00
		ColorPlayer_G[3] = 0.00
		ColorPlayer_B[3] = 129.00
		--желтый (yellow) PLAYER_COLOR_YELLOW = 4
		ColorPlayer_R[4] = 255.00
		ColorPlayer_G[4] = 252.00
		ColorPlayer_B[4] = 1.00
		--оранжевый (Orange) PLAYER_COLOR_ORANGE = 5
		ColorPlayer_R[5] = 254.00
		ColorPlayer_G[5] = 137.00 --186.00
		ColorPlayer_B[5] = 14.00
		--зеленый (green) PLAYER_COLOR_GREEN = 6
		ColorPlayer_R[6] = 32.00
		ColorPlayer_G[6] = 192.00
		ColorPlayer_B[6] = 0.00
		--розовый (pink) PLAYER_COLOR_PINK = 7
		ColorPlayer_R[7] = 229.00
		ColorPlayer_G[7] = 91.00
		ColorPlayer_B[7] = 176.00
		--серый (gray) PLAYER_COLOR_LIGHT_GRAY = 8
		ColorPlayer_R[8] = 149.00
		ColorPlayer_G[8] = 150.00
		ColorPlayer_B[8] = 151.00
		--светло-синий (light blue) PLAYER_COLOR_LIGHT_BLUE = 9
		ColorPlayer_R[9] = 126.00
		ColorPlayer_G[9] = 191.00
		ColorPlayer_B[9] = 241.00
		--темно-зеленый (dark green) PLAYER_COLOR_AQUA = 10
		ColorPlayer_R[10] = 16.00
		ColorPlayer_G[10] = 98.00
		ColorPlayer_B[10] = 70.00
		--коричневый (brown) PLAYER_COLOR_BROWN = 11
		ColorPlayer_R[11] = 78.00
		ColorPlayer_G[11] = 42.00
		ColorPlayer_B[11] = 4.00
		--бордовый (Maroon) PLAYER_COLOR_MAROON = 12
		ColorPlayer_R[12] = 156.00
		ColorPlayer_G[12] = 0.00
		ColorPlayer_B[12] = 0.00
		--темно-синий (Navy) PLAYER_COLOR_NAVY = 13
		ColorPlayer_R[13] = 0.00
		ColorPlayer_G[13] = 0.00
		ColorPlayer_B[13] = 195.00
		--бирюзовый (Turquoise) PLAYER_COLOR_TURQUOISE = 14
		ColorPlayer_R[14] = 0.00
		ColorPlayer_G[14] = 235.00
		ColorPlayer_B[14] = 255.00
		--пурпурный (Violet) PLAYER_COLOR_VIOLET = 15
		ColorPlayer_R[15] = 189.00
		ColorPlayer_G[15] = 0.00
		ColorPlayer_B[15] = 255.00
		--игрок цвета пшеницы/пшеничный (Wheat) PLAYER_COLOR_WHEAT = 16
		ColorPlayer_R[16] = 236.00
		ColorPlayer_G[16] = 206.00
		ColorPlayer_B[16] = 135.00
		--игрок цвета персика/персиковый (Peach) PLAYER_COLOR_PEACH = 17
		ColorPlayer_R[17] = 247.00
		ColorPlayer_G[17] = 165.00
		ColorPlayer_B[17] = 139.00
		--игрок цвета мяты (Mint) PLAYER_COLOR_MINT = 18
		ColorPlayer_R[18] = 191.00
		ColorPlayer_G[18] = 255.00
		ColorPlayer_B[18] = 129.00
		--игрок цвета лаванды (Lavender) PLAYER_COLOR_LAVENDER = 19
		ColorPlayer_R[19] = 219.00
		ColorPlayer_G[19] = 184.00
		ColorPlayer_B[19] = 235.00                       
		--темно-серый - игрок угольного цвета (Coal) PLAYER_COLOR_COAL = 20
		ColorPlayer_R[20] = 79.00
		ColorPlayer_G[20] = 80.00
		ColorPlayer_B[20] = 85.00   
		--белый (Snow) PLAYER_COLOR_SNOW = 21
		ColorPlayer_R[21] = 236.00
		ColorPlayer_G[21] = 240.00
		ColorPlayer_B[21] = 255.00   
		--изумрудный (Emerald) PLAYER_COLOR_EMERALD = 22
		ColorPlayer_R[22] = 0.00
		ColorPlayer_G[22] = 120.00
		ColorPlayer_B[22] = 30.00  
		--коричнево-арахисовый (Peanut) PLAYER_COLOR_PEANUT = 23
		ColorPlayer_R[23] = 165.00
		ColorPlayer_G[23] = 111.00
		ColorPlayer_B[23] = 52.00 
		--черный-нейтральный (Black) ConvertPlayerColor(24) = 24
		ColorPlayer_R[24] = 46.00
		ColorPlayer_G[24] = 45.00
		ColorPlayer_B[24] = 46.00 

--цветовой текст игрока
	PlayerColor = {}
		PlayerColor[0] = "|cffff0303"
		PlayerColor[1] = "|cff0042ff"
		PlayerColor[2] = "|cff1be7ba"
		PlayerColor[3] = "|cff550081"
		PlayerColor[4] = "|cfffefc00"
		PlayerColor[5] = "|cfffe890d"
		PlayerColor[6] = "|cff21bf00"
		PlayerColor[7] = "|cffe45caf"
		PlayerColor[8] = "|cff939596"
		PlayerColor[9] = "|cff7ebff1"
		PlayerColor[10] = "|cff106247"
		PlayerColor[11] = "|cff4f2b05"
		PlayerColor[12] = "|cff9c0000"
		PlayerColor[13] = "|cff0000c3"
		PlayerColor[14] = "|cff00ebff"
		PlayerColor[15] = "|cffbd00ff"
		PlayerColor[16] = "|cffecce87"
		PlayerColor[17] = "|cfff7a58b"
		PlayerColor[18] = "|cffbfff81"
		PlayerColor[19] = "|cffdbb8eb"
		PlayerColor[20] = "|cff4f5055"
		PlayerColor[21] = "|cffecf0ff"
		PlayerColor[22] = "|cff00781e"
		PlayerColor[23] = "|cffa56f34"
		PlayerColor[24] = "|cff2e2d2e"
		PlayerColor[25] = "|cff2e2d2e"
		PlayerColor[26] = "|cff2e2d2e"
		PlayerColor[27] = "|cff2e2d2e"
константы снижения урона
это может кому-нибудь пригодиться. помогает определить коэффициент снижения урона от типа атаки по типу брони
источник
тема
cons_damage_bonus = {}
    
    --light, medium, large, fort, normal, hero, divine, none (0-7 defenses type)
    normal = {1.00,1.00,1.00,1.00,1.00,0.75,0.05,1.00} --normal is spells
    melee = {1.00,1.50,1.00,0.70,1.00,1.00,0.05,1.00}
    pierce = {2.00,0.75,1.00,0.35,1.00,0.50,0.05,1.50}
    siege  = {1.00,0.50,1.00,1.50,1.00,0.50,0.05,1.50}
    magic = {1.25,0.75,2.00,0.35,1.00,0.50,0.05,1.00}
    chaos = {1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}
    hero = {1.00,1.00,1.00,0.50,1.00,1.00,0.05,1.00}
    cons_damage_bonus = {normal, melee, pierce, siege, magic, chaos, hero}
    
	-- 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 (без брони)
	function GetUnitDefenseType(unit)
		return BlzGetUnitIntegerField(unit, UNIT_IF_DEFENSE_TYPE)
	end

    --damager - юнит, наносящий урон
    --index - индекс атаки (0-первая атака, 1-вторая атака, 2 - двойная атака)
    --target - юнит, который принимает урон
    function CoefficientDamage(damager,index,target)
        local type_attack = GetUnitAttackType(damager,index)+1
        local type_defense = GetUnitDefenseType(target)+1

		print('type_attack: '..type_attack  )
		print('type_defense : '..type_defense )
        local k = cons_damage_bonus[type_attack][type_defense]
        
        return k
    end
    
    --damage - кол-во урона
    function GetAttackDamage(damager,index,target,damage)
        local k = CoefficientDamage(damager,index,target)
        
        if damage then
            return damage*k
        end
        return 0
    end
    
    function GetTeoriticPureDamage(damager,index,target,damage)
        local attack_damage = GetAttackDamage(damager,index,target,damage)
        local armor = BlzGetUnitArmor(target)
        local Multiplier = 0.06 
        
        local pure_damage = attack_damage/( 1 + Multiplier * armor)
        
        return pure_damage
    end
	

	local type_defense = GetUnitDefenseType(unit)+1
    local damage_base = GetUnitAttackType(unit,index)
    local k = cons_damage_bonus[type_attack_1][type_defense]
    
	local armor = BlzGetUnitArmor(unit) --выдает инфу об общий armor. Никак не подразделяет на базовый и бонус
	
	--формула снижения армора
	--https://xgm.guru/p/wc3/get-unit-armor
	local Multiplier = 0.06
	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
Damage Reduction = Multiplier * Armor / (1 + Multiplier * Armor);
где Multiplier - это значение из Gameplay Constants - Combat - Armor Damage Reduction Multiplier, по умолчанию равное 0.06

карта путей, сетка и др.

центр collision (центровка)
В редакторе можно получить размер collision BlzGetUnitCollisionSize(unit). Можно узнать упирается ли юнит об что либо. Один раз хотел сделать collision видимым, чтобы посмотреть как упираются юниты. Однако, заметил, что центр collision не всегда совпадает с точкой координат юнита, т.е. есть смещение от центра.
у юнитов с размером 16
collision =16 является самым минимальным у наземных, меньше только у воздуха =8. это у всех дефолтных юнитов. Если присмотреться, то центр коллижион съезжает в правый верхний угол
чтобы устранить не красивое недоразумение, можно добавить оффсеты x=-16,y=-16
у юнитов с размером 31
31 тоже часто встречаемый размер в редакторе для collision
чтобы устранить не красивое недоразумение, можно добавить оффсеты x=-16,y=-16
у юнитов с размерами 32
у юнитов с 32 все в порядке. нет отклонении
для обычных
для героев (кроме героев-тауренов)
для юнитов с размерами 48
как правило, это для самых больших юнитов: горных гигантов до мясников, да тауренов. Всякие машины, транспорты и корабли. Да, и драконы. У них тоже есть смещение
чтобы устранить не красивое недоразумение, можно добавить оффсеты x=-16,y=-16
для юнитов с размером 8
как правило, это воздушные юниты. но у них нет коллижена в воздухе. Я специально опустил круг выбора в ро, чтобы было видно.
это самые стандартные размеры, которые чаще встречаются в редакторе. Есть, конечно, и редкие, пример для гран-при азерот для гоночных болидов применялись размеры 33.
Нестандартные размеры только у здании, но у здании нормально центрируются collision. Если здание сделать не-здание, обычного юнита, то центр смещается.
Попробовал задать размеры различные, и посмотреть.
1-15 нет смещения
16-31 смещение
32-47 нет смещения
больше 48 - смещение
дальше чем 128 не проверялось, но и это и не нужно. На зданиях все центрируется
RealGetUnitX = GetUnitX
        RealGetUnitY = GetUnitY

    function GetUnitRealX(unit)
        local collision = math.floor(BlzGetUnitCollisionSize(unit) + 0.5)

        if not IsUnitType(unit, UNIT_TYPE_STRUCTURE) then
            if (collision < 32 and collision > 15) or collision > 47 then return RealGetUnitX(unit) - 16. end
        end

        return RealGetUnitX(unit)
    end

    function GetUnitRealY(unit)
        local collision = math.floor(BlzGetUnitCollisionSize(unit) + 0.5)

        if not IsUnitType(unit, UNIT_TYPE_STRUCTURE) then
            if (collision < 32 and collision > 15) or collision > 47 then return RealGetUnitY(unit) - 16. end
        end

        return RealGetUnitY(unit)
    end
У эльфийских древ collision меняется, когда трансформируются в ходячие древа. Размер collision уменьшается в 3 раза. Можно отследить трансформацию, а чтобы понять, что это ходячее древог => можно по типу защиты/атаки (у здания-древа и ходячего древа разные типы).
границы collision
В отличии от центровки коллижиона, где искали центр. Здесь все иначе, тут мы выискаем прямоугольный размер каоллижиона. Достаточно отсчитать, от точки юнита радиус. Квадратики показывают можно ли строить здания на этом участке. Это оч удобно. Во-первых, помогает в карты путей, во-вторых, визуально, можно отобразить карту, пример при строительстве источник
не секрет, что самая минимальная клетка в игре 32x32, т.е. мин размер сетки 32. меньше бесполезно делать. наша выборочная площадка строительства состоит из таких квадратиков. Когда в точке нельзя строить, она отображается красным, иначе зеленым.
для юнитов пришлось много мучеении сделать:
  • коллижион 1-15 необходимо сместить x+16,y+16, клетка принимает размеры 32x32
  • коллижион 16-31 смещение x,y делать не нужно, клетка принимает размеры 64x64
  • коллижион 32-47 необходимо сместить x+16,y+16, клетка принимает размеры 96x96
  • коллижион 48-63 смещение x,y делать не нужно, клетка принимает размеры 96x96
  • коллижион больше 64 смещение x,y делать не нужно, клетка принимает размеры 128x128, больше чем 128 не видел. только у здании. но здания используют карты путей
для здании и декорации не используется карта путей, необходимо забивать бд размеров всех здании и декорации, что будут у вас на карте. В том числе и блокираторы путей итд.
для итемов. С итемами было проще всего. У них нет коллижиона. Но занимают клетку 32x32. По факту в функцию bordersForCircle указываем радиус = 8 со смещением x+16,y+16. Замечано смещение
			function bordersForCircle(x,y,r,size)

				local minx,maxx,miny,maxy
				
				--радиус коллижиона = 1..15 нет смещения, добавляем 
				if r<16 then 
					x=x+16.
					y=y+16.
					r=8.
				--радиус коллижиона = 16..31 есть видимое смещение 
				elseif r<32 then
					r=16.
				--радиус коллижиона = 32..47 нет смещения, добавляем  
				elseif r<48 then 
					x=x+16.
					y=y+16.
					r=24.
				end
					

				local R = r%%size
				local count = math.modf(r/size)
				
				R = R*2 + count*size
					
				minx,maxx,miny,maxy = x-R,x+R,y-R,y+R

				minx=math.floor(minx/size)*size
				miny=math.floor(miny/size)*size
				maxx=math.floor(maxx/size)*size
				maxy=math.floor(maxy/size)*size

				return minx,maxx,miny,maxy
			end
размеры коллизии
как ответили ребята из хайва размеры коллижиона имеет ряд:
0-8-16-24-32-40-48
Если размер равен 9, то будет равен 8. Если равен 47, то равен будет 40
проверка паффинга в ректе
function GetPathingRect(re, pathingtype, pathable)
    
--[[available pathing types
PATHING_TYPE_ANY                 -if this is false you can't walk/build/fly on it
PATHING_TYPE_WALKABILITY         -if this is false you can't walk on it
PATHING_TYPE_FLYABILITY          -if this is false you can't fly on it
PATHING_TYPE_BUILDABILITY        -if this is false you can't build on it
PATHING_TYPE_PEONHARVESTPATHING  -don't know
PATHING_TYPE_BLIGHTPATHING       -if this is false you can't build ziggs on it
PATHING_TYPE_FLOATABILITY        -don't know
PATHING_TYPE_AMPHIBIOUSPATHING   -don't know
]]
    local r = 32  --size of pathing blocks
    local x = GetRectMinX(re)
    local y
    local x2 = GetRectMaxX(re)
    local y2 = GetRectMaxY(re)
    local b = pathable
    local k = 0
    
	repeat
		y = GetRectMinY(re)
		repeat
			if y < y2 and x < x2 then
                b = (not IsTerrainPathable(x, y, pt)) --точка где можно строить, функция инверсная.
                if not b then 
                    k = k + 1 --кол-во точек, в которых нельзя строить  
                end
            end
            y = y + r
		until y >= y2 or b~=pathable
		x = x + r
	until x >= x2 or b~=pathable
	
	--print("проверка на стройку: "..(k) )

    return k --если бы хотя бы одна точка не подходит под площадку значит здесь невозможно применить площадку 
end
для работы с сеткой
ключи
достает на каждую клетку ключ: номер. чаще ключ берут под x,y. это для двухмерной таблицы луа. обычно каждая клетка хранит свой обхем данных. Очень уоно доставать по ключам.
    --возвращает ключ клетки
    function KeyGrid(x, size, Debug)
        if size==0 then return 0 end
        
        --номер клетки
        local num =math.abs(math.ceil(x/size))
        if x<0 then
            num = -num
        end
        
        if Debug then
            local minx = ((num-1)*size)+1
            local maxx = num*size
            
            minx,maxx=math.min(minx,maxx),math.max(minx,maxx)
            
            if minx<=x and x<=maxx then
                --print('|cffffcc00'..x..'|r |cff00ff00находится в промежутке '..tostring(minx)..' и '..tostring(maxx)..'|r')
                print(x..' находится в промежутке '..tostring(minx)..' и '..tostring(maxx))
            else
                --print('|cffffcc00'..x..'|r |cffff0000не находится в промежутке '..tostring(minx)..' и '..tostring(maxx)..'|r')
                print(x..' не находится в промежутке '..tostring(minx)..' и '..tostring(maxx))
            end
            print('num: '..num)
        end
        
        return num
    end
координаты центра клетки
центр нужен больше для метки индикаторами. чтобы проверить. пусть и в функции лишние проверки, я добавил, чтобы проверить работу функц
	--номер клетки
    function NumGrid(x,size, Debug)
        if size==0 then return 0 end
        
        --номер клетки
        local num =math.abs(math.ceil(x/size))
        
        --в отличии от ключей, тут есть сдвиг для центровки клетки
        if x<0 then
            num = -(num+1)
        end
        
        if Debug then
            local minx = ((num-1)*size)+1
            local maxx = num*size
            
            minx,maxx=math.min(minx,maxx),math.max(minx,maxx)
            
            if minx<=x and x<=maxx then
                --print('|cffffcc00'..x..'|r |cff00ff00находится в промежутке '..tostring(minx)..' и '..tostring(maxx)..'|r')
                print(x..' находится в промежутке '..tostring(minx)..' и '..tostring(maxx))
            else
                --print('|cffffcc00'..x..'|r |cffff0000не находится в промежутке '..tostring(minx)..' и '..tostring(maxx)..'|r')
                print(x..' не находится в промежутке '..tostring(minx)..' и '..tostring(maxx))
            end
            print('num: '..num)
        end
        return num
    end
        
    --координаты клетки
    function GridCellCenter(x,y, size)
        local nx = NumGrid(x, size,true)
        local ny = NumGrid(y, size,true)
        
        if nx >= 0 then
            nx=(nx-0.5)*size
        else
            nx=(nx+0.5)*size
        end
        if ny >= 0 then
            ny=(ny-0.5)*size
        else
            ny=(ny+0.5)*size
        end
        --print(nx,ny)
        return nx,ny
    end
для бд
W3X2LNI Drag&Drop

математическая библиотека

высота террейна
function GetHeightZWater takes real x, real y returns real
    local location loc = Location(x,y)
    local real r = GetLocationZ(loc)
    if (IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x,y,PATHING_TYPE_AMPHIBIOUSPATHING)) then
        set r = r - 128.0
    endif
    call RemoveLocation(loc)
    set loc = null
    return r
endfunction
или
          local zTesterLocation = Location(0,0)
          local getTerrainZ = function(x,y)
            MoveLocation(zTesterLocation, x, y)
            return GetLocationZ(zTesterLocation)
          end

Хорошие идеи

юнит бездействует/работает
Хорошую нароботку заметил. Идеально, я вот не мог точно определять бездействие юнита. Нашел тут мистему на хайве, пока не знаю как она работает. нужно проверить лично
как определить строителя?
`
ОЖИДАНИЕ РЕКЛАМЫ...