Barotrauma

Barotrauma

Ikke nok vurderinger
Моддинг в Barotrauma 2
Av Gleb_St og 1 medarbeidere
Вторая часть гайда по моддингу, которая должна объяснить непонятные моменты, которые могут вызвать вопросы.
   
Utmerkelse
Favoritt
Favoritter
Fjern som favoritt
Небольшое введение
Руководство находится в "сыром" состоянии на данный, я постараюсь время от времени добавлять новые разделы и обновлять информацию.
Прошу понимать, что я не мастер моддинга, а, скорее, любитель. Это руководство, скорее, для начинающих моддеров.
Первую частью руководства нужно посмотреть хотя бы до пункта "Предпоследний этап. Создаём filelist.xml". Я обновлю первое руководство, чтобы оно было актуально для текущей версии Barotrauma.(потом как-нибудь)
Первое руководство:
https://steamcommunity.com/sharedfiles/filedetails/?id=2757066177
Официальное руководство Barotrauma: https://regalis11.github.io/BaroModDoc/
Буду брать оттуда многие вещи.
Как создать любой предмет, который вы хотите
По сути всё, что нужно сделать, это найти в файлах игры похожий код предмета, который Вы хотите сделать.
Например, я хочу сделать оружие, поэтому мне нужно открыть папку Items, затем Weapons и weapons.xml, где находится код почти всего оружия в игре, и скопировать нужный код оружия.
То есть нужно вспомнить какие предметы/существа в игре обладают свойствами, которые вы хотите добавить своему предмету, и посмотреть/скопировать его код.
Как быстро делать проверку кода не выходя из игры
Иногда не все значения в коде удаётся занести правильно с первого раза, поэтому приходится редактировать код, но, при изменении xml файла, игра не воспроизводить эти изменения, оставляя старый код. Но как же это исправить?
1. Выключить и включить мод
Очень простой и очевидный метод. Для этого нужно:
1) Зайти в настройки в главном меню игры
2) Перетащите свой мод в "ЗАПРЕЩЕНЫ ОБЫЧНЫЕ НАБОРЫ" и нажмите "ПРИМЕНИТЬ"
3) Перетащите свой мод в "РАЗРЕШЕНЫ ОБЫЧНЫЕ НАБОРЫ" и нажмите "ПРИМЕНИТЬ"
Данный метод плох только в том случае, если Вам нужно обновить базовый набор, тогда быстрее будет просто перезапустить игру.
Да, многие не знают, что можно просто включить и выключить мод, в результате чего каждый раз перезапускают игру из-за ошибки в коде. Но это можно понять, хоть этот метод и очевиден, никто тебе не скажет, что так можно делать.
И если вы делаете проверку предмета, то разместите предмет в тестовой комнате и сохраните её, чтобы каждый раз не размещать предмет. Но учтите, что бывают изменения, которые требуют заново заспавнить предмет, чтобы изменения вступили в силу.

2. XML Hot Reloader
Данный мод позволяет воспроизводить изменения в коде, не выходя из редактора субмарин, что очень сильно сокращает время подбора правильных значений.(мог тут что-то придумать, так что проверьте описание мода. А так этот мод экономит время больше чем любой другой метод)
https://steamcommunity.com/sharedfiles/filedetails/?id=2940288384

3. reloadpackage
Метод, о котором мне в комментария сказал DrBruhman(спасибо за это ему), вот этот метод схож с XML Hot Reloader, и, в принципе, это самый лучший метод, если вы не хотите скачивать XML Hot Reloader. Сейчас распишу все моменты для работы с ним.
Если вы хотите обновить мод не выходя из редактора субмарин и даже внутри проверки(когда вы тестируете субмарину и как следствие предмет в самой игре), то нужно ввести команду: reloadpackage (имя мода указанный в filelist.xml, то есть при наведении на предмет мода снизу будет название, которое нужно вводить) force
Самый быстрый способ это делать, если лень спавнить предметы через консоль: размещаете на тестовой субмарине свои предметы, запускаете режим проверки, если предмет не работает правильно пишете в консоль эту команду и возвращаетесь в редактор субмарин, а затем сразу переходите опять в режим проверки, если так сделать, размещённые предметы сохранятся и не нужно будет заново их спавнить/размещать.
Особые моменты:
1) Команда чувствительна к регистру поэтому заглавные буквы нужно прописывать.
2) Если название имеет пробел, то запись будет вот такая: reloadpackage "имя мода" force
3) После ввода все предметы удаляться, поэтому нужно иметь наготове spawnitem (identifier предмет) cursor(или inventory).
По факту команду можно написать так: reloadpackage "имя мода" (любая цифра/буква) результат будет один и тот же и не надо писать лишние 4 буквы.
Очень удобно настраивать позицию рук и прочее этими командами.
4) Не все изменения вступят в силу, а что-то может сломаться, поэтому иногда придётся выйти из редактора и ввести эту команду в меню(можно как reloadpackage имя_мода, так и reloadpackage имя_мода force? особо разницы я не видел)
Единственный минус метода в том, что все предметы надо заново спавнить, даже когда вы не в режиме проверки.
5) Если вы изменили filelist.xml нужно включить и выключить мод в настройках, так как этот метод, вроде как, не обновляет filelist.xml, по крайней мере, у меня не обновлял.

