Добавлен 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
Заключение
Как видите, в оптимизации нет ничего сложного, но если всётаки у вас остались вопросы или появились предложения, то можее смело оставлять их в комментариях.
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Отредактирован nazarpunk
Отредактирован BARZZ
При создании Спец Эффекта (как через встроенные функции игрового редактора так и посредством lua-кода) заметил следующую беду: звук спецэффекта проигрывается несколько раз (в зависимости от его продолжительности). Визуальное отображение исчезает после одного проигрывания (как и задумано). Триггерное удаление эффекта или установка минимальной продолжительности существования не помогают.
Один из используемых эффектов: 'Abilities/Spells/Human/ManaFlare/ManaFlareBoltImpact.mdl' (звук проигрывается 7 раз).
Подобные проблемы возникают, как в картах с массой триггеров, так и в пустых тестовых.
Используется клиент Reforge.
тандерклэп тоже проигрывается несколько раз. Мне кажется, что это просто такой звук у эффекта.
Отредактирован BARZZ
У стандартных заклинаний такого счастья не наблюдается. Я так понимаю, эта проблема решаема.
Поделится кто мудростью Рефорджа?