Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
Lua
Тип:
Способность
Версия Warcraft:
Reforged
» MUI: да
» Импорт: нет
» Утечки: нет
» Требования: нет
Герой запускает волну, которая наносит 100/200/300 урона и рикошетит от рельефа.

Скриншот

Технические подробности

Перенос в свою карту
Триггеры
  • WaterWave
Способности
  • Волна Воды 'SWaW:ANcl'
Настройка
local ABILITY_ID = AbilityId('SFiB')
local MISSILE_EFFECT = {'Abilities\\Weapons\\WaterElementalMissile\\WaterElementalMissile.mdl',2} --> model, scal
local MISSILE_HEIGHT = 100
local MISSILE_START_DISTANCE = 100

local TIMER_PERIOD = 0.03125 --> 1/32
local SPEED = 600
local DISTANCE = {1200, 1800, 2400}

local DAMAGE_UNIT = {50, 75, 100}
local DAMAGE_UNIT_RANGE = 64
local DAMAGE_UNIT_PERIOD = 0.09
local DAMAGE_UNIT_EFFECT = {'Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl', 'origin'}
local DAMAGE_EXPLODE = {100, 200, 300}
local DAMAGE_EXPLODE_RANGE = 254
local DAMAGE_EXPLODE_EFFECT = 'Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl'
Код
//! beginusercode
do
    -- На момент патча 1.31 эта функция всегда возвращает 0. Поэтому создадим её локальный аналог.
    local function AbilityId(id)
        return id:byte(1) * 0x1000000 + id:byte(2) * 0x10000 + id:byte(3) * 0x100 + id:byte(4)
    end

    -- Настройки
    local ABILITY_ID = AbilityId('SFiB')
    local MISSILE_EFFECT = {'Abilities\\Weapons\\WaterElementalMissile\\WaterElementalMissile.mdl',2} --> model, scal
    local MISSILE_HEIGHT = 100
    local MISSILE_START_DISTANCE = 100

    local TIMER_PERIOD = 0.03125 --> 1/32
    local SPEED = 600
    local DISTANCE = {1200, 1800, 2400}

    local DAMAGE_UNIT = {50, 75, 100}
    local DAMAGE_UNIT_RANGE = 64
    local DAMAGE_UNIT_PERIOD = 0.09
    local DAMAGE_UNIT_EFFECT = {'Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl', 'origin'}
    local DAMAGE_EXPLODE = {100, 200, 300}
    local DAMAGE_EXPLODE_RANGE = 254
    local DAMAGE_EXPLODE_EFFECT = 'Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl'

    -- Заклинание
    local SPEED_INC = SPEED/(1/TIMER_PERIOD)

    local function InMapXY(x, y)
        return
            x > GetRectMinX(bj_mapInitialPlayableArea)
            and
            x < GetRectMaxX(bj_mapInitialPlayableArea)
            and
            y > GetRectMinY(bj_mapInitialPlayableArea)
            and
            y < GetRectMaxY(bj_mapInitialPlayableArea)        
    end

    local GetTerrainZ_location = Location(0, 0)
    local function GetTerrainZ(x, y)
        MoveLocation(GetTerrainZ_location, x, y);
        return GetLocationZ(GetTerrainZ_location);
    end

    local TRIGGER = CreateTrigger()
    for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1
    do
        TriggerRegisterPlayerUnitEvent(TRIGGER, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT)
    end
    TriggerAddCondition(t, Condition(function()
        return GetSpellAbilityId() == ABILITY_ID
    end))
    TriggerAddAction(TRIGGER, function()
        local caster = GetTriggerUnit()
        local x = GetUnitX(caster)
        local y = GetUnitY(caster)

        local angle = Atan2(GetSpellTargetY() - y, GetSpellTargetX() - x)
        local cos = Cos(angle)
        local sin = Sin(angle)

        x = x + MISSILE_START_DISTANCE*cos
        y = y + MISSILE_START_DISTANCE*sin
        local z = GetTerrainZ(x, y) + MISSILE_HEIGHT
        local zx
        local zy

        local level = GetUnitAbilityLevel(caster, ABILITY_ID)
        local distance = DISTANCE[level]

        local missile = AddSpecialEffect(MISSILE_EFFECT[1], x, y)
        BlzSetSpecialEffectYaw(missile, angle)
        BlzSetSpecialEffectHeight(missile, MISSILE_HEIGHT)
        BlzSetSpecialEffectScale(missile, MISSILE_EFFECT[2])
        
        local damaged = CreateGroup()
        local damaging = CreateGroup()

        local time = 0
        
        TimerStart(CreateTimer(), TIMER_PERIOD, true, function()
            zx = GetTerrainZ(x + 2*SPEED_INC*Cos(angle), y + 1*SPEED_INC*Sin(angle)) - z + MISSILE_HEIGHT
            zy = GetTerrainZ(x + 1*SPEED_INC*Cos(angle), y + 2*SPEED_INC*Sin(angle)) - z + MISSILE_HEIGHT
            
            if zx > z then angle = math.pi - angle end
            if zy > z then angle = 0 - angle end
            if zx > z or zy > z then
                cos = Cos(angle)
                sin = Sin(angle)
                BlzSetSpecialEffectYaw(missile, angle)
            end

            time = time + TIMER_PERIOD

            x = x + SPEED_INC*cos
            y = y + SPEED_INC*sin
            distance = distance - SPEED_INC

            if
                not InMapXY(x,y)
                or
                distance <= 0
            then
                
                DestroyEffect(AddSpecialEffect(DAMAGE_EXPLODE_EFFECT, x, y))
                GroupEnumUnitsInRange(damaging, x, y, DAMAGE_EXPLODE_RANGE, Filter(function()
                    return  
                            UnitAlive(GetFilterUnit())
                            and
                            IsPlayerEnemy(GetOwningPlayer(caster), GetOwningPlayer(GetFilterUnit()))
                            and
                            not IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)
                            and
                            not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING)
                end))
                
                ForGroup(damaging, function()
                    GroupAddUnit(damaged, GetEnumUnit())
                    DestroyEffect(AddSpecialEffectTarget(DAMAGE_UNIT_EFFECT[1], GetEnumUnit(), DAMAGE_UNIT_EFFECT[2]))
                    UnitDamageTarget(caster, GetEnumUnit(), DAMAGE_UNIT[level], false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                end)

                DestroyGroup(damaged)
                DestroyGroup(damaging)
                DestroyEffect(missile)
                DestroyTimer(GetExpiredTimer())
                return
            end

            BlzSetSpecialEffectX(missile, x)
            BlzSetSpecialEffectY(missile, y)
            BlzSetSpecialEffectHeight(missile, z - GetTerrainZ(x, y))

            if
                time > DAMAGE_UNIT_PERIOD
            then
                time = 0
                GroupEnumUnitsInRange(damaging, x, y, DAMAGE_UNIT_RANGE, Filter(function()
                    return  UnitAlive(GetFilterUnit())
                            and
                            IsPlayerEnemy(GetOwningPlayer(caster), GetOwningPlayer(GetFilterUnit()))
                            and
                            not IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)
                            and
                            not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING)
                            and
                            not IsUnitInGroup(GetFilterUnit(), damaged)
                end))
                
                ForGroup(damaging, function()
                    GroupAddUnit(damaged, GetEnumUnit())
                    DestroyEffect(AddSpecialEffectTarget(DAMAGE_UNIT_EFFECT[1], GetEnumUnit(), DAMAGE_UNIT_EFFECT[2]))
                    UnitDamageTarget(caster, GetEnumUnit(), DAMAGE_UNIT[level], false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                end)

                GroupClear(damaging)
            end

        end)
        
    end)
    