Совет если вы решили делать основной набор
Кто не помнит, это та же штука, что и ванильная игра Vanilla.xml, вообще лучше вообще его не делать, а просто сделать Override(о нём ниже в руководстве) всему, что вы добавляете(даже если вы меняете половину файлов игры), так как баротраума постоянно обновляется и очень вероятно, что мод сломается и вам придётся его постоянно обновлять.
Но если мои предупреждения вас не остановили, то объясню как делать быструю проверку таких модов.
Разработчики вместе с методом reloadpackage также добавили reloadcontentfile, что круто, потому что раньше был только reloadcorepackage, которые очень долго обновлял каждый файл игры.
Вот как им пользоваться: reloadcontentfile LocalMods/my_mod_folder/my_mod.xml
Следовательно не получится больше писать %ModDir% для сокращения пути. Данный метод обновляет только определённый xml файл.
Как понимать код игры
На самом деле всё очень просто, обычно название переменных и других штук в коде описывают назначение этой штуки. Для человека, который не знает английского языка, код выглядит как магические слова, поэтому самым простым методом будет скопировать непонятное слово и вставить в переводчик.
Например, <Price storeidentifier="merchantoutpost" minavailable="10"/>
Price - это "цена", следовательно делаем вывод, что эта строчка отвечает за цену предмета.
storeidentifier - это "идентификатор магазина", следовательно это значит, что этот предмет будет продаваться в магазине челика с идентификатором "merchantoutpost".
minavailable - вот тут уже сложнее, так как переводчик неправильно переводит это сочетание слов, тут имеется в виду "minimal available" минимально доступный, просто minimal был сокращён до min, это строчка означает минимальное количество предметов, которое будет продавать продавец.
Ну, смысл Вы поняли, но всё же советую учить английский он понадобится вам не только в моддинге, но и много где ещё.
О ссылках на ванильные файлы
На случай если вы хотите указать путь к ванильной фотографии(чтобы взять текстуру, которая есть в игре), то знайте о таком моменте: barotrauma при обновлениях постоянно меняется и есть вероятность, что указанный путь фото станет недействительным из-за того, что разработчики перенесли файлы куда-то в другое место.
Это к тому, что есть два варианта, как организовать путь до файла, и каждый со своими недостатками:
1. Указать путь к ванильным файлам через Content(то есть указываем на файлы игры). Преимущество в том, что вес мода будет меньше, а недостаток в том, что долговечность мода понижается.
2. Скопировать папку с картинками и оставить нужные и уже через %ModDir% прописывать путь. Преимущество в том, что так мод прослужит дольше и не придется каждое обновление игры выслушивать жалобы о том, что мод не работает. Недостаток понятен - увеличение веса мода, что не есть хорошо.

Много раз встречал в скачанных модах ошибки, которые возникают по этой причине, поэтому решил сделать отдельный пункт про это.
Это, конечно же, не касается основных наборов, там страдать придется каждое обновление, поэтому их никто и не делает.
Примечание
Поскольку принцип создания предметов один и тот же, я буду описывать или объяснять далее только ключевые или непонятные моменты в создании предметов. Поскольку и так понятно, что нужно просто открыть ванильный код игры, скопировать его и отредактировать.
Body, Holdable
Body
<Body width="72" height="40" density="25" />
Body - это это границы предмета. Когда вы нажимаете на предмет в редакторе субмарин Вы увидите белый прямоугольник, этот прямоугольник как раз таки и есть наш Body.
Учтите, что Body очень важно сделать правильным, так как некоторые переменные связаны с Body и если Вы допустите в нём ошибку, то придётся переделывать все остальные переменные тоже.
Как заносить переменные?
width - это ширина, то есть мы её уже получили в sourcerect, так что просто копируем своё значение из sourcerect.

