Добавлен quq_CCCP
Есть задача крепить к обьекту ссылки на множество триггеров, точное кол-во которых не известно. Своего рода "Group", только для триггеров.
Собственно структуры vJass позволяют создавать структуры с массивами на N элементов, а так же есть хештаблицы с ключам id + N.
Хотелось бы послушать народ о способах реализации этой задачи, мб я что-нибудь упустил?
Собственно структуры vJass позволяют создавать структуры с массивами на N элементов, а так же есть хештаблицы с ключам id + N.
Хотелось бы послушать народ о способах реализации этой задачи, мб я что-нибудь упустил?
Принятый ответ
У меня к каждому юниту крепится ссылка на объект структуры, в которой есть отдельные списки для разных типов баффов. Если же бафф имеет два разных эффекта, то ссылка на него хранится в двух списках. При удалении конфликтов не возникает, потому что при удалении бафф удаляет все ячейки, которые были к нему привязаны, а ячейки удаляются линейно.
Ячейка списка
struct MBSNode
readonly MinionBuff buf
readonly integer number
thistype prev = 0
thistype next = 0
method basicInit takes MinionBuff buf, integer number returns nothing
static if ErrorDetectionEnabled_MBSNode then
if this == 0 then
call ErrorOccurred("Error: MBSNode struct has run out of indexes. Current amount of indexes is 8190", "MBSNodeError")
endif
endif
set this.buf = buf
set this.number = number
endmethod
method removeFromList takes nothing returns nothing
if prev != 0 then
set prev.next = next
endif
if next != 0 then
set next.prev = prev
endif
endmethod
endstruct
struct MBSNodeReal extends MBSNode
real value = 0.
endstruct
struct MBSNodeInt extends MBSNode
integer value = 0
endstruct
struct MBSNodeIntNReal extends MBSNode
integer value = 0
real rvalue = 0.
endstruct
Структура, в которой содержится списки, называется MBS, в ней есть счётчик количества баффов, это нужно для определения, какой бафф был добавлен раньше.
Списки в основном задаются таким макросом.
Списки в основном задаются таким макросом.
Список
// Name - имя типа баффа
// ntyp - тип ячейки
// values - если есть значения у баффа
// bool - если значения типа boolean
// null - нуль для заданного типа значений.
//! textmacro MBSList takes Name, ntyp, values, type, bool, null
private MBSNode$ntyp$ head$Name$
readonly integer buffsAmount$Name$ = 0
method add$Name$Buff takes MinionBuff obj returns MBSNode$ntyp$
local MBSNode$ntyp$ node = MBSNode$ntyp$.create()
if buffsAmount$Name$ == 0 then
set head$Name$ = node
else
set node.next = head$Name$
set head$Name$.prev = node
set head$Name$ = node
endif
set BuffCounter = BuffCounter + 1
set buffsAmount$Name$ = buffsAmount$Name$ + 1
call node.basicInit(obj, BuffCounter)
//call DebugMsg("Current amount of $Name$ buffs is " + I2S(buffsAmount$Name$) + ".")
return node
endmethod
method remove$Name$Buff takes MBSNode$ntyp$ node returns nothing
set buffsAmount$Name$ = buffsAmount$Name$ - 1
if head$Name$ == node then
set head$Name$ = node.next
endif
static if $values$ then
static if $bool$ then
set booleanAmount$Name$ = booleanAmount$Name$ - node.value
set total$Name$Bonus = booleanAmount$Name$ > 0
else
set total$Name$Bonus = total$Name$Bonus - node.value
endif
endif
call node.removeFromList()
call node.destroy()
//call DebugMsg("Current amount of $Name$ buffs is " + I2S(buffsAmount$Name$) + ".")
endmethod
static if $values$ then
static if $bool$ then
private integer booleanAmount$Name$ = 0
readonly boolean total$Name$Bonus = false
else
readonly $type$ total$Name$Bonus = $null$
endif
method change$Name$Value takes MBSNode$ntyp$ node, $type$ value returns nothing
static if $bool$ then
local integer v = B2I(value)
set booleanAmount$Name$ = booleanAmount$Name$ - node.value + v
set total$Name$Bonus = booleanAmount$Name$ > 0
set node.value = v
else
set total$Name$Bonus = total$Name$Bonus - node.value + value
set node.value = value
endif
endmethod
endif
//! endtextmacro
В этой же системе определяется текущее кол-во брони, уязвимый ли он или нет, уровень замедления или ускорения, и пр.
При удалении объекта системы удаляются и все навешанные баффы.
При удалении объекта системы удаляются и все навешанные баффы.
Удаление
// Макрос ниже также используется для удаления баффов конкретного типа при каких-то обстоятельствах.
// pos - бафф положительный.
// Ячейки удаляются с удалением баффа.
//! textmacro DeleteBuffs takes Name, first, pos
static if $first$ then
local MBSNode node = head$Name$
local MBSNode temp
else
set node = head$Name$
endif
loop
exitwhen node == 0
set temp = node.next
$pos$if node.buf.buffdata.negative then
call node.buf.destroy()
$pos$endif
set node = temp
endloop
//! endtextmacro
...
method onDestroy takes nothing returns nothing
//! runtextmacro DeleteBuffs("EoT", "true", "//# ")
//! runtextmacro DeleteBuffs("Shield", "false", "//# ")
//! runtextmacro DeleteBuffs("MoveSpeed", "false", "//# ")
//! runtextmacro DeleteBuffs("Stun", "false", "//# ")
//! runtextmacro DeleteBuffs("Persistence", "false", "//# ")
//! runtextmacro DeleteBuffs("PhysArmor", "false", "//# ")
//! runtextmacro DeleteBuffs("MagcArmor", "false", "//# ")
//! runtextmacro DeleteBuffs("Armor", "false", "//# ")
//! runtextmacro DeleteBuffs("PhysImmune", "false", "//# ")
//! runtextmacro DeleteBuffs("MagcImmune", "false", "//# ")
//! runtextmacro DeleteBuffs("Protection", "false", "//# ")
//! runtextmacro DeleteBuffs("Invul", "false", "//# ")
call DebugMsg("MinionBuffStorage " + I2S(this) + " is deleted.")
endmethod
Сами баффы.
Каждый бафф - отдельная структура, которая наследуется от общей.
Каждый бафф - отдельная структура, которая наследуется от общей.
Бафф
struct MinionBuff
integer typ
Minion target
unit source
CustomPlayer owner
MinionBuffData buffdata
integer currticks = 0
boolean isRunning = false
MBSNode node1
MBSNode node2
MBSNode node3
//! runtextmacro CustomTimer("t", "Timer", "MinionBuff", "false")
method onDestroy takes nothing returns nothing
call DeleteTimer()
call RemoveSavedInteger(Hash, target.id, typ)
call UnitRemoveAbility(target.minion, buffdata.effectid)
set source = null
call DebugMsg("MinionBuff " + I2S(this) + " is deleted.")
endmethod
method basicInit takes Minion host, unit src, CustomPlayer p, integer T returns nothing
static if ErrorDetectionEnabled_MinionBuff then
if this == 0 then
call ErrorOccurred("Error: MinionBuff struct has run out of indexes. Current amount of indexes is 8190", "MinionBuffError")
endif
endif
set typ = T
set target = host
set source = src
set owner = p
set buffdata = p.minion_buffdata[T]
call InitTimer()
call SaveInteger(Hash, target.id, T, this)
//call DebugMsg("MinionBuff " + I2S(this) + " is created.")
endmethod
...
endstruct
Может быть всего 3 разных типа эффекта у баффа, пока максимум было 2.
Примеры баффов
struct BuffMultishotDoT extends MinionBuff
method onCreate takes nothing returns nothing
set node1 = target.addEoTBuff(this)
endmethod
method onDestroy takes nothing returns nothing
call target.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, false)
return currticks == 0
endif
return true
endmethod
static method launch takes Minion m, Tower caster returns nothing
// target, sourceunit, owner, name, neg, disabl, chkowne, args
//! runtextmacro InitBuff("m", "caster.tower", "caster.owner", "MultishotDoT", "true", "false", "false", "")
call startPeriodic(buffdata.startticks)
endmethod
endstruct
struct BuffMultishotSlow extends MinionBuff
method onCreate takes real slow returns nothing
set node1 = target.addMoveSpeedBuff(this, slow)
endmethod
method onDestroy takes nothing returns nothing
call target.removeMoveSpeedBuff(node1)
endmethod
static method launch takes Minion m, Tower caster, real slow returns nothing
//! runtextmacro InitBuff("m", "caster.tower", "caster.owner", "MultishotSlow", "true", "true", "false", "slow")
call start()
endmethod
endstruct
Макрос InitBuff инициализирует любой бафф, но вопрос не об устройстве баффов, потому опустим его полное устройство. При вызове баффа (метод launch) делаются некоторые проверки, если всё хорошо, то создаётся объект и вызывается его метод onCreate, где сохраняются ссылки на его ячейки.
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Про unit indexer что такое?
Я думал о примерно таком коде:
Ред. PT153
Списки в основном задаются таким макросом.
При удалении объекта системы удаляются и все навешанные баффы.
Каждый бафф - отдельная структура, которая наследуется от общей.
Есть другие вещи - псевдоконтроль, помните мою статью про руны и как сделать дуель легион команнедра, в от личии от всяких пауз, скрытия карт команд и прочего говна которое городят картоделы, реализация с помощью мемхака выше не на одну голову. Т.к работает по механике стандартных дизейблов варкрафта, т.е карта команд не скрывается, вы неможите управлять юнитов но его очередь приказов не сбивается и приказы добавленные во время дизейбла будут выполнены после его окончания, если это конечно возможно, это чертовски удобно и правильно. Вспомните доту айсфрога, герой Axe заставляет атаковать себя с помощью одной абилки а при ваших приказах атаки у него прокает пассивка хотите вы в него зарядить спелл чтобы отталкнуть его от себя или застанить а неможите, его агр таймер который тупо приказывает атаковать его много раз в сек, когда агр закончится - вы стоите и ниче не делайте, нужно отдавать приказ чето делать, а жмакать кнопки во время агра себе дороже - чаще прокает пассивка!
Мемхаком же возможно сделать все похожие способности по человечески, выдаем флаг стана и следим за то что юнит получил приказ цель-обьект, юнит умер, время вышло, спелл рассеяли. Приказ нужно ослеживать обязательно, иначе на юнита под флагом стана перестанут действовать станы и все что основано на оглушении (все стандартные дизейблы не дающие двигаться + триггерная пауза), поэтому нам нужно узнать что юниту суют приказ стана, тут же убрать флаг стана, тогда стандартный дизейбл на него подействует и он будет в нем до его окончания, а как отследить его конец ! - правильно, по урону в 0 ед. и текущему приказу, триггер еще и урон должен отслеживать, какая туча событий на 1 юнита. Тут именнно и нужны динамические триггеры а таймеры не подходят по ряду причин.
Надеюсь я объяснил почему именно триггеры, поверь отравление наносящие только урон или какую-нибудь фрост нову я на триггерах бы не делал.