Battle Brothers

Battle Brothers

View Stats:
centurion-x Aug 25, 2020 @ 6:30am
Введение в моддинг для новичков / Intro to modding for beginners
В данном материале разбирается модифицирование игр, использующих squirell в качестве языка сценариев, на примере "Battle Brothers", которая в значительной мере написана на этом языке. К сожалению, у меня нет возможности оформить всё это в виде руководства, т. к. моя копия "боевых братьев" на GOG. А Steam в качестве обязательного условия для публикации требует от меня повторной покупки игры. Прошу прощения: не имею в наличии свободных средств для этого 8-((

In this theme explores modifying games that use squirell as the language of scripts, using the example of "Battle Brothers", which largely written in this language. But, unfortunately, I do not have the opportunity to design all this in the form of a manual, since my copy of "battle brothers" on GOG. And Steam requires from me to repurchase the game as a prerequisite for the publication of my guide. I am sorry, but... I do not have free funds for that 8-((

Приветствуется любая обратная связь! Any feedback is appreciated!



__________________________________________________________Русская версия

Вступление

Прежде всего, помучаемся вопросом: но почему именно Squirell[www.squirrel-lang.org]? Почему, например, не LUA[www.lua.org] или Python[www.python.org]?

Может быть, потому что эта "Белка" изначально разрабатывалась для применения "в условиях ограниченности ресурсов в приложениях реального времени", т. е. именно в компьютерных играх? Этот язык действительно компактен (шесть тысяч строк кода на C++), но вместе с тем умеет всё, ну или почти всё, что необходимо (функции и генераторы? - да, массивы и таблицы? - да, классы и наследования? - да... и много чего ещё, включая рекурсию), не потребляет впустую оперативной памяти, с которой управляется автоматически, и при этом достаточно производителен, конечно для интерпретируемого языка... Кроме того, ещё и свободно распространяемого.

Может быть, потому что эту "Белку" использует в своих играх компания <Valve>, к примеру, в "Counter-Strike: Global Offensive" или в "Portal 2". Да и не только она одна. Про "War Thunder" слышали, что-нибудь, когда-нибудь? Там тоже словили "Белочку".

Может быть, потому что белочки милые.., и пушистые.., и любят крепкие орешки?

Лучше, конечно, переадресовать этот вопрос разработчикам "боевых побратимов", потому что, для нас, причина, собственно, в этом: для модификации любимой игры, которая, почему-то, использует SQUIRELL 8))

Картинка 1: Кстати говоря, Альберто Демикелис, создатель данного языка программирования, вложил в его разработку не менее двенадцати лет своей жизни!

P.S. Если быть совсем кратким, то squirell - это такой вспомогательный инструмент, заточенный под написание сценариев (aka scripts) и предназначенный для использования в комплекте с языком программирования "покрупнее" и "потяжелее".
https://www.youtube.com/watch?v=MkWMC3PZnxg
Теория

Если Вы никогда прежде не занимались модификацией игр и ничего не знаете об этом, но очень хотите попробовать, то по прочтении моего краткого руководства Вы сможете самостоятельно сделать свой самый первый мод! И я это гарантирую 8-)

Для этого, прежде всего, нам нужно научиться декомпилировать файлы с расширением .cnut, содержащие в себе код для виртуальной машины squirell, т. е. практически все внутриигровые данные (и операции!).

Если Вам кажется, что это "сложновато", то разочарую: на самом деле всё гораздо проще, чем могло бы показаться! Весь процесс, на практике, будет сведён к банальной распаковке отдельных cnut-файлов в определённую директорию и запуску одного из двух bat-файлов. Т. е. всё будет сделано почти что без Вашего участия.

Но прежде чем мы это сделаем...

Картинка 2: Что такое любая программа? Как не последовательность действий, реализующая решение задачи и ведущая к достижению цели. Или алгоритм.
https://steamcommunity.com/sharedfiles/filedetails/?id=2220637530
Давайте свою первую "программу" попытаемся описать человеческим языком. Потому что "Hello, World!" - знают и умеют все 8)

Наша первая программа для себя самого:
  1. скачать мод-комплект[www.adammil.net] от Адама;
  2. прочитать руководство от Адама;
  3. скачать мод-совместитель[www.nexusmods.com] от Адама;
  4. мысленно сказать: "Спасибо, Адам".
...

Декомпиляция сценариев:

Распакуйте содержимое архива bbros.zip (см. выше пункт один) в любую папку по Вашему выбору. Я предпочитаю, чтобы эта всегда была соседняя с игрой директория (например, modkit).

Теперь откройте архив data_001.dat (на самом деле - это обычный zip-архив!), выберите файл[ы], с которым[и] планируете в дальнейшем работать, пусть, например, это будет файл iron_lungs_trait.сnut, и распакуйте прямо в папку bin в директории с мод-комплектом. И там запустите massdecompile.bat. Собственно, всё.

И в моём случае это выглядит примерно так:
Games / Battle Brothers / data / data_001.dat: scripts / skills / traits / iron_lungs_trait.сnut
-> Games / modkit / bin / ... -> massdecompile.bat -> iron_lungs_trait.nut

...

Создание модификации:

...

Картинка 3: Обратите внимание, что результаты Вашего труда, как итог, в архиве или в распакованном виде, должны оказаться по адресу: ... / game directory / data / ...
https://steamcommunity.com/sharedfiles/filedetails/?id=2198459748
При этом, загрузка файлов игры в память компьютера осуществляется в алфавитном порядке! И поскольку оригинальные файлы находятся в архивах с префиксом data_, то по аналогии, заодно по умолчанию, для архивов с модификациями в сообществе принято использовать префикс mod_.

Но самое главное в процессе сборки - точно воспроизвести файловую структуру из data_001.dat!!! Всего один лишний или пропущенный элемент - будь то сама папка или же символ в названии папки! - и ничего работать правильно у Вас не будет 8( Без плясок с бубном 8)