height - это высота, её тоже уже получали.

radius - Вам может встретиться данное значение вместо height, это нужно для круглых объектов, которые могут катиться. Для получение значения, нужно поделить на 2 высоту предмета.

density - это что-то типа удельного веса, влияет на то, как будет предмет себя вести в воде, то есть либо тонуть, либо всплывать. Чем ниже значение, тем быстрее он всплывает, а чем выше, тем быстрее падает.

Holdable
<Holdable slots="RightHand+LeftHand,Any" controlpose="true" aimpos="60,-43" handle1="-95,35" handle2="8,6" holdpos="60,-43" holdangle="-10" msg="ItemMsgPickUpSelect" />
Holdable - означает, что предмет можно держать.
slots - это то, где можно размещать предмет. Если между слотами стоит +, то это значит, что предмет будет размещён в этих двух слотах, то есть на примере видно, что RightHand+LeftHand, это значит, что предмет будет держаться в правой и левой руке.
Если стоит запятая, то это означает, что предмет можно поместить и так и сяк.
Можно либо держать предмет в двух руках, либо положить в инвентарь, то есть Any(так обозначаются слоты инвентаря).

Всего у персонажа есть вот такие слоты: Card(слот карты), Headset(там где наушники), Head(шлемы и прочее), InnerClothes(одежда), OuterClothes(бронежилеты и вод.скафандры), LeftHand(левая рука), RightHand(правая рука), Bag(пояс инструментов), Any(слот инвентаря), HealthInterface(слот для ген.сплайсеров).

controlpose - честно, не знаю за что оно отвечает. При отключении, никаких изменений я не вижу, но лучше оставлять включенной.

aimpos и holdpos - по сути они выполняют одну и ту же функцию, а именно то на каком уровне будет находиться оружие(выше, ниже, левее, правее). aimpos - положение при прицеливании, holdpos - дефолтное состояние.
Как определить значения?
По сути все значения находятся на координатной прямой, где за ед. измерения взят пиксель. Первое значение - это Х, а второе У, следовательно Х определяет положение по горизонтали, то насколько предмет будет держаться(правее(увеличивая значение) или левее(уменьшая значение))
Следовательно У определяет высоту. Чем выше значение, тем выше персонаж будет держать предмет, а чем ниже, тем ниже он будет.

handle1 и handle2 - handle1 - положение правой руки, handle2 - положение левой руки.
Как их определять?
Вот тут и кроется проблема. Никак. Только примерно занося значения и постоянно перезагружаясь, пока не получится правильно расположить руки.(Возможно, уже нашли секретный метод того как это делать. Если вы его знаете, то напишите, я внесу его сюда)
Тут нужно понять ещё и одну вещь, в <Sprite мы указали origin="0.5,0.5", это значит, что мы поставили координатную прямую по середине нашего предмета, и от неё и ведётся отсчёт пикселей для практически всего. Вот примерная зарисовка:
Руки не всегда могут достать до указанных координат, поэтому персонаж будет просто тянутся рукой до этих координат и не доставать до них.

holdangle - угол наклона предмета в градусах. Просто посмотрите градусы окружности и поймёте как определить значение.

msg - это надпись, которая высвечивается при наведении на предмет. Например, в примере, при наведении на предмет, будет высвечиваться сообщение, что предмет можно подобрать на кнопку взаимодействия.
Более лучше объяснение StatusEffect
StatusEffect - это штука, на которой строится вся игра, по сути. Она отвечает за все: афликшоны(иконки, которые отображается в меню здоровья при уроне и бафах и не только), появление гильз, появление пуль, спавн НПС и т.д.
Она состоит из нескольких элементов, основные из которых я объясню.

<StatusEffect type="OnNotContained" target="This" > <Remove /> </StatusEffect>

Target - это цель StatusEffect, то есть все эффекты StatusEffect, которые мы указали, будут применены к указанной цели. В примере это This(в переводе:"это", то есть сам объект, в котором находится StatusEffect)

Type - это условие, при котором StatusEffect будет выполнятся. В данном случае StatusEffect выполнится если target не будет находится в чьём-то инвентаре, а именно не будет находится в контейнере или в инвентаре персонажа/монстра (В общем, если он не находится внутри чего-либо, то эффект выполнится)

