Вторая часть.
Как было отмеченно в предыдущей главе, ваша работа с модульной системой заключается в:
  1) Редактировании одного или более module-файлов (которые начинаются с “module_ ...“ и заканчиваются с  “.py”) и вносить в них любые изменения на ваш вкус. (Обычно, вам нужно щелкнуть правой кнопкой мышки и выбрать Edit with IDLE/редактировать с IDLE чтобы сделать это).
  2) Затем, дважды щелкнуть на файле build_module.bat в папке где расположена модульная система. Это действие позволит сконструировать ваш модуль (и доложит об ошибках, если они есть).
  3) Если ошибок не отмечено, вы можете загрузить ваш модуль с помощью загрузчика Mount&Blade и проверить измения, которые вы сделали. Иногда вам будет необходимо начать новую игру,  для того чтобы изменения возымели эффект.

2.1 Редактирование module-файлов.

Модульная система использует python-овские списки (прим: по-простому - это блоки данных; для более продвинутых - список это составной тип данных, в конкретном случае составными элементами для него послужит тип данных определямый как запись). Python-овские списки начинаются  с квадратных скобок, внутри скобок находится список объектов, отделенных друг от друга запятыми, и заканчиваются они (списки) закрытием квадратных скобок. Если вы откроете и посмотрите любой module-файл, вы увидете, что он состоит из подобных списков. Для примера, файл module_map_icons.py (он описывает значки на глобальной карте) включает:

map_icons = [
  ("player",0,"player", 0.2, snd_footstep_grass),
  ("player_horseman",0,"player_horseman", 0.2, snd_gallop),
  ("gray_knight",0,"knight_a", 0.2, snd_gallop),
  ("vaegir_knight",0,"knight_b", 0.2, snd_gallop),
  ("peasant",0,"peasant_a", 0.2,snd_footstep_grass),
  ("khergit",0,"khergit_horseman", 0.2,snd_gallop),
  ("axeman",0,"bandit_a", 0.2,snd_footstep_grass),
  ("woman",0,"woman_a", 0.2,snd_footstep_grass),
  ("town",mcn_no_shadow,"City", 0.9,snd_footstep_grass),
]

Описанный выше список, с именем  map_icons , является обычным python-овским списком и каждый его элемент это значок на карте. Разберем первый объект в списке - (“player”,0,'player”,0.2,snd_footstep_grass) . В дальнейшем мы будем определять тип таких объектов как “запись” (прим: в английском руководстве "tuple").  (прим. 2:  запись/tuple это объект, состоящий из нескольких элементов. Эти элементы могут быть разных типов). Записи, как и списки, включают в себя элементы отделённые запятой, но в отличе от списков, они заключены в круглые скобки. Структура каждого объекта типа  “запись” объясняется вначале module-файла и отличается от файла к файлу.

Для простоты восприятия иерархии, запомните простую и логичную фразу: список записей элементов.
Наглядная структура:
список = [
(элемент,элемент), <--запись
(элемент,элемент), <--запись
]

Запись каждого значка на карте содержит следущие элементы:

1) название значка, которое мы увидим на карте (набор символов)
2) метки - задаваемые условия, влияющие на отображение (это определённые параметры, о них позже)
3) название модели, которая будет отображена (должно соответствовать названию файла модели без расширения)
4) размеры модели (число; 1 соответствует 100% величине)
5) идентификатор звука - идентификатор записи, содержащей данные звукового сопровождения (должен соответствовать названию звукового файла без расширения)

Итак, первая запись это - (“player”,0,'player”,0.2,snd_footstep_grass) -
1) Название значка на карте = “player”
2) Флаги = 0
3) mesh name/название модели = “player”
4) mesh scale/масштаб = 0.2
5) индентификатор звука = snd_footstep_grass

Изучая шапку файла с описаниями и анализируя затем содержимое списков, вы можете самостоятельно разложить все структуры игровых объектов в каждом из module-файлов.

2.2 Добавление новых игровых объектов

Изучив структуру записи значков на карте, мы можем приступить к добавлению наших собственных значков. Давайте посмотрим на следущий python-овский список:

map_icons = [
  ("player",0,"player", 0.2, snd_footstep_grass),
  ("player_horseman",0,"player_horseman", 0.2, snd_gallop),
  ("gray_knight",0,"knight_a", 0.2, snd_gallop),
  ("vaegir_knight",0,"knight_b", 0.2, snd_gallop),
  ("peasant",0,"peasant_a", 0.2,snd_footstep_grass),
  ("khergit",0,"khergit_horseman", 0.2,snd_gallop),
  ("axeman",0,"bandit_a", 0.2,snd_footstep_grass),
  ("woman",0,"woman_a", 0.2,snd_footstep_grass),
  ("town",mcn_no_shadow,"City", 0.9,snd_footstep_grass),
]