Chikanuk: Я по 10 раз просмотрел все видео и перечитал все посты и ничего не помогало, пока в конце концов до меня не допёрло, что у меня при архивировании у файлов в архиве получается отличная от оригинальных дата-архивов система.

Ещё раз: Вы хотите, как пример, изменить боевые характеристики ножа. Для этого Вы распаковали (и декомпилировали!) соответствующий файл из архива: data_001.dat => scripts / items / weapons / knife.cnut...

Теперь Вы должны воссоздать всю соответствующую структуру папок заново в директории data (и далее либо упаковать это в архив zip, либо оставить как есть).

Вот так: my_mod / knife.nut - не заработает (структура директорий не скопирована)!
И так: scripts / weapons / knife.nut - тоже работать не будет (пропущена папка items)!
И так: scripts / items / weapon / knife.nut - тоже работать не будет (пропущена буква s)!

Рабочая структура: data / scripts / items / weapons / knife.nut => [ mod_knife.zip ] ! ! !

...

Редактирование сценариев

Если модифицируемый файл не слишком велик по размеру (или, наоборот, вносится значительное количество изменений), то рекомендую работать непосредственно с ним, точнее с его копией.

Давайте, опять, обратимся к алгоритмизации действий, в данном случае как-то вот так...

Наша вторая программа для себя самого:
  1. декомпилировать имя_файла.cnut в имя_файла.nut;
  2. добавить файл, с сохранением структуры папок, в модификацию;
  3. отредактировать скрипт;
  4. не забыть сохранить скрипт;
  5. запустить игру;
  6. получить ошибку;
  7. сохранить игру;
  8. просмотреть журнал;
  9. не полениться закрыть игру;
  10. исправить ошибку;
  11. ещё раз запустить игру;
  12. загрузить сохранение... и получить ещё одну ошибку или же нет!)
По сути, это - просто 8-) Но в реальной жизни ситуация наподобие - я же всё поменял, почему ничего не поменялось? - не редкость. Причём по причине: см. пункт четыре 8) Или два 8))

Картинка 4: Если, вдруг, у Вас что-то не будет получаться, то, знайте: если можете алгоритмизировать - то можете всё! Мыслите алгоритмически. Пробуйте снова.
https://steamcommunity.com/sharedfiles/filedetails/?id=2222876342
Причина ошибки в программировании - на 99% - действия программиста 8-)

Тестирование модификаций

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

Как узнать, что пошло не так? Просто просмотрите игровой "журнал":
C: \ Users \ User Name \ Documents \ Battle Brothers \ log.html
Там красным цветом будет выделена вся нужная информация: в каком именно файле и в какой строке случилась ошибка, а также будет указан тип ошибки. Отловите жучка!)

Картинка 5: Для ускорения процесса тестирования используйте редактор сохранений от Shank Lord'a.
https://steamcommunity.com/sharedfiles/filedetails/?id=2200508539

Перечень источников (все на английском языке):

1) Первоисточник за авторством Адама, с которого всё началось:
https://steamcommunity.com/sharedfiles/filedetails/?id=1630767682
2) Альтернативная инструкция (давно не обновлялась и частично устарела):
https://steamcommunity.com/sharedfiles/filedetails/?id=825789503

Практика

Итак, поехали. Вернём "железным лёгким" прежнее значение параметра восстановления выносливости.

Извлечём и декомпилируем нужный нам файл: ...\ game directory \ data \ data_001.dat => scripts \ skills \ traits \ iron_lungs_trait.nut... Открываем и в самом конце видим:

... function onUpdate( _properties ) { _properties.FatigueRecoveryRate += 3; }

И что нужно сделать? А всего-навсего поменять тройку на пятёрку!)

Ещё раз: не забудьте сохранить изменения и повторить структуру папок из data_001! Собственно, всё... Ваш первый мод готов.

Ведь, действительно, это было не так-то и трудно?

* - *

А для выработки и закрепления навыка попробуем вернуть прежнюю стоимость в очках действия для умения "неукротимости".

Извлечём и декомпилируем файл по адресу: ...\ game directory \ data \ data_001.dat => scripts \ skills \ actives \ indomitable.nut... Откроем и здесь уже в самом начале увидим:

function create() { ... this.m.ActionPointCost = 5; ... } ...

На этот раз всё с точностью до наоборот: замените пятёрку на тройку. Снова всё.

В принципе, ничего сложного. Разве нет? ¯ \ _ (ツ) _ / ¯ (c) Caroline Eisenmann

Следующая тема

Для дальнейшего, нам нужно попытаться осмыслить понятия "объекта" и "класса". Если коротко... Класс всегда один - это "прототип" объекта! Тогда как объекты - это вариации класса. Объектов может быть сколько угодно, сколько позволяет вместить объём памяти...

https://steamcommunity.com/sharedfiles/filedetails/?id=2234585683
Короче говоря, конечно же, это может быть сложно, но на самом деле, чем больше Вы будете иметь дело с этим на практике, тем лучше Вы будете это понимать и в этом разбираться в теории 8)

Данные и функции

Разберём шаблон подкласса weapon (для оружия ближнего боя) на примере боевого кнута.