То, что между <StatusEffect type="OnNotContained" target="This" > и </StatusEffect>: в данном случае это <Remove />, в переводе означает "Убрать". Всё, что находится внутри такой конструкции будет применено к target, следовательно будет удалён предмет, в котором находится StatusEffect.(Учтите, есть значения, которые находятся в одной строчке с type и target и они тоже могут влиять на предмет. Например, condition="-1" он будет у target отнимать состояние на 1 при условии type. Это к тому, что есть конструкции, которые, например будут записаны вот так: <StatusEffect type="OnNotContained" target="This" condition="-1" delay="1" stackable="false" /> и они будут верными и рабочими. delay="1" - это задержка, перед которой будет выполнен StatusEffect, то есть, примерно, через одну секунду будет уменьшено состояние, а stackable="false" означает, что эффект не будет стакаться(это, конечно, нужно в другом месте объяснять, но всё же поясню. Эта строчка нужна, чтобы delay не выполнялся в промежуток своего выполнения, то есть без stackable="false" во время задержки в одну секунду StatusEffect опять выполнится, а потом опять и опять, в результате вместо -1 состояния в 1 секунду мы получим где-то 30 StatusEffect, которые вычитают 1 и состояние target за секунду улетит вниз очень быстро, поэтому нужно ставить stackable="false", либо делать вместо delay interval, но о их различиях позже))

По итогу наш предмет будет удалён, если он будет не внутри чего-либо.
StatusEffect
StatusEffects — это функция, которую можно использовать для выполнения различных эффектов: изменение состояния какого-либо объекта, создание вещей, воспроизведение звуков, испускание частиц, создание огня и взрывов, повышение навыков персонажей и многое другое.
Типы StatusEffect (type):
Значение
Описание
Always
StatusEffect выполняется каждый кадр постоянно без прекращения, независимо от того в каком состоянии находится предмет/сущность
OnUse
Выполняется, когда предмет используется. Значение «использования» зависит от предмета, но обычно это означает действие, которое происходит, когда предмет держат и щелкают ЛКМ. Действует только для предметов.
OnSecondaryUse
Выполняется, когда держится предмет и удерживается кнопка прицеливания. Действует только для предметов.
OnWearing
Выполняется непрерывно, пока предмет надет. Действует только для надетых вещей.
OnContaining
Выполняется непрерывно, когда определенный Containable(предмет, который можно поместить в ящики, полки и т.д.) находится внутри ItemContainer(ящик, полка и т.д.). Допустимо только для Containables, определенных в компоненте ItemContainer.
OnContained
Выполняется постоянно, когда предмет находится в чьём-то инвентаре. Действует только для предметов.
OnNotContained
Выполняется постоянно, когда предмет НЕ содержится в инвентаре. Действует только для предметов.
OnActive
Выполняется непрерывно, когда элемент активен. Значение «активный» зависит от предмета, но обычно означает, что предмет включен, запитан(энергией) и выполняет то, для чего он предназначен(Например, ручной сонар, если я всё правильно понял. В общем, если Вы включили предмет и он работает, то этот StatusEffect выполняется). Действует только для предметов.
OnFailure
Выполняется при неудачном использовании предмета из-за проваленной проверки навыка(Например, если нужный навык для использования оружия 50, а у персонажа навык = 40, то этот StatusEffect выполняется). Действует только для предметов.
OnBroken
Выполняется, когда Condition(состояние) предмета падает до 0. Действует только для предметов.
OnFire
Выполняется постоянно, когда объект находится в пределах зоны поражения огнем. Выполнятся для предметов и персонажей.
InWater
Выполняется непрерывно, когда сущность погружена в воду. Действительно для предметов и персонажей.
NotInWater
Выполняется непрерывно, когда объект НЕ погружен в воду. Действительно для предметов и персонажей.
OnImpact
Выполняется, когда сущность ударяется обо что-то достаточно сильно. Для предметов порог определяется ItemPrefab.ImpactTolerance,
для персонажей Ragdoll.ImpactTolerance. Действительно для предметов и персонажей.
OnEating
Выполняется постоянно, когда персонаж ест другого персонажа. Действует только для персонажей.(Если я правильно понял, пример: когда кравлер поедает мертвое существо)
OnDamaged
Выполняется, когда сущность получает урон от внешнего источника (affliction(имеется в виду болезнь, или любой affliction, который ухудшает состояние персонажа), которая становится все более серьезной, или предмет, который сам по себе ухудшается, - не считается). Действительно для предметов и персонажей.
OnSevered
Выполняется, когда конечность отрубается. Действует только для конечностей
OnProduceSpawned
Выполняется, когда Items.Components.Growable производит элемент (например, когда растение выращивает плод). Действует только для выращиваемых предметов.
OnOpen
Выполняется при открытии Items.Components.Door. Актуально только для дверей.
OnClose
Выполняется при закрытии Items.Components.Door. Действует только на двери
OnSpawn
Выполняется при появлении объекта. Актуально только для дверей(честно, не понимаю, как это работает)
OnSuccess
Выполняется при успешном использовании предмета на основе проверки навыка. Действует только для предметов.
OnAbility
Выполняется, когда Ability(Способность) (эффект от таланта) активирует StatusEffect. Действует только в Ability(способностях), целью выполнения StatusEffect может быть либо персонаж, либо предмет, в зависимости от типа способности.
OnDeath
Выполняется, когда персонаж умирает. Действует только для персонажей.
Под "Действует только для персонажей)" имеется в виду, что целью выполнения StatusEffect является только персонаж, существо. Если сказано, что только предмет, то то же самое, только для предмета.

