Добавлен nazarpunk,
опубликован
Раздел:
Триггеры и объекты
Идея
Основная идея заключается в том, что lua позволяет хранить функции в таблицах и при срабатывании триггера нам всего лишь нужно вызвать определённую функцию. Основная проблема в том, как это красиво сделать.
Шаблон
Воспользовавшись тем, что редактор собирает код в том порядке, в котором он там размещён, создадим папку для способностей:
В блоке Ability определим глобальную таблицу, для хранения всех способностей:
ABILITY = {}
В самом простом случае, хранить способности можно таким образом:
ABILITY[FourCC('A000')] = function()
print('spell')
end
Но как мы знаем у способности есть пять событий, вызываемых в таком порядке:
- EVENT_PLAYER_UNIT_SPELL_CHANNEL
- EVENT_PLAYER_UNIT_SPELL_CAST
- EVENT_PLAYER_UNIT_SPELL_EFFECT
- EVENT_PLAYER_UNIT_SPELL_ENDCAST
- EVENT_PLAYER_UNIT_SPELL_FINISH
Поэтому немного изменим шаблон:
ABILITY[FourCC('A000')] = {
CHANNEL = function()
print('EVENT_PLAYER_UNIT_SPELL_CHANNEL')
end,
CAST = function()
print('EVENT_PLAYER_UNIT_SPELL_CAST')
end,
EFFECT = function()
print('EVENT_PLAYER_UNIT_SPELL_EFFECT')
end,
ENDCAST = function()
print('EVENT_PLAYER_UNIT_SPELL_ENDCAST')
end,
FINISH = function()
print('EVENT_PLAYER_UNIT_SPELL_FINISH')
end
}
Триггер
Осталось только сделать триггер, который будет работать с этим шаблоном. Для этого вернёмся в блок Ability, откроем do ... end и начнём.
Для начала сохраним id всех событий, чтоб каждый раз не вызывать функцию:
Для начала сохраним id всех событий, чтоб каждый раз не вызывать функцию:
local EventChannelId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_CHANNEL)
local EventCastId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_CAST)
local EventEffectId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_EFFECT)
local EventEndCastId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_ENDCAST)
local EventFinishId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_FINISH)
Далее создадим триггер и добавим ему все события.
local AbilityTrigger = CreateTrigger()
for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_CHANNEL)
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST)
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT)
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_ENDCAST)
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_FINISH)
end
Если вам не нужны все события, то ненужную строчку можете просто удалить.
Так как доступ к локальным переменным быстрее чем к глобальным, то включим дух оптимизаторства на спичках и определим переменную поближе к месту использования:
local ABILITYS = ABILITY ---@type table
И в завершении добавим действия триггеру:
TriggerAddAction(AbilityTrigger, function()
local eventId = GetHandleId(GetTriggerEventId())
local ability = ABILITYS[GetSpellAbilityId()]
if ability ~= nil then
if eventId == EventChannelId and ability.CHANNEL ~= nil then ability.CHANNEL()
elseif eventId == EventCastId and ability.CAST ~= nil then ability.CAST()
elseif eventId == EventEffectId and ability.EFFECT ~= nil then ability.EFFECT()
elseif eventId == EventEndCastId and ability.ENDCAST ~= nil then ability.ENDCAST()
elseif eventId == EventFinishId and ability.FINISH ~= nil then ability.FINISH()
end
end
end)
Как видите, код довольно таки прост, что зная шаблон комментировать его не вижу смысла
Весь код
ABILITY = {}
do
local EventChannelId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_CHANNEL)
local EventCastId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_CAST)
local EventEffectId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_EFFECT)
local EventEndCastId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_ENDCAST)
local EventFinishId = GetHandleId(EVENT_PLAYER_UNIT_SPELL_FINISH)
local AbilityTrigger = CreateTrigger()
for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_CHANNEL)
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST)
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT)
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_ENDCAST)
TriggerRegisterPlayerUnitEvent(AbilityTrigger, Player(i), EVENT_PLAYER_UNIT_SPELL_FINISH)
end
local ABILITYS = ABILITY ---@type table
TriggerAddAction(AbilityTrigger, function()
local eventId = GetHandleId(GetTriggerEventId())
local ability = ABILITYS[GetSpellAbilityId()]
if ability ~= nil then
if eventId == EventChannelId and ability.CHANNEL ~= nil then ability.CHANNEL()
elseif eventId == EventCastId and ability.CAST ~= nil then ability.CAST()
elseif eventId == EventEffectId and ability.EFFECT ~= nil then ability.EFFECT()
elseif eventId == EventEndCastId and ability.ENDCAST ~= nil then ability.ENDCAST()
elseif eventId == EventFinishId and ability.FINISH ~= nil then ability.FINISH()
end
end
end)
end
Добавление способностей
Основное правило добавления способностей - соблюдать шаблон и размещать их ниже блока Ability. Для примера создадим тестовую способность Ability_test:
ABILITY[FourCC('A000')] = {
CHANNEL = function()
print('EVENT_PLAYER_UNIT_SPELL_CHANNEL')
end,
CAST = function()
print('EVENT_PLAYER_UNIT_SPELL_CAST')
end,
EFFECT = function()
print('EVENT_PLAYER_UNIT_SPELL_EFFECT')
end,
ENDCAST = function()
print('EVENT_PLAYER_UNIT_SPELL_ENDCAST')
end,
FINISH = function()
print('EVENT_PLAYER_UNIT_SPELL_FINISH')
end
}
Если принцип работы понятен, то добавим ещё одну способность, более приближённую к настоящим реалиям:
do
local DELAY = 1
local DAMAGE = 100
local EFFECT_CAST = 'Abilities/Spells/Human/MassTeleport/MassTeleportCaster.mdl'
local EFFECT_LIGHTNING = 'Effect/Spell/Lightning.mdx'
local GROUP = CreateGroup()
ABILITY[FourCC('ALig')] = {
EFFECT = function()
local caster = GetTriggerUnit()
local ability = GetSpellAbility()
local level = GetUnitAbilityLevel(caster, GetSpellAbilityId())
local x, y = GetSpellTargetX(), GetSpellTargetY()
local radius = BlzGetAbilityRealLevelField(ability, ABILITY_RLF_AREA_OF_EFFECT, level - 1)
DestroyEffect(AddSpecialEffect(EFFECT_CAST, x, y))
TimerStart(CreateTimer(), DELAY, false, function()
DestroyEffect(AddSpecialEffect(EFFECT_LIGHTNING, x, y))
GroupEnumUnitsInRange(GROUP, x, y, radius + 128)
for index = BlzGroupGetSize(GROUP) - 1, 0, -1 do
local target = BlzGroupUnitAt(GROUP, index)
if UnitAlive(target) and IsUnitInRangeXY(target, x, y, radius) and not IsUnitType(target, UNIT_TYPE_FLYING) then
UnitDamageTarget(caster, target, DAMAGE * level, false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
end
end
GroupClear(GROUP)
DestroyTimer(GetExpiredTimer())
end)
end
}
end
Заключение
Как видите, в оптимизации нет ничего сложного, но если всётаки у вас остались вопросы или появились предложения, то можее смело оставлять их в комментариях.
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Немного не понял этот момент.
Отредактирован PT153
Отредактирован MpW
Отредактирован nazarpunk
Отредактирован BARZZ
При создании Спец Эффекта (как через встроенные функции игрового редактора так и посредством lua-кода) заметил следующую беду: звук спецэффекта проигрывается несколько раз (в зависимости от его продолжительности). Визуальное отображение исчезает после одного проигрывания (как и задумано). Триггерное удаление эффекта или установка минимальной продолжительности существования не помогают.
Один из используемых эффектов: 'Abilities/Spells/Human/ManaFlare/ManaFlareBoltImpact.mdl' (звук проигрывается 7 раз).
Подобные проблемы возникают, как в картах с массой триггеров, так и в пустых тестовых.
Используется клиент Reforge.
тандерклэп тоже проигрывается несколько раз. Мне кажется, что это просто такой звук у эффекта.