• Новые темы в этом разделе публикуются автоматически при добавлении файла в менеджер ресурсов.
    Ручное создание новых тем невозможно.

Мануал doordata.txt - формат и описание параметров

Алиос

Выдающийся
Участник
Сообщения
44
Розыгрыши
0
Решения
1
Репутация
184
Реакции
55
Баллы
1 338
В данном гайде постараюсь описать все возможные параметры, встречающиеся в данном файле. Очевидные - кратко, более интересные - подробно. Также, для подобных мне разрабов яв, которым ПТС-ка нужна разве что для парса данных оттуда для своей явы и всяческих тестов - дам несколько полезных лайфхаков, которые могут кому-то пригодиться.

Для начала опишу несколько используемых мною терминов, чтобы сократить текст, а у вас не возникало вопросов, что же имелось ввиду.
Параметры - то, что разделено табами в строке двери и имеет формат param_name=value.
Неименованный параметр - то, что разделено табами, но указывается просто значение, без имени параметра и знака равенства.
Обязательный параметр - тот параметр, который указан абсолютно у каждой двери.
Опциональный параметр - параметр, который указан не у всех дверей, а по необходимости. Предполагается, что имеет какое-то значение по умолчанию.
Pts_name - так я называю имя различных объектов, указываемое в скриптах, pch и АИшках ПТС сервера. Указывается в квадратных скобках примерно в таком формате skill_name = [s_power_strike11]. Как правило, оно используется для взаимодействия объектов в, так сказать, внутренней реализации сервера и не отображается в клиенте. В этом, кстати, основное отличие от явы, в ней обращение к скиллам, нпц, дверям и т.д., как правило, идет по ID, а в PTS - по pts_name напрямую [name], либо через получение ид из pch в формате @name.
Boolean-like - параметры, имеющие лишь 2 варианта значений - 0 и 1, что соответствует логическим false и true.
Enum-like - параметры, которые могут иметь ограниченное количество вариантов значений. Например, параметр type.


Итак, начнем с перечисления и краткого описания параметров.

pts_name - единственный неименованный параметр. Всегда указывается сразу после "door_begin".
type - Обязательный enum-like параметр. Тип двери. Его суть станет более понятна при перечислении вариантов значений.
  • normal_type - подавляющее большинство дверей. Ничего необычного.
  • wall_type - стены замков. Особенность - можно бить лишь осадными големами.
  • parent_type - некое связующее звено, объединяющее двери в группу. По сути, он не спавнится в игровом мире, не имеет id, содержит крайне минимальное количество параметров, которые укажу позже. Вся группа открывается либо закрывается синхронно. Примеры: 3 дверцы в комнату Core в Круме либо 2 двери к Анаису в МОСе.
  • child_type - собственно, групповые двери, имеющие связь с родителем(предыдущий тип). В каком-то смысле, они несамостоятельны, так как все попытки открыть такую дверь перенаправляются родителю, там производятся необходимые проверки, и родитель сам открывает всю группу и также сам закрывает по времени либо иным причинам. Показательным примером может выступить эффект скилла ключика к дверям Анаиса в МОС-е.
    effect = {{i_unlock;byitem;0;0;0;{{[brilliance_parent];100}}}} - как видим, указано имя родителя, хотя чаще всего указывается имя самой двери. Но, так как родитель не спавнится в мире и, соответственно, его нельзя взять в таргет, попытка открытия двери, если она child_type, перенаправляется её родителю.
editor_id - Обязательный параметр для всех, кроме parent_type. Собственно, ID двери, передающийся клиенту в пакете StaticObject. Видимо, по нему клиент определяет, какую текстуру использовать и т.д.

parent - Параметр, обязательный к указанию для всех child_type. Собственно, указатель на родителя.

open_method - Обязательный enum-like параметр. Правда, есть несколько(буквально на пальцах пересчитать) дверей, у которых он не указан. Подозреваю, что дефолтное значение - by_npc. Спобоб открытия двери. Как и с типом, суть будет более понятна при описании возможных вариантов значений.
  • by_npc - такие двери открывают АИшки нпц и, возможно, мейкеров. Иными способами, кроме взаимодействия с npc, игрок не может повлиять на открытие/закрытие двери. Самый популярный метод, использующийся в большинстве случаев.
  • by_click - как правило, это двери кланхоллов. Открываются и закрываются при клике по ним, если игрок состоит в клане, владеющем данной резиденцией и имеет права на это.
  • by_skill - открываются скиллами вроде Unlock у ножей. То есть, скиллами с эффектом вроде "i_unlock;bypc;100;5;0". При подсчете шансов учитывается уровень двери(от 1 до 3) и шансы для каждого уровня, прописанные в эффекте скилла.
  • by_item - по сути, тоже открываются скиллами, только такие скиллы, как правило, прописаны предметам-ключам, а не самим персонажам. Эффект тот же, но с немного другим типом. Вроде "i_unlock;byitem;0;0;0;{{[brilliance_parent];100}}", где перечислены имена конкретных дверей и шансы их открытия(как правило, 100%).
  • by_time - двери, которые открываются и закрываются сами по себе, имея некий цикл по времени. Пример: двери к саб-рб в ТОИ. Само время до открытия\закрытия указывается в двух другим параметрах, до которых дойдем чуть позже.
  • by_skill_item - совмещение методов "by_skill" и "by_item". То есть, такую дверь можно открыть любым из этих способов на выбор.
  • by_time_skill - совмещение методов "by_time" и "by_skill". То есть, дверь живет своей жизнью, но игрок может открыть её скиллом до того, когда она сама откроется по времени.
  • by_cycle - встречается лишь у некоторых дверей на Hellbound. Они открываются/закрываются в ядре сервера, в зависимости от уровня доверия ХБ.