data_001.dat: scripts / items / weapons / weapon / battle_whip.nut:
function create() { this.weapon.create(); // создание объекта по шаблону подкласса <оружие>; this.m.ID = "weapon.battle_whip"; // идентификатор объекта (для системы); this.m.Name = "Battle Whip"; // имя объекта (для пользователя); this.m.Description = "A long whip with a barbed tip that can tear terrible bleeding wounds over significant range, but is very inefficient against armor."; // описание объекта (для пользователя); this.m.Categories = "Cleaver, One-Handed"; // категория объекта "одноручный тесак" (для системы); this.m.IconLarge = "weapons/melee/whip_01.png"; // изображение объекта для экрана "куклы персонажа"; this.m.Icon = "weapons/melee/whip_01_70x70.png"; // изображение объекта для инвентаря; this.m.SlotType = this.Const.ItemSlot.Mainhand; // тип слота под объект (для системы), в данном случае, это правая рука; this.m.ItemType = this.Const.Items.ItemType.Weapon | this.Const.Items.ItemType.MeleeWeapon | this.Const.Items.ItemType.OneHanded; // тип[ы] объекта (для системы) - одноручное оружие ближнего боя; this.m.IsDoubleGrippable = true; // применение к объекту модификатора двуручного хвата; this.m.AddGenericSkill = true; // добавление объектом активных умений, для кнута это "whip" & "disarm"; this.m.ShowQuiver = false; // отображение объекта подкласса "ammo" на персонаже (в бою); this.m.ShowArmamentIcon = true; // отображение объекта на персонаже (в бою); this.m.ArmamentIcon = "icon_whip_01"; // изображение объекта в entity_icons.png (версия без следов крови!); this.m.RangeMin = 1; // минимальная дистанция воздействия объекта (используется системой); // по факту необходимо настраивать в параметрах умений "whip" & "disarm"; this.m.RangeMax = 3; // максимальная дистанция воздействия объекта (используется системой); // по факту необходимо настраивать в параметрах умений "whip" & "disarm"; this.m.RangeIdeal = 3; // дистанция воздействия объекта (рекомендуемая искусственному интеллекту); this.m.Value = 450; // стоимость объекта на рынке; this.m.Condition = 40; // текущий запас прочности объекта; this.m.ConditionMax = 40; // максимальный запас прочности объекта; this.m.StaminaModifier = -6; // затраты выносливости при использовании объекта персонажем; this.m.RegularDamage = 15; // минимальное повреждение от объекта (изменяется коэффициентами от умений); this.m.RegularDamageMax = 30; // максимальное повреждение от объекта (изменяется коэффициентами от умений); this.m.ArmorDamageMult = 0.25; // коэффициент повреждения от объекта для брони; this.m.DirectDamageMult = 0.1; // коэффициент повреждения (проникающего урона) от объекта для тела; }

function onEquip() { this.weapon.onEquip(); // вызов экипировочной функции подкласса; local skill = this.new("scripts/skills/actives/whip_skill"); // определение локальной переменной для умения "whip"; skill.m.Icon = "skills/active_171.png"; // изображение умения под экраном "куклы персонажа" (цветной вариант); skill.m.IconDisabled = "skills/active_171_sw.png"; // изображение умения под экраном "куклы персонажа" (чёрно-белый вариант); skill.m.Overlay = "active_171"; // наименование умения (для системы); this.addSkill(skill); // добавление объектом при экипировке умения "whip"; local skill = this.new("scripts/skills/actives/disarm_skill"); // определение локальной переменной для умения "disarm"; this.addSkill(skill); // добавление объектом при экипировке умения "disarm"; }

...

data_001.dat: scripts / items / weapons / weapon / short_bow.nut:
function create() { this.weapon.create(); // создание экземпляра подкласса <оружие>; this.m.ID = "weapon.short_bow"; // идентификатор экземпляра для системы; this.m.Name = "Short Bow"; // имя объекта для пользователя; this.m.Description = "A simple wooden short bow with medium range. Requires some expertise to use effectively."; // описание объекта для пользователя; this.m.Categories = "Bow, Two-Handed"; // категория объекта для системы; this.m.IconLarge = "weapons/ranged/bow_02.png"; // изображение объекта для "куклы"; this.m.Icon = "weapons/ranged/bow_02_70x70.png"; // изображение объекта для инвентаря; this.m.SlotType = this.Const.ItemSlot.Mainhand; // тип слота для объекта, в данном случае, это правая рука; this.m.BlockedSlotType = this.Const.ItemSlot.Offhand; // тип парного слота для блокировки объектом, в данном случае, это левая рука; this.m.ItemType = this.Const.Items.ItemType.Weapon | this.Const.Items.ItemType.RangedWeapon | this.Const.Items.ItemType.Defensive; // тип объекта для системы - оборонительное оружие дальнего боя; this.m.EquipSound = this.Const.Sound.ArmorLeatherImpact; // список звуков для системы для проигрыша в случае экипировки объекта; this.m.AddGenericSkill = true; // добавление объектом активных умений, для лука - quick & aimed shots; this.m.ShowQuiver = true; // отображение объекта типа "колчан" на персонаже (для оружия дальнего боя); this.m.ShowArmamentIcon = true; // отображение объекта на персонаже (в бою); this.m.ArmamentIcon = "icon_short_bow"; // изображение объекта в entity_icons.png; this.m.Value = 200; // стоимость объекта на рынке; this.m.StaminaModifier = -4; // затраты выносливости при использовании объекта персонажем; this.m.RangeMin = 2; // минимальная дистанция поражения объекта (используется системой); // по факту необходимо настраивать в параметрах quick & aimed shots; this.m.RangeMax = 7; // максимальная дистанция поражения объекта (используется системой); // по факту необходимо настраивать в параметрах quick & aimed shots; this.m.RangeIdeal = 7; // рекомендуемая дистанция поражения объекта (искусственному интеллекту); this.m.Condition = 60.0; // текущий запас прочности объекта; this.m.ConditionMax = 60.0; // максимальный запас прочности объекта; this.m.RegularDamage = 30; // минимальное повреждение от объекта (типа "оружие"); this.m.RegularDamageMax = 50; // максимальное повреждение от объекта (типа "оружие"); this.m.ArmorDamageMult = 0.5; // коэффициент повреждения для брони; this.m.DirectDamageMult = 0.35; // коэффициент повреждения (проникающего урона) для тела; }

function getAmmoID() { return "ammo.arrows"; // возвращение идентификатора типа боеприпасов; } function getAdditionalRange( _actor ) { return _actor.getCurrentProperties().IsSpecializedInBows ? 1 : 0; // увеличение дистанции поражения объекта при специализации на луках; } function onEquip() { this.weapon.onEquip(); // вызов экипировочной функции класса; this.addSkill(this.new("scripts/skills/actives/quick_shot")); // добавление объектом при экипировке им умения quick shot; this.addSkill(this.new("scripts/skills/actives/aimed_shot")); // добавление объектом при экипировке им умения aimed shot; }

Список слотов (this.Const.ItemSlot.* <= переменная SlotType)

Accessory - аксессуар (для категории accessory, включая falcon & wardog);
Ammo - боеприпасы (для категории ammo, либо powder_bag, либо quiver);
Bag - поясная сумка (для категорий ammo & tool, shield & weapon);
Body - тело (для категории armor);
Head - голова (для категории helmet);
Mainhand - правая / ведущая рука (для разных категорий weapon);
Offhand - левая / вспомогательная рука (для категорий shield & tool).

Список категорий (this.Const.Items.ItemType.* <= переменная ItemType)

Accessory - аксессуары (ожерелья и всякое прочее, включая даже сокола, собак и волка);
Ammo - боеприпасы;
Armor - броня;
Crafting - ингредиенты для квалифицированного рукоделия;
Defensive - предметы для использования в целях самообороны;
Food - еда;
Helmet - шлем;
Legendary - легендарный предмет;
Loot - трофеи;
MeleeWeapon - оружие для ближнего боя;
Misc - разное (если не вписывается в иные категории, то это должно быть именно здесь);
Named - именной предмет;
OneHanded - одноручное [оружие];
RangedWeapon - оружие для дальнего боя;
Shield - щит;
Supply - условные инструменты, снаряды, травы;
Tool - баночки, бомбочки, сеточки и такое прочее;
TradeGood - товары (для торговли);
TwoHanded - двуручное [оружие];
Usable - для, предположительно, одноразового использования;
Weapon - оружие...

...

Разберём шаблон подкласса background на базовом примере подмастерья, относительно которого видоизменяется статистика прочих шаблонов.

data_001.dat: scripts / skills / backgrounds / apprentice_background.nut:
function create() { this.character_background.create(); // создание объекта по шаблону подкласса <персонаж> (далее - персонажа); this.m.ID = "background.apprentice"; // идентификатор персонажа (для системы); this.m.Name = "Apprentice"; // тип персонажа (для пользователя); this.m.Icon = "ui/backgrounds/background_40.png"; // иконка персонажа для отображения пользовательским интерфейсом; this.m.BackgroundDescription = "Apprentices tend to be eager for knowledge and learn faster than others."; // базовое описание типа персонажа (для пользователя); this.m.GoodEnding = "Perhaps one of the sharpest men you\'ve ever met, %name% the apprentice was the quickest learner in the %companyname%. With plenty of crowns stored, he retired from fighting to take his talents to the business world. Last you heard he was doing very well for himself across multiple trades. If you ever have a son, this is the man you\'ll send him to for apprenticeship."; // текст для истории удачного завершения карьеры (для пользователя); this.m.BadEnding = "%name% the apprentice was, by far, the quickest learner in the %companyname%. Little surprise then that he was also one of the quickest to recognize its inevitable downfall and leave while he still could. Had he been born in a different time he would have gone on to do great things. Instead, many wars, invasions, and plagues spreading across the land ultimately ensured %name% and many other talented men went to total waste."; // текст для истории неудачного завершения карьеры (для пользователя); this.m.HiringCost = 90; // базовая стоимость найма персонажа; this.m.DailyCost = 8; // базовое ежедневное содержание персонажа; this.m.Excluded = [ "trait.asthmatic", "trait.athletic", "trait.bloodthirsty", "trait.brute", "trait.clumsy", "trait.dumb", "trait.fear_undead", "trait.hate_undead" ]; // список черт, исключённых из списка черт (для Генератора Случайных Чисел); this.m.Titles = [ "Goodhand", "Quickmind", "the Apprentice", "the Bright", "the Kid", "the Learner", "the Student", "the Understudy", "the Young" ]; // список прозвищ для персонажа (для ГСЧ функции onAdded); this.m.Faces = this.Const.Faces.AllMale; // список наименований изображений лиц (для ГСЧ функции setAppearance); // gt.Const.Faces.AllMale <- [ // "bust_head_01", // "bust_head_02", // .., // "bust_head_17", // "bust_head_18"]; this.m.Hairs = this.Const.Hair.YoungMale; // список номеров изображений причёсок (для ГСЧ функции setAppearance); // gt.Const.Hair.YoungMale <- [ // "shaved", // "01", // "04", // "05", // "06", // "07", // "08", // "09", // "10", // "11", // "20"]; this.m.HairColors = this.Const.HairColors.Young; // список оттенков цвета волос (для ГСЧ функции setAppearance); // gt.Const.HairColors.Young <- [ // "black", // "blonde", // "brown", // "red"]; this.m.Beards = this.Const.Beards.All; // список номеров изображений бород (для ГСЧ функции setAppearance); // gt.Const.Beards.All <- [ // "01", // "02", // .., // "16", // "17"]; this.m.Bodies = this.Const.Bodies.Muscular; // список наименований изображений тел (для ГСЧ функции setAppearance); // gt.Const.Bodies.Muscular <- [ // "bust_naked_body_01"]; }

Последовательность вызова функций подкласса в игре (данные на основе log.html):
create() -> onAdded() -> onChangeAttributes() -> onBuildDescription -> onAddEquipment() -> onSetAppearance...

Подсказка по использованию оператора If в функциях onAddEquipment() и прочих:
  • // = Любой комментарий -> не будет выполнен программой;

  • ! = Логическое не -> если условие не выполнено;

  • || = Логическое или -> если одно из условий будет выполнено;

  • && = Логическое и -> если все условия будут равно выполнены.
// Ветвление / Branching: if (!condition_1) { return; } else if (condition_1 || condition_2) { doThis(); } else if (condition_1 && condition_2) { doThat(); } else { doSomethingElse(); }

[Продолжение следует...]

Часто задаваемые вопросы

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

Комментарий Адама:
Originally posted by Adam:
Полезно, на самом деле, перекомпилировать исходные файлы игры, после того как Вы их модифицировали... Но тем не менее, если Вы добавляете новый файл .nut, а не изменяете оригинальный файл .cnut, то рекомендую не компилировать. Намного проще и быстрее редактировать скрипты, когда они не скомпилированы.

* - *

Игра скачала последнее обновление и модификации перестали работать. Что делать?
— Модифицированные файлы должны иметь дату перезаписи, более позднюю, чем у оригинальных файлов... Иначе работать не будет! Альтернативный способ решения проблемы: заново скомпилировать модифицированные файлы.

Комментарий Адама:
Originally posted by Adam:
Да, это не очень весело и не надёжно. Лучше скомпилировать свои файлы (если Вы модифицируете существующие файлы игры). В этом случае Вы можете быть уверены, что они будут загружены, и Вам не придется беспокоиться о том, чтобы дата их изменения всегда была бы позже, чем у оригинальных файлов.

Однако в идеале Вы не должны изменять исходные файлы игры. Это делает Вашу модификацию ненадёжной, поскольку каждое обновление игры может сломать её, и она может легко конфликтовать с другими модификациями. Лучше научиться использовать mod_hooks[www.nexusmods.com]], чтобы Вам не приходилось изменять какие-либо оригинальные файлы игры, а Ваши моды были бы совместимы с другими модами.

* - *

Какие программы лучше использовать при работе над модификациями?
— Для распаковки dat-архива вполне подойдёт WinZip. Или же воспользуйтесь 7-zip.
— Для редактирования внутриигровых скриптов порекомендую Notepad++.
— Для работы с графикой используйте Photoshop или же попробуйте Paint . NET.

Ссылки на программы с бесплатной лицензией:
7-zip => https://7-zip.org/
Notepad ++ => https://notepad-plus-plus.org/
Paint . NET => https://getpaint.net/

Комментарий Адама:
Originally posted by Adam:
Вам на самом деле не нужно ничего устанавливать [моё примечание: для работы с архивами], поскольку проводник Windows отлично справляется с файлами .zip. Чтобы создать архив, выделите нужные файлы и каталоги, щелкните правой кнопкой мыши и выберите: «Send to -> Compressed (zipped) folder».

* - *

Чтобы стать хорошим моддером, нужно быть неплохим кодером! Разве нет?
— Вероятно, скорее, всё наоборот: любой мододел со временем вполне может стать программистом 8)



________________________________________________________English translation

Theory

If You have never dealt with modifying games before and do not know anything about this, but really want to try it, then after reading my quick guide You will can make Your very first own mod yourself! And I guarantee it 8-)

To do this, first of all, we need to learn how to decompile files with the .cnut extension, containing the code for the virtual machine squirell[www.squirrel-lang.org], i. e. practically all in-game data (and operations!).

First remark: Alberto Demichelis, the creator of this programming language, has invested at least twelve years of his life in its development!

If it seems to You that this is very "complicated", then I will disappoint: in fact, everything is much simpler than it might seem! In practice, the whole process will be reduced to a ordinary unpacking of individual .cnut files into a specific directory and launching one of the two bat files. That is, everything will be done almost without Your participation.

But before we will do that...

Second remark: What is the program? As not a sequence of steps that implements a solution of tasks that lead to the achievement of definite goal. Or algorithm.

https://steamcommunity.com/sharedfiles/filedetails/?id=2220637530
So let us try to describe such an algorithm in human language. After all "Hello, World!" - everyone knows and can 8)

Our first program for most self:
  1. download the modkit[www.adammil.net] from Adam;
  2. read the manual from Adam;
  3. download mod-deconflicter[www.nexusmods.com] from Adam;
  4. mentally say - "Thanks, Adam".
...

Decompilation of the scripts:

Unpack completely the contents of the archive bbros.zip (see point one above) into any folder of Your choice. I prefer this directory to always be adjacent to the game directory (let us say, modkit).

Now open the archive data_001.dat (it is a regular zip-archive!) and select the file[s], with which You plan to work in the near future, for example, let it be the file iron_lungs_trait.сnut, then unpack it directly to the folder "bin" in the directory "modkit". And there run massdecompile.bat. Actually that is all.

So in my case, it will look something like this:
Games / Battle Brothers / data / data_001.dat: scripts / skills / traits / iron_lungs_trait.сnut
-> Games / modkit / bin / ... -> massdecompile.bat -> iron_lungs_trait.nut

...

Pay attention! Your modification, in summary, in the archive file or unpacked, should be located at: ... / game directory / data / ...

At the same time, loading the game files into the computer memory is carried out in alphabetical order! And since the original files are in the archives with name data_***, by analogy and together with that by default, it is customary in the community for the archives with the modifications to use name mod_***.

https://steamcommunity.com/sharedfiles/filedetails/?id=2198459748
But most importantly in the mod assembly process - correctly reproduce the original file structure from data_001.dat!!! Just one extra or missing element - be it the folder itself or the symbol in the folder name! - and nothing will work for You 8( Without dancing with tambourine 8)

...

If the file that being modified is not too large in size (or, on the contrary, a significant number of changes will be made), then I recommend working directly with it or rather with its copy.

Third remark

https://steamcommunity.com/sharedfiles/filedetails/?id=2222876342
Our second program for most self:
  1. decompile file_name.cnut to file_name.nut;
  2. add the file to the modification, preserving the folder structure;
  3. edit the script;
  4. do not forget save the script;
  5. start the game;
  6. get an error;
  7. save the game;
  8. read the log;
  9. do not be lazy and close the game;
  10. fix the error;
  11. start the game again;
  12. load the save and... get one more error or not!)
