Голосование

Как вы оцениваете Смуту?












Оформление



Пользователей
Сейчас на форуме
Пользователи: 4
Гостей: 434
Всего: 438

0 Пользователей и 1 Гость просматривают эту тему.

Тема: [MS] Восьмая часть. Модульная система, файлы simple_triggers и triggers.  (Прочитано 10741 раз)

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


8.1 Файл module_simple_triggers.py.

В настоящий момент файл module_simple_triggers.py выполняет только одну фунцию: при столконовении игрока с другими отрядами на глобальной карте, направить его к соответствующему меню. (прим: это неправда. По видимому, автор ссылается на файл из устаревшей версии МиБа (ниже 1.0))  Для реализации этого эффекта используется python-овский список, состоящий из всего одной, но действительно длинной записи:

  (ti_on_party_encounter,
   [
       (store_encountered_party, reg(1)),
       (store_encountered_party2,reg(2)), # encountered_party2 is set when we come across a battle or siege, otherwise it's a minus value
       (try_begin),
         (lt, reg(2),0), #Normal encounter. Not battle or siege.
         (try_begin),
           (ge, reg(1), towns_begin),
           (lt, reg(1), towns_end),
           (jump_to_menu, "mnu_town"),
         (else_try),
         (else_try),
           (ge, reg(1), castles_begin),
           (lt, reg(1), castles_end),
           (jump_to_menu, "mnu_castle"),
         (else_try),
           (eq, reg(1), "p_zendar"),
           (jump_to_menu, "mnu_zendar"),
         (else_try),
           (eq, reg(1), "p_salt_mine"),
           (jump_to_menu, "mnu_salt_mine"),
         (else_try),
           (eq, reg(1), "p_four_ways_inn"),
           (jump_to_menu, "mnu_four_ways_inn"),
         (else_try),
           (eq, reg(1), "p_dhorak_keep"),
           (jump_to_menu, "mnu_dhorak_keep"),
         (else_try),
           (eq, reg(1), "p_training_ground"),
           (jump_to_menu, "mnu_training_ground"),
         (else_try),
           (store_current_hours, reg(7)),
           (le, reg(7), "$defended_until_time"),
           (assign, "$defended_until_time", 0),
           (jump_to_menu, "mnu_in_castle_under_attack"),
         (end_try),
       (else_try), #Battle or siege
       (try_end)
    ]),



Этот список состоит из одного единственного триггера. Запись триггера имеет очень простую конструкцию, состоящую из двух полей.

Разбор записи простого триггера:

1) Интервал проверки. Задает как часто или в каких случаях будет проверяться триггер.
2) Блок операций. Для подробного разбора видов операций смотри файл header_operations.py


Разбор записи триггера из примера, приведенного выше:

1) Интервал проверки = ti_on_party_encounter.
2) Блок оперции. Мы разберем его чуть ниже.

Значение ti_on_party_encounter в поле интервала проверки означает, что триггер будет проверен всякий раз, когда игрок встретит другой отряд на глобальной карте. Рассмотрим по очереди каждую секцию блока операций данного триггера:


Секция 1:

       (store_encountered_party, reg(1)),
       (store_encountered_party2,reg(2)), # encountered_party2 is set when we come across a battle or siege, otherwise it's a minus value

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

1) (store_encountered_party, reg(1)),
Во-первых, индикатор еncountered_party - это индикатор подобный encountered_party2. Он хранит в себе идентификатор отряда, который встретил игрок. Второе, store_ + индикатор  encountered_party говорит системе: “помести значение еncountered_party в <регистре или переменной, что будет указана после запятой>”.  В данном случае это reg(1)
2) (store_encountered_party2,reg(2)),
Делает почти то же самое. Говорит системе взять значение из индикатора encountered_party2 и поместить его в <регистр после запятой>,  в данном случае в reg(2). Но используется только в том случае, если вы встретили битву либо осаду, то есть в регистры будут записаны идентификаторы нападающего и защищающегося отрядов.


Секция 2:

       (try_begin),
         (lt, reg(2),0), #Normal encounter. Not battle or siege.

         #Нормальное столкновение. Ни битва ни осада.
         # lt - "lower than" - "меньше чем"

Выражение (try_begin) - это операция, открывающая блок ветвления. Блок ветвления является обычным блоком операций, но с одним отличием – если за выражением (try_begin) следуют операции условия и если хотя бы одно из них не удовлетворяется, то система прерывает обработку блока ветвления. Т.е. система переходит к выполнению операции, стоящей после выражения (try_end), закрывающего блок ветвления. Если мы имеем дело с  блоками ветвления, вложенными один в другой, то следует учитывать, что система перебирает выражение за выражением, пропуская встреченные вложенные блоки ветвления, пока не находит соответствующий (try_end) (либо выражение (else_try), но о нем позже) и возобновляет выполнение кода сразу после него.

