Хотелось бы знать какие пути решения без использования отдельных массивов/хэштэйбла видит кто-либо для разрешения ситуации следующего характера:
Скилл поражает цели в выбранной зоне и оставляет даммика, находясь возле которого юниты, задетые заклинанием, получают урон. В один момент времени может существовать хоть с десяток таких даммиков, но они должны наносить повреждения лишь целям, задетыми заклинанием их создателя. Проверка на бафф не актуальна, поскольку два таких кастера будут перебивать баффы друг друга.
В данный момент под каждый каст скилла выделяется перерабатываемая группа на время жизни этого скилла, которая содержит юнитов, задетых этим конкретным кастом, а также группа, содержащие все цели, пораженные этими же заклинаниями кастера. Поскольку нельзя добавить в группу юнита, который уже содержится в ней, нерешенным остается вопрос о том, как же удалять юнита из второй группы, только когда он не содержится в первых группах. Сейчас на ум приходит только выделение, скажем, 64 перерабатываемых элементов параллельных массивов юнит+интегер, куда в интегер записывается число групп, в которых содержится юнит. Солюшн весьма хреновый, поскольку придется каждый раз искать этого юнита в 64 элементах массива...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
20
7 лет назад
0
полный бред которого у меня нету и который хз зачем нужен
да и размер массива всегда фиксирован и равен 8192(2 в 13 степени)
Кто-то из нас явно понимает другого не-правильно. Либо оба :> Но я вижу в твоем описании свое решение.
nvc123:
Diaboliko:
Таймер реализован как отдельный поток работы одного глобального, так что использую ресурсы, находящиеся в простОе.
это не понял вообще
сколько таймеров(игровых объектов), с каким периодом работают таймеры и каким образом ты реализуешь свои таймеры?
Ну если тебе хочется взглянуть на индусский порнокод...
1 таймер для работ с нулевым временем(захил после нанесения урона и т.п.)
scope ZeroTimeEvent

    globals
        constant integer ZTEArraySize = 64//Even 32 is alot, 64 is too much! Exactly what I need!
        timer Zero//Used for 0. sec uses
        integer ZTECurrent = 0
        unit array ZTEUnits[ZTEArraySize]
        integer array ZTEIntegers[ZTEArraySize]
        real array ZTEReals[ZTEArraySize]
        trigger array ZTETriggers[ZTEArraySize]
    endglobals
    
    function ZeroTimeEvent takes nothing returns nothing
            loop
                set  ZTECurrent = ZTECurrent - 1
                call TriggerExecute( ZTETriggers[ZTECurrent] )
                exitwhen ZTECurrent == 0
            endloop
    endfunction
    
    #define ZTEAddUnit(u) = {
        set  ZTEUnits[ZTECurrent] = u
    }
    
    #define ZTEAddInteger(i) = {
        set  ZTEIntegers[ZTECurrent] = i
    }
    
    #define ZTEAddReal(r) = {
        set  ZTEReals[ZTECurrent] = r
    }
    
    #define ConfirmZTE(trig) = {
        set  ZTETriggers[ZTECurrent] = trig
        set  ZTECurrent = ZTECurrent + 1
        call TimerStart( Zero, ZeroTime, false, function ZeroTimeEvent )
    }
    
    
    
