Добавлен MpW,
опубликован
спецэффект
спецэффект
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. Именные способности плохо работают, тем более в редакторе можно несколько таких одноименных восоздать. Возможно, есть в редакторе список дефолтных, как у юнитов. Или может быть это строковый указать на равкод.
---@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 в ноль
идея только сместить в угол и там взорвать эффект. ссылка
-прятал альфа-каналом
-скрывал размер 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 меняешь, а первый не трогаем
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
Также классификация 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
Однако, здание может сместиться с первоначальной позиции из-за 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
кол-во ударов
это из системы BonusMode
--сколько ударов нанесет юнит за заданное время
--возможно надо будет еще учесть скорость анимации атаки - обратного броска 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
это начало работы абилки. В этот момент запускается 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
EVENT_PLAYER_UNIT_SPELL_CAST
Start the effect of an ability (Приводит способность в действие). В этот момент времени проигрываются эффекты магии: кастер как маг получается различные эффекты, какие указаны в способности: пример над головой свечения, или небо светится итд. Если это заклинание таргетное, то заклинание может выпускать снаряды. Доступны костанты цели: точка или юнит. Если быть короче, в это время на цель накладывается эффект или выпускаются снаряды. Скорость снаряда указана в абилках. Тут разные способности, и у каждого различное действие У молота бурь пример запускается полет снаряда, и только после того как долетит молот до цели, цель получает урон .Пример в буране начинается падение сосулек итд. Еще самое важное, что в этот момент у юнита и игрока забирают требуемые ресурсы (мана, золото, дерево итд), проходит под требования.
EVENT_PLAYER_UNIT_SPELL_EFFECT
EVENT_PLAYER_UNIT_SPELL_EFFECT
Finished casting an ability (Завершает применение способности) - Заканчивает каст абилки.
Все заклинания разные, и могут по разному заканчиваться. Этот момент предвищает, что юнит закончил анимацию.
Пример, молот бурь. Как только юнит запустил молот (в этот момент снаряд еще не нанес никакого урона, кастер их только-только отправил до цели, снаряд еще летит), кастер тут же опускает руки - проигрывает анимацию обратного хода
Пример, свет паладина. Как только юнит нацелился на цель (в этот момент начинается проигрывает эффект свечения, якобы исцеления или очищения светом нежити, и происходит урон), кастер тут же опускает руки - проигрывает анимацию обратного хода
Пример, буран имеет channeling-внимацию. Когда запускаешь длительный каст и падение сосулек. После того как завершает проигрывать channeling-анимацию, кастер проигрывает опускание рук - анимацию обратного хода.
Finished casting an ability показывает, что кастер завершил махание рук. пример
EVENT_PLAYER_UNIT_SPELL_FINISH
Все заклинания разные, и могут по разному заканчиваться. Этот момент предвищает, что юнит закончил анимацию.
Пример, молот бурь. Как только юнит запустил молот (в этот момент снаряд еще не нанес никакого урона, кастер их только-только отправил до цели, снаряд еще летит), кастер тут же опускает руки - проигрывает анимацию обратного хода
Пример, свет паладина. Как только юнит нацелился на цель (в этот момент начинается проигрывает эффект свечения, якобы исцеления или очищения светом нежити, и происходит урон), кастер тут же опускает руки - проигрывает анимацию обратного хода
Пример, буран имеет channeling-внимацию. Когда запускаешь длительный каст и падение сосулек. После того как завершает проигрывать channeling-анимацию, кастер проигрывает опускание рук - анимацию обратного хода.
Finished casting an ability показывает, что кастер завершил махание рук. пример
EVENT_PLAYER_UNIT_SPELL_FINISH
Stop casting an ability (Прекращает применение способности)
Отменяет каст абилки. (Сбивают как пример). Каст можно прервать. Часто это можно ассоциировать с бураном, который проигрывает channeling-анимацию. И когда игрок отдает новый приказ, кастер прерывает каст. Также кастер можно сбить, пример накинуть стан, и маг останется обездвиженным. Прерывает не работает на мгновенных заклинаниях, и таких очень много 80-90%.
Отменяет каст абилки. (Сбивают как пример). Каст можно прервать. Часто это можно ассоциировать с бураном, который проигрывает channeling-анимацию. И когда игрок отдает новый приказ, кастер прерывает каст. Также кастер можно сбить, пример накинуть стан, и маг останется обездвиженным. Прерывает не работает на мгновенных заклинаниях, и таких очень много 80-90%.
У не channel-заклинании вроде бурана (мгновенных) после события "приводит в действие" проигрывается анимация обратного хода, которую можно перебить отдачей юниту приказа сразу же после завершения каста, тогда юнит не поспевает завершить полностью анимацию. В тот момент проигрывается событие завершения каста.
EVENT_PLAYER_UNIT_SPELL_ENDCAST
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())
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 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" - сторожевая сова
"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
Пример: есть приказ на гуи "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
Пример: к примеру есть приказ на гуи "dropitem" выбросить предмет targetWidget или приказ использовать итем instantTargetWidget в точку
order_dropitem = 852001
юнит передает предмет цели target (можно так и продать в магазин, если магазин будет целью)
852002 to 852007 (moveslot): Эти приказы перемещают указанный предмет в соответствующий слот инвентаря героя, отдавшего приказ. Идентификатор 852002 переместит предмет в первый слот, идентификатор 852003 – во второй и т.д. Можно с помощью IssueInstantTargetOrderById перетащить итем самому себе.
852008 to 852013 (useslot): Заставляют героя, отдавшего приказ, использовать предмет, находящийся в соответствующем слоте инвентаря. Идентификатор 852008 использует предмет в первом слоте, идентификатор 852009 – во втором и т.д.
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, отслеживать можно:
При реинкарнации событие смерти не фиксирует, что юнит умер. Абилка блочит 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' , но с явным отличием => ее не делают пермаментной. После морфа она исчезает.
здесь все происходит аналогично реинкарнации. Здесь тоже выдают способность 'Adef' , но с явным отличием => ее не делают пермаментной. После морфа она исчезает.
- выдают на старте всем спрятанную абилку
- в начале трансформации юнит получает приказ "undefend" как и в реинкарнации.
- при морфе юнит меняет модель, и абилка исчезает. Таймером через 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 универсальность опять показала. Даже перед удалением юнита игра зачем то отдает юниту приказ
короче, это тоже самое, что и с реинкарнацией и трансформацией. Абилка 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
где Multiplier - это значение из Gameplay Constants - Combat - Armor Damage Reduction Multiplier, по умолчанию равное 0.06
карта путей, сетка и др.
центр collision (центровка)
В редакторе можно получить размер collision BlzGetUnitCollisionSize(unit). Можно узнать упирается ли юнит об что либо. Один раз хотел сделать collision видимым, чтобы посмотреть как упираются юниты. Однако, заметил, что центр collision не всегда совпадает с точкой координат юнита, т.е. есть смещение от центра.
у юнитов с размером 16
у юнитов с размером 31
у юнитов с размерами 32
для юнитов с размерами 48
для юнитов с размером 8
это самые стандартные размеры, которые чаще встречаются в редакторе. Есть, конечно, и редкие, пример для гран-при азерот для гоночных болидов применялись размеры 33.
Нестандартные размеры только у здании, но у здании нормально центрируются collision. Если здание сделать не-здание, обычного юнита, то центр смещается.
Попробовал задать размеры различные, и посмотреть.
1-15 нет смещения
16-31 смещение
32-47 нет смещения
больше 48 - смещение
дальше чем 128 не проверялось, но и это и не нужно. На зданиях все центрируется
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
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
Хорошие идеи
юнит бездействует/работает
Хорошую нароботку заметил. Идеально, я вот не мог точно определять бездействие юнита. Нашел тут мистему на хайве, пока не знаю как она работает. нужно проверить лично
как определить строителя?
`
ОЖИДАНИЕ РЕКЛАМЫ...
Комментарии пока отсутcтвуют.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.