Выражение (lt, reg(2),0) это условие, требующие чтобы значение регистра “reg(2)” было меньше нуля: (lt, “первое значение”, “второе значение”) ==  “первое значение” < “второго значения”. Как было сказано выше, значение регистра всегда будет меньше нуля, если игрок не столкнулся с осадой или с полевым сражением. Таким образом, если значение в регистре reg(2) меньше нуля, система перейдет к выполнению операций секции 3.  Если это не так, то система прекратит выполнение блока ветвления, и  возобновит работу с операции, расположенной сразу после ближайщего выражения (try_end).

Кроме того, существует операция (else_try). Она входит в состав блока ветвления (т.е. находится между выражениями (try_begin) и (try_end)) и открывает блок операций, который будет обработан лишь в том случае, если требования  других активных операций, находящихся перед (else_try), не были удовлетворенны. Это также касается и других блоков (else_try), если таковые находятся выше. Другими словами, если в блок ветвления входят сразу несколько блоков (else_try), выполнен будет лищь один из них. Это как максимум, а как минимум – ни один.


Секция 3:

         (try_begin),
           (ge, reg(1), towns_begin),
           (lt, reg(1), towns_end),   
           (jump_to_menu, "mnu_town"),


           # В операторах сравнения и рассчёта главное не путаться:
           # ge - "greater or equal" - "больше или равно"
           # gt - "greater than" - "больше чем"
           # le - "lower or equal" - "меньше или равно"
           # lt - "lower than" - "меньше чем"


Эта секция начинается с выражения открывающего блок ветвления, расположенного внутри предыдущего блока ветвления (см. Секция 2). Секция будет обработана если значение регистра “reg(1)” -- встреченного игроком отряда -- находится между значениями констнат towns_begin (идентификатор “p_town_1” из файла module_parties.py) и towns_end ("p_salt_mine"). Если эти условия выполняются, игрок будет направлен к меню города "mnu_town". Если нет, то система прервет обработку этой части блока (try_begin), и перейдёт к секции 4.


Секция 4:

         (else_try),
           (ge, reg(1), castles_begin),
           (lt, reg(1), castles_end),
           (jump_to_menu, "mnu_castle"),


Секция 4 будет расмотренна лишь в случае, если условия  предыдущей секции не удовлетворены. Иными словами, она будет рассмотренна лишь в случае, если значение в reg(1) не соответствует идентификатору города. Таким образом придя к выводу, что встреченный игроком отряд это не город, в этой секциии система проверит соответствие значения регистра идентификатору замка. Он должен лежать в промежутке ограниченном константами castles_begin ("p_castle_1") и castles_end  ("p_river_pirate_spawn_point"). Если проверка успешна, игрок будет направлен в меню замка "mnu_castle". Если нет, система перейдет к обработке секции 5. Все это реализованно теми же самыми операциями, что и в секции 3.


Секция 5:

         (else_try),
           (eq, reg(1), "p_zendar"),
           (jump_to_menu, "mnu_zendar"),


Прийдя к выводу, что это и не город и не замок, в этой секции проверяется возможность столкновения игрока с отрядом, определяющимся идентификатором "p_zendar". Если проверка завершается успешно, игрок будет направлен в меню Зендара "mnu_zendar". Если нет, система перейдет к обработке секции 6. Все это реализованно с помощью операции eq.


Секция 6:

         (else_try),
           (eq, reg(1), "p_salt_mine"),
           (jump_to_menu, "mnu_salt_mine"),


Проверка на соответствие между идентификатором встреченной группы и  соляными шахтами  - "p_salt_mine" .


Секция 7:

         (else_try),
           (eq, reg(1), "p_four_ways_inn"),
           (jump_to_menu, "mnu_four_ways_inn"),


Проверка на соответствие между идентификатором встреченной группы и таверной четыре дороги  - "p_four_ways_inn".


Секция 8:

         (else_try),
           (eq, reg(1), "p_dhorak_keep"),
           (jump_to_menu, "mnu_dhorak_keep"),


Проверка на соответствие между идентификатором встреченной группы и усадьбой Дхорак  - "p_dhorak_keep".


Секция 9:

         (else_try),
           (eq, reg(1), "p_training_ground"),
           (jump_to_menu, "mnu_training_ground"),