Цель StatusEffect (target)
У StatusEffects должна быть цель. Цель определяет, на какую сущность воздействует эффект — часто это то же самое, что и сущность, выполняющая эффект, но это может быть и что-то еще: например, гидрокостюм может иметь статус-эффект, который нацеливается на кислородный баллон внутри него, вызывая его истощение. когда костюм надет.
Значение
Описание
This
Сущность (предмет, персонаж, конечность), в которой определен StatusEffect. В общем где написан StatusEffect, на тот предмет или персонажа действует StatusEffect
Parent
В контексте предмета это значит, что StatusEffect действует на контейнер, в котором находится предмет (если он есть). В контексте конечностей - StatusEffect действует на персонажа, которому принадлежит конечность.
Character
Персонаж, в котором определен StatusEffect. В контексте предметов и атак персонаж, использующий предмет/атаку.
(Если правильно понимаю, то, например, у гаечного ключа есть StatusEffect, который дает кровотечение, то, следовательно, при ударе персонаж, которого ударили, получит кровотечение)
Contained
Элемент(ы), содержащиеся в инвентаре сущности, в которой определен StatusEffect.
NearbyCharacters
Персонажи/существа, которые находятся рядом с сущностью, в которой определен StatusEffect. Расстояние действия определяется с помощью Range.
NearbyItems
Предметы рядом с сущностью, в которой определен StatusEffect. Диапазон определяется с помощью Range.
UseTarget
Сущность, на которой используется предмет/атака.
Hull
Hull, внутри которого находится сущность
StatusEffect 2
Limb
Сущность, на которой используется предмет/атака. В контексте персонажей — одна из конечностей персонажа (указать какую с помощью targetLimbs).
AllLimbs
Все конечности персонажа, на котором применяется эффект.
LastLimb
Последняя конечность персонажа, на котором применяется эффект(не особо понимаю, что является последней конечностью)