In principle, nothing complicated 8-) But in real life, the situation like this - I changed everything, but why did nothing change? - not rare at all. And for the reason: see points number two 8) Or four 8))

After modification, into the testing process of changes, in especially at first, You will definitely and constantly received the some messages about some errors. Do not be discouraged! It was happening, is happening and it will be happening not exclusively to You! The errors are absolutely usual practice, and, at the beginning, even useful!

But how do You know what went wrong? Just look at the game log:
C: \ Users \ User Name \ Documents \ Battle Brothers \ log.html
All the necessary information will be highlighted there in red: in which file and in which line the error occurred, the type of error will also be indicated. Catch the bug!)

¯ \ _ (ツ) _ / ¯ (c) Caroline Eisenmann

Practice

So begin. Let us return the "iron lungs" to their previous value of stamina recovery parameter.

Extract and decompile the file we need for: ...\ game directory \ data \ data_001.dat => scripts \ skills \ traits \ iron_lungs_trait.nut... Open in notepad and at the very end we see:

... function onUpdate( _properties ) { _properties.FatigueRecoveryRate += 3; }

But what needs to be done? And just change the three to the five!)

And again: do not forget to save all changes and repeat the folder structure from data_001! And that is all... Your first mod is already done.

So, is not it, nothing complicated?