endscope
Плюс немного отличающаяся версия(но руки не доходят один момент пофиксить), с выделением "потока" таймера пот статический, этого
ужаса
scope GlobalTimerEvent

    globals
        constant integer       GTE002ArrayMaxSize = 64
        constant integer       GTE002ArrayOverflow = 63//While < then this - do stuff else - start from zero
        constant integer       GTE002ArrayOverflowExit = 62//If something > this, then start from zero
        constant integer       GTE010ArrayMaxSize = 125
        constant integer       GTE010ArrayOverflow = 124
        constant integer       GTE010ArrayOverflowInitExit = 123//Whatever you wanna call it like. Its for proper init :P
        constant integer       GTE010ArrayOverflowExit = 119//5 ticks per second with increment of 5 are limited at 125 variables([124])
                                                            //  (starting from zero). So 124 - 5 = exit so it gets up to 124, but no more.
        constant integer       GTEDataArrayMaxSize = 2048
        constant integer       GTEDataArrayOverflow = 2047
        constant integer       GTEDataArrayOverflowExit = 2046
        constant integer       GTEDataArrayCheckOverflow = 2000//Проверка на переполнение запускается после добавления всех нужных объектов
                                                               //   могут теряться до 46 переменных, но памяти на них хватит :)
        constant real          GlobalTimerTickRate = 0.02
        constant real          GlobalTimerTicksPerSecond = 50.
                 timer         GlobalTimer
                 integer       GTE002NextEvent = 0//Ячейка, в которую будет произведена запись
                 integer       GTE010NextEvent = 0//Ячейка, в которую будет произведена запись
        //constant integer       GTE010MaxLoopStartingValue = 4
                 integer       GTE010CurrentLoopStartingValue = 0//Why not to make it go from 4 to zero, avoiding the need of var. above?
                 integer       TimedLoopOf3 = 0//Switches between 0,1,2 every GlobalTimer tick
                 integer       LoopOf3 = 0//Increased whenever registering a knockback event. Switches between 1,2,3. If I'll make it to switch between 1 and 2 only, there will  be no need really for local variable(its barely profitable now already)
                 integer       GTENextVariable = 0
                 integer       GTELoopCounter = 0
                 integer array GTE002Loops             [GTE002ArrayMaxSize]
                 integer array GTE002CurrentTime       [GTE002ArrayMaxSize]
                 integer array GTE002Timeout           [GTE002ArrayMaxSize]
                 trigger array GTE002TriggerToExecute  [GTE002ArrayMaxSize]
                 integer array GTE002FirstVariable     [GTE002ArrayMaxSize]
                 integer array GTE010Loops             [GTE010ArrayMaxSize]
                 integer array GTE010CurrentTime       [GTE010ArrayMaxSize]
                 integer array GTE010Timeout           [GTE010ArrayMaxSize]
                 trigger array GTE010TriggerToExecute  [GTE010ArrayMaxSize]
                 integer array GTE010FirstVariable     [GTE010ArrayMaxSize]
                 integer array GTEIntegers             [GTEDataArrayMaxSize]
                 real    array GTEReals                [GTEDataArrayMaxSize]
        //Как это устроено:
        //Массив  64 переменных - для экзекута с периодом 0.02
        //Массив 128 переменных - для экзекута с периодом 0.10 (делятся на 5 периодов для снижения нагрузки).
        //Два массива по 1024 переменных - для сохраняемых данных.
        //Массив в 1024 переменные, ссылающийся на первую ячейку в дате. По дефолту использовал столько же массивов дабы ссылались
        //  каждый на свой массив, но 1024 значения и так дохрена, плюс я могу использовать одновременно 2 переменные на халяву
        //  короче это, имхо, самый оптимальный вариант по расходу памяти, хотя и усложняет кодинг, да.
        //Поскольку два массива - массивы Real и Integer, может возникнуть вопрос как же сейвить юнитов?
        //  Я использую базу данных, так что Integer может ссылаться на базу.
    endglobals
    
    //Эти дефайны использованы, в общем то, только потому что система переделывается 2 раз.
    //Первый раз был хэштейбл.
    //Второй раз были 3 массива с 3 поинтерами.
    //И вот сейчас я решил сделать все ну совсем кошерно. Хотя названия все-равно оставляют желать мне пойти в задницу.
    
    #define GTE002InitVariableAdding() = {
                                             set GTE002FirstVariable[GTE002NextEvent] = GTENextVariable
                                         }
    #define GTE010InitVariableAdding() = {
                                             set GTE010FirstVariable[GTE010NextEvent] = GTENextVariable
                                         }
    #define GTEIncreaseVariablePointer() = {
                                             set  GTENextVariable = GTENextVariable + 1
                                         }
    #define GTEIncreaseVariablePointer(n) = {
                                             set  GTENextVariable = GTENextVariable + n
                                         }
    #define GTEAddInteger(variable1) = {
                                           set  GTEIntegers[GTENextVariable] = variable1
                                       }
    #define GTEAddReal(variable1) = {
                                        set  GTEReals[GTENextVariable] = variable1
                                    }
    #define GTECommitVariableAdding() = {
                                            if ( GTENextVariable > GTEDataArrayCheckOverflow ) then
                                                set  GTENextVariable = 0
                                            endif
                                        }
    
    function GTE002AddEventAndCommit takes integer periods, integer timeOut, trigger triggerToExecute returns nothing
        set  GTE002Loops[GTE002NextEvent] = periods
        set  GTE002CurrentTime[GTE002NextEvent] = 0
        set  GTE002Timeout[GTE002NextEvent] = timeOut
        set  GTE002TriggerToExecute[GTE002NextEvent] = triggerToExecute
        if ( GTE002NextEvent < GTE002ArrayOverflow) then
            set  GTE002NextEvent = GTE002NextEvent + 1
        else
            set  GTE002NextEvent = 0
        endif
    set  triggerToExecute = null
    return
    endfunction
    
    function GTE010AddEventAndCommit takes integer periods/*AKA amount of ticks*/, integer timeOut/*AKA tickrate*/, trigger triggerToExecute returns nothing
        set  GTE010Loops[GTE010NextEvent] = periods
        set  GTE010CurrentTime[GTE010NextEvent] = 0
        set  GTE010Timeout[GTE010NextEvent] = timeOut
        set  GTE010TriggerToExecute[GTE010NextEvent] = triggerToExecute
        if ( GTE010NextEvent < GTE010ArrayOverflow) then
            set  GTE010NextEvent = GTE010NextEvent + 1
        else
            set  GTE010NextEvent = 0
        endif
    set  triggerToExecute = null
    return
    endfunction
    
    function GTE002Tick takes nothing returns nothing
        loop
            if ( GTE002Loops[GTELoopCounter] > -1 ) then
                if ( GTE002CurrentTime[GTELoopCounter] < GTE002Timeout[GTELoopCounter] ) then
                    set  GTE002CurrentTime[GTELoopCounter] = GTE002CurrentTime[GTELoopCounter] + 1
                else
                    call TriggerExecute(GTE002TriggerToExecute[GTELoopCounter])
                    if ( GTE002Loops[GTELoopCounter] > 0 ) then
                        set  GTE002CurrentTime[GTELoopCounter] = 0
                        set  GTE002Loops[GTELoopCounter] = GTE002Loops[GTELoopCounter] - 1
                    else
                        set  GTE002Loops[GTELoopCounter] = -1
                    endif
                endif
            endif
            exitwhen GTELoopCounter > GTE002ArrayOverflowExit
            set  GTELoopCounter = GTELoopCounter + 1
        endloop
        return
    endfunction
    
    function GTE010Tick1 takes nothing returns nothing
        loop
            if ( GTE010Loops[GTELoopCounter] > -1 ) then
                if ( GTE010CurrentTime[GTELoopCounter] < GTE010Timeout[GTELoopCounter] ) then
                    set  GTE010CurrentTime[GTELoopCounter] = GTE010CurrentTime[GTELoopCounter] + 1
                else
                    call TriggerExecute(GTE010TriggerToExecute[GTELoopCounter])
                    if ( GTE010Loops[GTELoopCounter] > 0 ) then
                        set  GTE010CurrentTime[GTELoopCounter] = 0
                        set  GTE010Loops[GTELoopCounter] = GTE010Loops[GTELoopCounter] - 1
                    else
                        set  GTE010Loops[GTELoopCounter] = -1
                    endif
                endif
            endif
            exitwhen GTELoopCounter > GTE010ArrayOverflowExit
            set  GTELoopCounter = GTELoopCounter + 5
        endloop
        return
    endfunction
    
    function UpdateCustomBars takes unit u returns nothing
        local integer i = 0
        local real maxhp = GetUnitState( u,UNIT_STATE_MAX_LIFE )
        local real hp = GetWidgetLife(u)
        local integer color = R2I( 100. * hp / maxhp + 0.5 )
            loop
                call SetUnitAnimationByIndex( UnitDBHeroHPBar[i], color )
                if ( color > 50. ) then
                    call SetUnitVertexColor( UnitDBHeroHPBar[i], ( 100 - color ) * 6, 255, 0, 255 )
                else
                    call SetUnitVertexColor( UnitDBHeroHPBar[i], 255, color * 6, 0, 255 )
                endif
                call SetUnitAnimationByIndex( UnitDBHeroMPBar[i], R2I( 100. * GetUnitState( u, UNIT_STATE_MANA )/GetUnitState( u, UNIT_STATE_MAX_MANA ) + 0.5 ) )
                set  hp = 100. * ( hp + UnitDBAdditionalHealth[i] ) / maxhp - 0.5//So it doesnt show up if shield = 0
                if ( hp > 100. ) then
                    set hp = 100.
                endif
                call SetUnitAnimationByIndex( UnitDBHeroSPBar[i], R2I( hp ) )
                exitwhen i > UnitDBPreviousHero
                set  i = i + 1
                set  u = UnitDBUnit[i]
                set  maxhp = GetUnitState( u,UNIT_STATE_MAX_LIFE )
                set  hp = GetWidgetLife(u)
                set  color = R2I( 100. * hp / maxhp + 0.5 )
            endloop
        set  u = null
    endfunction
    
    function GlobalTimerTick takes nothing returns nothing
        local integer i = GTE010CurrentLoopStartingValue
        local unit u = UnitDBUnit[0]
            set  GTELoopCounter = 0
            call GTE002Tick()
            set  GTELoopCounter = i// - 1
            call GTE010Tick1()
            //call GTE010Tick2()//128 is low enough to never reach stream overflow.
            call ImpaleMechanicsOnTimerTick( i )
            if ( GTE010CurrentLoopStartingValue > 0 ) then
                set  GTE010CurrentLoopStartingValue = i - 1
            else
                set  GTE010CurrentLoopStartingValue = 4
                call UpdateCustomBars( u )//its actually not for just a single unit. loop is inside of called func
            endif
            if ( ICTicks < ICPeriod ) then
                set  ICTicks = ICTicks + 1
            else
                set  ICTicks = 0
                call TriggerExecute( gg_trg_SECore )
            endif
            set  i = 0
            loop
                call SetUnitX( UnitDBHeroHPBar[i], GetUnitX(u) )
                call SetUnitY( UnitDBHeroHPBar[i], GetUnitY(u) )
                call SetUnitX( UnitDBHeroMPBar[i], GetUnitX(u) )
                call SetUnitY( UnitDBHeroMPBar[i], GetUnitY(u) )
                call SetUnitX( UnitDBHeroSPBar[i], GetUnitX(u) )
                call SetUnitY( UnitDBHeroSPBar[i], GetUnitY(u) )
                exitwhen i > UnitDBPreviousHero
                set  i = i + 1
                set  u = UnitDBUnit[i]
            endloop
            if ( LoopOf3 < 2 ) then
                set  LoopOf3 = LoopOf3 + 1
            else
                set LoopOf3 = 0
            endif
        set  u = null
        return
    endfunction
    