Новый игровой объект в любом module-файле должен быть добавлен внутрь списка. Как мы видим, список в module_map_icons заканчивается сразу после ("town",mcn_no_shadow,"City", 0.9,snd_footstep_grass). Давайте освободим место под наш новый значок, для этого мы должны сдвинуть квадратную скобку “]” на одну строку ниже.

Теперь мы можем добавить в освободившееся место наш новый объект. Простейший способ сделать это – скопировать и вставить предыдущюю запись, а затем отредактировать ее содержимое. Для примера:

map_icons = [
  ("player",0,"player", 0.2, snd_footstep_grass),
  ("player_horseman",0,"player_horseman", 0.2, snd_gallop),
  ("gray_knight",0,"knight_a", 0.2, snd_gallop),
  ("vaegir_knight",0,"knight_b", 0.2, snd_gallop),
  ("peasant",0,"peasant_a", 0.2,snd_footstep_grass),
  ("khergit",0,"khergit_horseman", 0.2,snd_gallop),
  ("axeman",0,"bandit_a", 0.2,snd_footstep_grass),
  ("woman",0,"woman_a", 0.2,snd_footstep_grass),
  ("town",mcn_no_shadow,"City", 0.9,snd_footstep_grass),
  (
"new_icon",mcn_no_shadow,"City", 0.9,snd_footstep_grass),
]

В этом примере, мы скопировали ("town",mcn_no_shadow,"City", 0.9,snd_footstep_grass) и задали новое название для нашего значка на карте; "new_icon". У этого объекта есть метка-флаг. Метки указывают на дополнительные свойства объекта, (каждое свойство имеет соответствующюю метку-переключатель и может быть “включенно” или  “выключенно”  при помощи добавления или удаления такой метки). В нашем примере метка mcn_no_shadow на новом объекте указывает, что он не отбрасывает тени на землю.

Удалим метку mcn_no_shadow с нашего нового значка. Для этого заменим метку mcn_no_shadow на 0. Это скажет модульной системе, что меток для данного объекта нет.

map_icons = [
  ("player",0,"player", 0.2, snd_footstep_grass),
  ("player_horseman",0,"player_horseman", 0.2, snd_gallop),
  ("gray_knight",0,"knight_a", 0.2, snd_gallop),
  ("vaegir_knight",0,"knight_b", 0.2, snd_gallop),
  ("peasant",0,"peasant_a", 0.2,snd_footstep_grass),
  ("khergit",0,"khergit_horseman", 0.2,snd_gallop),
  ("axeman",0,"bandit_a", 0.2,snd_footstep_grass),
  ("woman",0,"woman_a", 0.2,snd_footstep_grass),
  ("town",mcn_no_shadow,"City", 0.9,snd_footstep_grass),
  ("new_icon",
0,"City", 0.9,snd_footstep_grass),
]

Оба значка - “town” и “new_icon” - используют меш/модель “City”, это значит что оба используют одну и ту же 3D модель “City” в resource-файлах игры. Изменяя этот элемент мы можем сменить графическое отображение значка на любую 3D модель из resourse-файлов.

Т.к. оба значка используют одну и ту же 3D модель, то наш новый значок "new_icon" будет выглядеть в точности как значок "town".

Давайте попробуем задать нашему значку немного отличный от "town" облик.

map_icons = [
  ("player",0,"player", 0.2, snd_footstep_grass),
  ("player_horseman",0,"player_horseman", 0.2, snd_gallop),
  ("gray_knight",0,"knight_a", 0.2, snd_gallop),
  ("vaegir_knight",0,"knight_b", 0.2, snd_gallop),
  ("peasant",0,"peasant_a", 0.2,snd_footstep_grass),
  ("khergit",0,"khergit_horseman", 0.2,snd_gallop),
  ("axeman",0,"bandit_a", 0.2,snd_footstep_grass),
  ("woman",0,"woman_a", 0.2,snd_footstep_grass),
  ("town",mcn_no_shadow,"City", 0.9,snd_footstep_grass),
  ("new_icon",0,"City",
5.0,snd_footstep_grass),
]