* - *

For to develop and to consolidate modding competence let us return previous cost in action points for the "Indomitability" skill.

Extract and decompile the file to this address: ...\ game directory \ data \ data_001.dat => scripts \ skills \ actives \ indomitable.nut... Open it and now at the very beginning we see:

function create() { ... this.m.ActionPointCost = 5; ... } ...

This time, everything is exactly from the opposite: replace the five with the three. Again that is all.

...

Next theme

For further, we need to try to comprehend the concepts of "object" and "class". In short... There is always one class - this is the object's "prototype"! Whereas objects are variations of a their class. There can be as many objects as You like, as much as the memory size allows...

https://steamcommunity.com/sharedfiles/filedetails/?id=2234585683
In short, of course, it can be difficult, but the more You will work with it practically, the better You will understand it theoretically 8)

Data and Functions

...

[To be continued...]

Frequently Asked Questions

Do I need to recompile the modified files?
— Not necessary. Since it makes scripts editing difficult. But it is desirable if there are many such files. Because the compiled files run faster.

Adam's comment:
Originally posted by Adam:
Actually, it is useful to recompile built-in game files if you modify them... However, if you are adding a new .nut file rather than changing an existing file, then I recommend not recompiling. It is much easier and quicker to edit your mod if it's not compiled.

* - *

