Файлы миров лежат в /worldgen/worlds и имеют расширение .world. Формат у них похож на формат var-ов.
Пример (artifacts_v1.0.1.world):
Identifier: artifacts_v1.0.1
Name: Мир артефактов
#Редкость артефактов уменьшена на 2#
/
Filename: item.var
Attribute: Rarity
Value: -2
Condition: Rarity>2 and Rarity<8
/
Filename: item.var
Attribute: Rarity
Value: -1
Condition: Rarity=2
где:
Identifier - Уникальный идентификатор мира (Идентификатор текущего мира сохраняется в worldgen.cfg).
Имя и описание думаю понятно и так.
Дальше идут модификации со следующими параметрами:
Filename - var-файл, в котором мы производим изменения
Attribute - атрибут из var-файла, значение которого меняет данная модификация.
Если в названии атрибута в var-е содержится что-то кроме a-z, 0-9 и "_", то нужно это заменить (пробелы на подчеркивание, остальное удалить). К примеру "Gold income" из raсe.var нужно писать как "Gold_income".
Value - новое значение. Можно использовать синтаксис Javascript или принятые сокращения. Примеры:
-2 : уменьшить на 2
+2 : увеличить на 2
2 : установить на 2 (абсолютное значение)
+20% : увеличить на 20%
-20% : уменьшить на 20%
Fn.random(1, 5) : случайное число от 1 до 5
(Attack + CounterAttack)*2 + Fn.random(1, 2) : формула с использованием других аттрибутов, и функции random
Condition - условие (опционально, можно убрать всю строку). Можно использовать синтаксис Javascript.
Примеры:
Life>10
ShootingRange>=4 or UnitClass!=2
contains([9, 14, 123], Identifier) : идентификатор входит в указаный список
contains([1, 2], UnitClass) and (Speed>2 or Level!=2) : более сложное условие, со скобками
Номер элемента в var-е называется Identifier (число, которое стоит после "/"), так что если мы хотим поменять что-то скажем у Пегаса, то делаем условие "Identifier=24"
Во многих местах в файлах миров используются формулы (к примеру в Condition).
Эти формулы основаны на Javascript и используют синтаксис этого языка.
Вот тут есть справочник.
Есть следующие отличия:
В теле фрагментов и в некоторых других местах можно использовать так называемые встроенные формулы. Такие формулы заключены в фигурные скобки, к примеру {Fn.random([92, 170])}. В этих формулах нет доступа к атрибутам и спискам, но можно к примеру сделать что-нибудь в этом роде: {LastId_unit+1}
Сразу на примерах:
Эти функции используются только в модификациях списков (смотри ниже) и с префиксом в виде названия списка (к примеру Effects.containsAttr(...) или Abilities.anyIn(...)).
После всех модификаций находится опциональный раздел "snippets". Он содержит фрагменты текста/варов, которые можно использовать в некоторых модификациях, задав в атрибуте "Snippet" имя соответствующего фрагмента.
Пример из мира трупоедов:
/
Filename: unit.var
Action: add
ListName: Abilities
Snippet: cannibal_ability_5
Condition: Identifier>0 and !Abilities.anyIn('Value', [79, 535]) and Level<3
/
Filename: unit.var
Action: add
ListName: Abilities
Snippet: cannibal_ability_10
Condition: Identifier>0 and !Abilities.anyIn('Value', [79, 535]) and Level>2
=== snippets
-- cannibal_ability_5
Cannibalise: 535
-- cannibal_ability_10
Cannibalise: 79
Строка "=== snippets" обозначает начало раздела фрагментов (должна идти после всех модификаций и только один раз).
Каждый фрагмент начинается с "-- " и дальше идет его название, которое можно использовать в модификациях.
"Тело" фрагмента начинается со следующей строки и идет до следующего фрагмента/конца файла.
При написании фрагментов, учитывайте, что они копируются "как есть", то есть с пустыми строками или без них, если они не заданы. Там где нужно, необходимо добавить в начале пустую строку.
В теле фрагментов можно использовать встроенные формулы, к примеру
{Fn.random([92, 170])}
(смотри
Встроенные формулы)
Под списками подразумеваются списки элементов, в которых каждый элемент состоит из одного или больше атрибута (примеры списков: эффекты, способности, виды местности и т.п.).
Вот, к примеру, список способностей из unit.var:
Abilityes:
Lesser_Undead: 61
Skeletal: 576
Round_attack: 108;
В данном случае каждый элемент состоит лишь из одной строки/одного атрибута.
Другой пример:
Effects:
Attack: 2
Power: 2
Duration: 5
CounterAttack: 3
Power: 2
Duration: 5
Тут уже каждый элемент состоит из нескольких атрибутов.
Answers, Effects, Abilities, Units, Upgrades, Loot, Guards, Events, ResourceBoni, Objectives, Hero_Upgrades, Squad_Upgrades, Terrains, Talents, Items.
Hero_Upgrades и Squad_Upgrades: skill.var
Objectives: quest.var
ResourceBoni: outer_build.var
Talents: hero_class.var
Остальные встречаются как правило в нескольких варах и понять где какой там не сложно.
/
Filename: guard.var
Action: add
ListName: Units
Snippet: new_guard_unit_1
Condition: Identifier=18
...
=== snippets
-- new_guard_unit_1
Unit6: {Fn.random([92, 170])}, 3, 1, 0
Action: действие ("add" означает, что мы добавляем элемент к списку).
В ListName задано название списка.
В Snippet указано название добавляемого фрагмента.
Condition - условие, которое может содержать специальные функции списков (смотри
Функции списков).
/
Filename: site.var
Action: remove
ListName: Guards
Condition: contains([100, 101, 102], $.Guard)
Action: действие ("remove" означает, что мы удаляем элементы из списка).
В ListName задано название списка.
Condition - условие, которое может содержать специальные функции списков (смотри
Функции списков).
$.Guard означает атрибут "Guard" сравниваемого элемента списка (в данном случае списка "Guards")
/
Filename: unit_upg.var
Action: add_entry
Snippet: unit_upg_1
...
=== snippets
-- unit_upg_1
/{LastId_unit_upg+1}
Name: Посланник смерти;
...
Action: действие ("add_entry" означает добавление записи в var-файл)
Snippet: название фрагмента для добавления
В теле фрагмента вместо идентификатора мы используем константу с последним идентификатором и добавляем +1. Так мы можем не привязываться к конкретному моду и если количество записей изменится, не нужно будет подстраивать мир. При добавлении нескольких записей в один и тот же var можно продолжать увеличивать идентификатор:
{LastId_unit_upg+2}
,
{LastId_unit_upg+3}
и т.д.
/
Filename: Site.txt
Action: add_text
Snippet: text_site_1
...
=== snippets
-- text_site_1
{LastId_site+1}. Кладбище
...
Action: действие ("add_text" означает добавление записи в txt-файл)
Snippet: название фрагмента для добавления
/
Filename: Units.dat
Action: add_image
ImageFile: envoy_of_death.bmp
ImageName: Unit{Fn.leftZeroPad(LastId_unit+1, 3)}
Action: действие ("add_image" означает добавление картинки в dat-файл)
ImageFile: имя файла с картинкой (сама картинка должна лежать в /worlds/images/ в подкаталоге с тем же именем, что и идентификатор мира, к примеру в /worlds/images/undead_v1.0.2)
ImageName: Название картинки внутри dat-файла (как видно на примере, можно использовать встроенные формулы)
При добавлении юнитов необходимо помнить, что нужно несколько картинок (для Units.dat, Unit_icons.dat, Unit_shadow.dat и Unit_shadowf.dat)
/
Filename: unit_sound.dat
Action: add_sound
SoundFile: new_unit_sound.ogg
SoundName: S{Fn.leftZeroPad(LastDatId_unit_sound+1, 3)}
Action: действие ("add_sound" означает добавление звука в dat-файл)
SoundFile: имя файла со звуком (сама картинка должна лежать в /worlds/images/ в подкаталоге с тем же именем, что и идентификатор мира, к примеру в /worlds/images/undead_v1.0.2)
SoundName: Название звука внутри dat-файла (как видно на примере, можно использовать встроенные формулы)
Звуки должны быть в формате OGG.
/
Filename: unit.var
Action: replace_entry
Snippet: units
...
=== snippets
-- units
/31
Name: Гарпия;
...
/32
Name: Василиск;
...
Action: действие ("replace_entry" означает замену записей в var-файле)
Snippet: название фрагмента для добавления
В теле фрагмента могут быть несколько записей, они будут автоматически найдены через ID и заменены в соответствующем var-файле.
Обычно модификации проще делать через изменения конкретных атрибутов, элементов списка и т.д. (см. выше), но если мы меняем очень многое, то бывает проще заменить всю запись целиком и для этого и существует данный тип действия.
/
Filename: Defender.txt
Action: replace_text
Snippet: defender_texts
...
=== snippets
-- defender_texts
2. Шайка воров
#...#
3. Племя
#...#
...
Action: действие ("replace_text" означает замену записей в txt-файле)
Snippet: название фрагмента для добавления
В теле фрагмента могут быть несколько записей, они будут автоматически найдены через ID и заменены в соответствующем txt-файле.
/
Filename: PortraitsMen.dat
Action: replace_image
ImageFile: normal/000Warrior.bmp
ImageName: 000Warrior
Action: действие ("replace_image" означает замену картинки в dat-файле)
ImageFile: имя файла с картинкой (сама картинка должна лежать в /worlds/images/ в подкаталоге с тем же именем, что и идентификатор мира, к примеру в /worlds/images/portraits_men_v1)
ImageName: Название картинки внутри dat-файла
/
Filename: unit_sound.dat
Action: replace_sound
SoundFile: phoenix_attack.ogg
SoundName: S165
Action: действие ("replace_sound" означает замену звука в dat-файле)
SoundFile: имя файла со звуком (сама картинка должна лежать в /worlds/images/ в подкаталоге с тем же именем, что и идентификатор мира, к примеру в /worlds/images/undead_v1.0.2)
SoundName: Название звука внутри dat-файла (как видно на примере, можно использовать встроенные формулы)
Звуки должны быть в формате OGG. Заменять звуки можно только в spell_sound.dat и unit_sound.dat.
Строка, начинающаяся с "§", является комментарием.
На русской клавиатуре, к сожалению, нет этого символа, поэтому пока что можно либо копировать из имеющихся миров, либо использовать следующую комбинацию клавиш: Зажав "Alt", набрать 0167, отпустить "Alt".