level - Опциональный параметр, который обязательно нужно указывать дверям с open_method-ами "by_item", "by_skill", "by_time_skill" и "by_skill_item". Имеет значения от 1 до 3. Как и указывалось выше, используется при расчете шансов открытия некоторыми open_method-ами.

pos - Обязательный параметр для всех, кроме parent_type. Точка спавна двери. Зачастую в углу, что заметно по тому, куда бежит персонаж при попытке автоатаки двери замка.

range - Обязательный параметр для всех, кроме parent_type. Набор точек, описывающих зону коллизии двери. То есть, участка, через который нельзя пройти или прострелить луком/нюком. Важный момент: зона - трехмерный объект, которому, помимо набора самих точек, необходимо указать минимальную и максимальную высоту(min_z и max_z). Здесь же указаны точки лишь с одной z-координатой - min_z. Откуда же взять max_z? Для этого и нужен наш следующий параметр.

height - Обязательный параметр для всех, кроме parent_type. Высота двери. Именно она плюсуется к min_z каждой точки предыдущего параметра для получения max_z.

check_collision - Опциональный boolean-like параметр с дефолтным значением "1". Если указан "0", то эта дверь не создает непроходимую коллизию, игнорируя параметр "range" и, по сути, выполняет декоративную функцию. Как пример, мост возле Дариона и 3 моста в камаэлевском инсте Nirnil Garden.

hp, physical_defence - Обязательные параметры, хоть и не имеют смысла для parent_type. Без комментариев - тут все понятно по названию.
magical_defence - Аналогично предыдущим двум, но, как ни странно, не указан у многих дверей. Возможно, не указан лишь у неуязвимых дверей, атака которых не предполагается. Скорее всего, имеет дефолтное значение, но какое - не знаю.

default_status - Открыта ли дверь по умолчанию сразу после её спавна. Варианты: open и close. Как ни странно, опциональный параметр. На адвексах эпилога не прописан у 277 дверей. Думаю, дефолтное значение - close.

is_open - Опциональный boolean-like параметр. Указан лишь у нескольких дверей замков Аден, Годдард, Руна и Шутгарт. Означает, что эти двери всегда открыты, но закрываются на время осады. Кстати, эти двери не могут открывать владельцы замков ни кликом, ни через Door Manager-ов, но последние позволяют тпшиться за них. Правда, не знаю, доступен ли диалог с менеджерами во время осады.

hp_showable - Boolean-like параметр, определяющий показывать ли хп двери при взятии её в таргет. По идее, должен бы быть обязательным параметром, но по факту не указан у дверей замков\фортов\осаждаемых кланхоллов. Так как их хп отображается всегда, предположу, что дефолтное значение - 1. Также этот параметр связан со статусом неуязвимости двери и невозможности её атаковать, хотя технически это все разные переменные. Скорее всего, изначально статус "unbreakable"(неуязвимость двери и невозможность её атаковать) ставится тем дверям, у которых hp_showable=0, однако позже unbreakable-статус может быть переопределен ядром и, возможно, АИшками, что наглядно видно по дверям осаждаемых резиденций. Также на такую механику намекает вот эта ГМ-команда: "//set_door_status door [init|breakable|unbreakable|open|close]".

targetable - Опциональный boolean-like параметр с дефолтным значением "1". Определяет, можно ли брать дверь в таргет.

instantzone_id - Опциональный параметр. ID шаблона инста, в котором может спавниться данная дверь. Указывается у дверей, которые спавнятся только в инстах. Важный момент: editor_id и даже pts_name могут повторяться у двух дверей в этом файле. Связано это с тем, что, скорее всего, для обычных и инстовых дверей технически используются разные хранилища. В реальном мире не спавнятся инстовые двери, а в инстах - обычные. Соответственно, при старте сервера спавнятся все обычные двери, а при создании инста берутся двери, у которых значение данного параметра совпадает с ID его шаблона. Совпадение id дверей легко объяснимо на примере СОД-а. Так поход к Тиаде - инст, а вторая стадия(сбор кристаллов атрибута) - нет. Соответственно, для клиента там одни и те же двери с одинаковыми текстурами и точками спавна, но отличающиеся другими параметрами. Например, открытостью/закрытостью, возможностью брать их в таргет и т.д.