The game downloaded the last update and the modifications no longer work. What should I do?
— The modified files must have a rewriting date later than the original files... Otherwise it will not work! An alternative way to solve the problem just is to recompile the modified files.

Adam's comment:
Originally posted by Adam:
Yes, this is not very fun or reliable. Better to compile your files (if you modify existing game files). Then you can be sure they will be loaded and won't have to worry about the modification date being later than the original.

However, ideally you would not be modifying existing game files. That makes your mod fragile, because every game update may break it, and it may easily conflict with other mods. Better to learn to use mod_hooks[www.nexusmods.com] so you don't have to alter any existing game files, and so your mods will be compatible with other mods.

* - *

What programs are best to use when working on modifications?
— For unpacking files from an dat-archive usual WinZip is fine. Or employ free 7-zip.
— For editing game scripts I recommend free Notepad++.
— For work with graphics use Photoshop or try free Paint . NET.

Links to programs with free license:
7-zip => https://7-zip.org/
Notepad ++ => https://notepad-plus-plus.org/
Paint . NET => https://getpaint.net/

Adam's comment:
Originally posted by Adam:
You don't actually need to install anything, since Windows Explorer can handle .zip files just fine. To create an archive, highlight the files and directories you want, right-click, and choose Send to -> Compressed (zipped) folder.

* - *

To become a good modder You have to be a good programmer! Is not it so?
— The opposite is probably more likely: any modder may well become a professional programmer with time 8)

Благодарности / Gratitudes
  • Спасибо, Adam, за инструментарий для модифицирования скриптов игры и комментарии!
  • Спасибо, Drake_hound, за подсказки по поводу полезных утилит для моддинга!
  • Спасибо, Alberto Demichelis[www.facebook.com], за разработку языка программирования squirell!
  • Спасибо разработчикам[battlebrothersgame.com], конечно же, за игру, которую мы все любим!!!
  • Особое спасибо компаниям Google[translate.google.ru] и Yandex[translate.yandex.ru] за помощь в преодолении языкового барьера 8)
  • Thanks, Adam, for the toolkit for scripts modification and comments!
  • Thanks, Drake_hound, for the tooltips about usefull utilities for modding!
  • Thanks, Alberto Demichelis[www.facebook.com], for development of squirell language!
  • Thanks of course to the developers[battlebrothersgame.com] for the game we all love!!!
  • Particular thanks to companies Google[translate.google.ru] and Yandex[translate.yandex.ru] for help on overcoming the language barrier 8)
Спасибо каждому из вас, кто задавал вопросы и делился мыслями / Great Thanks to everyone who asked questions and share thoughts:
  • Chikanuk
  • Datchannin
  • East Vikingr
  • Pelias117

_______________Работа не завершена <= WIP => Work in progress_______________
Last edited by centurion-x; Oct 10, 2020 @ 11:51am
< >
Showing 16-26 of 26 comments
centurion-x Aug 29, 2020 @ 2:05am 
Originally posted by East Vikingr:
...

Вам нужно будет использовать старый добрый способ дедовский - "принтовать":