Проверка на соответствие между идентификатором встреченной группы и учебным лагерем  - "p_training_ground".


Секция 10:

         (else_try),
           (store_current_hours, reg(7)),
           (le, reg(7), "$defended_until_time"),
           (assign, "$defended_until_time", 0),
           (jump_to_menu, "mnu_in_castle_under_attack"),


В этой секции количество часов, прошедших с момента начала игры, помещается в регистр "reg(7)" (операция (store_current_hours, reg(7))). Затем значение регистра "reg(7)" сравнивается со значением переменной "$defended_until_time", значение регистра должно быть меньше либо равно $defended_until_time (операция (le, reg(7), "$defended_until_time")). Если это так, система присвоит значение "$defended_until_time" равным нулю (операция (assign, "$defended_until_time", 0)) и направит игрока в меню "замок под атакой" -- "mnu_in_castle_under_attack". Если же проверка не пройдена, система приступит к обработке секции 11. (прим: скорее всего эта секция используется как часть скрипта "замок в осаде". Из-за того, что триггер относится к устаревшей версии МиБа, у меня нет возможности сказать что-то более конкретное.)


Секция 11:
         (end_try),

Сигнализирует системе о завершение второго, вложенного оператора ветвления, см. секция 3.


Секция 12:

       (else_try), #Battle or siege (битва или осада)
       (try_end)


Эта последняя операция (else_try) из блока ветвления нашего триггера. Она будет обработанна если игрок сошелся в бою с другой группой. Так как блок не включает в себя никаких других операций, он завершится боевым столкновением (а не меню) -- в точности как в случае с городом "new_town", который мы создали во второй части документации. Он все еще не имеет операций привязывающих его к собственному меню. Мы исправим это в следущем разделе.


8.2 Редактирование триггера столкновенний групп.
При создании нашего нового города мы должны побеспокоиться о том, чтобы любые столкновения с ним на глобальной карте перенаправлялись в соответствующие меню. Это оставляет нам два варианта: либо привязывать новые объекты к одному из существующих нативовских меню (стандартное mnu_town например), либо создать свое собственное меню.

Для нашего  new_town мы создадим свое уникальное меню, но позже. Сейчас мы разберем, что потребуется сделать для привязки нового объекта на карте к стандартному нативовскому меню города.


Во-первых, любые дальнейшие изменения в триггере столкновений отрядов следует добавлять перед секцией 10. Если вы добавите любые данные после нее, то создадите проблеммы при обработке столкновения с отрядом в полночь. Чтобы этого не произошло, мы добавим наши новые данные перед этой секцией, и сразу после секции 9.

Создайте немного пространства между секциями 9 и 10:

         (else_try),
           (eq, reg(1), "p_training_ground"),
           (jump_to_menu, "mnu_training_ground"),

         # Здесь мы сделаем новую секцию
         (else_try),
           (store_current_hours, reg(7)),
           (le, reg(7), "$defended_until_time"),
           (assign, "$defended_until_time", 0),
           (jump_to_menu, "mnu_in_castle_under_attack"),



Любые новые добавления в этот триггер должны начинаться с (else_try). После else_try, мы добавим операции условия -- когда наш блок должен сработать, а когда нет. Затем, когда все условия определены и записаны, мы должны добавить операцию последствия, такую как например jump_to_menu – операцию, перенаправляющую в меню. Операции последствия могут быть различны и не ограничиваться одним лишь jump_to_menu.

Скопируйте и вставьте секцию 9 на освобожденное для этого место. Затем, замените "p_training_ground" на "p_new_town" и "mnu_training_ground" на "mnu_new_town". Плов готов.

Для того чтобы сделать наш город функциональным, нам остается закончить только одну деталь – создать его меню. Но прежде чем мы перейдем к изучению файла module_game_menus.py, гораздо разумней будет закончить с триггерами. Окройте файл module_triggers.py и мы переходим к следующему разделу.


8.3 Файл module_triggers.py.

В модульной системе МиБа существует два типа триггеров: простые триггеры, они записаны в module_simple_triggers.py, и расширенные триггеры, записанные в module_triggers.py. Расширенные триггеры работают по тому же принципу, но имеют несколько больше возможностей.


  (0.1, 0, ti_once, [(map_free,0)], [(tutorial_box,"str_tutorial_map1")]),

Это первый триггер из этого файла, и он прост и приятен. Когда игрок появляется в первый раз на глобальной карте, этот триггер вызывает туторитал по глобальной карте.


Разбор записи обычного (не простого) триггера:

1) Интервал проверки. Как часто будет проверен триггер.
2) Интервал задержки. Сколько пройдет времени, прежде чем будут примененны последствия триггера (если разумеется, до этого все проверки блока условий были проведенны успешно).
3) Интервал перезарядки. Сколько времени должно пройти, прежде чем триггер будет готов к повторной ативации.
4) Блок условий. Это должен быть блок операций. Если этот блок пуст, то значит, что проверка условий проходит вседа успешно.
5) Блок последствий. Должен быть блоком операций.


Разбор полей триггера вызывающего окно туторитала по карте.

1) Интервал проверки = 0.1
2) Интервал задержки = 0
3) Интервал перезарядки = ti_once
4) Блок условий = (map_free,0)
5) Блок последствий = (tutorial_box,"str_tutorial_map1")


Как видно из примера, триггер проверяется каждые 0.1 часа внутригрового времени; он не имеет интервала задержки; он никогда не появится снова -- реализованно с помощью метки ti_once. Из блока условий следует, что триггер сработает если игрок будет находится на глобальной карте, неважно где именно. Таким образом, окно туториала появится на экране всего один раз - в начале игры.


Теперь мы создадим наш собственный триггер. Скопируйте триггер, вызывающий туторитал по глобальной карте, и вставьте в конец python-овского списка.

Наш новый триггер должен инициировать появление отряда банды Джоффри на глобальной карте. Замените (map_free,0) в блоке условий триггера на следущие операции:

(eq,"$geoffrey_duel",1),
(store_time_of_day,reg(1)),
(gt,reg(1),19),


Если вы помните, в седьмой части этой документации, после того как Джоффри вызывает игрока на дуэль, мы присваивали переменной $geoffrey_duel" значение 1. Таким образом операция (eq,"$geoffrey_duel",1), проверяет вызвал ли Джоффри игрока на дуэль. Если условие не удовлетворено, проверка заканчивается неуспешно.

Следующие две операции сохраняют текущее дневное внутригровое время в регистр reg(1), и затем проверяют его значение. Если оно больше 19:00, то проверка блока условий завершается успешно и триггер срабатывает. Банда Джоффри "Красные Всадники" появится на карте между 19:00 и 00:00.


Теперь заменим (tutorial_box,"str_tutorial_map1") в блоке последствий на следующий блок операций:

(set_spawn_radius,0),
(spawn_around_party,"p_zendar","pt_red_riders"),
(assign,"$geoffrey_party_id",reg(0)),
(party_set_ai_behavior,"$geoffrey_party_id",ai_bhvr_track_party),
(party_set_ai_object,"$geoffrey_party_id","p_main_party"),


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

Вторая операция инициирует появление отряда, генерируемого шаблоном "pt_red_riders" около отряда "p_zendar". Кроме того, в результате этой операции, в регистр reg(0) помещается идентификатор вызванного отряда. Чтобы он не потерялся при следующем изменении reg(0), мы сохраним его значение в пременную "$geoffrey_party_id". (операция (assign,"$geoffrey_party_id",reg(0))).

Ну и, наконец, мы установим поведение ИИ отряда и зададим объект-цель для ИИ. Мы реализуем это с помощью очень простых операций: party_set_ai_behavior и party_set_ai_object. В первой мы задаем для группы Джоффри тип поведения  ai_bhvr_track_party (преследовать отряд). А во второй задаем объектом-целью отряд игрока -- "p_main_party". Когда вы задаете ИИ отряду установку преследовать другой отряд --  ai_bhvr_track_party –- это заставит отряд преследовать и атаковать свою цель, даже несмотря на отношения их фракций.

Сохраните ваш прогресс. Мы еще не закончили, т.к. не создали меню для к нашего нового города new_town. Мы сделаем это в следующей, девятой части документации.
« Последнее редактирование: 29 Июня, 2011, 13:23 от Leon473 »

СиЧЪ Total War СиЧЪ Total War
Сайт "Всадники Кальрадии" не является СМИ. Администрация не несет ответственность за высказывания и публикацию каких-либо материалов, сделанные любыми пользователями форума, в том числе посредством личных и публичных сообщений. Материалы, размещенные на ресурсе третьими лицами, могут содержать информацию, не предназначенную для лиц, не достигнувших совершеннолетия. При обнаружении на ресурсе материалов, нарушающих законодательство Российской Федерации, необходимо обращаться к администрации.
Сайт работает на быстром VPS/VDS хостинге от FASTVPS


Powered by SMF 2.0 | SMF © Simple Machines LLC