Attributes(атрибуты)
Вот тут нужно подробнее. Вспомните пример, который удалял предмет. Ну, так вот Remove это как раз был атрибут, то есть атрибуты - это то, что находится внутри конструкции StatusEffect и выполняют определённую функцию. Они тоже могут иметь определённые значения внутри себя. Например, выдача опыта будет иметь параметр, который отвечает за количество выдаваемого опыта.
Пример такого кода:
<StatusEffect type="OnUse" target="UseTarget" disabledeltatime="true"> <Sound file="Content/Items/Button/button.ogg" type="OnUse" range="500" /> <GiveExperience amount="275" /> </StatusEffect>
Элемент
Тип
Описание
explosion
Explosion
Создает взрыв при срабатывании StatusEffect
removeitem
Удаляет все предметы, на которые нацелен эффект
dropcontaineditems
Выбрасывает все предметы из инвентаря предметов или персонажей, на которые нацелен эффект.
dropitem
Выбрасывает все предметы предметы, на которые нацелен эффект, из инвентарей, в которых они находятся.
removecharacter
Удаляет всех персонажей, на которых нацелен эффект, или, если эффект нацелен на конечности, персонажей, которым принадлежат эти конечности.
breaklimb
Отрубает все конечности, на которые нацелен эффект.
hidelimb
Скрывает все конечности, на которые нацелен эффект.
requireditem
RelatedItem
Определяет элемент(ы), которые должна иметь сущность, выполняющую эффект. Может использоваться по-разному: например. чтобы проверить, есть ли у персонажа что-то в инвентаре или руках, находится ли предмет в контейнере определенного типа или внутри предмета есть предмет определенного типа
requireditems
RelatedItem
"requireditems" идентичен "requireditem"
requiredaffliction
Какой тип afflictions должна получить цель, чтобы эффект StatusEffect был применен. Действителен только для типа эффекта OnDamaged.
affliction
Болезнь, накладываемая на персонажа или конечность, на которую нацелен эффект.
aitrigger
Может использоваться для запуска какого-либо изменения поведения ИИ-персонажа. Применимо только к вражеским персонажам, а не к людям.
talenttrigger
Может использоваться с помощью AbilityConditionStatusEffectIdentifier для реагирования на определенный вид срабатывания эффекта состояния
giveexperience
Может использоваться, чтобы дать очки опыта персонажам, на которых нацелен эффект
giveskill
GiveSkill
Может использоваться, чтобы дать очки навыков персонажам, на которых нацелен эффект.
conditional
Conditional
Некоторое условие, которое необходимо выполнить для выполнения эффекта. См. Conditional страницу для получения дополнительной информации.

Всё это есть в официальном руководстве, ссылка на который есть в начале. Перевёл для тех, кто плохо знает английский + пояснил некоторые моменты, которые могут вызвать сомнения.
В общем, копировать всё руководство баротраумы я не вижу, поэтому в будущем сделаю пункт, в котором объясню, как ориентироваться в в английском руководстве бары и куда какие значения нужно засовывать в StatusEffect.
Вот руководство, чтобы вверх не проматывать: https://regalis11.github.io/BaroModDoc/
Conditional
Conditional позволяет задавать условия, при которых statuseffect выполняются. Воспринимайте это как if в программировании.
Но есть важные нюансы, которые следует знать, чтобы правильно сделать то, что вы хотите.
Давайте разберём на примере эти моменты.
<StatusEffect type="OnWearing" target="Contained,Character" Condition="-0.3" comparison="and"> <Conditional IsDead="false" /> <Conditional hasstatustag="divinghelmet" /> <RequiredItem items="oxygensource" type="Contained" /> </StatusEffect>

Первый момент с target. У нас есть 2 вещи, с которыми "взаимодействует" StatusEffect, а именно Character и Contained (персонаж и то, что в контейнере у предмета). Если мы уберём хоть одну из этих штук, то код не будет правильно работать, потому что Conditional проверяет IsDead и hasstatustag у Character(персонажа), а Condition="-0.3" взаимодействует с Contained, если убрать Contained из target(цели), то и уменьшаться состояние не будет. Как и условия проверяться не будут, если убрать Character.
Для <RequiredItem items="oxygensource" type="Contained" /> не нужен target="Contained" для выполнения. RequiredItem выполняется для предмета, в котором находится StatusEffect и для этой строки target является type="Contained", следовательно то, что находится внутри предмета(просто чтобы вы знали, что если из target убрать Contained, то эта строчка будет выполнятся).
RequiredItem - означает необходимый предмет, то есть нам нужен определённый предмет, чтобы StatusEffect выполнялся.

Второй момент с Conditional. У нас их два(кстати, их можно в 1 строчку записывать, но у меня это никогда не работало, поэтому пишу каждый Conditional отдельно) и тут важна строчка comparison="and", comparison означает "сравнение", то есть как будут работать эти 2 Conditional. Должны ли Conditional выполняться одновременно или тот либо другой, чтобы StatusEffect выполнялся.
есть comparison="and" и comparison="or"
And - означает "И", а Or - "ИЛИ". То есть в нашем случает StatusEffect выполнится только тогда когда все 2 Conditional будут верны(персонаж не мёртв и имеет тэг "divinghelmet"), если бы стоял or, то StatusEffect выполнялся бы если персона был либо не мёртв, либо имел тэг "divinghelmet".

Проверка условия у указанной цели
Пока просто пометка для себя, что сюда нужно добавить про то, как таргетить определенные предметы в Conditional