this.logWarning("А это вообще работает или нет?"); ::mods_hookNewObject("entity/tactical/player", function ( o ) { this.logWarning("Эта функция была выполнена в программе или нет?"); ... this.unlockPerkBasedOnBackground("perk.student"); this.logWarning("Компьютер применил мою модификацию или нет?"); ... }

Сохраниться и запуститься.., в очередной раз.., - и внимательно, буквально строчка за строчкой, прочитать журнал. Я подозреваю, что там отладочных сообщений не появится... но тогда это будет означать, что почему-то не запускается mod_hooks.zip 8( А это уже совсем другой вопрос... - и, соответственно, методы решения 8((

UPDATE

Originally posted by East Vikingr:
Может дело в разных версиях и dlc? У меня стоит 1.4.40 и dlc Blazing Deserts, а у Вас?

Я обновился до версии 1.4.0.40 и... у меня по-прежнему всё нормально работает... Так что единственное различие в том, что у меня GOG-версия, а у Вас Steam-версия.

"PRINTуйте"!
Last edited by centurion-x; Aug 29, 2020 @ 4:15am
Adam Aug 29, 2020 @ 7:57pm 
I appreciate everyone doing my work for me by writing documentation on modding. :-) Some comments:
Originally posted by centurion-x:
Do I need to recompile the modified files?
— Not necessary. But it is desirable if there are many such files. Because the compiled files run faster.
Actually, it is useful to recompile built-in game files if you modify them. Then you can be sure they will be loaded and won't have to worry about the modification date being later than the original. However, if you are adding a new .nut file rather than changing an existing file, then I recommend not recompiling. It is much easier and quicker to edit your mod if it's not compiled.

Originally posted by centurion-x:
The game downloaded the last update and the modifications no longer work. What should I do?
— The modified files must have a rewriting date later than the original files... Otherwise it will not work!
Yes, this is not very fun or reliable. Better to compile your files (if you modify existing game files).

However, ideally you would not be modifying existing game files. That makes your mod fragile, because every game update may break it, and it may easily conflict with other mods. Better to learn to use mod_hooks[www.nexusmods.com] so you don't have to alter any existing game files, and so your mods will be compatible with other mods.

Originally posted by centurion-x:
What programs are best to use when working on modifications?
— For unpacking files from an dat-archive usual WinZip is fine. Or employ free 7-zip.
You don't actually need to install anything, since Windows Explorer can handle .zip files just fine. To create an archive, highlight the files and directories you want, right-click, and choose Send to -> Compressed (zipped) folder.
Last edited by Adam; Aug 29, 2020 @ 7:58pm
centurion-x Aug 30, 2020 @ 4:30am 
Originally posted by Adam:
I appreciate everyone doing my work for me by writing documentation on modding. :-) Some comments...

Спасибо за полезнейшие комментарии! Добавил в основной текст.

Thanks for the helpful comments! I added their to the main text.
Last edited by centurion-x; Aug 30, 2020 @ 4:30am
lumiscent Aug 31, 2020 @ 2:22pm 
Originally posted by centurion-x:
Originally posted by East Vikingr:
...

Вам нужно будет использовать старый добрый способ дедовский - "принтовать":

this.logWarning("А это вообще работает или нет?"); ::mods_hookNewObject("entity/tactical/player", function ( o ) { this.logWarning("Эта функция была выполнена в программе или нет?"); ... this.unlockPerkBasedOnBackground("perk.student"); this.logWarning("Компьютер применил мою модификацию или нет?"); ... }

Сохраниться и запуститься.., в очередной раз.., - и внимательно, буквально строчка за строчкой, прочитать журнал. Я подозреваю, что там отладочных сообщений не появится... но тогда это будет означать, что почему-то не запускается mod_hooks.zip 8( А это уже совсем другой вопрос... - и, соответственно, методы решения 8((

UPDATE

Originally posted by East Vikingr:
Может дело в разных версиях и dlc? У меня стоит 1.4.40 и dlc Blazing Deserts, а у Вас?

Я обновился до версии 1.4.0.40 и... у меня по-прежнему всё нормально работает... Так что единственное различие в том, что у меня GOG-версия, а у Вас Steam-версия.

"PRINTуйте"!
уже давно опустил руки. Появился доступ к другому компьютеру. На днях буду пробовать ставить чистую версию, с последни хуком. Ну, там и глянем. А насчет не запускающегося хука, то у меня также стоит множество модов (с которыми мод работал раньше)), так что он работает.

centurion-x Sep 1, 2020 @ 2:50am 
Originally posted by East Vikingr:
Уже давно опустил руки.

Не опускайте, пожалуйста, руки!!! Очень прошу!!!!! Я сделал с десяток модификаций на боевых братишек для себя. Парочку даже решился выложить для всех... Но если Вы бы знали бы, как часто у меня также ничего не получалось! И я буквально отползал от компьютера, посреди ночи, проклиная тот ****** день, "когда сел за баранку этого пылесоса" 8) Но, отдохнув и выспавшись, как следует, я на другое утро просыпался с новой идей, а что, если сделать вот так и так... И, конечно, не с первого раза, но со второй или с третьей, а иногда и с десятой попытки, но, таки, всё получалось 8)) И у Вас всё непременно получится!) Будьте уверены. Я нисколько в этом не сомневаюсь.

Originally posted by East Vikingr:
Появился доступ к другому компьютеру. На днях буду пробовать ставить чистую версию, с последни хуком. Ну, там и глянем.

Это очень хорошая идея! Буквально сегодня хотел предложить нечто подобное!

Originally posted by East Vikingr:
А насчет не запускающегося хука, то у меня также стоит множество модов (с которыми мод работал раньше)), так что он работает.

Кстати говоря, это вполне может быть именно той самой причиной! Потому что даже с установленным mod_hooks.zip модификации умудряются каким-то неведомым образом конфликтовать между собой!!! Несколько раз мне приходилось удалять этот самый мод!) Что, сразу, каким-то "чудом", помогало безошибочно работать моим собственным модификациям. Хотя вот, казалось бы, где повод для конфликта!? А всё равно ведь всё ломалось! С ошибкой в доступе к стэку. Так что, попробуйте поставить всё зачисто и запустить игру с единственным модом. Тем самым. Думаю что, всё заработает 8)