В этом примере мы изменили масштаб значка с 0.9 до 5.0. Это значит, что значок будет отображен в пять раз крупнее обычного. Это поможет нам отличить наш значок от обычного значка “town", когда мы добавим его в игру.

Далее мы создадим новый отряд (party) в файле module_parties.py  (прим: все объекты на игровой карте ислючая ландшафт являются “отрядами”), который будет использовать наш значок на карте. Чтобы сделать это, нам необходимо “сослаться” на созданный нами значок из файла module_parties.py.

2.3 Ссылки на игровые объекты

Откройте файл module_parties.py в папке с модульной системой. Нам предстоит разобрать другой python-овский список – parties = [.

Как видим, структура записей в module_parties.py отличается от module_icons.py. Впрочем как и многие - если не все - другие "module_" файлы. Пока есть возможность, изучим структуру этого.

Пример записи отряда:

("zendar","Zendar",icon_town|pf_is_static|pf_always_visible|pf_hide_defenders, "zendar", pt_none, fac_neutral,0,ai_bhvr_hold,0,(2,46),[(trp_swadian_knight,6,0)]),

Эта запись определяет местонахождение города Zendar на карте. Свойства объекта Zendar описываются в соответствующих полях – довольно похожие на те, что мы успели разобрать в файле module_icons.py.

Итак:

1) Идентификатор отряда. Служит для обращения к объекту из разных частей файла и из других файлов вообще.
2) Имя отряда. Это имя будет отображенно как название объекта в игре. Может быть отлично от индентификатора отряда, если пожелаете.
3) Метки отряда. Первая метка для каждого отряда (их может быть несколько, отделяются друг от друга значком “|”) должна указывать на значок, используемый при отображении отряда на карте.
4) Меню. Это поле устарело и с версии M&B 0.730 больше не используется.
5) Шаблон отряда. Индентификатор (ID) шаблона, к которому описываемый отряд принадлежит. Используйте метку “pt_none”, как значение по умолчанию.
6) Фракция отряда. Может иметь любое значение входящее в файл module_factions.py.
7) Характеристики отряда. Для объяснения значения Personality/характеристика смотри и разбирай записи из файла header_parties.py.
8) Поведение ИИ (искуственный интелект). Определяет как ИИ отряд будет действовать на глобальной карте.
9) Группы-цели для ИИ. Определяет цели для ИИ.
10) Инициализация координат. Определяет стартовое положение отряда на карте; X,Y.
       11.1) Идентификатор войска. Любое значение (как регулярные войска, так и герои) из файла module_troops.py.
       11.2) Число войск в описываемом стеке/отряде; не варьируется. То колличество, что введете, то и будет. (прим: имеетсе ввиду, что нельзя задать количество войск, определяющееся из заданного интервала, скажем: ..., (свадийские рыцари, от50..до60),...)
       11.3) Метки войска. Опционально, т.е. необязательно к заполнению. Используйте метку pmf_is_prisoner если хотите отметить, что заявленный стек – заключенный.

Рассмотрим запись объекта Zendar:

("zendar","Zendar",icon_town|pf_is_static|pf_always_visible|pf_hide_defenders, "zendar", pt_none, fac_neutral,0,ai_bhvr_hold,0,(2,46),[(trp_swadian_knight,6,0)]),

1) Идентификатор отряда = “zendar"
2) Имя отряда = “Zendar”
3) Метки = icon_town|pf_is_static|pf_always_visible|pf_hide_defenders
4) Меню = "zendar"
5) Шаблон отряда = pt_none
6) Фракция отряда = fac_neutral
7) Характеристики отряда = 0
8) Поведение ИИ = ai_bhvr_hold
9) Отряды-цели ИИ = 0
10) Координаты отряда на глобальной карте = (2,46)
11) Список войск
       11.1) Индентификатор = trp_swadian_knight
       11.2) Число войск в этом стеке = 6
       11.3) Метки войск = 0

Рассматривая поле (3), мы можем заметить, что Zendar ссылается на значок  “town”  из файла module_icons.py, добавляя перед его именем префикс icon_. Этот префикс указывает системе на соответствующий module-файл, где описан данный объект. Для того, чтобы сослаться на файл module_icons.py мы будем использовать префикс icon_; для того, чтобы сослаться на module_factions.py мы будем использовать префикс fac_ ; для ссылки на module_parties.py префикс p_; и так далее. В конце статьи вы найдете список префиксов для каждого module-файла.

