Я больше чем на 70% уверен, что у меня код написан плохо. Так как взаимодействия с отрядами не очень сложилось у меня, прошу помочь оптимизировать код, и убрать лишнее. Наворотил всякого.
Код и карту приложил.
Код:
return GetSpellAbilityId() == 'A001'
endfunction
function FilterR takes nothing returns boolean
local unit z = LoadUnitHandle(udg_Hash,StringHash("x"),1)
local player p = GetOwningPlayer(z)
return  IsPlayerEnemy(p, GetOwningPlayer(GetFilterUnit())) and GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING)
endfunction
function Trig_R_Boom takes unit d returns nothing
local real x = GetUnitX(d)
local real y = GetUnitY(d)
local group g = CreateGroup()
local unit f
call GroupEnumUnitsInRange(g, x, y,500,Condition(function FilterR))
    loop
    set f = FirstOfGroup(g)
    exitwhen f == null
    call UnitDamageTarget(d,f,400, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
    call GroupRemoveUnit(g,f)
endloop
set g = null
set f = null
call DestroyGroup(g)
endfunction
function Trig_LOCAL_TimerR takes nothing returns nothing
local timer timerer = GetExpiredTimer()
local integer i = GetHandleId(timerer)
local unit Caster = LoadUnitHandle(udg_Hash,i,4)
local unit Dummy = LoadUnitHandle(udg_Hash,i,3)
local real xd = GetUnitX(Dummy)
local real yd = GetUnitY(Dummy)
if (GetWidgetLife(Dummy) < 0.405) then
call Trig_R_Boom (Dummy)
call FlushChildHashtable(udg_Hash,i)
call FlushChildHashtable(udg_Hash,StringHash("x"))
call DestroyTimer(timerer)
set Dummy = CreateUnit(GetOwningPlayer(Caster),'u001',xd,yd,0)
call UnitApplyTimedLife(Dummy,'BTLF', 2)
set Caster = null
set Dummy = null
else
set xd=GetUnitX(Dummy)+10*Cos(GetUnitFacing(Dummy)*bj_DEGTORAD)
set yd=GetUnitY(Dummy)+10*Sin(GetUnitFacing(Dummy)*bj_DEGTORAD)
call SetUnitPosition(Dummy,xd,yd)
endif
set Caster = null
set Dummy = null
endfunction

function Trig_R_Actions takes nothing returns nothing
local unit Caster = GetTriggerUnit()
local location Target = GetSpellTargetLoc()
local real xt = GetLocationX(Target)
local real yt = GetLocationY(Target)
local real xc = GetUnitX(Caster)
local real yc = GetUnitY(Caster)
local real Angle = bj_RADTODEG * Atan2(yt-yc,xt-xc)
local unit Dummy = CreateUnit(GetOwningPlayer(Caster),'u000',xc,yc,Angle)
local timer timerer = CreateTimer()
local integer i = GetHandleId(timerer)
call SetUnitAnimation( Dummy, "Birth" )
call UnitApplyTimedLife(Dummy,'BTLF', 1)
call SaveUnitHandle(udg_Hash,i,3,Dummy)
call SaveUnitHandle(udg_Hash,i,4,Caster)
call SaveUnitHandle(udg_Hash,StringHash("x"),1,Caster)
call TimerStart(timerer, 0.01, true, function Trig_LOCAL_TimerR)
call RemoveLocation(Target)
set Caster = null
set Dummy = null
endfunction
Карта:

Принятый ответ

call SaveInteger(udg_Hash,StringHash("x"),1,GetPlayerId(GetOwningPlayer(Caster)))

function Trig_R_Boom takes unit d, unit c returns nothing

call GroupEnumUnitsInRange(g, x, y,500,Condition(function FilterR))
loop
	set f = FirstOfGroup(g)
    exitwhen f == null
    call UnitDamageTarget(c,f,400, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
    call GroupRemoveUnit(g,f)
endloop

В конце функции Trig_R_Actions( )не обнулена переменная типа timer.
- Короче, вот:
function Trig_LOCAL_TimerR takes nothing returns nothing
    local  timer   timerer =  GetExpiredTimer( )
    local  integer i       =  GetHandleId( timerer )
    local  unit    Caster  =  LoadUnitHandle( udg_Hash, i, 4 )
    local  unit    Dummy   =  LoadUnitHandle( udg_Hash, i, 3 )
    local  real    xd      =  GetUnitX( Dummy )
    local  real    yd      =  GetUnitY( Dummy )
    local  group   g       =  null
    local  unit    f       =  null

    if ( GetWidgetLife( Dummy ) < 0.405 ) then

        set  g  =  CreateGroup( )

        call GroupEnumUnitsInRange( g, xd, yd, 500.0, null )
        loop
            set  f  =  FirstOfGroup( g )
            exitwhen ( f == null )
            call GroupRemoveUnit( g, f )

            if IsUnitEnemy( f, GetOwningPlayer( Caster ) ) and ( GetWidgetLife( f ) > 0.405 ) and ( not IsUnitType( f, UNIT_TYPE_STRUCTURE ) ) and ( not IsUnitType( f, UNIT_TYPE_FLYING ) ) then
                call UnitDamageTarget( Caster, f, 400.0, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null )
            endif

        endloop

        call DestroyGroup( g )
        set  g  =  null

        call FlushChildHashtable( udg_Hash, i )
        call DestroyTimer( timerer )
        set  Dummy  =  CreateUnit( GetOwningPlayer( Caster ), 'u001', xd, yd, 0.0 )
        call UnitApplyTimedLife( Dummy, 'BTLF', 2.0 )

    else
        set  xd = GetUnitX( Dummy ) + 10.0 * Cos( GetUnitFacing( Dummy ) * bj_DEGTORAD )
        set  yd = GetUnitY( Dummy ) + 10.0 * Sin( GetUnitFacing( Dummy ) * bj_DEGTORAD )
        call SetUnitPosition( Dummy, xd, yd )
    endif

    set  timerer  =  null
    set  Caster   =  null
    set  Dummy    =  null
endfunction


function Trig_R_Actions takes nothing returns nothing
    local  unit     Caster   =  GetTriggerUnit( )
    local  real     xt       =  GetSpellTargetX( )
    local  real     yt       =  GetSpellTargetY( )
    local  real     xc       =  GetUnitX( Caster )
    local  real     yc       =  GetUnitY( Caster )
    local  unit     Dummy    =  CreateUnit( GetOwningPlayer( Caster ), 'u000', xc, yc, bj_RADTODEG * Atan2( yt - yc, xt - xc ) )
    local  timer    timerer  =  CreateTimer( )
    local  integer  i        =  GetHandleId( timerer )

    call SetUnitAnimation( Dummy, "Birth" )
    call UnitApplyTimedLife( Dummy, 'BTLF', 1.0 )
    call SaveUnitHandle( udg_Hash, i, 3, Dummy )
    call SaveUnitHandle( udg_Hash, i, 4, Caster )
    call TimerStart( timerer, 0.01, true, function Trig_LOCAL_TimerR )

    set  Caster   =  null
    set  Dummy    =  null
    set  timerer  =  null
endfunction
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
7
6 лет назад
0
quq_CCCP, а, ну если фильтр, тогда да. А почему это я должен забыть про одновременность?
1
21
6 лет назад
1
вообще в варкрафте ниче не происходит одновременно это да
но все-таки с глобалками бывают побочки типа ты ее перезапишешь в триггере и там произойдет что-то на что среагирует уже совершенно другой триггер, где юзается та же глобалка
очень интересная порнуха бывает
так что хз сами см как удобнее и лучше
2
7
6 лет назад
Отредактирован WoLLFeR
2
ClotPh, я о том же, без глобалки иногда не обойтись, когда нужно установить её в других триггерах, а вот локалки как раз подходят для того, чтобы их на разок юзнуть, обнулить и забыть.
0
21
6 лет назад
Отредактирован scopterectus
0
WoLLFeR, Ваш фильтр перебирал каждого воина в группе, это означает, что функция фильтр будет вызвана столько раз, сколько воинов в группе. Если там будет 100 воинов, то функция будет вызвана 100 раз и создаст те самые локалки тоже 100 раз, и всё это произойдет за один кадр. Поэтому, quq_CCCP, порекомендовал Вам использовать глобалки, так как они не будут создаваться при каждом запуске. Разумеется, их нужно правильно использовать, чтобы они не перезаписывались.
0
7
6 лет назад
0
ScopteRectuS, я понял, и всё же условием обойтись проще, хотя в таком случаи выбираются ВСЕ юниты в области и только при условии им наносит урон, а остальных просто перебирает и удаляет.
0
21
6 лет назад
Отредактирован scopterectus
0
WoLLFeR, ну фильтр тоже перебирает ВСЕХ юнитов, но добавляет в группу лишь тех, кто прошёл проверку. А в цикле мы уже перебираем юнитов, которые записались в группу.
0
7
6 лет назад
0
ScopteRectuS, вот этого я не знал. Значит циклом проще всё-таки.
0
32
6 лет назад
0
WoLLFeR, почему проще?
0
7
6 лет назад
Отредактирован WoLLFeR
0
quq_CCCP:
WoLLFeR, почему проще?
Потому что в фильтр я не могу обратиться, я не могу поставить туда условие связанное с кастером, потому что фильтр вызывается в таймере. Мне нужно, чтобы именно кастеру засчитывали нанесённый урон(он убивает(чтобы опыт зачислился), он своим не наносит урон). Либо я что-то не знаю, точнее как сделать иначе (внимательно на код в вопросе взгляните, мне приходится сохранять кастера, чтобы фильтр настроить, разве это удобно?). А как показал ScopteRectuS, используя всего лишь условие сразу видно, что не нужны лишние функции и могу непосредственно выбрать всё связанное с кастером, просто загрузив его хэндл привязанный к таймеру. Если не сложно, расскажите в чём преимущество фильтра, может я просто не знаю?
function FilterR takes nothing returns boolean

	local integer p = LoadInteger(udg_Hash,StringHash("x"),1)
	
return  IsPlayerEnemy(Player(p), GetOwningPlayer(GetFilterUnit())) and GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING)
endfunction
Чтобы не заниматься подобной ерундой (не приводящей к нужному результату), как на коде сверху, проще будет сделать так, без фильтра и всё сразу:
   if ( GetWidgetLife( Dummy ) < 0.405 ) then

        set  g  =  CreateGroup( )

        call GroupEnumUnitsInRange( g, xd, yd, 500.0, null )
        loop
            set  f  =  FirstOfGroup( g )
            exitwhen ( f == null )
            call GroupRemoveUnit( g, f )

            if IsUnitEnemy( f, GetOwningPlayer( Caster ) ) and ( GetWidgetLife( f ) > 0.405 ) and ( not IsUnitType( f, UNIT_TYPE_STRUCTURE ) ) and ( not IsUnitType( f, UNIT_TYPE_FLYING ) ) then
                call UnitDamageTarget( Caster, f, 400.0, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null )
            endif
Да, я понимаю, что с глобалкой я решу это, но что, если мне хотелось бы обойтись без неё? Предположим, если я юзаю спелл, он через таймер нанесёт урон через 1 секунду с помощью глобалки Кастера, но а если в этот момент, точнее где-то в 0.5 после моего юза, юзает кто-то еще, тогда глобалка запишет последнего кастера и урон в результате двух юзов сочтется для последнего кастера. Я так могу от своего же скилла подохнуть.
0
21
6 лет назад
0
Да вроде нет разницы какой-то существенной.. Разве что, через фильтр это официальный способ, который нам предоставили BLIZZARD.

Предположим, если я юзаю спелл, он через таймер нанесёт урон через 1 секунду с помощью глобалки Кастера, но а если в этот момент, точнее где-то в 0.5 после моего юза, юзает кто-то еще, тогда глобалка запишет последнего кастера и урон в результате двух юзов сочтется для последнего кастера. Я так могу от своего же скилла подохнуть.
В глобалки данные нужно записать прямо перед тем, как будет вызвана функция фильтра. И нужно уследить за тем, чтобы в функции фильтра не было функций, которые создают новые потоки, а если создают, то нужно смотреть, чтобы в новом потоке не использовалась это глобалка. Новые потоки могут вызываться при использовании следующих функции: TimerStart( ), ExecuteFunc( ), TriggerEvaluate( ), TriggerExecute( ), ForGroup( ) и другие, а также новые потоки могут создаваться при совершении события какого-либо триггера (например, приказ кастануть способность запустит новый поток, если имеется триггер на отлов каста способностей). Новые потоки имееют приоритет над уже работающими, поэтому сперва исполнится код в новом потоке, а после этого возобновится поток, который остановился из-за запуска нового потока.
0
32
6 лет назад
0
фильтр намного быстрее перебирает...
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.