endscope
Понятия не имею куда заведут комментарии, поэтому предлагаю им не верить. Это было так давно что я уже и не помню как их писал. А с тех пор изменения были, да...
Эти "потоки" так или иначе сидят в простое и персонаж сам по себе ест не много этих "потоков", поэтому я их с легким сердцем пускаю в оборот.
Реализуется поток примерно так:
GTE002InitVariableAdding
             GTEAddInteger( ticks )//amount of ticks(to get to target point)
        set  r = x * lightning_spear_projectile_speed1
             GTEAddReal( r )
             GTEIncreaseVariablePointer
             GTEAddInteger( UGRGetGroup() )
             GTEAddReal( x2 + r )
             GTEIncreaseVariablePointer
             GTEAddInteger( UnitDBAddDummy( CreateUnit( P, lightning_spear_projectile_unit, x2 + lightning_spear_projectile_initial_offset * x, y2 + lightning_spear_projectile_initial_offset * y, angle * RadToDeg ), i ) )
        set  r = y * lightning_spear_projectile_speed1
             GTEAddReal( r )
             GTEIncreaseVariablePointer
             GTEAddInteger( GetPlayerId( P ) )
             GTEAddReal( y2 + r )
             GTEIncreaseVariablePointer
             GTEAddInteger( i )//caster user data for lifesteal
             GTEAddReal( 25. * GetUnitAbilityLevel( u, QLightningSpearId ) + GetUnitAbilityLevel( u, QLightningSpear2Id ) )//Spell damage           //GTEAddReal( x2 )//Unused because of aoe-check usage
             //GTEIncreaseVariablePointer
             //UNUSED INT
             //GTEAddReal( y2 )//Unused because of aoe-check usage
             GTEIncreaseVariablePointer
             GTECommitVariableAdding
        call GTE002AddEventAndCommit( 9999, 0, gg_trg_Lightning_spear_on_tick )