Навигация в официальном руководстве
Пока в планах
Интерфейс предмета(кнопки и т.д.)
Пока тут ничего нет. В планах на будущее.
Varof
Override
Иногда нужно заметь уже существующий предмет в игре. Для этого и есть Override.(например, заменить текстуру ванильного дробовика, а не создавать новый. Но это не ограничивается предметами, так что менять можно почти всё в игре, например: людей, монстров, стены, биомы, карту)
Чтобы это сделать нужно поместить код того, что мы заменяем, между <Override> и </Override>
Пример:
<Override> <Item identifier="identifier предмета, который заменяем" *значения*> *код* </Item> </Override>
Создание "Основного набора"
Основной набор - это то, что меняет всё или почти всё в игре. Изменения, которые касаются всего или многих элементов. Ванильная игра является основным набором, например.
В filelist.xml нужно указать все направления до ванильных файлов игры и файлов, что вы изменили.
Чтобы создать свой filelist.xml нужно скопировать Vanilla.xml и поменять название(желательно) его можно найти по этому пути: Barotrauma\Content\ContentPackages

Как редактировать файл субмарины
Зачем это нужно? В основном только для установки другой цены.
Чтобы открыть файл нужен любой архиватор файлов. WinRAR, 7-ZIP, например.
Открываем файл субмарины через архиватор, там будет файл, открываем его через любой текстовый редактор(блокнот, например), там в первой строке и можно всё настроить: price(цену), описание, класс, тир и т.д.

Немного задезинформировал людей. В общем, чтобы изменить какие-либо данный, нужно не просто через любой редактор текстовый открывать, нужно именно через тот, который позволит изменить файл в архиве. С WinRAR у меня как-то не получилось это сделать, а вот с 7-ZIP другое дело, поэтому напишу инструкцию как это сделать, используя 7-ZIP
1. Открываем файл субмарины через архиватор 7-ZIP
2. Жмём ПКМ по файлу и находим строчку "Редактировать файл" или нажимаем ЛКМ и F4
3. Изменяем, например, цену (price="1")
4. Сохраняем и выходим, должно появиться окно, которое скажет, что файл был изменён и нужно ли менять его в архиве. Соглашаемся.
Вот и всё. Теперь наша отредаченная субмарина стоит 1 кредит.
О xml файлах и коде игры
XML файлы
Для начала нужно объяснить, что такое xml на самом деле. Сперва приведу определение из интернета, а потом объясню понятными словами, что для нас важно.

XML расшифровывается как eXtensible Markup Language (расширяемый язык разметки).

Протокол XML помогает разработчикам наладить уникальную разметку, адаптировав её под конкретный проект или задачу. Благодаря таким возможностям его и называют расширенным.

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


Лично нам нужно лишь понять то, что xml файлы это не сам код, а данные, которые передаются в код и уже он делает всё в игре. Почему это важно объясню далее.

Barotrauma написана на языке C#
Я не буду описывать, что это объектно ориентированный язык и всё такое, нам важно то, что данные из xml файлов передаются в этот код и посмотреть, что он делает мы можем, так как файлы бары выложены в github.
https://github.com/FakeFishGames/Barotrauma/tree/master/Barotrauma/BarotraumaShared/SharedSource
Немного пояснения. Например, все данные, которые написаны в StatusEffect уходят в StatusEffect.cs и уже там код выполняет свои действия.

Конечно, просмотр и понимание того, что там написано, требует знаний С# (ну, или java), так что если вы не знакомы с ними, то сильного понимания того, как всё работает, вам не даст. Хотя это не особо-то и нужно, так как это просто пункт для общего развития.

Эта штука важна, так как можно посмотреть в коде, что можно писать в том же StatusEffect, ItemContainer и т.д. то есть не искать какие-то методы в xml файлах, а сразу знать, что можно делать, а что нельзя, но, как уже говорил, это не особо нужная вещь в нашем случае.
Чтение ошибки в консоли
Для этого нужно знать английский, но суть ошибки всегда написана в начале. Вот пример


У меня в файле предмет с именем "M2 fueltank" и с identifire "handheldterminal" имеет схожее имя с identifier предмета из ванильной игры. Это то, что написано в ошибке. По такому же принципу можно понимать в чём проблема.
Возможные ошибки
Пункт, в который со временем будет пополняться. Тут будут написаны все ошибки, с которыми можно столкнуться во время моддинга.
1. Не уникальный identifier.
Возникает, когда 2 предмета имеют один и тот же identifier. Очень часто люди забывают поменять identifier, когда копируют предмет. Она легко исправляется и её также легко обнаружить в ошибке, которая возникает в консоли.