close_time - Время(в секундах), через которое дверь автоматически закроется после её открытия(вне зависимости от метода). Если параметр не указан - дверь не будет автоматически закрываться.

open_time, random_time - эти два параметра всегда работают в связке. Обязательно указываются для дверей с open_method = by_time и by_time_skill. То есть, двери с указанными выше open_method-ами автоматически откроются через (open_time + (случайное число от 0 до random_time)) секунд после закрытия.

inactive_time - откат на попытки открыть дверь скиллом или ключом. По умолчанию, отсутствует. То есть, указанное время после открытия двери игроком, она не будет реагировать на попытки её открытия. На открытие не игроком(само по себе по времени, AI-шками npc и т.д.) данный откат не влияет, хоть и счетчики времени автооткрытия/автозакрытия при вмешательстве игрока перезапускаются.

master_name, master_open_event, master_close_event - опциональные параметры, всегда работающие в связке друг с другом. Ещё один способ связи нескольких дверей между собой. Работает так: дверь при открытии/закрытии рассылает ивент всем дверям, у которых она прописана в атрибуте master_name. В свою очередь, master_open_event - как реагировать на открытие двери-мастера, а master_close_event - как реагировать на её закрытие. Варианты последних двух параметров: "act_open" и "act_close". Примеры:
"master_name=[hubris_3F_001] master_open_event=act_open master_close_event=act_close" - означает, что данная дверь будет открываться и закрываться синхронно с дверью [hubris_3F_001]
"master_name=[sunrise] master_open_event=act_close master_close_event=act_open" - означает, что когда открывается дверь [sunrise] - эта дверь закрывается, а когда мастер-дверь закрывается - эта дверь открывается. То есть, открытие\закрытие этой двери с мастерской зеркально.

stealth - Опциональный параметр, указанный у крайне малого количества дверей и всегда со значением "0". Точное его значение мне неизвестно, однако предполагаю, что двери, у которых указан данный параметр, являются валидной целью для скиллов с "affect_object=hidden_place".

need_to_log - Опциональный boolean-like параметр, указанный со значением "0" у дверей в Кубе Кратеи. Видимо, использовался корейцами для дебага. Вам вряд ли пригодится :)

emitter_id - На закуску оставил, пожалуй, самый интересный и редко реализованный на явах параметр. Он опционален, указан лишь у нескольких дверей в одной локации Камаэль виладжа, одном его инсте и у двери к химерам на хб. Отвечает за накладываемый на прозрачную текстуру двери красивый анимированный эффект. Попытки прописать другое значение, не как изначально в doordata.txt приводили к тому, что дверь становилась прозрачной. что говорит о том, что в клиенте те или иные эффекты как-то тесно связаны со своими дверьми. Суть в том, что если указан эмиттер, то вместе с пакетом инфы о двери отсылается ещё один доп. пакет, содержащий emitter_id и статус active(0 или 1), который и указывает клиенту, какой эффект прикрепить к двери.
Класс того самого доп. пакета:
Java:
package ngs.game.network.serverpackets;

import ngs.game.network.serverpackets.L2GameServerPacket;

/**
 * Format: cdс
 * Пример: CF 81 DD 24 00 01
 */
public class EventTrigger extends L2GameServerPacket
{
    private static final String _S__CF_EventTriger = "[S] CF EventTriger";
    private final int _trapId;
    private final boolean _active;

    public EventTrigger(final int trapId, final boolean active)
    {
        _trapId = trapId;
        _active = active;
    }

    @Override
    protected final void writeImpl()
    {
        writeC(0xCF);
        writeD(_trapId); // trap object id
        writeC(_active ? 1 : 0); // trap activity 1 or 0
    }

    @Override
    public String getType()
    {
        return _S__CF_EventTriger;
    }
}

Пример, где его отправлять с моей сборки. Адаптируете под свою уже сами :)

Класс L2Player:
Java:
public GArray<L2GameServerPacket> addVisibleObject(final L2Object object, final L2Character dropper)
{
    // Код метода
    if(object.isDoor())
    {
        final L2DoorInstance door = object.getAsDoor();
        result.add(new StaticObject(door));
        if(door.getEmitterId() > 0)
            result.add(new EventTrigger(door.getEmitterId(), !door.isOpen()));
        return result;
    }
    // Код метода
}

Класс L2DoorInstance:
Java:
@Override
public void broadcastStatusUpdate()
{
    final StaticObject su = new StaticObject(this);
    final EventTrigger emitterPacket = _emitterId > 0 ? new EventTrigger(_emitterId, !isOpen()) : null;
    for(final L2Player player : L2World.getAroundPlayers(this))
        if(player != null)
        {
            player.sendPacket(su);
            if(emitterPacket != null)
                player.sendPacket(emitterPacket);
        }
}

На этом у меня всё. Всем спасибо за внимание и, надеюсь, меня не сильно закидают помидорами за осквернение PTS-раздела java-кодом, пусть даже и под спойлером :)
 

Назад
Сверху Снизу