с последующим запуском при звонке потока таймера шапки кода, выглядящей для данного примера как
local integer i = GTE002FirstVariable[GTELoopCounter]
    local integer ticksRemaining = GTEIntegers[i]
    local real r
    //GTEReals[i] contains x offset per step
    set  G = UGRGroups[GTEIntegers[i + 1]]
    set  X2 = GTEReals[i + 1]
    set  U2 = UnitDBUnit[GTEIntegers[i + 2]]//dummy
    //GTEReals[i + 2] contains y offset per step
    set  P = PlayerArray[GTEIntegers[i + 3]]
    set  Y2 = GTEReals[i + 3]
    set  U3 = UnitDBUnit[GTEIntegers[i + 4]]//caster
    set  R = GTEReals[i + 4]
0
28
7 лет назад
Отредактирован nvc123
0
Кто-то из нас явно понимает другого не-правильно. Либо оба :> Но я вижу в твоем описании свое решение.
как ты можешь видеть своё решение если
полный бред которого у меня нету и который хз зачем нужен
зачем информация о числе задеваний таргета Т1 кастами кастера C1?
зачем ты ставишь 64 если оно всеравно преобразуется в 8192?
твоё решение содержит часть моего + кучу ненужного говна
по поводу твоих "потоков"
кривое дерьмо юзающее кучу триггеров и не имеющее никакого смысла
если будет не лень то завтра напишу этот спелл
0
20
7 лет назад
Отредактирован Diaboliko
0
зачем ты ставишь 64 если оно всеравно преобразуется в 8192?
Поиск по 64 меня устраивает. И 64 так и останется 64 в моем случае. Я выделяю это пространство для юнита в этих массивах:
кат
scope UnitGroupEmulation
    globals
        constant integer       UGEAllocatedAmountOfCells = 64//per unit
        constant integer       UGEOverflow = 63
        constant integer       UGEStartingSize = 512
        constant integer       UGEInitExit = 511
        constant integer       UGESizeOfSubArray = 8// 512/64 and round it up to 2^X
        constant integer       UGESizeOfSubArrayExit = 8
                 //integer array UGEAllocatedCells
                 integer array UGEIntegers[UGEStartingSize]
                 unit    array UGEUnits[UGEStartingSize]
                 integer       UGENext = 0//*UGEAllocatedAmountOfCells to get the variable with minimal ID of allocated part of array
                 integer array UGENextUnitOfThisSpace[UGESizeOfSubArray]
    endglobals
    
    function FillUGEArray takes nothing returns nothing
        local integer i = 0
            loop
                set  UGEIntegers[i] = 0
                set  UGEUnits[i] = null
                exitwhen i == UGEInitExit
                set  i = i + 1
            endloop
    endfunction
    
    #define UGEGetSpace( nothing ) = {
             UGENext
        set  UGENextUnitOfThisSpace[UGENext] = UGENext * UGEAllocatedAmountOfCells
        set  UGENext = UGENext + 1
    }
    
    #define UGESimplyAddUnitToSpace( whichUnit, whichSpace ) = {//Base local code upon this. Would be wrong to use it raw.
        set  UGEUnits[UGENextUnitOfThisSpace[whichSpace]] = whichUnit
        if ( UGENextUnitOfThisSpace[whichSpace] == ( whichSpace * UGEAllocatedAmountOfCells ) + UGEOverflow ) then
            set  UGENextUnitOfThisSpace[whichSpace] = whichSpace * UGEAllocatedAmountOfCells
        endif
    }