Теперь, когда мы знаем как "устроены" отряды, мы можем добавить свой. Но перед этим, стоит отметить следущее: в файле module_parties.py, как и в некоторых других module-файлах, не следует добавлять ваш новый объект в конец списка. Внутри самого файла вы даже найдёте предупреждение об этом. Добавление записи в неправильном месте может дизорганизовать работу кода игры. В файле module_parties.py, рекомендуется добавлять ваш новый объект в список parties между строками "training_ground"  и "castle_1".

Теперь, скопируем и вставим в место оговоренное выше строку начинающуюся как: ("town_14" ...

  ("training_ground","Training Ground",  icon_town|pf_town|pf_disabled, "training_ground", pt_none, fac_vaegirs,0,ai_bhvr_hold,0,(-2,-3),[(trp_vaegir_knight,6,0)]),

  ("new_town","Mod_Town",  icon_town|pf_town, "town", pt_none, fac_vaegirs,0,ai_bhvr_hold,0,(-4,-37),[(trp_vaegir_knight,6,0)]),

  ("castle_1","Culmarr_Castle",icon_town|pf_is_static|pf_always_visible, "castle", pt_none, fac_outlaws,0,ai_bhvr_hold,0,(-47,-51),[(trp_swadian_knight,5,0),(trp_swadian_crossbowman,25,0)]),

В этом примере мы изменили идентификатор новой группы с “town_14” на “new_town”, и название группы с “Halmar” на “Mod_Town”.

Глядя на запись, можно установить следующее:.

1) Ссылаясь на этот отряд из другого файла, мы должны использовать идентификатор "new_town" с префиксом "p_". Суммируя, получаем "p_new_town" .
2) В игре мы будем видеть имя объекта только как "Mod Town" и никогда не увидим идентификатор.
3) Этот отряд использует icon_town (объект town из файла icons_modules.py) и метку pf_town – метку, она добавляет общие свойства города. С полем меток мы ещё поэкспериментируем.
4) Mod Town принадлежит королевству Вегир.
5) Если мы добавим наш город в игру, его местонахождение будет идентично координатам города Halmar. Это мы тоже изменим в дальнейшем.

  ("training_ground","Training Ground",  icon_town|pf_town|pf_disabled, "training_ground", pt_none, fac_vaegirs,0,ai_bhvr_hold,0,(-2,-3),[(trp_vaegir_knight,6,0)]),

  ("new_town","Mod_Town", icon_new_icon|pf_town, "town", pt_none, fac_neutral,0,ai_bhvr_hold,0,(-1,-1),[(trp_vaegir_knight,6,0)]),

  ("castle_1","Culmarr_Castle",icon_town|pf_is_static|pf_always_visible, "castle", pt_none, fac_outlaws,0,ai_bhvr_hold,0,(-47,-51),[(trp_swadian_knight,5,0),(trp_swadian_crossbowman,25,0)]),

Мы поменяли значок нашего города на значок icon_new_icon, вставив вместо метки icon_town метку icon_new_icon. (прим. для несообразительных: префикс icon_ + название значка на карте;  icon_ +  new_icon =  icon_new_icon). А также, мы изменили координаты местоположения объекта на карте на (-1,-1) и изменили фракцию города на fac_neutral.

Город теперь использует наш значок при отображении на экран и обладает собственным местоположением на карте. И все это без особых проблемых. Побробуйте это сделать сами.

Сохраните ваш прогресс, а затем два раза щелкните на build_module.bat. И если все прошло хорошо, вы можете запустить ваш мод и увидеть новый город в центре карты.

Если все не прошло хорошо, внимательно проверьте синтаксические ошибки. Неправильно, в разных местах по разному, указаны свои же названия,  запятые и скобки не на своих местах. Плохой синтаксис наиболее распространенная причина всех ошибок. Не забывайте пробелы в начале записей, а также что надо ставить не кавычки на русской раскладке по shift+2, а двойной апостроф по shift+э на английской.

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

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

fac_   -- module_factions.py
icon_   -- module_map_icons.py
itm_   -- module_items.py
mnu_   -- module_game_menus.py
mno_   -- module_game_menus.py -- References an individual menu option in module_game_menus.
mt_   -- module_mission_templates.py
psys_   -- module_particle_systems.py
p_      -- module_parties.py
pt_   -- module_party_templates.py
qst_   -- module_quests.py
script_   -- module_scripts.py
scn_   -- module_scenes.py
spr_   -- module_scene_props.py
str_   -- module_strings.py
trp_   -- module_troops.py

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