2. Ошибка в filelist.xml. Старый gameversion.
Редкая ошибка, но всё же иногда появляется. По каким-то причинам если в filelist.xml стоит старый gameversion, то может возникнуть красная ошибка. Исправляется заменой старой gameversion на новую, которую можно узнать в Vanilla.xml.

3. Неправильно скопирован код. Потеря закрывающей конструкции.
Нарушена подобная структура:
<Items> <Item (Тут все значения Вашего предмета, типа имя, размер и прочее)> (Все остальные значения этого предмета) </Item> </Items>
Обычно забывают скопировать </Items>
Заключение
Предлагайте свои идеи о том, что добавить. Можете сообщить, если нашли ошибки.
Как всегда, можете задавать вопросы в комментариях.
43 kommentarer
Thalleous_Voltaris 18. mai kl. 4.09 
Спасибо огромное, теперь всё работает!
76561199517092193  [skaper] 18. mai kl. 2.06 
%ModDir% писать нужно, так как если баротраума перестала менять полный путь, то у людей, скачавших мод, он просто работать не будет, так как скаченные моды заносятся в папку не с название, а с id из воркшопа и следовательно путь будет неверный.(да и LocalMod там нету)
76561199517092193  [skaper] 18. mai kl. 2.01 
В первом руководстве в "Предпоследний этап. Создаём filelist.xml" всё это было написано. У вас как бы основные проблемы от того, что вы невнимательно прочитали руководство.
А ещё не выкладывайте мод, который не работает в воркшоп, сначала убедитесь, что всё работает.
76561199517092193  [skaper] 18. mai kl. 1.57 
Поменяйте "Guitar/Guitar.xml" на "%ModDir%/Guitar.xml". Опять же, перечитайте первое руководство. У вас не указан LocalMod в пути.
Ещё раз объясню, чтобы вы поняли. Путь(у вас) в filelist указывается так: LocalMod/название/предмет.xml
Баротраума даёт возможность сократить "LocalMod/название" до "%ModDir%" что в переводе означает "директория мода".
Пишите именно %ModDir% в каждом пути, потому баротраума при публикации и так должна будет заменить всё на %ModDir% (возможно, уже не меняет), да и полный путь уже люди не пишут.
Thalleous_Voltaris 17. mai kl. 16.06 
Это был мой косяк, я его решил. Но вернулась старая и главная проблема - сод выдаёт ошибку о том, что не может найти Guitar.xml, хотя они лежат рядом.
Guitar
├── filelist.xml
├── Guitar.xml
└── Content
└── Lagtrain.ogg

может это связано с filelist?

<?xml version="1.0" encoding="utf-8"?>
<contentpackage name="guitarMod" modversion="1.0.0" corepackage="false" steamworkshopid="3480931245" gameversion="1.8.8.1">
<Item file="Guitar/Guitar.xml"/>
</contentpackage>
76561199517092193  [skaper] 17. mai kl. 14.23 
Знаю, что существует ScriptedEvent, то есть цепочку событий создать, скорее всего, можно, но для вызова нужен триггер. Если событие, которые вызывает ивент, не может быть связано с StatusEffect, то это нужно прогать на c# или lua.
76561199517092193  [skaper] 17. mai kl. 13.59 
Трудно сказать. Не думаю, что такое можно сделать без Lua(в чём я не специализируюсь). Если можно, немного подробнее расскажи о том, что ты хочешь сделать, возможно, смогу придумать какую-то альтернативу, но, скорее всего, нужно будет создавать предмет.
☆☭∞GSN∞☭☆ 17. mai kl. 13.44 
Привет, помоги знаю что это скорее уровень выше чем любительский но как добавь цепочку условных скриптов? Без предмета. То есть действе повиликает действие со стороны сервера
76561199517092193  [skaper] 17. mai kl. 10.37 
Если у вас identifier="guitar" и только одна строчка <sound(то есть не указаны ванильные звуки), то могу предположить, что у вас не включен мод в настройках.
Thalleous_Voltaris 17. mai kl. 8.51 
у меня получилось примерно так(весь код не влезает)

<?xml version="1.0" encoding="utf-8"?>
<Override>
<Items>
*куски кода*
Conditional HasStatusTag="!equals clown" />
<sound file="Content/Lagtrain.ogg" type="OnUse" selectionmode="CharacterSpecific" range="600" loop="true" />
*куски кода*
</Item>
</Override>
</Items>