"Бафф" в ковычках, т.к. мне требуется только таймер, и ссылка на функцию.
Что то вроде:
код
есть родительский класс бафф
инициализация чилд классов
BuffIni(){
Buff(1,func)
Buff(2,func)
..//ид класса, функция
}
функция добавления бафа юниту:
AddBuff(integer unitid, integer buffid, real time){
если юнит имеет бафф то продлеваем жизнь таймера
if IsUnitHasBuff(unitid,buffid) {
добавить время таймеру
}else{
создать бафф с таймером
создать эффект и привязать к ид юнита (юзер дата)
выполнить функцию бафа
}
Функция удаления
DestroyBuff(integer unitid, integer buffid){
выполнить функциию удаления бафа
}
Использую подобную системку, слегка кривую.. для способностей, реализованную через хеш и массив триггеров с передачей аргументов через глобалки.

Баффов же у меня было до этого былр немного, и использовались примитивные заглушки. Однако в последнее время их кол-во стало разрастается, поэтому появилась необходимость в нормальной системе.

Отсюда вопрос. Может я велосипед изобретаю, и есть ли готовые решения?

Не особо смотрел раньше в сторону структур, хотя может и зря, но проблема то в основном с ссылкой на функцию, так как тип code с массивом не работает.

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

Нет универсальных решений нет и врятли будут, тут все надо своими руками, лучше для некоторых баффов юзать триггеры чтобы отследить смерть событием TriggerRegisterDeathEvent а так же применение диспелящих способностей на цель, либо самой целью.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
19
6 лет назад
0
Похожие вопросы:

ответ
Ты никак не заставишь одиноаковые заклинания стакнуться. Делай спеллы-пустышки, баффы вешай аурами, которые потом будешь удалять, эффекты заклинания делай триггерно. Иначе никак.
Единственное, что ещё, применимое именно к лечению - можно создавать несколько фонтанов жизни или юнитов с их способностью и регенить сильнее за счёт одной и той же способности.
ответ
Darknessay:
quq_CCCP:
что мешает юзнуть берсерк, манащит, канал, да хоть виндвалк?
Мешает то, что берсерк и виндвалк уже использованы, переключаемые абилки - хурма, а канал не моментальный.
Ты станишь юнита, какая тебе разница?
Канал пойдет с тем же успехом, юнит его кастанет в любом случае.
Переключаемые абилки работают нормально, если уметь немного искать и читать, как их юзать в качестве простых есть инфа в статьях на форуме.
Еще всякие вееры ножей, не сбивают приказ идти куда либо. Юзай его в качестве основы.
ответ
Pick every unit in range [250] matching condition [бафф спелла]
Всё что находится внутри данного блока произойдёт столько раз, сколько воинов находится внутри выбранной группы. Обратиться к воину можно через Picked Unit ( GetEnumUnit( ) ). Если Вам нужно добавить событие на смерть именно этих воинов, то прямо здесь внутри блока добавляете их в событие триггера, выбрав их через Picked Unit, или сохраняете их в переменные.

Также можно не сохранять каждого воина, а занести их в отдельную группу. А вместо проверки:
Условие: Dying unit = Aim [Integer A]
проверяете, находится ли воин в группе.
ответ
8gabriel8:
Это тот же принцип для второго пункта, мне казалось, что могут быть способы изящнее. Лучше по другим пунктам подскажите.
первый вопрос так и не понял, насчет третьего вопроса:
там весь прикол в ивентах, есть начало когда наводишь на цель, тогда даже анимация не проигрывается и мана не забирается.
Приводит в действие это уже когда ману сняло и проигралась анимация.
Где то был текст на всё это, но я не могу найти.
Ну а далее чекаешь уровень бафа у цели, если он больше 0 - значит хиляешь и удаляешь баф
Хотя возможно это я неправильно понял, можно просто отловить начало каста абилки и восстанавливать ману триггерно.

0
32
6 лет назад
0
Нет универсальных решений нет и врятли будут, тут все надо своими руками, лучше для некоторых баффов юзать триггеры чтобы отследить смерть событием TriggerRegisterDeathEvent а так же применение диспелящих способностей на цель, либо самой целью.
Принятый ответ
1
21
6 лет назад
1
Не особо смотрел раньше в сторону структур, хотя может и зря, но проблема то в основном с ссылкой на функцию, так как тип code с массивом не работает.
Можно использовать function interface вместо code array, в нём можно сохранять даже функции, которые требуют что-то.
1
28
6 лет назад
1
Зависит от того, что тебе нужно от этой системы.
В карте, что я сейчас делаю, отличная система кастомных баффов (баффы WarCraft 3 я не использую вообще). Её я собираюсь выложить и рассказать, когда создам проект на XGM.
Система долго эволюционировала, потому человеку, который её никогда не видел, возможно будет сложно её понять.

Вкратце.
Есть структура MinionBuff, в ней есть следующие функции.
раскрыть
    stub method tickAction takes nothing returns boolean
        return true
    endmethod
    
    static method tickEnd takes nothing returns nothing
        local thistype this = GetCustomTimer()
        set currticks = currticks - 1
        if tickAction() then
            call destroy()
        endif
    endmethod
    
    method extendTicks takes integer addticks returns nothing
        set currticks = currticks + addticks
        if currticks > buffdata.maxticks then
            set currticks = buffdata.maxticks
        endif
    endmethod
    
    method startWithPeriod takes real period returns nothing
        set currticks = buffdata.startticks
        call UnitAddAbility(target.minion, buffdata.effectid)
        call TimerStart(t, period, buffdata.periodic, function thistype.tickEnd)
        call DebugMsgIf(isStopped(), "MinionBuff " + I2S(this) + " is started.")
        set isRunning = true
    endmethod
    
    method start takes nothing returns nothing
        call startWithPeriod(buffdata.period)
    endmethod
    
    method startPeriodic takes integer addticks returns nothing
        if isRunning then
            call extendTicks(addticks)
        else
            call start()
        endif
    endmethod
endstruct
Объект этой структуры не создаётся, создаются объекты конкретных баффов (которые тоже структуры). Есть два типа баффов - периодический (максимальное количество тиков больше 1) и непериодический. Я знаю, какой бафф периодический, а какой нет, потому периодические баффы стартуются функцией startPeriodic, а непериодические - start. Их таймер запускается в функцию tickEnd, где вызывается tickAction. Если у баффа эта функция перезаписана, то выполнится его версия функции. Если нет, то вернётся правда, и бафф будет удалён.
Примеры баффов.
раскрыть
struct BuffMultishotDoT extends MinionBuff
    method onCreate takes nothing returns nothing
        set node1 = target.buffs.addEoTBuff(this)
    endmethod
    
    method onDestroy takes nothing returns nothing
        call target.buffs.removeEoTBuff(node1)
    endmethod

    method tickAction takes nothing returns boolean
        local Tower dd
        if UnitExists(source) then
            set dd = GetUnitUserData(source)
            call dd.dealDamage(target, AbilMultishot(dd.abil).dot, AbilMultishot.dottype)
            return currticks == 0
        endif
        return true
    endmethod
    
    static method launch takes Minion m, Tower caster returns nothing
        //! runtextmacro InitBuff("m", "caster.tower", "caster.owner", "MultishotDoT", "true", "false", "false", "")
        call startPeriodic(buffdata.startticks)
    endmethod
endstruct

struct BuffMultishotSlow extends MinionBuff
    method onCreate takes nothing returns nothing
        set node1 = target.buffs.addMoveSpeedBuff(this)
    endmethod
    
    method onDestroy takes nothing returns nothing
        call target.buffs.removeMoveSpeedBuff(node1)
        call target.updateMoveSpeed()
    endmethod
    
    static method launch takes Minion m, Tower caster, real slow returns nothing
        //! runtextmacro InitBuff("m", "caster.tower", "caster.owner", "MultishotSlow", "true", "true", "false", "")
        call m.alterMoveSpeed(node1, slow)
        call start()
    endmethod
endstruct

Можешь использовать перезапись stub метода, а можешь использовать интерфейс функций, реализованы они одинаково: в обоих используется массив триггеров.
0
17
6 лет назад
0
Есть два типа баффов - периодический (максимальное количество тиков больше 1) и непериодический.
Не проще было бы задавать бафф просто длительностью и интервалом между периодическим эффектом? В 6 секунд длительностью и 1.5 секундным интервалом срабатывает 4 раза. Вроде на порядок проще получается.
0
28
6 лет назад
Отредактирован PT153
0
Не проще было бы задавать бафф просто длительностью и интервалом между периодическим эффектом? В 6 секунд длительностью и 1.5 секундным интервалом срабатывает 4 раза. Вроде на порядок проще получается.
Я задаю длительностью, максимальным количеством тиков и начальным количеством тиков. Период вычисляется делением длительности на начальное количество тиков. Такие параметры необходимы для того, что система позволяла создавать баффы, которые изначально имеют 1 тик, но при повторном наложении могут увеличивать кол-во тиков вплоть до указанного максимума.
Что же касается вопроса простоты и удобства - дело личное. Мне было удобнее сделать так.
Я не показал БД, где прописываются свойства баффов, потому что не посчитал это нужным. Вопрос ведь про готовые системы баффов. Я ответил, что наличие такой системы зависит от требований к ней. Также я хотел привести рабочий пример псевдомассива code, о чём также спрашивалось.
2
26
6 лет назад
2
как написал ссср, единого универсального решения нет и не будет, нужно делать систему нужную под конкретно твои задачи
дополню своим примером такой системы
сначала я сделал описание всех свойств бафов, затем сделал базу данных самих бафов, а затем уже к ней систему наложения и снятия
на баф делается своя структура
struct MyBuffData
        real duration, tick = 0.
        int cell, level, state, total = 0
        bool Unpause = false
        unit source, victim
        
        real effect_over_time_value, effect_over_time_delay
        bool effect_over_time_type
        string effect_over_time_sfx, effect_over_time_sfx_point
        
        int param[5]
        real param_value[5]
        
        
        
        void get_level_data(int level){
            int c = 0
                this.level = level
                    if this.level == 1 {
                        while(c++ < 5) {
                            this.param[c-1] = WhichState_1[this.cell][c]
                            this.param_value[c-1] = WhichStateValue_1[this.cell][c]
                        }
                    }
                    elseif this.level == 2 {
                        while(c++ < 5) {
                            this.param[c-1] = WhichState_2[this.cell][c]
                            this.param_value[c-1] = WhichStateValue_2[this.cell][c]
                        }
                    }
                    elseif this.level == 3 {
                        while(c++ < 5) {
                            this.param[c-1] = WhichState_3[this.cell][c]
                            this.param_value[c-1] = WhichStateValue_3[this.cell][c]
                        }
                    }
                    elseif this.level == 4 {
                       while(c++ < 5) {
                            this.param[c-1] = WhichState_4[this.cell][c]
                            this.param_value[c-1] = WhichStateValue_4[this.cell][c]
                        }
                    }
                    elseif this.level == 5 {
                        while(c++ < 5) {
                            this.param[c-1] = WhichState_5[this.cell][c]
                            this.param_value[c-1] = WhichStateValue_5[this.cell][c]
                        }
                    }
        }
        
        void set_level(int level){
            if level > 0 {
                SetUnitAbilityLevel(this.victim, BuffId[this.cell][1], level)
                SetUnitAbilityLevel(this.victim, BuffId[this.cell][2], level)
                this.get_level_data(level)
            }
        }
        
        void set_duration(real time){
                if time == -1. {
                    time = BuffTime[this.cell][this.level]
                }
            this.duration = time
        }
        
        
        static thistype create(unit a, unit b, int l){
            thistype this = thistype.allocate()
                this.level = l
                this.source = a
                this.victim = b
                this.Unpause = false
                this.tick = 0.
                this.total = 0
            return this
        }
        
    endstruct
и делается типа менеджера который учитывает все активные баффы и смотрит нужно ли им еще висеть и производить эффект
кат
private void BuffsUpdate(){
        int index = 0, C1 = 1
        UD src
        
        if Stack == 0 { return }
        
            loop {
                exitwhen index >= Stack
                index++
                    if BuffStack[index].victim == null {
                        BuffStack[index].destroy()
                        BuffStack[index] = BuffStack[Stack]
                        Stack--
                    }
            }
            
            index = 0
            loop {
                exitwhen index >= Stack
                index++
                
                src = GetData(BuffStack[index].victim)
				if (src > 0 and (BuffStack[index].duration <= 0. or GetHp(BuffStack[index].victim) <= 0.045 or GetUnitAbilityLevel(BuffStack[index].victim, BuffId[BuffStack[index].cell][2]) == 0)) {
				
				и так далее...

в итоге выглядит типа
//=================================
        // curse
            BuffId[17][1] = 'A00F'; BuffId[17][2] = 'B01E'
            BuffType[17] = TYPE_MAGICAL
            BuffPolar[17] = BUFF_TYPE_NEGATIVE
            BuffTime[17][1] = 12.
            BuffRank[17] = 5
            WhichState_1[17][1] = OUTPUT_DAMAGE_SCALE
            WhichStateValue_1[17][1] = 0.5
            DebuffChance[17][1] = 75.
        //=================================
проклятие которое уменьшает исходящий урон цели на 50%, OUTPUT_DAMAGE_SCALE описана в структуре юнита и влияется через воздействие бафа
...

там где мне нужно я делаю просто
AddBuffToUnit(target, caster,  'A00F', 1, false)

карту прикрепил если понадобится
Загруженные файлы
1
25
6 лет назад
1
Всем спасибо! По изучаю, что как работает.

Для непериодических баффов у меня были обычные жасовые функции с изменением нужных переменных героя, и аттач эфекта с таймером удаления.
Для остальных юзалась другая логика. В общем, не то что бы прям мешанина была, для большинства я тупо копировал шаблон и менял атрибуты.
Но столкнулся с проблемой что бафф может быть наложен дважды, и получался просто стак. Но минус в том что висели лишние эффекты.
А простая проверка на имеющийся бафф требовала нахождения таймера который уже мог быть запущен, то бишь нужно было хранить его хендл, а там еще всякие коллизии начинали возникать.
Поэтому захотелось все таки покурить структуры и придумать более изящный вариант.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.