Есть задача крепить к обьекту ссылки на множество триггеров, точное кол-во которых не известно. Своего рода "Group", только для триггеров.
Собственно структуры 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, где сохраняются ссылки на его ячейки.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
16
динамически триггеры - топ. Они ж используются для регистрации конкретного ивента, они не нужны на всю продолжительность, они всегда MUI и безупречно работают, отключаются, чистятся. Не умеешь - не берись, как говорится.
Никаких лимитов там не существует
32
PT153, тебе точно нужно отследить EVENT_WIDGET_DEATH, и ни фреймом раньше, иначе бага. Так же получение других приказов на основе стана для взаимодействия с морфами.
28
тебе точно нужно отследить EVENT_WIDGET_DEATH, и ни фреймом раньше, иначе бага. Так же получение других приказов на основе стана для взаимодействия с морфами.
Ну у меня у юнита есть ссылки на все прикреплённые объекты, т. о. при смерти все навешанные баффы удаляется, а сами баффы сделаны на таймерах.
32
PT153, ну это у тебя, тут несколько другая реализация, т.к всеравно нужны триггеры, то использовать их хочтися по максимуму.
Ну есть идея аттачить как либо к юниту все эти триггеры и при диспеле экзекутить их, в кадом триггере есть функция утилизации и обнуления эффекта.
Ну вот и решил послушать людей о реализации подобного, нам нужно добавлять, удалять триггеры из списка который прикреплен к юниту, а так же хранить на юните весь этот массив триггеров.
30
Ну есть идея аттачить как либо к юниту все эти триггеры и при диспеле экзекутить их, в кадом триггере есть функция утилизации и обнуления эффекта.
Основная идея я как понимаю, по хэндлу юнита получить все навешанные на него триггеры? Можно использовать unit indexer и работать с массивами. Можно также использовать хэштаблицы с обёрткой и также работать как с массивами.
32
NazarPunk, идея сделать это удобно и гибко, а то что это можно сделать с помощью цикла + хт или структур я знаю.
Про unit indexer что такое?
Я думал о примерно таком коде:
код
struct BuffData 
    trigger array buffs[50]
    boolean array flags[50]
    integer count
    
    method Dispel takes boolean flag returns boolean
        local integer nIndex = 1
        
        if flag then
        loop
            exitwhen nIndex > this.count
            call TriggerExecute( this.buffs[nIndex] )
            set nIndex = nIndex + 1
        endloop
        else
           loop
            exitwhen nIndex > .count
            if not this.flags[nIndex] then
                call TriggerExecute( this.buffs[nIndex] )
            endif
            set nIndex = nIndex + 1
        endloop
        endif
        
        return true
    endmethod
    
    method AddBuff takes trigger trg, boolean flag returns boolean
        set this.count = this.count + 1
        
        if this.count > 50 then 
            return false
        endif
        
        set this.buffs[this.count] = trg
        set this.flags[this.count] = flag
        
        return true
    endmethod
    
    method RemoveBuff takes trigger trg returns boolean
        local integer nIndex = 1
        local boolean NotFound = true
        loop 
            exitwhen nIndex > this.count
            if trg == this.buffs[nIndex] then
                set this.buffs[nIndex] = null
                set this.flags[nIndex] = false
                set NotFound = false
                exitwhen true
            endif
            set nIndex = nIndex + 1
        endloop
        
        if NotFound then
            return false
        endif
        
        loop
         exitwhen nIndex > this.count
          set this.buffs[nIndex] = this.buffs[nIndex+1] 
          set this.flags[nIndex] = this.flags[nIndex+1] 
          set nIndex = nIndex + 1
        endloop
        
        set this.count = this.count - 1
        
        return true
    endmethod
    
endstruct
Пока банальное ветвление ифами, ибо сначала было таких триггеров немного и я не заваривался над реализацией.
30
Про unit indexer что такое?
Присваивает юнитам уникальный custom value.

И паралельно можно держать массив ваших структур на нужных юнитов.
function GetBuffStruct(unit u) -> BuffData {
	integer id = GetUnitCustomData(u);
	
	if (GlobalBuffData[id] == null) {
		GlobalBuffData[id] = BuffData.create();
	}
	return GlobalBuffData[id];
}

// любое событие
GetBuffStruct(GetTriggerUnit()).addBuff('rawcode'); 
28
У меня к каждому юниту крепится ссылка на объект структуры, в которой есть отдельные списки для разных типов баффов. Если же бафф имеет два разных эффекта, то ссылка на него хранится в двух списках. При удалении конфликтов не возникает, потому что при удалении бафф удаляет все ячейки, которые были к нему привязаны, а ячейки удаляются линейно.
Ячейка списка
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, где сохраняются ссылки на его ячейки.
Принятый ответ
32
PT153, насчет станов и почему негодится таймер - когда мы вешаем на юнита стан с помощью мемхака мы обязаны убедится что он жив и не сдохнет, прежде чем мы снимем с него оглушение, иначе начнется трешь и угар. В краце - есть событие - виджет помер, оно же и юзается стандартными бафами чтобы снять свой эффект ровно на фрейм раньше того как юнит реально умрет, это важно для многих эффектов, даже смерть с крестом перерождения снимает все баффы с цели (от дефолтных абилок варкравта).
Есть другие вещи - псевдоконтроль, помните мою статью про руны и как сделать дуель легион команнедра, в от личии от всяких пауз, скрытия карт команд и прочего говна которое городят картоделы, реализация с помощью мемхака выше не на одну голову. Т.к работает по механике стандартных дизейблов варкрафта, т.е карта команд не скрывается, вы неможите управлять юнитов но его очередь приказов не сбивается и приказы добавленные во время дизейбла будут выполнены после его окончания, если это конечно возможно, это чертовски удобно и правильно. Вспомните доту айсфрога, герой Axe заставляет атаковать себя с помощью одной абилки а при ваших приказах атаки у него прокает пассивка хотите вы в него зарядить спелл чтобы отталкнуть его от себя или застанить а неможите, его агр таймер который тупо приказывает атаковать его много раз в сек, когда агр закончится - вы стоите и ниче не делайте, нужно отдавать приказ чето делать, а жмакать кнопки во время агра себе дороже - чаще прокает пассивка!
Мемхаком же возможно сделать все похожие способности по человечески, выдаем флаг стана и следим за то что юнит получил приказ цель-обьект, юнит умер, время вышло, спелл рассеяли. Приказ нужно ослеживать обязательно, иначе на юнита под флагом стана перестанут действовать станы и все что основано на оглушении (все стандартные дизейблы не дающие двигаться + триггерная пауза), поэтому нам нужно узнать что юниту суют приказ стана, тут же убрать флаг стана, тогда стандартный дизейбл на него подействует и он будет в нем до его окончания, а как отследить его конец ! - правильно, по урону в 0 ед. и текущему приказу, триггер еще и урон должен отслеживать, какая туча событий на 1 юнита. Тут именнно и нужны динамические триггеры а таймеры не подходят по ряду причин.
Надеюсь я объяснил почему именно триггеры, поверь отравление наносящие только урон или какую-нибудь фрост нову я на триггерах бы не делал.
28
Надеюсь я объяснил почему именно триггеры, поверь отравление наносящие только урон или какую-нибудь фрост нову я на триггерах бы не делал.
Понял, было интересно. А что по поводу той системы прикрепления, что я предложил? Таймеры в ней не используются, они только в самих баффах.
32
PT153, ну я пока ниче не делал, пока обдумываю че к чему, т.к довольно много кода копипастить и переделывать нехотелось бы, если интересна подробная реализация в моей карте текущей системы - могу скинуть .
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.