end
//! endusercode
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
29
5 лет назад
0
волна сделана на основе Девятого Вала?
Волна сделана на основе Канала. Стандартные абилки от рельефа не отражаются.
0
28
5 лет назад
0
NazarPunk, а сама волна триггерно двигается?
0
29
5 лет назад
Отредактирован nazarpunk
0
а сама волна триггерно двигается?
Да. Зачем выкладывать стандартные абилки?
Этот комментарий удален
0
21
5 лет назад
Отредактирован scopterectus
0
TimerStart(CreateTimer(), TIMER_PERIOD, true, function() ...
Является ли безымянная функция утечкой? Каждый раз создаётся новая функция, а как её удалить я не знаю.
1
29
5 лет назад
1
Является ли безымянная функция утечкой?
Она умрёт вместе с таймером.
1
24
5 лет назад
1
Она умрёт вместе с таймером.
Уточнение. Она умрет со следующей сборкой мусора, при которой она будет признана ненужной.
И вот тут начинаются нюансы.
0
21
5 лет назад
Отредактирован scopterectus
0
И вот тут начинаются нюансы.
prog, а если подробнее?
0
29
5 лет назад
0
а если подробнее?
Если просто, тов lua, как и в js объекты сразу не уничтожаются, а ждут своего часа до прихода сборщика мусора который удаляет объекты, на которые нет ссылок. Но как недавно выяснилось, ручной запуск сборщика может прибить таймеры и события триггеров.
1
24
5 лет назад
1
ручной запуск сборщика может прибить таймеры и события триггеров
А ты проверил в итоге, не делает ли то же самое автоматический сборщик? У меня с тех пор пока не было столько времени чтобы сесть и довести вар до сборки мусора несколько раз. Что-то мне подсказывает, что неудачные попытки делать систему движения снарядов на PTR были вызваны именно этим - сборщик мусора ел анонимные таймеры на анонимных функциях в анонимных триггерах.
0
21
5 лет назад
Отредактирован scopterectus
0
удаляет объекты, на которые нет ссылок
То есть, если в коде просто написать CreateTimer( ), то он сам уничтожится? Как сборщик понимает, что этот таймер уже не нужен?
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.