endscope
и перерабатываю его. Благо я могу делать это без проблем т.к. не пишу на вжассе (scope используется для доп. табуляции)
зачем информация о числе задеваний таргета Т1 кастами кастера C1?
У меня конец времени дебаффа отсчитывается одним из "потоков" таймера, работая аналогично твоему отсчету времени до конца дебаффа. Информация о числе задеваний нужна чтобы из группы всех юнитов, задетых кастом кастера не удалять юнита, если тот содержится еще в какой-то группе(иначе лжедебафф, по-сути, еще активен, но будет снят).
твоё решение содержит часть моего + кучу ненужного говна
На твой взгляд оно, может, и ненужное говно, а в рамках используемых мной систем выглядит весьма адекватным решением.
по поводу твоих "потоков"
кривое дерьмо юзающее кучу триггеров и не имеющее никакого смысла
если будет не лень то завтра напишу этот спелл
Ну почему-же. Решение не кривее использования хэштэйблов. Все переменные сохраняются в глобальных массивах. Мне норм.
2
24
7 лет назад
2
Diaboliko, в варкрафте все массивы 8192, то что ты указал 64 ничего не значит, варкрафт все равно выделит 8192
0
20
7 лет назад
0
Diaboliko, в варкрафте все массивы 8192, то что ты указал 64 ничего не значит, варкрафт все равно выделит 8192
А в моей памяти сидит что они сперва имеют какой-то минимальный сайз, выше которого по степени двойки делается realloc.
0
28
7 лет назад
0
Diaboliko, указания размера массивам это фича вджасса для создания массивов с размером больше 8192
так что твоё 64 при компиляции попросту исчезает
0
18
6 лет назад
0
Вместо массива-счётчика можно использовать userdata.
0
23
6 лет назад
0
а чем не угодил баф яд который стакает.... оптимальный без изобретении велосипеда
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.