Нажмите, чтобы прочитать
Особенностью этого скрипта является то, что он охватывает все (199 ) поселения страткарты, для каждого из которых при осаде противником создает гарнизон, варьирующийся качественно по типу юнитов в зависимости от фракции-владельца поселения и количественно от уровня самого поселения.
В своем обзоре приведу краткое истолкование алгоритма скрипта и скриншоты из игры на примере тестирования одного отдельно взятого поселения (скрипт довольно масштабен и аналогичен, поэтому понять его замысел очень просто на примере одного поселения).
Рассмотрим исследуемую основу скрипта:
Вышеприведенный скрипт идейно состоит из двух составных конструкций: 1-ая (Wilderland_Owner) осуществляет проверку фракции-владельца поселения, а 2-ая (Wilderland_Owner) в зависимости от результата первой проверки определяет тип создаваемого принудительно гарнизона при осаде.
Приступлю с разбора полетов первой скриптовой части - Wilderland_Owner.
Концепт мода изначально предусматривал такое развитие событий, что спаун (авто-появление) гарнизона в поселении подчиняется разделению на доминантных и рецессивных юнитов. Чтобы понять смысл такой особенности, попробую кратко пояснить : в каждой провинции карты может согласно концепции игры создаваться один двух из типов гарнизона, причем выбор данного типа зависит от того, какая из держав владеет осаждаемым поселением (например, город во владении эльфов спаунит "светлых" юнитов, орков - "темных" юнитов). Именно поэтому было принято решение задать подобную вариацию гарнизона при помощи переменной Wilderland_Garrison, к-рая для фракция "светлого" менталитета принимала бы значение "1", а для фракций "темного" менталитета - "-1".
Так был построен первый алгоритм:
declare_counter Wilderland_Garrison - задание счетчика гарнизона со встроенным изначально нулевым значением.
monitor_event SettlementTurnStart SettlementName Wilderland - типичное скриптовое событие, срабатывающее для поселения с именем Wilderland.
and not SettlementIsLocal - дополнительное, но очень важное условие - поселением не должен владеть игрок.
Далее для каждой фракции игры приводятся блоки if-end_if, цель которых - инициализация фракции-владельца поселения с конкретным именем.
set_counter Wilderland_Garrison 1 - если "ДА" (владелец поселения совпадает с требованием условия), то счетчик гарнизона изменяется и принимает новое значение "1". Впоследствии оно будет соответствовать "светлому" типу гарнизона.
После этого оператор if закрывается - это необходимо для поддержания работоспособности скрипта (тестирование показывает, что if более полезен для предотвращения непредусмотренных вылетов при прожиге скрипта...) - ведь в дальнейшем нужно пошагово пробежаться по всем фракциям, дабы узнать, какое значение получит переменная при том или ином раскладе игры...
Аналогично определяется "темный" тип гарнизона : в этом случае счетчик должен быть равен "-1", что задается, в свою очередь, типом фракции-владельца.
На этом первая конструкция рассмотрена, переходи ко второй части основного скрипта:
Прежде чем ответить на этот вопрос, следует сказать. что для реализации второй конструкции скрипта была введена новая переменная - Wilderland_Siege, которая представляет собой счетчик, определяющий тип осады.
Тип осады... В Dagor Dagorath концепт предусматривает такую ситуацию, что гарнизон будет количественно зависеть от того, насколько продвинутым является осаждаемое поселение. Иными словами, чем сильнее укрепелен город или замок, тем большее число юнитов придет на помощь мирному поселению в случае вражеской осады.
Поэтому в подобном случае нельзя не отметить особенность движка Medieval 2 TW - разбиение поселение на город и замок, каждый из которых соответственно способен находиться в игре в 5 различных состояниях. В игре это определяется типом стен у города или замка. Именно поэтому вырисовывается ответ на предыдущий вопрос - да, 10 уровней должны отвечать 10 различным значениям переменной, и именно поэтому вторая часть скрипта разделена на 10 мониторов. А если бы, скажем, в нашей ситуации был старый добрый Rome TW, где такой дифференциации поселений на 2 типа нет, то скрипт был бы намного компактнее - использовались бы 5 похожих конструкций.
Конечно, при составлении и тестировании были попытки задействовать и более примитивные конструкции - с помощью того же оператора if, к-рый, казалось бы, очень кстати в подобной задаче, но к сожалению этот вариант проявил себя безуспешно в связи с неработоспособностью скриптовой команды SettlementBuildingExists с эти самым оператором if.
Для полной ясности приведу картко объяснение одного такого монитора (остальные аналогичны - меняется разве что количество юнитов в команде спауна и уровень постройки стен, определяющий уровень города или замка).
Итак,
Внимание - в этом и дальнейших мониторах применен скриптовый тип события SettlementTurnEnd, в отличие от начального, где использовался SettlementTurnStart.
Чем это вызвано ?
В процессе долгих и порой безрезультатных тестов приходилось наблюдать явление, когда спаун создается сразу же после осады, после чего следует котрвылазка вражеского обороняющегося персонажа, а то и хуже - вообще гарнизон не создавался...
Однако, стабильность показал именно вариант с SettlementTurnEnd, который позволяет осаждающему персонажу после взятия осады завершить ход, а уже на новом ходу видеть, как обороняющийся гарнизон возрос. И это вполне реально с точки зрения естественных соображений - для сбора ополчения среди мирных жителей случае осады требуется время, а с учетом, что в моде временной отрезок поделен так, что 1 ход равен одному месяцу, это кажется очень хорошим раскладом...
and SettlementBuildingExists = wooden_pallisade - условие, проверяющее, построено ли в данном поселении строение wooden_pallisade ("Частокол").
and I_SettlementUnderSiege Wilderland - далее следует условие, подразумевающее, что в данный момент поселение находится в состоянии осады.
Далее прибегаем к помощи уже знакомого нам оператора if-end_if с целью задать в случае успешного выполнения всех вышеуказанных монитором условий тип создаваемого гарнизона:
create_unit Wilderland, light city unit, num 1, exp 0, arm 0, wep 0, где light city unit - тестовый (пробный) юнит (в моде на данный момент интегрция юнитов и их баланс находятся в стадии разработки... но это вопрос времени - вставить записи о юнитах в рабочий отлаженный скрипт не является проблемой).
далее блок if-end_if повторяется, но уже для "темного" типа гарнизона:
Остается важнейший момент в рассматриваемом мониторе - ограничение циклического срабатывания скрипта.
Именно для этого и вводится вторая переменная Wilderland_Siege.
set_counter Wilderland_Siege 1 - так, счетчик принимает оличное от нуля уникальное значение, которое позволяет дать монитору сигнал прекращении прожига блоков if.
Неоднократное тестирование показывало, что неиспользование подобной меры приводит к бесконечному спауну - гарнизон поселения забивается "под завязку" тестовыми юнитами, потому что монитор не дает соответсвующей остановки. Введение команды set_counter стабилизирует подобное явление.
Ну и напоследок, используется перед закрытием каждого монитора команда terminate_monitor - она фиксирует единократное срабатывание скрипта (дополнительный способ ограничить цикличность монитора).
Далее структура скрипта аналогична - осуществляется прожиг еще 9 подобных мониторов для случаев:
- поселение имеет постройку "Деревянные стены" (Wilderland_Siege = 2)
- поселение имеет постройку "Каменные стены" (Wilderland_Siege = 3)
- поселение имеет постройку "Высокие каменные стены" (Wilderland_Siege = 4)
- поселение имеет постройку "Огромные каменные стены" (Wilderland_Siege = 5)
- поселение имеет постройку "Городище" (Wilderland_Siege = -1)
- поселение имеет постройку "Деревянный замок" (Wilderland_Siege = -2)
- поселение имеет постройку "Каменный замок" (Wilderland_Siege = -3)
- поселение имеет постройку "Твердыня" (Wilderland_Siege = -4)
- поселение имеет постройку "Цитадель" (Wilderland_Siege = -5)
И только после всего этого скрипт считается завершенным для конкретного поселения. Дальше - его расширение на оставшиеся 198 поселений по образцу и подобию.
Теперь после долгого обзора взглянем, как осуществляется подобный скрипт в игре.
Приведу в пример скриншоты, сделанные при тестировании
а) Поселением владеет "светлая" фракция, осаждает поселение "темная" фракция, спаунится "светлый" тип гарнизона
б) Поселением владеет "темная" фракция, осаждает поселение "светлая" фракция, спаунится "темный" тип гарнизона
В своем обзоре приведу краткое истолкование алгоритма скрипта и скриншоты из игры на примере тестирования одного отдельно взятого поселения (скрипт довольно масштабен и аналогичен, поэтому понять его замысел очень просто на примере одного поселения).
Рассмотрим исследуемую основу скрипта:
Нажмите, чтобы прочитать
declare_counter Wilderland_Garrison; Wilderland_Ownermonitor_event SettlementTurnStart SettlementName Wilderlandand not SettlementIsLocalif I_SettlementOwner Wilderland = noldorsset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = lorienset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = silvanset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = dwarvesset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = eriadorset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = daleset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = rohanset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = gondorset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = arnorset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = mordorset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = northernset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = gommset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = isengardset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = dunlandset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = rhunset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = haradset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = umbarset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = avariset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = vindansset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = arthanorset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = pharasainset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = slaveset_counter Wilderland_Garrison -1end_ifend_monitordeclare_counter Wilderland_Siege; Wilderland_Spawn monitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = wooden_pallisadeand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 1, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 1, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 1terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = wooden_walland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 2, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 2, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 2terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = stone_walland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 3, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 3, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 3terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = large_stone_walland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 4, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 4, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 4terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = huge_stone_walland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 5, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 5, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 5terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = motte_and_baileyand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 1, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 1, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -1terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = wooden_castleand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 2, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 2, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -2terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = castleand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 3, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 3, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -3terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = fortressand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 4, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 4, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -4terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = citadeland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 5, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 5, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -5terminate_monitorend_monitor
Приступлю с разбора полетов первой скриптовой части - Wilderland_Owner.
declare_counter Wilderland_Garrison; Wilderland_Ownermonitor_event SettlementTurnStart SettlementName Wilderlandand not SettlementIsLocalif I_SettlementOwner Wilderland = noldorsset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = lorienset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = silvanset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = dwarvesset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = eriadorset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = daleset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = rohanset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = gondorset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = arnorset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = mordorset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = northernset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = gommset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = isengardset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = dunlandset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = rhunset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = haradset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = umbarset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = avariset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = vindansset_counter Wilderland_Garrison 1end_ifif I_SettlementOwner Wilderland = arthanorset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = pharasainset_counter Wilderland_Garrison -1end_ifif I_SettlementOwner Wilderland = slaveset_counter Wilderland_Garrison -1end_ifend_monitorПрежде всего, стоит отметить, что очень долго не удавалось найти способ привязать тип гарнизона к нужной фракции, а если это и получалось, то скрипт был настолько габаритен по масштабам, что его использование в игре было бы неуместным. Однако, удалось найти выход из такого положения...
Концепт мода изначально предусматривал такое развитие событий, что спаун (авто-появление) гарнизона в поселении подчиняется разделению на доминантных и рецессивных юнитов. Чтобы понять смысл такой особенности, попробую кратко пояснить : в каждой провинции карты может согласно концепции игры создаваться один двух из типов гарнизона, причем выбор данного типа зависит от того, какая из держав владеет осаждаемым поселением (например, город во владении эльфов спаунит "светлых" юнитов, орков - "темных" юнитов). Именно поэтому было принято решение задать подобную вариацию гарнизона при помощи переменной Wilderland_Garrison, к-рая для фракция "светлого" менталитета принимала бы значение "1", а для фракций "темного" менталитета - "-1".
Так был построен первый алгоритм:
declare_counter Wilderland_Garrison - задание счетчика гарнизона со встроенным изначально нулевым значением.
monitor_event SettlementTurnStart SettlementName Wilderland - типичное скриптовое событие, срабатывающее для поселения с именем Wilderland.
and not SettlementIsLocal - дополнительное, но очень важное условие - поселением не должен владеть игрок.
Далее для каждой фракции игры приводятся блоки if-end_if, цель которых - инициализация фракции-владельца поселения с конкретным именем.
if I_SettlementOwner Wilderland = noldors set_counter Wilderland_Garrison 1end_ifI_SettlementOwner Wilderland = noldors - условие, спрашивающее "владеет ли указанным поселением фракция noldors (в ME-DD это Высшие эльфы)".
set_counter Wilderland_Garrison 1 - если "ДА" (владелец поселения совпадает с требованием условия), то счетчик гарнизона изменяется и принимает новое значение "1". Впоследствии оно будет соответствовать "светлому" типу гарнизона.
После этого оператор if закрывается - это необходимо для поддержания работоспособности скрипта (тестирование показывает, что if более полезен для предотвращения непредусмотренных вылетов при прожиге скрипта...) - ведь в дальнейшем нужно пошагово пробежаться по всем фракциям, дабы узнать, какое значение получит переменная при том или ином раскладе игры...
Аналогично определяется "темный" тип гарнизона : в этом случае счетчик должен быть равен "-1", что задается, в свою очередь, типом фракции-владельца.
На этом первая конструкция рассмотрена, переходи ко второй части основного скрипта:
declare_counter Wilderland_Siege; Wilderland_Spawn monitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = wooden_pallisadeand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 1, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 1, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 1terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = wooden_walland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 2, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 2, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 2terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = stone_walland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 3, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 3, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 3terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = large_stone_walland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 4, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 4, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 4terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = huge_stone_walland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 5, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 5, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 5terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = motte_and_baileyand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 1, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 1, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -1terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = wooden_castleand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 2, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 2, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -2terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = castleand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 3, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 3, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -3terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = fortressand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 4, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 4, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -4terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = citadeland I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light castle unit, num 5, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark castle unit, num 5, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege -5terminate_monitorend_monitorВторая часть рассматриваемого скрипта состоит из 10 скриптовых событий (мониторов), устройство каждого из которых аналогично. Почему мониторов именно 10 ?
Прежде чем ответить на этот вопрос, следует сказать. что для реализации второй конструкции скрипта была введена новая переменная - Wilderland_Siege, которая представляет собой счетчик, определяющий тип осады.
Тип осады... В Dagor Dagorath концепт предусматривает такую ситуацию, что гарнизон будет количественно зависеть от того, насколько продвинутым является осаждаемое поселение. Иными словами, чем сильнее укрепелен город или замок, тем большее число юнитов придет на помощь мирному поселению в случае вражеской осады.
Поэтому в подобном случае нельзя не отметить особенность движка Medieval 2 TW - разбиение поселение на город и замок, каждый из которых соответственно способен находиться в игре в 5 различных состояниях. В игре это определяется типом стен у города или замка. Именно поэтому вырисовывается ответ на предыдущий вопрос - да, 10 уровней должны отвечать 10 различным значениям переменной, и именно поэтому вторая часть скрипта разделена на 10 мониторов. А если бы, скажем, в нашей ситуации был старый добрый Rome TW, где такой дифференциации поселений на 2 типа нет, то скрипт был бы намного компактнее - использовались бы 5 похожих конструкций.
Конечно, при составлении и тестировании были попытки задействовать и более примитивные конструкции - с помощью того же оператора if, к-рый, казалось бы, очень кстати в подобной задаче, но к сожалению этот вариант проявил себя безуспешно в связи с неработоспособностью скриптовой команды SettlementBuildingExists с эти самым оператором if.
Для полной ясности приведу картко объяснение одного такого монитора (остальные аналогичны - меняется разве что количество юнитов в команде спауна и уровень постройки стен, определяющий уровень города или замка).
Итак,
monitor_event SettlementTurnEnd SettlementName Wilderlandand SettlementBuildingExists = wooden_pallisadeand I_SettlementUnderSiege Wilderland if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 1, exp 0, arm 0, wep 0 end_if if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 1, exp 0, arm 0, wep 0 end_ifset_counter Wilderland_Siege 1terminate_monitorend_monitormonitor_event SettlementTurnEnd SettlementName Wilderland - после задания нового счетчика осады Wilderland_Siege вводим новое скриптовое событие, проверющее изменения в структуре поселения на конце хода для тестируемого поселения указанного имени.
Внимание - в этом и дальнейших мониторах применен скриптовый тип события SettlementTurnEnd, в отличие от начального, где использовался SettlementTurnStart.
Чем это вызвано ?
В процессе долгих и порой безрезультатных тестов приходилось наблюдать явление, когда спаун создается сразу же после осады, после чего следует котрвылазка вражеского обороняющегося персонажа, а то и хуже - вообще гарнизон не создавался...
Однако, стабильность показал именно вариант с SettlementTurnEnd, который позволяет осаждающему персонажу после взятия осады завершить ход, а уже на новом ходу видеть, как обороняющийся гарнизон возрос. И это вполне реально с точки зрения естественных соображений - для сбора ополчения среди мирных жителей случае осады требуется время, а с учетом, что в моде временной отрезок поделен так, что 1 ход равен одному месяцу, это кажется очень хорошим раскладом...
and SettlementBuildingExists = wooden_pallisade - условие, проверяющее, построено ли в данном поселении строение wooden_pallisade ("Частокол").
and I_SettlementUnderSiege Wilderland - далее следует условие, подразумевающее, что в данный момент поселение находится в состоянии осады.
Далее прибегаем к помощи уже знакомого нам оператора if-end_if с целью задать в случае успешного выполнения всех вышеуказанных монитором условий тип создаваемого гарнизона:
if I_CompareCounter Wilderland_Garrison = 1 create_unit Wilderland, light city unit, num 1, exp 0, arm 0, wep 0end_ifI_CompareCounter Wilderland_Garrison = 1 - с помощью этого скриптового условия осуществляем логический возврат к первоначальной переменной Wilderland_Garrison и сравниваем ее действующее значение с требуемым: если счетчик равен "1", то получаем добро на создание "светлого" типа юнита в гарнизоне поселения:
create_unit Wilderland, light city unit, num 1, exp 0, arm 0, wep 0, где light city unit - тестовый (пробный) юнит (в моде на данный момент интегрция юнитов и их баланс находятся в стадии разработки... но это вопрос времени - вставить записи о юнитах в рабочий отлаженный скрипт не является проблемой).
далее блок if-end_if повторяется, но уже для "темного" типа гарнизона:
if I_CompareCounter Wilderland_Garrison = -1 create_unit Wilderland, dark city unit, num 1, exp 0, arm 0, wep 0end_ifЗдесь все симметрично: осуществляется проверка на показание переменной "-1", а затем спаунится в нужном количестве "темный" тестовый юнит dark city unit.
Остается важнейший момент в рассматриваемом мониторе - ограничение циклического срабатывания скрипта.
Именно для этого и вводится вторая переменная Wilderland_Siege.
set_counter Wilderland_Siege 1 - так, счетчик принимает оличное от нуля уникальное значение, которое позволяет дать монитору сигнал прекращении прожига блоков if.
Неоднократное тестирование показывало, что неиспользование подобной меры приводит к бесконечному спауну - гарнизон поселения забивается "под завязку" тестовыми юнитами, потому что монитор не дает соответсвующей остановки. Введение команды set_counter стабилизирует подобное явление.
Ну и напоследок, используется перед закрытием каждого монитора команда terminate_monitor - она фиксирует единократное срабатывание скрипта (дополнительный способ ограничить цикличность монитора).
Далее структура скрипта аналогична - осуществляется прожиг еще 9 подобных мониторов для случаев:
- поселение имеет постройку "Деревянные стены" (Wilderland_Siege = 2)
- поселение имеет постройку "Каменные стены" (Wilderland_Siege = 3)
- поселение имеет постройку "Высокие каменные стены" (Wilderland_Siege = 4)
- поселение имеет постройку "Огромные каменные стены" (Wilderland_Siege = 5)
- поселение имеет постройку "Городище" (Wilderland_Siege = -1)
- поселение имеет постройку "Деревянный замок" (Wilderland_Siege = -2)
- поселение имеет постройку "Каменный замок" (Wilderland_Siege = -3)
- поселение имеет постройку "Твердыня" (Wilderland_Siege = -4)
- поселение имеет постройку "Цитадель" (Wilderland_Siege = -5)
И только после всего этого скрипт считается завершенным для конкретного поселения. Дальше - его расширение на оставшиеся 198 поселений по образцу и подобию.
Теперь после долгого обзора взглянем, как осуществляется подобный скрипт в игре.
Приведу в пример скриншоты, сделанные при тестировании
а) Поселением владеет "светлая" фракция, осаждает поселение "темная" фракция, спаунится "светлый" тип гарнизона
б) Поселением владеет "темная" фракция, осаждает поселение "светлая" фракция, спаунится "темный" тип гарнизона
Сообщение отредактировал Master_TW_DAR: 07 мая 2014 - 20:44