И вот тогда мы, общими усилиями, как-то перепишем эту хрень!) Удачи Вам!!! Всё получится!!!!!
Last edited by centurion-x; Sep 1, 2020 @ 8:25am
lumiscent Sep 10, 2020 @ 9:07pm 
Originally posted by centurion-x:
Originally posted by East Vikingr:
Уже давно опустил руки.

Не опускайте, пожалуйста, руки!!! Очень прошу!!!!! Я сделал с десяток модификаций на боевых братишек для себя. Парочку даже решился выложить для всех... Но если Вы бы знали бы, как часто у меня также ничего не получалось! И я буквально отползал от компьютера, посреди ночи, проклиная тот ****** день, "когда сел за баранку этого пылесоса" 8) Но, отдохнув и выспавшись, как следует, я на другое утро просыпался с новой идей, а что, если сделать вот так и так... И, конечно, не с первого раза, но со второй или с третьей, а иногда и с десятой попытки, но, таки, всё получалось 8)) И у Вас всё непременно получится!) Будьте уверены. Я нисколько в этом не сомневаюсь.

Originally posted by East Vikingr:
Появился доступ к другому компьютеру. На днях буду пробовать ставить чистую версию, с последни хуком. Ну, там и глянем.

Это очень хорошая идея! Буквально сегодня хотел предложить нечто подобное!

Originally posted by East Vikingr:
А насчет не запускающегося хука, то у меня также стоит множество модов (с которыми мод работал раньше)), так что он работает.

Кстати говоря, это вполне может быть именно той самой причиной! Потому что даже с установленным mod_hooks.zip модификации умудряются каким-то неведомым образом конфликтовать между собой!!! Несколько раз мне приходилось удалять этот самый мод!) Что, сразу, каким-то "чудом", помогало безошибочно работать моим собственным модификациям. Хотя вот, казалось бы, где повод для конфликта!? А всё равно ведь всё ломалось! С ошибкой в доступе к стэку. Так что, попробуйте поставить всё зачисто и запустить игру с единственным модом. Тем самым. Думаю что, всё заработает 8)

И вот тогда мы, общими усилиями, как-то перепишем эту хрень!) Удачи Вам!!! Всё получится!!!!!
Эххх... Не знаю в чем была проблема, но на чистом ББ на другом компьютере удалось запустить сначала вашу версию, а потом и мою навороченную - все работает!) Теперь буду разбираться что же там за конфликты такие, которых не было никогда:)
lumiscent Sep 11, 2020 @ 10:25am 
Originally posted by centurion-x:
Originally posted by East Vikingr:
Уже давно опустил руки.

Не опускайте, пожалуйста, руки!!! Очень прошу!!!!! Я сделал с десяток модификаций на боевых братишек для себя. Парочку даже решился выложить для всех... Но если Вы бы знали бы, как часто у меня также ничего не получалось! И я буквально отползал от компьютера, посреди ночи, проклиная тот ****** день, "когда сел за баранку этого пылесоса" 8) Но, отдохнув и выспавшись, как следует, я на другое утро просыпался с новой идей, а что, если сделать вот так и так... И, конечно, не с первого раза, но со второй или с третьей, а иногда и с десятой попытки, но, таки, всё получалось 8)) И у Вас всё непременно получится!) Будьте уверены. Я нисколько в этом не сомневаюсь.

Originally posted by East Vikingr:
Появился доступ к другому компьютеру. На днях буду пробовать ставить чистую версию, с последни хуком. Ну, там и глянем.

Это очень хорошая идея! Буквально сегодня хотел предложить нечто подобное!

Originally posted by East Vikingr:
А насчет не запускающегося хука, то у меня также стоит множество модов (с которыми мод работал раньше)), так что он работает.

Кстати говоря, это вполне может быть именно той самой причиной! Потому что даже с установленным mod_hooks.zip модификации умудряются каким-то неведомым образом конфликтовать между собой!!! Несколько раз мне приходилось удалять этот самый мод!) Что, сразу, каким-то "чудом", помогало безошибочно работать моим собственным модификациям. Хотя вот, казалось бы, где повод для конфликта!? А всё равно ведь всё ломалось! С ошибкой в доступе к стэку. Так что, попробуйте поставить всё зачисто и запустить игру с единственным модом. Тем самым. Думаю что, всё заработает 8)

И вот тогда мы, общими усилиями, как-то перепишем эту хрень!) Удачи Вам!!! Всё получится!!!!!
Да, все хорошо и работает. Вычислил мод, который давал конфликт -

mod_the_elite_few_core-253-1-3-1599385355

внутри мода добавил строку "<mod_backgroundperksunlocked" и все заработало даже с ним. Спасибо)
centurion-x Sep 11, 2020 @ 12:30pm 
Originally posted by East Vikingr:
Спасибо)

Я всегда готов помочь, насколько в моих силах.

Originally posted by East Vikingr:
Вычислил мод, который давал конфликт -
mod_the_elite_few_core-253-1-3-1599385355

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

Originally posted by East Vikingr:
Внутри мода добавил строку "<mod_backgroundperksunlocked" и все заработало даже с ним.

Очень рад, что нашлась как причина проблемы, так и вариант её решения.

Если что, то возможен альтернативный способ добиться желаемого, с использованием функции onAdded() из character_background.nut:

... local actor = this.getContainer().getActor(); actor.getSkills().add(this.new("scripts/skills/perks/perk_name")); this.character_background.onAdded(); ...
Last edited by centurion-x; Sep 11, 2020 @ 12:40pm
Sneery Thug Mar 26, 2021 @ 1:08pm 
thanks for this manual! it helps really much in grasping the basics
Uni_inU Oct 17, 2021 @ 10:24am 
Не знаю дождусь ли я ответа, но все же. Как к примеру к оружейному перку прикрутить возможность возврата перка как у студента, на условном 7 лвле, но так что бы он оставался активным? Даже в том же студенте если поменять 11 на что то другое он не работает.
< >
Showing 16-26 of 26 comments
Per page: 1530 50