header_operations.py
Операции по работе с глобальной картой
(is_currently_night), - Проверяет что в игре ночь, когда игрок находиться на глобальной карте
из module_simple_triggers.py
# Checking escape chances of prisoners that joined the party recently. (6, [(gt, "$g_prisoner_recruit_troop_id", 0), (gt, "$g_prisoner_recruit_size", 0), (gt, "$g_prisoner_recruit_last_time", 0), (is_currently_night), ....
Всем известная ситуация, когда ночью некоторое количество завербованных на кануне из пленных рекрутов сбегает из отряда.
В данном случае операция проверки is_currently_night заставляет данный триггер срабатывать только ночью, хотя интервал проверки триггера 6 часов.
(map_free), - Проверка в условии триггера сработает только если игрок на глобальной карте и закрыты все окна
# Read books if player is resting. (1, [(neg|map_free), (gt, "$g_player_reading_book", 0), ....
Триггер отвечающий за чтение книг. Здесь проверка (neg|map_free), отвечает за то, чтобы книга не читалась, когда игрок находится просто в путешествии (на свободной карте), без этой проверки триггер будет срабатывать просто каждый час
операции для работы с погодой на глоб. карте (get_global_cloud_amount, ), - вернет в переменную текущую погоду (дождь, снег) на глобалке (значение от 0 до 100)
(set_global_cloud_amount, ), - устанавливает значение для погоды от 0 до 100.
- от значения погоды зависит также какой скайбокс для сцен движок будет использовать для определенного значения погоды. примерно можно разбить на четыре значения
sf_clouds_0 = от 0 до 25 - ясная погода
sf_clouds_1 = от 25 до 50 - облачная погода
sf_clouds_2 = от 50 до 75 - легкий моросящий дождь или пред дождевая погода
sf_clouds_3 = от 75 до 100 - дождь.
sf_clouds - флаг скайбокса в файле Skyboxes.py
в изначально погода установлена на значении 50. саморегуляция происходит в пределах /- 25 единиц. как происходят скачки погоды и от чего это зависит выяснить так и не удалось.
для работы с туманом
(get_global_haze_amount, ),вернет в переменную значение от 0 до 100
(set_global_haze_amount, ), назначает значение от 0 до 100
0 - ясно
100 - густой туман.
туман на карте также скажется в сценах.
(store_current_hours, ), - вернет в переменную сколько часов прошло с начала игры.
.... (24, #Kingdom ladies send messages [ (store_current_hours, ":hours_since_last_visit"), (troop_get_slot, ":last_visit_hour", ":troop_id", slot_troop_last_talk_time), (val_sub, ":hours_since_last_visit", ":last_visit_hour"), (gt, ":hours_since_last_visit", ":longest_time_without_visit"), ....
Триггер отвечает за получение сообщения от дамы сердца с просьбой о визите.
Здесь операция store_current_hours, записывает в переменную ":hours_since_last_visit" текущее время. Далее вычисляется разница между временем последнего визита и текущим временем, и если со времени последней встречи прошло больше времени, чем заданно в переменной ":longest_time_without_visit" (по умолчанию 120 часов), то триггер срабатывает и вы получаете сообщение и квест на посещение дамы
(store_time_of_day, ), - запишет в переменную текущее время суток. значение от 0 до 24
из module_game_menus.py
("wait_24_hours",[],"Wait until tomorrow.", [ (assign,"$auto_besiege_town","$g_encountered_party"), (assign, "$g_siege_force_wait", 1), (store_time_of_day,":cur_time_of_day"), (val_add, ":cur_time_of_day", 1), (assign, ":time_to_wait", 31), (val_sub,":time_to_wait",":cur_time_of_day"), (val_mod,":time_to_wait",24), (val_add, ":time_to_wait", 1), (rest_for_hours_interactive, ":time_to_wait", 5, 1), #rest while attackable (assign, "$cant_talk_to_enemy", 0), (change_screen_return), ]),
Этот пункт меню, при осаде позволяет дождаться следующего утра, если по каким то причинам сейчас вы на штурм идти не готовы, хотя все инженерные работы завершены.
Здесь в переменную ":cur_time_of_day" с помощью операции store_time_of_day записывается текущее время суток (количество часов, пошедших с последней полуночи). Далее высчитывается сколько времени осталось до ближайшего рассвета, записывается в переменную ":time_to_wait" и с помощью операции rest_for_hours_interactive игрок ждёт с пятикратным ускорением времени нужное время
(store_current_day, ), - запишет в переменную количество дней прошедшее от начала игры.
из module_dialogs.py
[anyone|plyr,"lord_talk",[#(troop_slot_eq, "$g_talk_troop", slot_troop_is_prisoner, 0), (neg|troop_slot_ge, "$g_talk_troop", slot_troop_prisoner_of_party, 0), (check_quest_active,"qst_lend_companion"), (quest_slot_eq, "qst_lend_companion", slot_quest_giver_troop, "$g_talk_troop"), (store_current_day, ":cur_day"), (quest_get_slot, ":quest_target_amount", "qst_lend_companion", slot_quest_target_amount), (ge, ":cur_day", ":quest_target_amount"), (quest_get_slot, ":quest_target_troop", "qst_lend_companion", slot_quest_target_troop), (str_store_troop_name,s14,":quest_target_troop"), (troop_get_type, reg3, ":quest_target_troop"), ], "I should like {s14} returned to me, {s65}, if you no longer require {reg3?her:his} services.", "lord_lend_companion_end", []],
Вариант диалога с лордом, если вы по квесту отдали одного из своих компаньонов ему на время.
Здесь операция store_current_day записывает в переменную ":cur_day" количество дней прошедших с начала игры. Далее это число сравнивается с датой возвращения компаньона оговоренной в условиях квеста, и если текущая дата больше, вы можете в диалоге попросить лорда вернуть вашего спутника.
(rest_for_hours, , [time_speed_multiplier], [remain_attackable]), - операция вынуждает партию игрока стать на отдых на определенный период времени.
из module_game_menus.py
("village_loot",[], "Plunder the village, then raze it.", [ (call_script, "script_village_set_state", "$current_town", svs_being_raided), (party_set_slot, "$current_town", slot_village_raided_by, "p_main_party"), (assign,"$g_player_raiding_village","$current_town"), (try_begin), (store_faction_of_party, ":village_faction", "$current_town"), (store_relation, ":relation", "$players_kingdom", ":village_faction"), (ge, ":relation", 0), (call_script, "script_diplomacy_party_attacks_neutral", "p_main_party", "$current_town"), (try_end), (rest_for_hours, 3, 5, 1), #rest while attackable (3 hours will be extended by the trigger) (change_screen_return),
При посещении деревни, в меню враждебных действий, вариант "Разграбить и сжечь деревню".
Здесь операция rest_for_hours заставляет отряд игрока ждать на глобальной карте 3 часа ( = 3), без возможности самостоятельно прекратить это ожидание, с пятикратным ускорением времени ([time_speed_multiplier] = 5) и возможностью, что на игрока может в это время напасть враждебный отряд ([remain_attackable] = 1).
(rest_for_hours_interactive, , [time_speed_multiplier], [remain_attackable]), вынуждает стать на отдых но с возможностью в любой момент его прервать
из module_game_menus.py
("start_collecting", [], "Start collecting.", [(assign, "$qst_collect_taxes_currently_collecting", 1), (try_begin), (quest_slot_eq, "qst_collect_taxes", slot_quest_current_state, 0), (quest_set_slot, "qst_collect_taxes", slot_quest_current_state, 1), (try_end), (rest_for_hours_interactive, 1000, 5, 0), #rest while not attackable (assign,"$auto_enter_town","$current_town"), (assign, "$g_town_visit_after_rest", 1), (change_screen_return), ]),
Пункт в меню, появляющегося в меню города, если игрок получил от лорда квест на сбор налогов, при выборе которого, начинается сам сбор ("начать сбор").
Здесь операция rest_for_hours_interactive заставляет отряд игрока ждать в городе 1000 часов ( = 1000), с возможностью самостоятельно прекратить это ожидание, с пятикратным ускорением времени ([time_speed_multiplier] = 5) и в это время на игрока не может напасть враждебный отряд ([remain_attackable] = 0).
Не удивляйтесь такой большой цифре, т.к. за окончание сбора здесь отвечает треггер и 1000 часов просто максимальное допущение
- на какой период времени идет остановка
[time_speed_multiplier]- мультипликатор скорости течения времени. можно ускорить или замедлить.
[remain_attackable] - 1 - отряд игрока может быть атакован враждебным отрядом во время ожидания.
0 - отряд игрока не может быть атакован враждебным отрядом во время ожидания.
Причём при значении 0 отряд игрока визуально пропадает с карты.
Операции блоков и циклов.
(try_begin), - открывает блок кондиции или блок ветвления.
(else_try), - операция ветвления блока, если один из блоков не прошел проверку. проходясь по всем циклам с использованием этой операции движок остановиться на первом верном, остальные не будут даже рассматриваться.
try_end - закрывает блок или цикл
(try_for_range, , , ), - открывает цикл по переменной с установленными границами. начиная с нижней границы до верхней, крайняя верхняя позиция не будет использована.
как пример
(try_for_range, ":chislo", 0, 5), - открывается цикл для переменной ":chislo", в которой записаны числа от 0 до 4.
(try_for_range_backwards, , , ), - то же самое что и выше только проверять начнет не с нижней границы а с верхней
(try_for_parties, ), - открывает цикл по всем без исключениям партиям на глобалке.
под переменную попадают партии из файла module_party_templates.py и module_parties.py
(try_for_agents, ), открывает цикл по всем без исключения агентам в сцене.
в переменную попадают лошади, боты, игрок, мертвые, раненые.
(call_script, , [...]), - операция вызова определенного скрипта из файла module_scripts.py.
[...] - указывается параметр скрипта для передачи или переноса данных. работает в обоих направлениях - можно в скрипт передать значение для каких то действий, можно извлечь.
store_script_param_1 (store_script_param_1,) записывает в первый параметр скрипта.
store_script_param_2 (store_script_param_2,) записывает в второй параметр скрипта.
store_script_param (store_script_param,,) записывает в параметр скрипта номер . Используется, если скрипт использует более двух параметров.
(set_result_string, ), - Есть некоторое количество скриптов, которые вызываются движком игры (начинаются с "game_") и которые должны вернуть движку строку. Вот эта операция - для них. Ещё потенциально может применяться для триггеров, но ЕМНИП триггеров, которые хотят получить строку, в игре нет. В остальном эта операция бесполезна, поскольку её результат средствами скриптовой системы прочитать невозможно.
Следующие операции используются в трригерах и некоторые параметры за декларированы в самих триггерах.
(см. подробнее header_triggers.py)
(store_trigger_param_1, ), - запишет в переменную первое значение триггера
(store_trigger_param_2, ), - запишет в переменную второе значение триггера
(store_trigger_param_3, ), - запишет в переменную третий параметр триггера.
(get_trigger_object_position, ), - запишет в переменную позицию стрелкового оружия для которого используется триггер
(set_trigger_result, ), - запишет в переменную значение которое будет установлено триггером.
Операции установок и статистики
(is_trial_version), - проверяет пробную версию игры без введеного ключа.
(set_player_troop, ), - Незаменимая операция, если необходимо подменить игрока на кого-то ещё при выполнении большинства операций change_screen_, т.к в самих этих операциях можно задать только объект (например с кем торговать), в то время как субъект всегда сам игрок, что не всегда удобно.
Главное после всех манипуляций не забыть снова вернуть игрока на место с помощью (set_player_troop, "trp_player"),
(options_get_damage_to_player, ), вернет в переменную процент урона наносимый игроку.
(options_set_damage_to_player, ), позволяет вручную независимо от установок назначить урон игроку
(options_get_damage_to_friends, ), - вернет урон наносимый дружественным ботам - в партии игрока и союзникам
(options_set_damage_to_friends, ), назначает урон дружественным ботам.
значения которые веренет/можно назначить
0 - 50% урона
1 - 75% урона
2- 100% урона
(options_get_combat_ai, ),- вернет в переменую текущую сложность поведения ИИ на поле боя
(options_set_combat_ai, ), - назначает сложность ИИ на поле боя
(options_get_campaign_ai, ), -вернет текущий уровень ИИ для поведения на глобалке.
(options_set_campaign_ai, ), - назначит уровень ИИ поведения на глобалке
значеня-
0 - высокий
1 - средний
2 - низкий
(options_get_combat_speed, ), вернет скорост времени боя
(options_get_combat_speed, ), назначит скорость времени боя
значения
0 - оч медленно
1 медлено
2 средний
3 быстрый
4 оч быстрый
(get_average_game_difficulty, ), - запишет в переменную общую сложность игры
(get_achievement_stat, , , ), - записывает индекс для открытия достижения.
само достижение прописано в module_constants.py
(unlock_achievement, ), - открывает достижение.
Что это, как работает. что дает - без малейшего понятия. в файлах встречал но вразумительно и подробно описать не берусь.
(get_player_agent_kill_count, , [get_wounded]), - операция вернет в переменную общее количество поверженых врагов, если [get_wounded] - 0. если 1 подсчет только убитых.
(get_player_agent_own_troop_kill_count, , [get_wounded]),ведет статистику убитых\раненых союзников.
использование параметра [get_wounded] так же как и выше.
Операции с фракциями
(faction_set_slot, , , ), - записывает в слот фракции значение
(faction_get_slot, , , ), - записывает в переменную значение которое находиться в слоте.
(faction_slot_eq, , , ), проверяет равен ли слот фракции значению
(faction_slot_ge, , , ), проверяет равен/больше слот чем значение.
(faction_get_color, , ) записывает в переменную цвет фракции.
(faction_set_color, , ), - назначает цвет фракции.
- цвет в кодовом значении.
(faction_set_name, , ), позволяет переименовать фракцию. Имя должно быть записано в файле Модуль_стрингс. можно также использовать строковые регистры s1 s2 s3 ...
также можно использовать "быстрый стринг"
пример
(faction_set_name, "fac_kingdom, "@ USSR"),
Это можно использовать везде где используются строковые регистры как какие то параметры.
(store_relation, , , ), запишет в переменную текущий уровень отношений между 2 определенными фракциями. значение имеет диапазон от -100 до 100
Операции для работы с партиями
(hero_can_join, [party_id]), проверяет может ли бот с флагом Hero присоеденится к партии. если [party_id] не указана подразумевает партию игрока
(hero_can_join_as_prisoner, [party_id]), - проверит может ли присоеденится бот с флагом геро в качестве заключенного. работа с ай ди партии та же
(party_can_join), - проверит может ли партия с которой ведет диалог игрок присоеденится к партии игрока
(troops_can_join, ), - проверит имеет ли партия игрока достаточно места для присоденения ботов.
(troops_can_join_as_prisoner, ), - проверит на наличее места для присоеденения ботов в качестве заключенных.
(party_can_join_party, , , [flip_prisoners]), проверит может ли <joiner_party_id> присоедениться к партии <host_party_id> в качестве солдат или заключенных.
(main_party_has_troop, ), - проверит имеет ли партия игрока определенного бота.
(party_is_in_town, , ), проверяет наличие определенной партии партии в определенном поселении.
(party_is_in_any_town, ), проверит находиться ли определенная партия в поселении\центре
(party_is_active, ), - проверяет активна партия или нет
(party_set_name, , ), присваивает имя партии
(remove_party, ), убирает партию с глобалки движок перестает ее видеть и учитывать.
(enable_party, ), активирует дезактивированную партию
(disable_party, ), отключает активную парию. партия включена в учет системой. и при проверке на цикл (try_for_parties, ), попадет в переменную. можно работать как и с включенной партией
но ии партии и игрок ее не видят
(set_spawn_radius, ), назначет радиус спауна для партии из модуль_парти_темплс для следующей операции
(spawn_around_party, , ), спаунит партию из парти темплс в радиусе назначенном выше вокруг партии из модуль_парти
(set_party_creation_random_limits, , ), назначает число ботов спаунящейся партии из парти темплс в диапазоне от минимального до максимального. предел диапазана от 0 до 100
(party_get_current_terrain, , ), запишет в переменную терраин который в днный момент под ногам партии. значение переменной вернет числом из файла header_terrain_types.py
значения
rt_water = 0
rt_mountain = 1
rt_steppe = 2
rt_plain = 3
rt_snow = 4
rt_desert = 5
rt_bridge = 7
rt_river = 8
rt_mountain_forest = 9
rt_steppe_forest = 10
rt_forest = 11
rt_snow_forest = 12
rt_desert_forest = 13
из скрытых
rt_deep_ocean = 15
(party_relocate_near_party, , , ), телепортирует партию <party_id> в радиусе <value_spawn_radius> от <target_party_id>.
(party_get_position, , ), - запишет координаты партии в позицию. Используйте pos0 для записи точных координат x y z . используеться на глобалке.
(party_set_position, , ), - телепортирует указаную партию на указаную позицию. используеться на глобалке.
(set_camera_follow_party, ), назначает движение камеры за определенной партией. в нативе используется для движением за партией у которой игрок в плену
(party_attach_to_party, , ), привязывает <party_id> к <party_id to attach to>
эта операция используется, когда отряды лордов ждут в замке или во время битвы, создавая одну коллективную партию из нескольких
(party_detach, ), "отвязывает" партию от коллектива.
(party_collect_attachments_to_party, , ), - используется для групповой привязки
(бой на карте где только ИИ?)
(party_get_attached_to, , ), возвращает в переменной партию к кторой привязаня
(party_get_cur_town, , ), - Эта операция используется, если партия лорда находится в городе, для определения города. То есть, если партия лорда в городе, то в записывается ID города из module_parties.py
(party_get_num_attached_parties, , ), - возвращает в переменной число привязанных партий
(party_get_attached_party_with_rank, , , ),- Если к <party_id> приаттачено несколько партий, эта операция получает энную по номеру. Сколько всего партий приаттачено, сообщает предыдущая операция (party_get_num_attached_parties).
(party_set_extra_text, , ), добавляет текст к тексту в высвечивающимся окне статуса партии
при наведении указателя мыши
(party_get_icon, , ), возвращает в переменной map_icons используемый партией
(party_set_icon, , ), позволяет назначить иконку для партии
(party_set_banner_icon, , ), назначает баннер из мап иконс для партии при указании
-0 убирает баннер.
(party_set_extra_icon, , , , , , ), добавляет партии дополнительную иконку. параметры позволяют организовать дополнительной иконке некоторую примитивную анимацию: "прыжки" вверх-вниз на определённое расстояние с определённой частотой, вращение с определённой частотой, исчезновение-проявление с определённой частотой.
(party_add_particle_system, , ), добавляет к иконке партии партикл. в родном используется для горящих деревень.
(party_clear_particle_systems, ), очищает указаную партию от партикла
(party_get_template_id, , ), - в переменной взвращается ай ди партии из парти_темплс
в основном для работы с операциями партий для парти темплс
(try_for_parties, ":cur_party"), (party_get_template_id, ":cur_template", ":cur_party"), (eq, ":cur_template", "pt_village_farmers"), (party_set_icon, ":cur_party", "icon_что нибудь"), (try_end),
(party_set_faction, , ), назначает партии фракцию
(store_faction_of_party, , ), записывает в переменную фракцию партии.
(store_random_party_in_range, , , ), записывает в переменную случайную партию из диапазана. позволяет выбрать случайно скажем одну деревню из всех имеющихся.
(store_distance_to_party_from_party, , , ), запишет и вернет в переменной дистанцию между двумя партиями
(store_num_parties_of_template, , ), - запишет в переменную число партий определенной парти темплс находящихся на глобалке( например число парий лесных бандитов)
(store_random_party_of_template, , ), вернет случайную партию из однотипных партий из парти_темплс
(store_num_parties_created, , ), вернет в переменной общее число порожденных партий одного типа
(store_num_parties_destroyed, , ), вернет общее число деклассированных (убитых, разрушенных) партий одного типа
(store_num_parties_destroyed_by_player, , ), - вернет число партий одного типа побежденных игроком
(party_get_morale, , ), - вернет текущую мораль партии игрока. значение от 0 до 100
(party_set_morale, , ), задает значение морали . от 0 до 100
Следующие операции используются только в файле module_dialogs.py
(party_join), в конце диалога пария присоеденяется к паритии игрока
(party_join_as_prisoner), в конце диалога партия присоеденяется к партии игрока в качестве заключенных
(troop_join, ), в конце диалога с этим ботом он присоеденится к партии игрока
(troop_join_as_prisoner, ), в конце диалога с эитм ботом он присоеденится к партии игрока в качестве пленника
-------------------------------------------конец операция в модуль_диалог
(add_companion_party, ), - добавляет к партии игрока бота с флагом геро
(party_add_members, , , ), добавляет к партии указанное число ботов
общее число будет записано в reg0
(party_add_prisoners, , , ), - добавляет указаное число ботв в качестве пленных к партии . число вернется в reg0
(party_add_leader, , , []),добавляет к партии бота и делает его(их) лидером.
(по всей видимости для говорящего бота для диалогов с партиями х.з.)
(party_force_add_members, , , ), добавит ботов к партии насильно без учета лимита партии.( только героев?)
(party_force_add_prisoners, , , ),добавит ботов к партии в качестве пленных насильно без учета лимита партии.( только героев?)
(party_add_template, , , [reverse_prisoner_status]), добавлят к партии партию из парти темлс
[reverse_prisoner_status] либо подкрепление либо заключенные.
(distribute_party_among_party_group, , ), - распределяет между партиями ИИ после боя заключенных и подкрепление в виде освобожденных ботов
(remove_member_from_party, , [party_id]), удаляет из партии бота с флагом геро. Для партии игрока [party_id] не указывается
(remove_troops_from_prisoners, , ), удаляет заданое число пленных из партии игрока.
(party_remove_members, , , ), удаляет заданное число ботов одного вида из партии
количество запишется в reg0
(party_remove_prisoners, , , ), удаляет заданое количество ботов одного типа из партии . количество сохранится в reg0
(party_clear, ), - удаляет из партии и солдат и пленных
(add_gold_to_party, , ), добавляет заданое число денег партии
(party_get_num_companions, , ),вернет общее число бойцов в партии включительно лидера
(party_get_num_prisoners, , ), - запишет в переменную общее количество пленных в данной партии
(party_count_members_of_type, , , ), - вернет общее количество ботов определенного вида
(party_count_prisoners_of_type, , , ), вернет общее количество пленных ботов одного типа
(party_get_free_companions_capacity, , ), вернет число свободных мест для бойцов в партии
(party_get_free_prisoners_capacity, , ),- вернет общее число свободных мест для пленников в партии
(party_get_num_companion_stacks, , ), вернет число занятых стэков для типов ботов
включает стеки для героев и игрока
(party_get_num_prisoner_stacks, , ), вернет количество занятых стеков для пленных в партии. включает число для героев
(party_stack_get_troop_id, , , ),запишет определенного бота из определенного стэка в переменную
(party_stack_get_size, , , ),запишет число ботов в определенном стэке
(party_stack_get_num_wounded, , , ), запишет число раненых ботов в определенном стэке
(party_get_prisoner_stack_troop, , , ), запишет определенных ботов из определенного стэка пленных
(party_get_prisoner_stack_size, , , ), - запишет число ботов в определенном стэке пленных
(party_prisoner_stack_get_troop_dna, , , ), - запишет в переменную
днк юнита находящегося в партии.
(party_stack_get_troop_dna, , , ), - запишет в переменную днк юнита
находящегося в партии в качестве заключенного.
Пояснения ДНК от shturmfogel
что такое "dna": на сколько я понял это некое число, на основании которого движок определяет как будет выглядеть компьютерный болванчик и, возможно, как он будет одет (какие шмотки из имеющихся у него он выберет, чтобы показаться в сцене). Это распространяется на обычных болванчиков, не на NPC.
думаю party_stack_get_troop_dna позволяет получить вид бота, который будет показан в окне партиино не уверен
я использовал dna так: добавление священника в мирную сцену деревни, священник не имеет флага "герой", в модуле тропс это всего один юнит. Однако в сцене конкретной деревни священник будет появлятся всегда с одним лицом и насколько я могу судить в одном и том же наборе одежды, т.е. он как бы там живет и не спаунится по всей кальдарии при появлении ГГ:)для проверки первый вариант - священник спаунится каждый раз со случайно выбраным лицом:
(try_begin), (party_slot_ge,"$current_town",slot_center_has_cerkov,1), (assign, ":walker_troop_id", "trp_village_priest"), (store_random_in_range, ":cur_dna", 1, 1000000), (set_visitor, town_walker_entries_start, ":walker_troop_id",":cur_dna"), (try_end),
второй вариант - священник при первой встречей с ГГ выбирает случайным образом себе личину и потом в этой сцене появляется только с этим лицом
выбранный dna заносится в слот и при последующих спаунах применяется только этот dna, создается иллюзия, что в каждой деревне индивидуальный болванчик, хотя он один на всех
(try_begin), (party_slot_ge,"$current_town",slot_center_has_cerkov,1), (assign, ":walker_troop_id", "trp_village_priest"), (store_add,":cur_slot_dna",sa_troop_slot_end,"$current_town"), (troop_get_slot,":cur_dna",":walker_troop_id",":cur_slot_dna"), (try_begin), (eq,":cur_dna",0), (store_random_in_range, ":cur_dna", 1, 1000000), (troop_set_slot,":walker_troop_id",":cur_slot_dna",":cur_dna"), (try_end), (set_visitor, town_walker_entries_start, ":walker_troop_id",":cur_dna"), (try_end),
в общем как то так используется
в первоначальной истории героя, насколько помню, рандомные лица были поистине ужа сающи и напоминали каких то имбицилов
в варбанде же сделали некие наборы настроек лиц, и этот самый дна позволяет ими как то управлять
(store_party_size, ,[party_id]), запишет общее число бойцов и пленных в партии. без опции парти_ид
по умолчанию партию игрока
(store_num_regular_prisoners, , ), запишет в переменную общее количество пленных без учета героев
(party_add_xp_to_stack, , , ), позволяет добавить определенное число хр определенному стэку в партии
(party_upgrade_with_xp, , , ), -распределяет указанное число хр между всеми ботами и делает апгрейд если бот достиг уровня для апгрейда.
значения для апгрейда
0 - случайно
1 - первый путь (апгрейд2 в модуль трупс)
2 - второй путь (апгрейд2 в модуль трупс)
(party_add_xp, , ), добавляет хр партии и распределяется между всеми участниками партии
(party_get_skill_level, , , ), запишет уровень скилла партии имеющей героя скилл для партии общий.(не личный)
(heal_party, ), лечит партии
(party_wound_members, , , ), - делает ранеными определенное количество ботов одного типа в партии
(party_remove_members_wounded_first, , , ), удаляет из партии ботов начиная с раненых. общее число запишеться в reg0
(party_quick_attach_to_current_battle, , ), добавит указаную партию к битве на указаной стороне
значение side
0- союзник
1 враг
(party_get_battle_opponent, , ) запишет в переменную противника партии если она ведет бой.
(inflict_casualties_to_party, , , ), -авторасчет раненых и убитых ботов для ИИ партий.
Эти операции используются только для ИИ партий
(party_set_marshall, , ),назначает или очищает партию от звания маршал.
значение или 0(очищает) или 1(назначает).
(party_set_flag, , , ), задает или убирает определенный флаг из файла header_parties.py (пояснение флагов будет позже в отдельном посте)
0- снимает определенный флаг, 1 - назначает.
(party_set_aggressiveness, , ), - задает величину агрессивности для партии .
- имеет диапазон от 0 до 15. 15 -максимальное значение агрессивности.
агрессивность влияет на способность партии атаковать другие отряды при наивысшей паритя будет атаковать любой отряд не зависимо от размера атакуемой партии.
(party_set_courage, , ), - задает кураж (как долго партия будет преследовать другую партию.) значение - от 4 до 15
(party_get_ai_initiative, , ), запишет в переменную текущею инициативу партии в диапазоне от 0 до100.
(party_set_ai_initiative, , ), позволяет назначить инициативу партии в диапазоне от 0 до 100
(party_set_ai_behavior, , ), назначает ИИ партии поведение.
флаги для ИИ поведения в файле header_parties.py описание будет позже.
(party_set_ai_object, , ), при задании линии поведения операцией выше скажем
ai_bhvr_travel_to_party(следовать к партии) - эта операция задает партию которая будет являться целью путешествия .
(party_set_ai_target_position, , ), задает партии движении к определенной позиции
на глобальной карте. при флаге ai_bhvr_travel_to_point
(party_set_ai_patrol_radius, , ), задает радиус патрулирования партии при при линии поведения заданой флагами
ai_bhvr_patrol_location
ai_bhvr_patrol_party
значение числовое в км придется вычислять методом тыка или с помощью вот такого триггера
в файл module_triggers.py
(0.1, 0, 0, [(party_get_position, pos1, "p_main_party"), (party_get_position, pos2, "p_Bridge_37"), (get_distance_between_positions_in_meters, reg1, pos1, pos2) ], [(display_message,"@ {reg1}.",0xFF4040) ])
(party_ignore_player, , ), задает партии ИИ игнорирование партии игрока определенное время. - внутри игровое время в часах.
(party_set_bandit_attraction, , ), не уверен, но по всей видимости задает партии привлекательность для нападения партий с флагом поведения бандит. значение от 0 до 100
(party_get_helpfulness, , ),- заисывает полезность партии в значении от 0 до 100
(party_set_helpfulness, , ), - задает полезность партии от 0 до 10 000 дефлолтное 100. устанавливает уровень стремления помочь союзнику (вступить в уже идущее сражение)
(get_party_ai_behavior, , ), возвращает в переменную ai_behavior используемый партией.
(get_party_ai_object, , ), возвращает в переменную партию заданную как цель
для
(party_get_ai_target_position, , ), возвращает заданную позицию цель для партии.
(get_party_ai_current_behavior, , ), - вернет в переменную поведение партии
которое было назначено до определенных событий. Как пример возвращение к действиям партии предшествующим преследованию ее другой партией.
(get_party_ai_current_object, , ), запишет в переменную партию которая сделала сбой поведения .
Операции по работе с Итемом.
(item_set_slot, , , ), - запишет в слот итема значение
(item_get_slot, , , ), запишет в переменную значение из слота итема
(item_slot_eq, , , ), Проверит равенство значения в слоте итема значению
(item_slot_ge, , , ), проверит что значение в слоте итема больше или равно значению.
(item_get_type, , ), - запишет в переменную тим итема . Типы итема указаны в файле header_items.py и имеют приставку itp_type_ . Значения каждого флага позже
(store_item_value, , ), - запишет в переменную номинальную цену которая назначена вещи в файле module_items.py ( без учета модификаторов вещей)
(reset_price_rates), сброс наценок назначенных торговцу. ( продаваться будет по номиналу учитывая модификатор вещи )
(set_price_rate_for_item_type, , ), назначает цену определенному - тип итема. Типы итема указаны в файле header_items.py и имеют приставку itp_type_ .
(set_merchandise_modifier_quality, ), - значение - процент вероятности появления в продаже у торговца вещей с модификаторами.
(reset_item_probabilities, ), - устанавливает предмету частоту встречаемости в продаже иную, чем диктует параметр abundance. Предполагаю необходимо, чтобы ассортимент торговца отражал обилие товара в деревне или городе (в нативе применяется именно к товарам, не к оружию).
(set_item_probability_in_merchandise, , ), возвращает предмету исходную частоту встречаемости в продаже. Кстати, предметы в луте тоже формально "продаются".
Операции для работы с Troops (бот)
(troop_has_item_equipped, , ), - проверит что определенный бот имеет /оборудован
(одет или вооружен) определенным итемом.
(troop_is_mounted, ), - проверит что бот имеет флаг tf_mounted (задается в файле module_troops.py определяет бота как всадника ). Операция не проверит на наличие у заданного бота лошади.
Флаги см. в файле header_troops.py
(troop_is_guarantee_ranged, ), - проверит что бот имеет флаг tf_guarantee_ranged (флаг задает
обязательное оборудование бота вещью/оружием. Например если стоит флаг tf_guarantee_helmet - бот обязательно получит шлем при загрузке сцены). Операция не проверит на наличие оборудования которое задано как гарантированное. Флаги см. в файле header_troops.py
(troop_is_guarantee_horse, ),- проверит что бот имеет флаг tf_guarantee_horse . не проверяет
на наличие лошади
(troop_is_hero, ), - проверит что заданный бот имеет флаг tf_hero . К таким ботам относятся
игрок, Лорды, торговцы, спутники игрока, леди ... смотрите в оригинальной МС в файле module_troops.py начиная с "tournament_master".
(troop_is_wounded, ), - проверит что заданный бот ранен. Операция работает только с ботами имеющими флаг tf_hero.
(player_has_item, ), проверит что игрок имеет определенный итем. проверит как то что оборудовано
так и то что находится в вещевых слотах.
(troop_set_slot, , , ), - запишет в слот бота значение
(troop_get_slot, , , ), - запишет в переменную значение слота бота
(troop_slot_eq, , , ),проверит значение которое находится в слоте равно значению
(troop_slot_ge, , , ),проверит что значение в слоте бота больше или равно значению
(troop_set_type, , ), операция задает боту тип из файла module_skins.py.
в оригинале используется два типа - man (мужчина) и woman (женщина). Назначены они сразу в module_troops.py
флагами tf_male и tf_female.
Позволяет задать новый тип, который предварительно будет создан в module_skins.py.
(troop_get_type, , ), запишет в переменную тип данного бота. в оригинале запишет
или 0 - tf_male или 1 - tf_female
(troop_set_class, , ), - назначает боту класс. К ним относятся
grc_infantry = 0 - пехота
grc_archers = 1 - стрелки
grc_cavalry = 2 - кавалерия
grc_heroes = 3 - класс геро
от 4 до 8 - можно назначить по своим потребностям
grc_everyone = 9 - флаг определяющий все имеющиеся классы. в операции не используется
В можно вписывать как цифру обозначающую класс так и имя флага. записи имеют такой вид
(troop_set_class, "trp_Constable_Hareck", 0), либо (troop_set_class, "trp_Constable_Hareck",grc_infantry),
(troop_get_class, , ), запишет в переменную класс заданный определенному боту.
запишет значение от 0 до 8. (9 - не учитывается)
(class_set_name, , ), - позволяет записать имя для класса для отображения в окне партии.
(add_xp_to_troop, , [troop_id]), - добавляет или убавляет (с знаком -) число хит поинтов (опыта). Операция работает только для игрока (запись без [troop_id]) и ботов с флагом геро.
(add_xp_as_reward, ), - Добавляет указанное число хит поинтов игроку.
(troop_get_xp, , ) запишет в переменную имеющееся количество хит поинтов(опыт)
(store_attribute_level, , , ), запишет в переменную текущий уровень атрибутов. к атрибутам относятся
ca_strength = 0 сила
ca_agility = 1 ловкость
ca_intelligence = 2 интелект
ca_charisma = 3 харизма
(troop_raise_attribute, , , ), позволяет добавить или отнять количество
очков заданного атрибута. Для уменьшения нужно использовать отрицательное число.
При работе с ботами не имеющими флаг геро изменение будет для всего типа.
(store_skill_level, , , [troop_id]), - запишет в переменную текущий уровень скилла.
Скиллы смотрите в файле module_skills.py
(troop_raise_skill, , , ), изменяет заданный скилл на заданое число.
работает с положительным и отрицательным числом. Для ботов не имеющим флаг геро изменение будет для всего типа.
(store_proficiency_level, , , ), запишет в переменную текущий уровень заданного атрибута владением оружия
атрибуты
wpt_one_handed_weapon = 0 - одноручное оружие
wpt_two_handed_weapon = 1 - двуручное оружие
wpt_polearm = 2 - полеармы (древковое)
wpt_archery = 3 - лук
wpt_crossbow = 4 - арбалет
wpt_throwing = 5 - метательное
wpt_firearm = 6 - огнестрел
(troop_raise_proficiency, , , ),изменяет заданный атрибут владения оружием на заданое число. работает с положительным и отрицательным числом. Для ботов не имеющим флаг геро изменение будет для всего типа.
(troop_raise_proficiency_linear , , , ), - работает также как операция выше, но позволяет насильно без учета скилла weapon_master добавить или отнять заданное число от заданного атрибута владением оружием
(troop_add_proficiency_points, , ), добавит к уровню владением оружием которой имеет бот заданное число.
(store_troop_health, , , [absolute]), -запишет в переменную текущий уровень жизни юнита.
[absolute] значение-
0 - запишет процентное значение.
1 - запишет количество хит поинтов.
(troop_set_health, , ), - добавит юниту жизни в процентном соотношении.
(troop_get_upgrade_troop, , , ), - запишет в переменную юнита которого имеет как путь апгрейда.
например юнит имеет апгрейд (см в модуль_трупс)
upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
значение -
0- вернет тот кторый проставлен первым в пути. из примера "caravan_guard"
1 - вернет проставленного вторым. из примера "mercenary_crossbowman"
если юнит не имеет апгрейда вернет -1
(store_character_level, , [troop_id]), - запишет в переменную текущий уровень развития юнита. по умолчанию используется trp_player
(get_level_boundary, , ), - Возвращает, сколько экспы надо для уровня.
(troop_set_auto_equip, , ), - автоэкипировка юнита вещами которые он имеет в инвентаре.
- позволяет
0 - запретить автоэкипировку
1 - назначить ее.
(troop_ensure_inventory_space, , ), - удаляет из слота, заданого , инвентаря
вещи.
(troop_sort_inventory, ), - сортирует вещи в инвентаре торговца по цене.
(troop_add_merchandise, , , ), - добавляет юниту торговцу вещи
по типам. задается тип итема из хедер_итемс. Добавит вещи только с флагом itp_merchandise
(troop_add_merchandise_with_faction, , , , ), - добавляет вещи торговцу только специфической фракции. принадлежность вещи фракции задается флагом в модуль_итемс.
(troop_add_item, , , [modifier]), - добавляет юниту определенную вещь с определенным модификатором.
(troop_remove_item, , ), - удаляет определенную вещь из инвентаря или экипировки юнита.
(troop_clear_inventory, ), - удаляет все вещи из инвентаря юнита. не работает с экипировкой.
(troop_equip_items, ), - заставляет пересмотреть юнита свою экипировку и то что есть в инвентаре и заменить вещи на более лучшие по показателям. не совсем корректно работает с оружием.
(troop_inventory_slot_set_item_amount, , , ), - позволяет добавить юниту вещи имеющие численное количество. например еда, боеприпасы (стрелы болты пули).
Добавляет к экипировке или инвентарю.
- количество.
если к экипировке -
- используется флаг из хедер_итемс.
ek_item_0 = 0 слот оружия
ek_item_1 = 1 слот оружия
ek_item_2 = 2 слот оружия
ek_item_3 = 3 слот оружия
ek_head = 4 слот для головного убора
ek_body = 5 слот брони
ek_foot = 6 слот для сапог
ek_gloves = 7 слот для перчаток
ek_horse = 8 слот для лошади
ek_food = 9 слот для еды.
(troop_inventory_slot_get_item_amount, , , ), запишет в переменную количество итема находящегося в слоте ek_ или инвентаре
(troop_inventory_slot_get_item_max_amount, , , ), запишет в переменную максимальное количество которое имеет слот. например если в слоте у юнита 20 стрел из 30,
то в переменную запишет число 30, как максимально возможное которое имеет данный вид боеприпасов.
(troop_add_items, , , ), - позволяет добавить юниту определенное число заданной вещи.
- количество .
(troop_remove_items, , , ), - удаляет заданное число заданных вещей у юнита. общее количество изъятых вещей поместится в reg0.
(troop_loot_troop, ,, ), - добавляет с заданной вероятностью (процент?) вещи которые есть в инвентаре.
увещи не изымаются.
(troop_get_inventory_capacity, , ), - запишет в переменную общее количество
слотов инвентаря и экипировки для данного юнита.
(troop_get_inventory_slot, , , ), запишет в переменную
ай-ди вещи находящуюся в определенном слоте экипировки или инвентаря.
(troop_get_inventory_slot_modifier, , , ), - запишет в переменную модификатор вещи находящуюся в определенном слоте экипировки или инвентаря.
(troop_set_inventory_slot, , , ), - помещает определенную вещь в слот инветаря или экипировки заданного юнита.
(troop_set_inventory_slot_modifier, , , ), - назначает модификатор для вещи находящейся в определенном слоте инвентаря или экипировки.
(store_item_kind_count, , , [troop_id]), - запишет в переменную количество заданной вещи у юнита. (по умолчанию ,без [troop_id] trp_player)
(store_free_inventory_capacity, , [troop_id]), - запишет в переменную общее количество свободных слотов у юнита. по умолчанию trp_player
(troop_set_name, , ), - назначает новое имя для юнита.
(troop_set_plural_name, , ), - назначает новое множественное имя для юнита.
(troop_set_face_key_from_current_profile, ), - назначает юниту фейс код из мультиплеерного профиля игрока.
(troop_add_gold, , ), - добавляет заданному юниту определенное количество денег.
используется для игрока и юнитов героев.
(troop_remove_gold, , ), - отнимает у заданного юнита определенное количество денег. работает только для игрока и юнитов героев
(store_troop_gold, , ), - записывает в переменную сумму денег которую имеет юнит.
(troop_set_faction, , ), - назначает юниту фракцию. в Нативе используется для перебежек лордов.
(store_troop_faction, , ), - запишет в переменную фракцию к которой принадлежит юнит.
(store_faction_of_troop, , ), - аналогичная операция той что выше.
(troop_set_age, , ), - назначает юниту возраст. происходит генерация нового кода типа лица с старением или омоложением.
Математические операции , дополнение.
Примечание: - в МС отсутствует работа с дробными числами.
(neg|), - операция обратного действия любой операции.
пример -
(party_slot_eq, "$current_town", slot_town_lord, "trp_player"),- последующие за этой строкой операции сработают только в том случае если владелец города игрок. (neg|party_slot_eq, "$current_town", slot_town_lord, "trp_player"), - при использовании neg последующие операции сработают только для тех городов которыми не владеет игрок и не будут работать для городов которые находятся во владении игрока.
(this_or_next|),- this_or_next группирует однотипные операции в блок или. дословно перевод это или следующее.
(this_or_next|eq, ":chislo", 1), (this_or_next|eq, ":chislo", 2), (eq, ":chislo", 3),
(eq - операция равенства. в данном примере проверяет что ":chislo" равно какому то значению)
последующие за этим блоком строки сработают в случае если переменная ":chislo" равна 1 ИЛИ 2 ИЛИ 3.
без использования this_or_next следующие операции сработают только если ":chislo" будет равно и 1, и 2, и 3,
Синтаксис - в последней строке this_or_next не используется.[/div]
(gt, , ), - операция проверяет что больше чем .
(ge, , ), проверяет что больше или равно
(eq, , ), - проверяет что равно
(neq, , ),- проверяет что не равно
(le, , ), - проверяет что меньше или равно
(lt, , ), - проверяет что меньше
(is_between, , , ), операция проверит что больше или равно и меньше .
(assign, , ), операция утверждение. записывает в переменную значение.
(store_add, , , ), - запишет в переменную сумму двух значений.
формула - = +
(store_sub, , , ), - запишет в переменную разницу двух значений
формула - = -
(store_mul, , , ), - запишет в переменную результат умножения значения на значение.
формула = *
(store_div, , , ), - запишет в переменную результат деления значеня на значение
формула = /
(store_mod, , , ), - это вычисление остатка от деления value1 на value2.
То есть:
(store_mod, reg0, 5, 2), ## reg0 = 1
(val_min, , ), - устанавливает что значение в переменной не может быть ниже значения
(val_max, , ), - устанавливает что значение которое находится в переменой не может превышать
(val_clamp, , , ), - устанавливает диапазон для переменной
от нижнего предела до верхнего ( = - 1 )
(val_abs, ),- Абсолютное значение (т.е. если отрицательное - станет положительным).
(store_random_in_range, , , ), запишет в переменную случайное число находящееся в диапазоне (нижний предел), (верзний предел -1)
(shuffle_range, , ), - Берёт указанный диапазон регистров, и случайно "перетасовывает" их значения. В коде обычно используется для рандомизации порядка (например, порядка в котором бойцы сражаются на арене).
(store_or, , , ), - ИЛИ
(store_and, , , ), - И
(val_or, , ), - ИЛИ
(val_lshift, , ), - Побитовое смещение влево
(val_rshift, , ), - Побитовое смещение вправо
(set_fixed_point_multiplier, ), - множитель для работы с дробными числами. дефолтное
один.
после назначения множителя в последующих операциях числовое значение будит делится на .
пример -
(set_fixed_point_multiplier, 100),
(entry_point_get_position, pos1, 0), - операция записывающая в pos1 координаты энтри поинт № 0
(position_move_z, pos1, 150), передвинет pos1 на 1,5 метра (не на 150, как указано) по z оси
(convert_to_fixed_point, ), - конвертирует целое число в дробное умножая на заданный множитель
(convert_from_fixed_point, ), - извлекает целое число из дробного деля на заданный множитель
(store_sqrt, , ),- запишет в переменную корень квадратный
(store_pow, , , <value_fixed_point), - запишет в переменную число взведенное в степень
(store_sin, , ), - синус числа
(store_cos, , ),- косинус числа
(store_tan, , ),тангенс числа
(store_asin, , ), арксинус числа
(store_acos, , ), арккосинус числа
(store_atan, , ), - атангенс
(store_atan2, , , ), вычисление угла по значениям катетов
Операции по работе с квестами
(quest_set_slot, , , ), - запишет в слот значение для квеста
(quest_get_slot, , , ), запишет в переменную значение из слота
(quest_slot_eq, , , ), проверит равенство значения в слоте и значения
(quest_slot_ge, , , ), - проверит что значение в слоте больше или равно значению.
(start_quest, , ), - задает старт квеста и отмечает юнита который выдал квест
(check_quest_active, ), - проверит что квест в активной фазе ( не провален и не завершен)
(check_quest_finished, ), - проверит что заданый квест завершен.
(check_quest_failed, ), - проверит что заданный квест был провален
(check_quest_succeeded, ), - проверит что задданый квест выполнен
(check_quest_concluded, ) - проверит на завершенность квеста, но с учетом того что квест завершен не так как того хотел наниматель.
(conclude_quest, ), - установит квест завершенным, с учетом того что квест завершен не так как хотел того наниматель.
(succeed_quest, ), - устанавливает что квест завершен но игрок должен вернутся к юниту который его выдал для завершения квеста.
(complete_quest, ), устанавливает что заданный квест завершен. изымает информацию из списка активных квестов
(fail_quest, ), - устанавливает что заданный квест провален. из списка не изымает - игрок должен поговорить с юнитом выдавшим квест
(cancel_quest, ), - отменяет квест
может быть устанавливает завершение многоступенчатого квеста
(store_partner_quest, ), - запишет в переменную ID юнита выдавшего квест.
Операции для работы с звуком, музыкой.
(play_sound, , [options]), - проигрывает заданный звук. [options] - опционально можно установить флаг из файла header_sounds.py
(play_sound_at_position, , , [options]), - проиграет звук из заданной позиции.
[options] - опционально можно установить флаг из файла header_sounds.py
(stop_all_sounds, [options]), - останавливает звук. (трэк?)
[options] -
0 - остановит текущий звук позволив проиграть до конца
1 - остановит его медленно с угасанием звука
2 - остановит немедленно.
(play_track,, [options]), - проигрывает трэк из файла module_music.py.
[options]
0 - проигрывать заданный после звучащего
1 - угасание звучащего и проигрывание заданного
2 - резкая смена играющего на заданный
(play_cue_track,), - будет проигрывать заданный трэк совместно с играющим.
(music_set_situation, ), - задает ситуацию для проигрывания трэка. флаг см. в header_music.py . трэки для проигрывания в ситуациях задаются в строке самого трэка.
также есть скрипт music_set_situation_with_culture который можно вызвать для проигрывания нужного трэка, который задан скажем для культуры_1 и должен играть в таверне.
(music_set_culture, ), - задает культуру для проигрывания трэка. флаг см. в header_music.py . трэки для проигрывания для определенных культур задаются в строке самого трэка.
Операции для работы с клавиатурой , мышью
назначение клавиш см. подробнее в header_triggers.py
(key_is_down, ), - проверит что была зажата определенная клавиша.
(key_clicked, ), - проверит что было ,,клацанье,, по определенной клавише
(key_is_down, ), - проверит что определенная клавиша зарегистрированная в движке зажата (например клавиша движения вперед)
(key_clicked, ), - проверит что определенная клавиша зарегистрированная в движке кратковременно нажата
(mouse_get_position, ), - запишет в позицию X и Y координаты указателя мыши
(omit_key_once, ), - единовременно заставит движок проигнорировать нажатие определенной клавишы зарегистрированной в движке
(clear_omitted_keys),- Очень специфическая операция, и вроде как по моим экспериментам - совершенно бесполезная. Однако же, используется. В общем, если мы где-то перехватываем значения клавиш, которые используются для управления игрой (I, P, C итд.), то лучше в конце триггера/презентации сделать вызов clear_omitted_keys - сугубо на всякий случай и для очистки совести. В конце-концов, скриптеры Taleworlds так делают, чем мы хуже?
Операции вызывающие игровые окна зарегистрированные в движке
(change_screen_loot, ), - открывает окно луттинга используя для этого инвентарь определенного юнита.
(change_screen_trade, [troop_id]), - использутся для вызова окна торговли в файле module_dialogs.py.
[troop_id] - опция, дефолтно будет вызван инвентарь для торговли того юнита с кем происходит диалог
(change_screen_trade_prisoners), - открывает окно продажи юнитов находящихся у игрока в качестве пленных. юнит с флагом геро не может быть продан. цена на заключенных регулируется в зависимости от уровня в
script_game_get_prisoner_price в файле module_scripts.py
(change_screen_view_character), - открывает окно характеристик юнита с которым ведется диалог.
вызывается окно только из файла module_dialogs.py
(change_screen_mission), - используется для перехода в сцену.перед операцией должна быть указана сцена и миссия из файла module_mission_templates.py
(change_screen_map_conversation, ), открывает окно диалога при встрече партии игрока с активной партией на глобальной карте. Используется операция в
script_setup_troop_meeting
script_setup_party_meeting
с вызовом сцены для встречи из script_get_meeting_scene
в файле module_scripts.py
(change_screen_equip_other, [troop_id]), - вызывает окно экипировки юнита. работает только из файла
module_dialogs.py. [troop_id] - опционально и будет подразумевать собеседника
(change_screen_map), - закрывает окна сцены диалога или меню с выходом на глобальную карту
(change_screen_notes, , ), - открывает окно заметок(notes) -
-
1 - юнит
2 - фракция
3 - партия
4 - квест
5 - страница информации.
- объект типа
например
(change_screen_notes, 2, "fac_nord"), - откроет окно с информацией о фракции норд
(change_screen_quit), - выход из игры в меню
(change_screen_give_members, [party_id]), - -открывает окно передачи юнитов в другую партию. без [party_id] подразумевает партию с которой встретился игрок
(change_screen_exchange_members, [0,1 = exchange_leader], [party_id]), - вызывает окно гарнизона или изъятия с определенным лордом
0 - нельзя изъять из партии или передать юнита с флагом геро(лидера партии)
1 - можно изъять из партии или передать юнита с флагом геро(лидера партии)
[party_id] - опционально. если не указана, то будет поразумеваться та партия с которой произошла встреча игрока
(нас пункт либо активная партия)
Если подразумевается двухсторонний обмен с изъятием и отдачей то используются обе операции.
(change_screen_exchange_with_party, ), дублирующая операция (change_screen_exchange_members), но без выбора о возможности передачи лидера партии
(change_screen_controls), - вызывает окно конроля
(change_screen_options), - вызывает окно опций
(start_map_conversation, , [troop_dna]), - откроет окно сцены встречи с опциональным параметром которым можно вызвать днк юнита для говорящего в партии которая не имеет лидера
Операции для module_game_menus.py
(set_background_mesh, ), - устанавливает определенный фон для определенного меню.
позиция изображения будет зависеть от координат самого меша. для использование мешей с текстурой которые заданы в родном меню, нужно поставить флаг для имени меню - mnf_scale_picture
(set_game_menu_tableau_mesh, , , ), - добавит в определенное меню табле меш.
- X, Y, координаты означают расположение по осям меша. Z - размер изображения.
, - сочитается с параметром самого табле меша
(jump_to_menu, ), операция перехода из одного меню в другое. либо же при выходе с определенной миссии (сцены) адресует выход в определенное меню
Операции используемые при встрече игрока с другими партиями, для определения последующих действий.
(set_party_battle_mode), -Влияет на состояние игрока и его команды в начале миссии. Если бэттл-мод, то все начинают миссию в полной боеготовности, с обнажённым оружием.
finish_party_battle_mode - останавливает команду set_party_battle_mode
(start_encounter, ), - вынуждает партию игрока встретится с партией .
(leave_encounter), - завершает встречу.
(encounter_attack), - используется в модуль_диалог для завершения разговора с переходом к боевым действиям.
(select_enemy, ), - определяет противника игрока при присоединении его к уже идущему сражению.
-
0 - к партии агрессору
1 - к защищающейся партии
(set_passage_menu, ), - устанавливает номера пассажей в сцене по порядку определенного меню.
если использовать переход из гейм_меню в определенную миссию и установить
(set_passage_menu,"mnu_town"),
номера пассажей (телепортов) буду совпадать с подменю mnu_town.
(auto_set_meta_mission_at_end_commited), - хз
(start_mission_conversation, ), - используется в файле module_mission_templates.py для инициирования диалога инрока с определенным юнитом находящимся в сцене.
(set_conversation_speaker_troop, ), - позволяет в диалоге переключить оппонента на реплику определенного юнита.
(set_conversation_speaker_agent, ),позволяет в диалоге переключить оппонента на реплику определенного агента в сцене
(store_conversation_agent, ), - запишет в переменную ID агента с которым ведется диалог
(store_conversation_troop, ), - запишет в переменную ID юнита с которым ведется диалог.
(store_partner_faction, ), - запишет в переменную ID фракции к которой относится юнит с которым ведется диалог
(store_encountered_party, ), - запишет в переменную ID партии c которой происходит встреча.
(store_encountered_party2, ), - запишет в переменную ID второй партии. если первая находится в бое то здесь запишется оппонент партии 1
(set_encountered_party, ), - ?
в нативе используется для определения ID партии (города) для перехода в миссию засады.
(end_current_battle), - ?
в нативе используется для завершения битвы, когда у противников игрока заканчиваются юниты для последующего перехода в бой.
(store_repeat_object, ), - записывает в переменную динамические реплики. используется вместе с repeat_for_. хранит в переменной реплики.
(talk_info_show, ), - используется для вк./отк. функции информации о собеседнике, когда указатель мыши расположен в окне для собеседника.
0 - отключает
1 - включает
(talk_info_set_relation_bar, ),- вызывает на экран в окне собеседника при наведении мыши на оппонента меш с текущим уровнем отношения с собеседником.
(talk_info_set_line, , ) - вызывает на экран имя собеседника при наведении указателя мыши на окно собеседника, вместе с тулбаром отношений.
header_scene_props.py
Файл декларирует "флаги", придуманные для работы с объектами сцен. Ничего не меняйте в этом файле и не обращайте внимания на конструкции, где нет приставки sokf_.
sokf_type_container Превращает объект сцены в сундук.
sokf_type_ai_limiter Превращает объект сцены в препятствие для всех агентов, кроме пешего игрока. Пеший игрок может проходить сквозь такой объект независимо от наличия у объекта "физического тела" (body mesh).
sokf_type_barrier Превращает объект сцены в препятствие для всех агентов.
sokf_type_barrier_leave Превращает объект в препятствие для всех агентов, с помощью которого игрок может покинуть данную сцену. При приближении к такому объекту появляется надпись "Leave area" (покинуть местность).
sokf_type_ladder Превращает объект сцены в лестницу с возможностью подниматься по ней под очень крутым углом. Точный градус не скажу, под текстом для пояснения привожу скриншот, где центральная колонна имеет минимально необходимый угол наклона.
sokf_type_barrier3d бессмысленный флаг, хотя и рабочий. Превращает объект сцены в препятствие для всех агентов. Объекты с таким флагом по сути в игре не используются.
sokf_type_mask Не используется.
sokf_add_fire Не используется. Огонь добавляется триггерами в файле scene_props.py
sokf_add_smoke Не используется. Дым добавляется триггерами в файле scene_props.py
sokf_add_light Не используется. Свет добавляется триггерами в файле scene_props.py
sokf_show_hit_point_bar Указывает, что у разрушаемого объекта должна отображаться строка состояния (индикатор степени разрушенности).
sokf_place_at_origin Объект с таким флагом при загрузке сцены всегда будет оказываться у правого башмака ГГ.
sokf_dynamic Не используется.
sokf_invisible Делает объект невидимым (если не активирован режим редактирования).
sokf_destructible Присваивается разрушаемым объектам, помимо него нужен триггер в файле scene_props.py (он определяет запас прочности, фиксирует удар, обеспечивает результат разрушения), примечательно, что без этого флага триггер будет фиксировать нулевой урон и разрушение никогда не произойдёт.
sokf_moveable Присваивается объектам, которые можно с помощью скриптов перемещать (анимировать) на сцене. Замена в строке disable_moveable_flag_optimization = 0 файла module.ini нуля на единицу позволяет обходиться без применения данного флага. Есть мнение, что такой подход увеличивает требовательность игры к системным ресурсам компьютера.
sokf_face_player Заставляет объект сцены всегда поворачиваться лицевой стороной к игроку, в нативе применяется для флагов (баннеров).
sokf_dynamic_physics Заставляет объект сцены реагировать на удары и в результате падать, скакать, сползать. Поведение такого объекта выглядит нереалистично и с привычной нам физикой имеет мало общего.
sokf_missiles_not_attached Не используется. Предполагается для указания, что достигшие объекта стрелы и т.п. не должны в нём оставаться.
Операции для работы с мультиплеером
# multiplayer
(multiplayer_send_message_to_server, ), - отправить сообщение на сервер(? не использовал ни разу) message_type прописываются в header_common.
(multiplayer_send_int_to_server, , ), - отправить на сервер информацию, что событие должно начаться с одним из параметров, равным . По сути, это тоже вызов скрипта, ведь все события записаны в #script_game_receive_network_message. Однако, в отличие от простого вызовы скрипта, данное событие произойдёт для всех.
(multiplayer_send_int_to_player, , , ), - работает аналогично предыдущей команде, но только для конкретного игрока . Как я считаю, эта команда нужна отчасти для того, чтобы сделать событие на сервере видимым для игрока. (Яркий пример - это инвентарь в мультиплеере, позволяющий игроку переодеваться прямо во время битвы. То есть, мы установили новую броню игроку, но никто не заметил изменения одежды. Поэтому следует продублировать изменение брони для всех игроков через эту команду.) Кроме того, она может использоваться для того, чтобы перемещать камеру конкретному игроку и прочего.
(multiplayer_send_string_to_player, , , ), - отправить игроку при событии строковую переменную , лежащую в файле module_strigns.py. Или же, вместо неё можно попробывать написать переменную в виде "@абырварг".
(get_max_players, ), - пишет в переменную то ли максимально возможное количество игроков на сервере, то ли максимально возможное вообще.
(player_is_active, ), - выдаёт истину, если игрок на сервере. вроде бы, точно не помню.
(player_get_team_no, , ), - пишет в переменную, в какой команде игрок. 0,1 или 2. 2 - наблюдатели.
(player_set_team_no, , ), - устанавливает игроку новую команду.
(player_get_troop_id, , ), - пишет в переменную, за какой тип солдата играет игрок. Солдаты лежат в module_troops.py
(player_get_troop_id, , ), - устанавливаем игроку тип солдата.
(player_get_agent_id, , ), - пишет в переменную идентификатор агента игрока. Агент, как я понимаю, это любое "живое" существо на карте, бот, игрок или лошадь.
(player_get_gold, , ),
(player_set_gold, , , ), #set max_value to 0 if no limit is wanted
первая команда пишет в переменную текущее количество золота у игрока, вторая - выдаёт игроку золото в количестве value.
(player_spawn_new_agent, , ), - заставляет появиться копию игрока на указанной entry_point.
player_add_spawn_item = 410 # (player_add_spawn_item, , , ), - ? как описать, не знаю, но ей выдаются предметы, выбранные в меню закупки.
multiplayer_get_my_team = 411 # (multiplayer_get_my_team, ),
multiplayer_get_my_troop = 412 # (multiplayer_get_my_troop, ),
multiplayer_get_my_gold = 414 # (multiplayer_get_my_gold, ),
multiplayer_get_my_player = 415 # (multiplayer_get_my_player, ),
пишут в переменные данные о команде, типе солдата, золоте и идентификаторе игрока для игрока.(когда расчёт идёт не для сервера, а для игрока. Лучше не знаю, как объяснить).
multiplayer_set_my_troop = 413 # (multiplayer_get_my_troop, ),
multiplayer_clear_scene = 416 # (multiplayer_clear_scene), -?
(multiplayer_is_server), возвращает истину, если игрок, у которого выполняется код, является сервером, создавшим сервер из игры(?).
multiplayer_is_dedicated_server = 418 # (multiplayer_is_dedicated_server),-?
game_in_multiplayer_mode = 419 # (game_in_multiplayer_mode), -?
(multiplayer_make_everyone_enemy), - это вроде делает всех врагами. для дезматча.(?)
## Set_slot operations. These assign a value to a slot.
Слоты! С ними можно всё. На них строиться код.
Слот - это, по сути, своя переменная с одним и тем же именем для множества однородных объектов.
Допустим, нам надо записать, что квест выполнен наполовину. Для этого можно создать переменную типа :half или $g_half. Но для каждого нового квеста нам придётся создавать новые переменные, дабы отразить его состояние. То есть много лишней информации.
Но мы можем использовать слоты. Слот - это такой ящик, в который мы можем положить любые предметы. Например, у нас два квеста - синий и зелёный. Чтобы записать, что квест пройден наполовину, мы сделаем так.
В module_constants.py сколотим новый ящик в разделе Quest Slots. Например, ящик quest_stage.
Потом мы просто делаем такой же и относим его в синий или зелёный домик.
(quest_set_slot,,,), - quest_set_slot - сама команда, кладущая в ящик информацию; - идентификатор квеста, в нашем случае "синий" или "зелёный". - это наш ящик; value - значение, вещь, которую мы положили в слот. Это может быть идентификатор игрока или агента, оружия, объекта сцены, самой сцены, любое число.
Итого, если зелёный квест выполнен наполовину, мы напишем:
(quest_set_slot,"qst_зелёный",slot_quest_stage,1)
После этого мы командой quest_get_slot можем в любом другом месте модульной системы(скрипты, триггер миссий) определить состояние нашего квеста.
Или вот так можно. Нам нужно записать, что игрок должен принести случайно выбранное программой оружие. например, был выбран itm_sword. Создадим новый слот quest_weapon.
(quest_set_slot,"qst_зелёный",slot_quest_weapon, "itm_sword").
Теперь мы можем легко проверить, какое оружие у нас должно найтись.
Так, а если нам надо два предмета? То есть, придётся сделать два слота? quest_weapon_1 и quest_weapon_2? Нет, можно проще.
Слот - это ящик, сущность которого одновременно пребывает в разных измерениях в количестве от одного до бесконечности. Так вот. Можно в зелёную комнату принести ещё такой же ящик и на него прикрепить бирку с номером. То есть в зелёной комнате будут два идентичных ящика с номерами 0 и 1.
И вот, второе оружие - лук.
Мы запишем так:
(quest_set_slot,"qst_зелёный",slot_quest_weapon, "itm_sword") - ящик с номером 0
(quest_set_slot,"qst_зелёный",slot_quest_weapon+1, "itm_bow") - ящик с номером 1
Вот и всё. И никаких глобальных переменных в неведомом числе
Пояснение понятия Слот.
Для целого ряда существующих в игре объектов возможно создание специальных ячеек памяти, называемых слотами (slot). Слоты упрощают хранение и систематизацию информации, избавляют нас от необходимости сочинять и запоминать тьму-тьмущую переменных. Вот список таких объектов: item, agent, faction, party, party_template, scene, scene_prop, troop, quest, player, team. Для каждой сцены, для каждого предмета, юнита и т.д. мы можем создать почти неограниченное множество слотов (ячеек памяти). Чтобы обращаться к этим слотам годятся как порядковые номера (от нуля до... почти бесконечности), так и названия. Названия вновь придуманных слотов необходимо прописать в файле module_constants.py. Учтите, что большое количество слотов уже имеют свои названия и используются игрой в различных ситуациях.
Например, для агентов в нативе используется 26 слотов, пронумерованных от 0 до 25 и снабжённых названиями типа slot_agent_is_running_away (в данном случе это слот с номером 15). Следовательно, надёжнее всего новый слот создать с номером 26, это на 100% защитит нас от багов, связнных с использованием одного и того же слота двумя разными скриптами. Упомянутый слот позволяет для любого из агентов, находящихся на сцене, сделать запись, что он в данный момент убегает (дезертирует):
(agent_set_slot, ":cur_agent", slot_agent_is_running_away, 1),
Даже если агентов на сцене 200, мы обходимся одной строкой и не мучаемся созданием двухсот (плюс ещё сколько-то про запас) переменных. Согласитесь, одна строка это гораздо удобнее, чем сотни строк. Причём приведённую выше строку мы можем записать и так:
(agent_set_slot, ":cur_agent", 15, 1),
Функционировать всё будет точно так же, разница лишь в том, что человеку обычно легче запомнить несущие значения слова, чем набор чисел. В нашем примере slot_agent_is_running_away означает - вот константа, используемая для обозначения слота агента, где хранится информация, убегает он или нет. Если какое-то название слота вам сложно запомнить, то вы можете ввести для него альтернативное название. Для этого достаточно в файле module_constants.py добавить соответствующую запись:
run_away = slot_agent_is_running_away
и тогда наша строка-пример преображается в следующую с полным сохранением своей функции:
(agent_set_slot, ":cur_agent", run_away, 1),
Для обращения к слотам мы также можем использовать переменные, например следующий скрипт позволяет с помощью трёх строк сделать значение всех двадцати шести слотов агента равным нулю:
(try_for_range, ":unused", 0, 26),
(agent_set_slot, ":cur_agent", ":unused", 0),
(try_end),
Кстати, для любого слота, в который мы ещё не записывали никакого числа, игра будет считать его содержимое равным нулю. Итак, для обращения к слоту можно применять его номер, название, любое альтернативное название, любую переменную, а также простые арифметические выражения:
(agent_set_slot, ":cur_agent", run_away + 1, 1),
в данном случае мы обратились уже к следующему слоту, имеющему номер 16.
По отношению к слотам нам доступны следующие операторы:
(agent_set_slot,,,), записывает в слот число (value)
(agent_get_slot,,,), узнаёт записанное в слот число
(agent_slot_eq,,,), делает строгую проверку (содержимое слота равно определённому значению)
(agent_slot_ge,,,), делает нестрогую проверку (содержимое либо больше, либо равно определённому значению)
(neg|agent_slot_eq,,,), делает нестрогую проверку (содержимое либо больше, либо меньше определённого значения)
(neg|agent_slot_ge,,,), делает строгую проверку (содержимое меньше определённого значения)
Разумеется при работе с другим объектом вместо слова agent будет фигурировать что-то из списка item, faction, party, party_template, scene, scene_prop, troop, quest, player или team.
Операции для работы с строковыми регистрами.(стринг)
Строковые регистры(s0, s1,..) , в отличии от простых регистров (reg0, reg1, reg2,...), которые хранят числовое значение, позволяют хранить буквенные символы - текст, для вывода его на экран. Текст можно хранить в файле module_strings.py, и затем с помощью операции помещать его в строковой регистр. например в файле module_strings.py первая запись - ("no_string", "NO STRING!"),
"no_string" -идентификатор (имя) стринга.
"NO STRING!" - Сам текст.
для того чтобы использовать текст сделаем следующее
(str_clear, s0), # Сотрем текст который может быть сохранен от предыдущего использования s0. (str_store_string, s0, "str_no_string"), # Запишем в s0 текст который хранится под идентификатором no_string
Можно пойти другим путем, без помещения текста в файл module_strings.py
(str_clear, s0), # Сотрем текст который может быть сохранен от предыдущего использования s0. (str_store_string, s0, "@ NO STRING! "), # В данном случае мы ввели текст непосредственно в самой операции. использование значка @ перед текстом является обязательным.
Работая с строковыми регистрами мы можем комбинировать несколько записей в одну в зависимости от обстоятельств. Например нам нужно вывести имя партии с которой происходит встреча игрока для ввода его в определенную строку, а поскольку оно нам не известно можно сделать таким образом.
(str_clear, s0), # Сотрем текст который может быть сохранен от предыдущего использования s0. (str_store_party_name, s0, "$current_town"), # Запишем имя партии которая идентификатор которой находится в $current_town "$current_town" - глобальная переменная в которой ID города с которым происходит встреча партии игрока. (str_clear, s1), # Сотрем текст который может быть сохранен от предыдущего использования s1. (str_store_string, s1, "@ You rode into in the gate of {s0} "), # В этом случае у нас будет динамически выводится имя города
(str_is_empty, ), проверит что определенный стриг чист
(str_clear, ), очищает заданный стринг
(str_store_string, , ), - запишет в стринг текст из module_strings.py, либо быстрый стринг.
(str_store_string, , ), - запишет в стринг текст из другого регистра.
(str_store_troop_name, , ), - запишет в стринг имя заданого юнита
(str_store_troop_name_plural, , ), запишет в стринг множественное имя заданого юнита
(str_store_troop_name_by_count, , , ), - запишет в стринг имя заданого юнита
и заданое число юнитов.
(str_store_troop_name_by_count, s1, "trp_bandit", 10), - запишет в стринг - "10 Bandits"
(str_store_item_name, , ), - запишет в стринг название вещи
(str_store_item_name_plural, , ), - запишет в стринг множественное название вещи
(str_store_item_name_by_count, , ), - запишет в стринг название вещи и его количество.
(str_store_party_name, , ), - запишет в стринг название заданной партии
(str_store_agent_name, , ), - запишет в стринг имя заданого агента.
(str_store_faction_name, , ), - запишет в стринг название фракции.
(str_store_quest_name, , ), - запишет в стринг название заданого квеста
(str_store_info_page_name, , ), - запишет в стринг название инфо страницы из module_info_pages.py
(str_store_date, , ), - запишет в стринг текущюю время и дату
Последующие операции для вывода текста с переходом к странице информации по заданной теме при клацании мышкой на тексте .
(str_store_troop_name_link, , ), - запишет в стринг имя юнита.
(str_store_party_name_link, , ), - запишет в стринг название партии
(str_store_faction_name_link, , ), -запишет в стринг название фракции
(str_store_quest_name_link, , ), - запишет в стринг название квеста
(str_store_info_page_name_link, , ), - запишет в стринг название темы инфо страницы
(str_store_class_name, , ) - запишет в стринг название класса юнитов
(Infantry, Archers, Cavalry)
По мультиплееру без понятия.
(str_store_player_username,,),
(str_store_server_password, ),
(str_store_server_name, ),
(str_store_welcome_message, ),
(str_encode_url, ),
Существует немало весьма полезных тем и туториалов, которые помогают на начальном этапе изучения модульной системы и учат, как можно с ее помощью изменять любые детали Mount&Blade Warband, но мне так и не удалось найти ни одной, которая бы досконально объясняла все самые основы и азы операций и их синтаксиса, используемого в модульной системе. Вместо этого существует множество небольших одиночных тем-вопросов в разделе "Вопросов и ответов", которые помогают начинающим кодерам и модульщикам разобраться в принципах работы модульной системы. Итак, я, как, без сомнения, наиболее опытный и умелый член этого сообщества, который лучше всех сумееет точно, понятно и толково разъяснить основы синтаксиса модульной системы, решил, что не будет хуже, если я попытаюсь.
Список всех существующих операций и команд, которые могут быть использованы, содержится в файле header_operations.py. Каждая команда сопровождается комментарием (отмеченным символом #), в котором прописаны все аргументы данной операции, и возможно — краткое описание и подсказки по использованию. Каждая операция модульной системы имеет следующий вид:
1. Операция заключена в круглые скобки: (operation)
2. Сразу после операции должна стоять запятая: (operation),
3. Аргументы пишутся внутри скобок сразу после названия самой операции в строго заданном порядке и разделяются запятыми: (operation, argument, argument),
Помимо этого, в header_operations каждой операции присвоен ее собственный номер. Например, call_script = 1. Когда игра выдает сообщения об ошибке, они имеют вид SCRIPT ERROR ON OPCODE ##: … (Здесь и далее # - целое число. Прим. пер.) Номер OPCODE соответствует номеру операции в header_operations. Таким образом, если у ошибки OPCODE 1, то можно понять, что ошибка произошла при попытке вызвать операцию call_script.
Вообще все элементы, содержащиеся в любом файле МС, строго пронумерованы по порядку. Нумерация начинается с 0, и каждый следующий элемент имеет номер на 1 больше, чем предыдущий. Таким образом классы, предметы, триггеры, сцены и т. д., после компиляции МС в игровые текстовые файлы, сортируются по их этим самым номерам. Итак, если вы видите, что ошибка в “ trigger 0” - значит, имеется в виду первый триггер в соответствующем файле, и если ошибка в 4-ой строке, искать нужно 5-ю операцию в этом триггере.
Переменные
Локальные переменные (local variables) - “:variable” - переменные, названия которых начинаются с двоеточия ( : ) - это локальные переменные. Они существуют только в данном фрагменте кода, ограниченном скобками ( [ ] ) и они не могут быть вызваны непосредственно из других фрагментов кода иначе, кроме как быть переданными в качестве аргументов операции. Перед тем, как использовать переменную в коде, необходимо ее сперва инициализировать — присвоить ей какое-либо значение (0 или любое другое, подходящее по типу). Названия локальных переменных заключаются в кавычки ( “” ), и начинаются с двоеточия ( : ). Пример: “:agent_id”
Глобальные переменные (global variables) - “$variable” - переменные, названия которых начинаются со знака доллара ( $ ) - это глобальные переменные. Они могут быть доступны из любой части кода, из любого module_*.py файла после того, как были однажды инициализированы. По умолчанию значение созданной глобальной переменной равно 0. Названия глобальных переменных заключаются в кавычки ( “” ), и начинаются со знака доллара ( $ ). Пример: “$g_talk_troop”
Регистры (registers) – reg(#) или reg# - это переменные, используемые движком игры для временного хранения информации. Регистры глобальны, но могут быть доступны из других частей кода только пока существуют. В header_common содержатся объявления всех существующих регистров от reg0 до reg65.
Строки (strings) – s# - это специальная разновидность регистров, предназначенная для хранения не чисел, а строк текста. Строки, не прописанные заранее в module_strings (быстрые строки(quick strings)) начинаются с символа @. В header_common содержатся объявления всех существующих строковых регистров от s0 до s67.
Позиции (positions) – pos# - В отличие от предыдущих двух видов регистров, позиции хранят больше одного элемента информации; каждая позиция содержит координаты по осям X, Y и Z, а также углы поворота объекта относительно каждой из этих осей. В header_common содержатся объявления всех существующих регистров - позиций от pos0 до pos64, а также начинающийся с pos64 неустановленный массив позиций, используемых осадными башнями.
Постоянные, константы (constants) – constant – это постоянные значения, прописанные в module_constants, содержащие численное значение, присвоенное им при инициализации. Их значения не могут быть изменены никак иначе, кроме как напрямую в module_constants. Они могут быть доступны из любой части кода, из любого module_*.py файла. Константы не заключаются в кавычки.
Локальные и глобальные переменные, как и регистры, инициализируются с помощью команды (assign, , ), Присваиваемое значение () может быть другой переменной. Строки и позиции имеют свои собственные уникальные операции, прописанные в header_operations.
Приставки
В модульной системе существует возможность обращаться из одного файла к объектам из другого с помощью специальных приставок, добавляемых перед названием нужного объекта. Таким образом, если нужно, например, в module_mission_templates использовать какую-либо анимацию, то название этой анимации пишется следующим образом: anim_<название анимации из module_animations>.
module_animations: "anim_" - Анимации
module_factions: "fac_" - Фракции
module_info_pages: "ip_" - Описания
module_items: "itm_" - Предметы
module_map_icons: "icon_" - Иконки глобальной карты
module_game_menus: "menu_" - Меню
module_meshes: "mesh_" - Модели
module_mission_templates: "mst_" - Миссии
module_particle_systems: "psys_" - Визуальные эффекты
module_parties: "p_" - Отряды, партии
module_party_templates: "pt_" - Шаблоны отрядов, партий
module_pstfx_params: "pfx_" - Параметры окружающей среды
module_presentations: "prsnt_" - Игровые ситуации
module_quests: "qst_" - Квесты
module_scene_props: "spr_" - Сценовые объекты
module_scenes: "scn_" - Сцены
module_scripts: "script_" - Скрипты
module_skills: "skl_" - Умения, навыки
module_sounds: "snd_" - Звуки
module_strings: "str_" - Строки
module_tableau_materials: "tableau_" - Скрипты, обрабатывающие текстуры
module_troops: "trp_" - Классы персонажей
Module_scripts, скрипты, параметры, аргументы и т. д.
Большая часть module_*.py файлов содержат в основном самостоятельный, изолированный код. Такие файлы как _troops, _skills, _items и т. д. представляют собой просто список различных игровых объектов с описаниями их свойств. module_game_menus содержит всевозможные меню в игре, их пункты, параметры и др. Presentations хранит данные, связанные с рисованием различных игровых ситуаций, и т. д.
Но module_scripts связан с каждым из этих файлов — он содержит «общие» функции, которые могут быть вызваны из любой части игрового кода. Поэтому предполагается, что скрипты из module_scripts будут вызываться, в основном, из других module_*.py файлов с помощью операции (call_script, , ),
Чтобы упростить процесс использования скриптов, операция вызова позволяет передавать информацию из текущего фрагмента кода в сам скрипт без использования глобальных переменных с помощью так называемых аргументов или параметров. Эти аргументы или параметры могут быть локальными переменными, объявленными в данном фрагменте кода. Сам скрипт в module_scripts при вызове начнет свое выполнение с приема и сохранения переданных аргументов как локальных переменных в своем теле, чтобы иметь возможность использовать их при выполнении. Правда, скрипты не могут передавать информацию в код, откуда они были вызваны тем же способом... Но для этих целей обычно используются регистры. В коде, из которого вызывается скрипт, сразу после завершения выполнения скрипта значения этих регистров для удобства сохраняются в локальные переменные. В скрипт за одну операцию вызова можно передавать до 15 аргументов.
Пример:
Фрагмент кода из module_mission_templates:
//...объявления, инициализация...// (assign, ":local_variable_1", 10), #объявление первой локальной переменной (assign, ":local_variable_2", 5), #объявление второй локальной переменной #вызов скрипта с передачей локальных переменных как аргументов (call_script, "script_example_script", ":local_variable_1", ":local_variable_2"), #получение результата выполнения скрипта из регистра #и сохранение его в новую локальную переменную (assign, ":local_variable_3", reg0), #local_variable_3 = 15 //...продолжение кода, работающего с local_variable_3...//
Скрипт из module_scripts:
# script_example_script # Input: variable_1, variable_2 # Output: Sum in reg0 ("example_script", [ #получение и сохранение переданных аргументов (store_script_param, ":num1", 1), #теперь num1 равен 10 (store_script_param, ":num2", 2), #теперь num2 равен 5 #тело скрипта, выполнение действий над аргументами (store_add, ":sum", ":num1", ":num2"), #сохранение результата выполнения скрипта в регистр, #чтобы он был доступен из исходного фрагмента кода в mission_templates (assign, reg0, ":sum"), ]),
ТЕРМИНОЛОГИЯ
«Класс» и «Агент» (Troop vs Agent)
Классы обозначают объекты, описанные в module_troops — классы персонажей игры, каждый из которых имеет какие-то свои уникальные свойства и иособенности. “trp_player” - это игрок, “trp_npc##” - это класс компаньонов, “trp_knight_#_##” - класс лордов, “trp_swadian_footman” - класс свадийских пехотинцев и т. д. Классы используются как шаблоны для создания персонажей с определенным набором свойств, причем каждый класс может содержать большое количество объектов. Например, солдаты в отряде, которые группируются по типу (классу), и которых в каждом типе(классе) может быть несколько.
Агенты же являются отдельными действующими лицами, например, в какой-либо сцене (будь то сцена сражения, таверна, улицы города или любая другая). Агенты создаются из классов-шаблонов из module_troops... Для игрока, компаньонов, лордов, но при этом каждый агент уникален, для любого персонажа создается его отдельный собственный агент. Так что даже для группы солдат одинакового класса все равно создаются несколько агентов одинакового класса, по одному для каждого солдата. Каждый агент на сцене уникален, но как только сцена закрывается, агенты перестают существовать вместе с ней.
Партии и Шаблоны Партий (Parties and Party Templates)
«Партия» - это любой объект на глобальной карте, будь то отряд игрока, разбойники, их убежища, армии лордов или города, замки, деревни. Типы партий поделены на категории и прописаны в первом слоте партии “slot_party_type”, в котором должно содержаться число, соответствующее нужной категории. Эти категории прописаны в module_constants и начинаются с приставки spt_ (slot_party_type). Примерами spt_* являются spt_kingdom_hero_party (для армий лордов) или spt_castle (для замков).
Каждая партия имеет свой уникальный ID номер, который может использоваться в коде. Например, партия игрока - это “p_main_party”, у которой значение ID — 0. Точно определенные партии имеют постоянный, статический ID, как партия игрока и все города, замки и деревни. Все такие партии со статическими ID прописаны в module_parties. Их ID можно просмотреть в ID_parties.py после того, как МС будет скомпилирована.
Для всех партий, которые НЕ прописаны в module_parties, ID создаются динамически, по мере создания самих партий. Партии же создаются с помощью шаблонов партий по тому принципу, что агенты и классы (см. выше). Шаблоны партий прописаны в module_party_templates.py и их названия начинаются с приставки “pt_*”. Шаблон содержит в первую очередь список классов персонажей, находящихся в этой партии и численные интервалы, означающие количество представителей каждого класса в этой партии (точное количество выбирается случайным образом в пределах этого интервала). Шаблоны партий используются для динамического создания отдельных партий с помощью команды (spawn_party). Созданной партии присваивается ID номер, и после этого партия может быть классифицирована по значению slot_party_type и т. д. Также шаблоны партий могут быть использованы для уже существующих партий, а именно можно добавить шаблон партии со всеми входящими в нее персонажами к уже существующей партии в качестве «подкрепления».
Слоты
Слоты, в сущности, - это способ сгруппировывать переменные по объектам (к которым относятся партии, классы, агенты, команды, фракции, сцены, сценовые объекты и шаблоны партий). Каждая партия, класс, агент, предмет и т. д. имеет определенный набор «слотов» - переменных, привязанных именно к этому объекту. Каждая такая переменная имеет название типа ”slot_item_SLOTNAME”, и они привязываются к каждому экземпляру объекта (предмета (item'a) в данном случае), что очень удобно, поскольку позволяет хранить свою собственную уникальную информацию для каждого отдельного объекта. Выглядят слоты как константы из-за того, что движок игры воспринимает их именно так, и имя каждого слота заменяет на число, прописанное в module_constants (slot_item_base_price = 53). Это значит, что чтобы узнать базовую цену данного объекта-предмета, движок должен взять значение 53-го слота, привязанного к этому объекту.
Итак, посмотрев на какую-нибудь операцию, работающую со слотами, как например (item_get_slot, “:base_price”, “:item_id”, slot_item_base_price), можно увидеть, что необходимо точно указывать, базовую цену какого именно предмета вам нужно узнать (“:item_id”). Но вы можете использовать цикл try_for_*, подставляя в каждой итерации цикла новое значение в “:item_id”, и перебрать таким образом любое количество предметов, чтобы произвести какие-то действия с ценой каждого из них, например.
Вы можете узнать цену какого-либо предмета, получив значение соответствующего слота с помощью операции item_get_slot, изменить ее, присвоив новое значение с помощью операции item_set_slot, проверять, не равна ли она какому-либо заданному значению с помощью item_slot_eq и многое другое.
Если вы знакомы с C-подобными языками программирования, то слоты работают примерно так же, как это:
slot_troop_spouse spouse[troop1] = spousename spouse[troop2] = spousename spouse[trp_player] = spousename
Движок игры этот код воспринимает так: troop_variable_30[troop1], troop_variable_30[troop2], troop_variable30[trp_player], поскольку slot_troop_spouse в module_constants имеет номер 30.
slot_item_base_price baseprice[item1] = priceA baseprice[item2] = priceB baseprice[item3] = priceC
Движок игры этот код воспринимает так: item_variable_53[item1], item_variable_53[item2], item_variable_53[item3],... поскольку slot_ item_base_price в module_constants прописан под номером 53.
Пока слотам не присвоено никакое значение операцией *_set_slot, значения всех слотов по умолчанию равны 0.
УСЛОВИЯ И ЦИКЛЫ
Необходимо упомянуть, что игровой движок в любой конструкции “Если-Тогда” воспринимает любую операцию проверки условия как “ЕСЛИ”, и весь код, который следует за ней — как “ТОГДА”. Так как код выполняется построчно, то если его выполнение прервется при первом же неверном условии, то вообще весь последующий код не будет выполнен.
Поэтому для изоляции конструкций “Если-Тогда”, чтобы код мог нормально выполняться и прерывание его выполнения на одном неверном условии не значило прекращение выполнения вообще, используются так называемые “try-блоки”, использующие операции (try_begin), (else_try), и (try_end), Подробнее о использовании try-блоков ниже.
Операции - условия
(eq,,), Значение 1 = Значение 2?
(gt,,), Значение 1 > Значение 2?
(ge,,), Значение 1 >= Значение 2?
(lt,,), Значение 1 < Значение 2?
(le,,), Значение 1 <= Значение 2?
(neq,,), Значение 1 != Значение 2?
(is_between,,,), Нижняя граница <= Значение < Верхняя граница?
Кроме этого любая операция, содержащая “_is_”, также является условием и может быть проверена на выполнение-невыполнение (true-false). Например, операция (agent_is_alive, ), - это проверка, жив ли в данный момент агент . Если да, то есть если данный агент жив, то выполнение кода продолжается. Если же агент мертв, то выполнение данного try-блока прерывается.
Для того, чтобы проверить операцию-условие, содержащую “_is_” на НЕвыполнение (выполнение кода продолжается, если условие неверно), нужно сделать следующее:
(neq|),
В нашем предыдущем примере, (neq|agent_is_alive, ), выполнение кода продолжится в том случае, если данный агент мертв (НЕ жив), и прервется, если он жив.
Управляющие операции
(try_begin),
(try_end),
(else_try),
(try_for_range,,,),
(try_for_range_backwards,,,),
(try_for_parties,),
(try_for_agents,),
- это переменная, значение которой будет изменяться в каждой итерации цикла в соответствии с текущей итерацией. Подробнее см.ниже.
Логические операторы И и ИЛИ
Поскольку, как уже упоминалось выше, движок воспринимает каждую операцию-условие в конструкции “Если-Тогда” как “ЕСЛИ”, а последующий код — как “ТОГДА”, логическое И может быть реализовано просто путем выписывания нужных условий одно за другим. Например, если нужно определить, является ли агент живой вражеской лошадью, то есть если агент жив И является лошадью И является врагом, то код будет выглядеть просто следующим образом:
(agent_is_alive,),
(neg|agent_is_human,),
(neg|agent_is_ally,),
Чтобы проверить выполнение одного ИЛИ другого условия, используется такая конструкция:
(this_or_next|),
По тем же самым причинам эти условия так же должны располагаться одно за другим. Например, так будет выглядеть проверка, равно ли значение переменной 1 ИЛИ 5:
(this_or_next|eq, “:test_variable”, 1),
(eq, “:test_variable”, 5),
Конструкция Если-Тогда-Иначе
Поскольку по умолчанию операции-условия относятся ко всему коду, следующему за ними, возникает необходимость разделять код на фрагменты, чтобы каждое условие относилось только к коду своей секции и не затрагивало остальное.
Это можно сделать, используя “try блок”: код, который должен быть изолирован в отдельную секцию, заключается между операциями (try_begin), и (try_end), Такой способ может быть использован при создании простейшей конструкции “Если-Тогда”: первые строки после (try_begin), должны быть условием “Если”, и за ними должен следовать код, выполняемый, если это условие верно (“Тогда”). После чего должна стоять операция (try_end), означающая конец “try блока” - секции.
И в любой уважающей себя конструкции Если-Тогда должна быть операция Если-Иначе. В МС такой операцией является (else_try), Если внутри try блока какое-либо условие окажется неверно, то выполнение кода прервется на нем и продолжится с ближайшей операции (else_try),
Пример:
#Какой-то предыдущий код (try_begin), (eq, 1, 1), #Верно, переходим к следующей строке (gt, 2, 5), #Неверно, переходим к ближайшему следующему else_try #consequence operations here (else_try), (eq, 0, 1), #Неверно, переходим к ближайшему следующему else_try #consequence operations here (else_try), (eq, ":favorite_lance", ":jousting"), # Возможно? (assign, ":prisoners", 100), (try_end), #Последующий код, не имеющий отношения к этому try блоку
Циклы
В МС существует множество вариантов цикла For-Next. Простейший из них выглядит следующим образом: начинается с операции (try_for_range, ":iterator", , ), (описание см. выше), затем идет тело цикла, состоящее из собственно тех операций, которые должны повторяться, и в конце стоит (try_end), означающий конец цикла.
Во время каждой итерации цикла изменяется значение переменной ":iterator". Значения этой переменной начинаются со значения, указанного в качестве нижней границы (lower_bound) и, пошагово изменяясь после каждой пройденной итерации, приближаются к значению, соответствующего значению верхней границы (upper bound), уменьшенного на 1. Эта переменная ":iterator" может быть использована в теле цикла try_for_range, но не может быть изменена, потому что это нарушит работу цикла — некоторые итерации могут быть пропущены. Если переменная ":iterator" не используется в теле цикла, то вместо нее в операции цикла НЕОБХОДИМО использовать переменную ":unused".
Пример:
(try_for_range, ":i", 0, 10), (store_add, ":count", ":i", 1), (assign, reg0, ":count"), (display_message, "@{reg0}"), (try_end), #Этот код будет выводить на экран сообщения, считающие от 1 до 10
Также существует цикл (try_for_range_backwards, ":iterator", , ), в котором стартовое значение итератора будет равно значению верхней границы — 1, а конечное — нижней границе. Не обращайте внимания на комментарии в header_operations, гласящие, что нужно поменять местами нижнюю и верхнюю границы. Это не так. Этот цикл очень удобен, например, для удаления элементов из списка (членов отряда, например), чтобы не возникало проблем с индексацией.
Заметьте, что ни верхняя, ни нижняя граница не обязаны быть просто числом: это с тем же успехом могут быть переменные с численным значением, присвоенным им в коде ранее. Примеры см. в следующем разделе.
Существуют еще два специальных варианта цикла try_for_*: (try_for_agents, ), и (try_for_parties, ). Эти циклы предназначены для перебора всех агентов на сцене или партий в игре соответственно. Итератор в процессе прохода по циклу последовательно принимает значения каждого агента или партии, и для использования в теле цикла должен быть сохранен как локальная переменная.
Пример:
(get_player_agent_no, ":player"), (agent_get_team, ":playerteam", ":player"), (try_for_agents, ":agent"), #Цикл перебора всех агентов на сцене (agent_is_alive, ":agent"), #Проверка, жив ли данный агент (agent_is_human, ":agent"), #Если жив, проверка, является ли человеком (не лошадью) (agent_is_non_player, ":agent"), #Если жив и человек, проверка, не является ли игроком (agent_get_team, ":team", ":agent"), # Если жив, человек и не игрок, узнаем его команду (eq, ":team", ":playerteam"), #Проверка, в одной ли команде этот агент с игроком #Последующие операции, производимые с этим агентом, если он в одной команде с игроком (try_end), #Переход к следующему агенту или если больше агентов нет — выход из цикла
Выходы из цикла
Вы, скорее всего, неоднократно столкнетесь с необходимостью перебирать в цикле всех агентов, чтобы найти одного конкретного агента, или же перебирать массивы любых других объектов, чтобы найти какой-то один конкретный. И после того, как искомый найден — нет больше необходимости проходить циклом по оставшимся — вы ведь уже нашли то, что искали. Нужно выходить из цикла. В МС нет никаких специальных операций для того, чтобы прекратить выполнение цикла, но существует несколько простых и эффективных способов сделать это вручную. Какой из них выбрать в данном случае, зависит от типа использующегося цикла try_for_*.
Способ 1: Изменение условия конца цикла.
- Для цикла try_for_range
Вы легко можете прервать цикл try_for_range, изменив в процессе выполнения верхнюю границу так, что она совпадет с нижней. Таким образом, когда цикл попытается выполнить следующую итерацию, он обнаружит, что итератор уже достиг верхней границы (итератор будет больше или равен верхней границе) и сразу же прекратит выполнение. Чтобы иметь возможность воспользоваться этим способом, нужно, чтобы верхняя граница была переменной, объявленной вне цикла, и необходимо убедиться, что при изменении этой переменной не произойдет потери данных, хранящихся в ней — создайте резервную копию этой переменной, чтобы не потерять ее исходное значение. Когда код был выполнен достаточное количество раз, когда нужный объект был найден и т. д., присвойте переменной верхней границы значение, равное значению нижней границы.
Пример:
#Проходим циклом (try_for_agents), по всем агентам (assign, ":end", "itm_glaive"), #Установка верхней границы (try_for_range, ":item", "itm_jousting_lance",":end"), #Перебираем все копья в игре (agent_has_item_equipped, ":agent", ":item"), #Проверяем, есть ли у данного агента данное копье в инвертаре (agent_set_wielded_item, ":agent", ":item"), #Если есть — агент берет его в руки (assign, ":end", "itm_jousting_lance"), #Выход из цикла — приравниваем верхнюю границу к нижней — перестаем перебирать копья, мы ведь уже нашли, какое есть у агента (try_end), #Продолжаем работать с агентами в цикле (try_for_agents),
- Для цикла try_for_range_backwards
Тот же самый способ используется и для цикла try_for_range_backwards. Но здесь условием конца цикла является нижняя граница, поэтому для выхода нужно изменять не верхнюю, а нижнюю границу — она должна быть приравнена к значению верхней границы.
Пример:
#Код, в котором присваивается какое-то значение переменной ":troop" (assign, ":array_begin", 0), # Установка нижней границы (try_for_range_backwards, ":i", ":array_begin", 10), #Цикл от 0 до 10 (party_slot_eq, "p_main_party_backup", ":i", 0), #Проверка, равняется ли i-тый слот данной партии 0 (party_set_slot, "p_main_party_backup", ":i", ":troop"), #Если да, то присваиваем этому слоту значение переменной ":troop" (assign, ":array_begin", 10), # Выход из цикла — приравниваем нижнюю границу к верхней — перестаем перебирать слоты, ведь нужный слот, равный 0, уже найден (try_end),
Способ 2: С помощью проверки условия
- Для циклов try_for_agents и try_for_parents
В циклах try_for_agents и try_for_parents нет возможности менять верхние и нижние границы. Вместо этого для выхода из цикла используется проверка какого-либо условия (как правило, проверка на равенство двух значений), которая располагается в начале тела цикла, чтобы проверять данное условие перед каждой итерацию. Пока условие выполняется, цикл продолжает работать. Когда условие становится неверным, цикл продолжает работать, однако в его теле не происходит уже никаких действий, поскольку условие, стоящее перед всем основным телом, неверно и выполнение кода тела цикла прерывается в самом начале. Таким образом, цикл очень скоро закончит свою работу. Чтобы воспользоваться этим способом, инициализируйте новую переменную перед циклом. Затем, в самом начале цикла поставьте проверку условия, связанного с этой переменной. После того, как нужный код в теле цикла выполнился, значение этой переменной должно измениться так, чтобы условие, стоящее в начале, стало неверным и произошел выход из цикла.
Пример:
#Код, в котором присваивается какое-то значение позиции pos1 (assign, ":break_loop", 0), #Инициализация переменной для выхода из цикла (try_for_agents, ":agent"), #Перебор всех агентов (eq, ":break_loop", 0), #Проверка условия: равна ли переменная 0? (agent_is_alive, ":agent"), #Если условие верно, продолжаем; жив ли данный агент? (agent_is_non_player, ":agent"), #Если жив, проверка, не игрок ли он? (agent_is_human, ":agent"), #Если жив и не игрок, проверка, человек ли он? (agent_get_position, pos0, ":agent"), #Если жив, человек и не игрок, сохраняем его местоположение в pos0 (get_distance_between_positions_in_meters, ":distance_to_target_pos", pos0, pos1), #Сохраняем расстояние между pos0 и pos1 в локальную переменную (lt, ":distance_to_target_pos", 10), #Проверка, находится ли агент менее, чем в 10 метрах от pos1 (assign, ":agent_at_target", ":agent"), #Если да, то сохранить ID этого агента в локальную переменную ":agent_at_target" (assign, ":break_loop", 1), #Выход из цикла — изменяем значение переменной, чтобы при следующем прохождении цикла условие не было выполнено (try_end), #Выход из цикла произойдет, как только будет найден первый живой агент-человек, не являющийся игроком и находящийся менее, чем в 10 метрах от целевой позиции pos1 #Дальнейший код, работающий с найденным агентом
Триггеры
Триггеры из module_mission_templates.py (да и из module_triggers.py, если уж на то пошло) всегда записываются в следующем виде:
Первая часть: частота проверки условия выполнения триггера, "интервал вызова", либо в секундах, либо по определенному событию, ка например "ti_on_agent_hit"
Вторая часть: задержка в секундах между проверкой условий из блока условий и выполнением тела триггера. Не работает, если в качестве частоты проверки условия указано событие, как например "ti_on_agent_hit".
Третья часть: задержка «перезарядки» в секундах, то есть время между моментом завершения выполнения триггера и моментом, когда он снова сможет быть активирован. Специальная задержка перезарядки "ti_once" предназначена для одноразовых триггеров, которые могут выполниться лишь однажды, и после одного выполнения не могут больше выполняться вообще.
Четвертая часть: Блок условий, которые всегда проверяются при вызове триггера
Пятая часть: Тело триггера, основной код, который выполняется только в том случае, если выполнены все условия из блока условий и после задержки, указанной во вторй части триггера.
Важно: В отличие от всех остальных чисел в МС, интервалы задержек в триггерах НЕ обязаны быть целыми числами.
На практике это выглядит как-то так:
(10, 2, 60, [ (eq, 1, 1), ], [ (val_add, "$global_variable", 10), ]),
В этом примере интервал вызова составляет 10 секунд, поэтому триггер будет вызываться через каждые 10 секунд. Задержка между проверкой блока условий и выполнением тела равна 2 секундам, поэтому если все условия из блока условий выполнены, то спустя 2 секунды начнется выполнение тела триггера. Интервал перезарядки составляет 60 секунд, значит после каждого выполнения триггера пройдет минута, прежде чем он снова сможет быть активирован.
Здесь блок условий — простая проверка 1==1, которая всегда будет выполняться, поэтому тело триггера будет всегда срабатывать через 2 секунды после проверки условий выполнения триггера. В теле производится простейшее действие: к глобальной переменной прибавляется число 10.
Временные триггеры
Чтобы понять, что интервалы проверки/задержки/перезарядки во временных триггерах могут быть весьма непростыми штуками, рассмотрим следующий пример:
(2, 1, 3, [<условие, которое иногда выполняется, иногда нет>], [ #некоторый код ]),
Этот триггер, как и любой триггер с интервалом проверки > 0, начнет проверяться с 1 секунды миссии:
Секунда Событие 1 Триггер вызван; условие неверно — ожидание следующего вызова ( 2 секунды) 3 Триггер вызван; условие неверно — ожидание следующего вызова ( 2 секунды) 5 Триггер вызван; условие верно — включение задержки ( 1 секунда) 6 Тело выполнено - ожидание следующего вызова ( 2); включение перезарядки ( 3) 11 Триггер вызван; условие неверно — ожидание следующего вызова ( 2 секунды) 13 Триггер вызван; условие верно — включение задержки ( 1 секунда) 14 Тело выполнено - ожидание следующего вызова ( 2); включение перезарядки ( 3) 19 Триггер вызван....
Итак, хотя интервал вызова равен 2 секундам, можно увидеть, что на самом деле вызов триггера не происходит каждые две секунды; вместо этого он происходит в 1, 3, 5, 11, 13, 19 секунды и т. д.
Если триггер должен вызываться точно «по расписанию», нельзя использовать ни задержку, ни перезарядку.
Два триггера с одинаковыми типами или интервалами
Если два триггера имеют одинаковые интервалы вызова (будь то в секундах или по условию ti_*), то порядок, в котором они будут выполнены, определяется текущим шаблоном миссии. Триггер, прописанный в шаблоне первым, первым и сработает, за ним уже выполнится второй с тем же интервалом и т. д. Это означает, что если у вас есть два триггера, срабатывающих по условию ti_on_agent_spawn, первым выполнится тот, который прописан в файле перед другим.
Триггеры в начале миссии
Логично предположить, что триггер ti_before_mission_start срабатывает перед тем, как сформирована сцена и появились агенты. Затем выполняются триггеры ti_on_agent_spawn – перед всеми остальными триггерами. Потом срабатывают триггеры ti_after_mission_start и все триггеры, интервал вызова у которых равен 0, поскольку на этом этапе запускается таймер миссии. Триггеры, срабатывающие по событию, не будут вызваны, пока это ti_* событие не произойдет. Остальные временные триггеры начинают вызываться где-то на первой секунде миссии, после выполнения всех триггеров ti_after_mission_start и с интервалами вызова 0.
Если у вас есть триггеры, которые не обязательно должны срабатывать сразу при запуске миссии, добавление в блок условий чего-нибудь в этом роде сильно поможет снизить нагрузку на процессор при запуске миссии:
(store_mission_timer_a, reg0),(gt, reg0, <время, прошедшее со старта миссии в секундах>),
Ни ti_before_mission_start, ни ti_after_mission_start не требуют использования "ti_once" в качестве перезарядки, поскольку они все равно и так будут выполнены только один раз.
Подводя итог, запуск миссии происходит в следующем порядке:
- Триггеры ti_before_mission_start
- Триггеры ti_on_agent_spawn
- Запуск таймера миссии
- Триггеры ti_after_mission_start и триггеры с интервалом вызова равным 0
- Временные триггеры (с 1 секунды миссии)
- Триггеры по событию
Диалоги
Первая часть любого диалога, с которой он начинается, выглядит примерно так:
"[ ...какой-то код... ]"
Это код, отвечающий за проверку условий при вызове диалога. Единственное и главное его назначение – проверять, выполнено ли данное условие или набор условий и возвращать результат. Каждый диалог при вызове проверяет это условие до тех, пока оно не будет выполнено.
Далее идут последующие части диалога, которые выполняются, только в том случае, если проверка условий пройдена успешно и активна именно их ветвь диалога. Поэтому, если вы хотите, чтобы какое-то одно действие выполнялось всегда, когда, игрок, например, встречает Главнокомандующего во вторник, но совершенно другое – когда они встречаются в среду, диалог может выглядеть как-то так:
#Начало диалога [ #См. header_dialogs, чтобы узнать, какие команды могут быть использованы здесь помимо "anyone". Но любой диалог обязательно должен иметь строку "start", anyone, "start", #Начало стартового блока проверки условий [ (eq, "$g_talk_troop", "trp_generalissimo_evilguy"),#Собеседник игрока – главнокомандущий? (try_begin), (eq, "$g_day_of_week", 2),#Сейчас вторник? (assign, "$g_conversation_temp",1), (str_store_string, s17, "@Так начинается разговор по вторникам"), (else_try), (eq, "$g_day_of_week", 3),# Сейчас среда? (assign, "$g_conversation_temp",2), (str_store_string, s17, "@ Так начинается разговор по средам "), (else_try), ,# Если сейчас не вторник и не среда (assign, "$g_conversation_temp",3) (str_store_string, s17, "@ Так начинается разговор во все остальные дни "), (try_end), ], #Допустим, проверка пройдена и собеседник игрока – главнокомандующий. Теперь надо вывести нужный текст "s17", #Теперь нужно добавить ответные реплики игрока, пускай даже какие-нибудь простейшие типа «Уйти» для выхода из диалога "player_response_or_responses_here", #Специальный код, если нужен: [], #Конец диалога ],
Но вообще создавать строки диалога, зависящие от классов, в одном блоке условий, как это было сделано выше — довольно плохой тон. Так делать не стоит, поскольку больше вероятность сделать какую-нибудь логическую ошибку. Лучше заключать создание каждой строки в отдельный блок условий, вот так:
[anyone,"start", [(eq, "$g_talk_troop", "trp_player_castellan"),], "Что вам угодно, {playername}?", "castellan_talk",[]],
С помощью такого подхода можно сделать несколько вариантов начала разговора, используя несколько блоков условий:
[code][anyone,"start", [ (eq, "$g_talk_troop", "trp_player_castellan"), (eq, "$g_some_game_global", 1), ], "Что вам угодно,{playername}?", "castellan_talk",[]], [anyone,"start", [ (eq, "$g_talk_troop", "trp_player_castellan"), (eq, "$g_some_game_global", 2), ], "А, это снова ты, {playername}! Подлый мерзавец,
Строки состояния
Строка состояния — это условное выражение, использующееся в строке для подстановки одной из двух данных строк в зависимости от значения определенного регистра. Если значение регистра не равно 0, подставляется первый вариант; в противном случае — если значение регистра равно 0 — подставляется второй вариант. Вари
Операции для работы с позициями.
Позиция (pos) - вид регистра позволяющий хранить x, y, z, координаты. используется для определения координат в сценах, в презентациях для определения расположения и размера контейнеров( блоков текста изображения из которых состоит) и для глобальной карты.
для сцен, для объектов сцены( агенты, сцен_пропсы) -
y ось, - вперед (положительное число)/назад(отрицательное число) по ходу движения агента
x ось - вправо(положительное число/влево(отрицательное число) по ходу движения агента
z ось - вверх (положительное число)/ низ (отрицательное число) относительно положения земли в сцене.
Для презентаций -
х ось - справо налево.
у ось - снизу вверх.
нулевая отметка нижний левый угол. ( не уверен)
для глобальной карты
х.у.оси (горизонтальное положение) - установлены самой 3д моделью карты.
х - восток/запад
у - север/юг
z ось - вертикальная ось относительно уровня земли
Операции для работы с агентом
Агент (agent ) - Субъект сцены. к агентам относятся - мертвые, живые, раненые юниты, игрок , а также итем
лошадь, котарая может являться отдельным агентом сцены.
Модификаторы предметов
id | Name | Cost mult | Abd mult | Dmg(w,a) | Req(w,d,s) | Spd(w,s) | Arm(h,s,d) | Hp(h,s) | Spd(h) | Mnv(h) | Chrg(h) | Req(h) | Amnt(f,a) | effect |
0 | Plain | 1,00 | 1,00 | |||||||||||
1 | Cracked | 0,50 | 1,00 | -5 | -4 | -56 | - | |||||||
2 | Rusty | 0,55 | 1,00 | -3 | -3 | - | ||||||||
3 | Bent | 0,65 | 1,00 | -3 | -3 | - | ||||||||
4 | Chipped | 0,72 | 1,00 | -1 | - | |||||||||
5 | Battered | 0,75 | 1,00 | -2 | -26 | - | ||||||||
6 | Poor | 0,80 | 1,00 | |||||||||||
7 | Crude | 0,83 | 1,00 | -2 | -1 | - | ||||||||
8 | Old | 0,86 | 1,00 | |||||||||||
9 | Cheap | 0,90 | 1,00 | |||||||||||
10 | Fine | 1,90 | 0,60 | 1 | + | |||||||||
11 | Well_Made | 2,50 | 0,50 | |||||||||||
12 | Sharp | 1,60 | 0,60 | |||||||||||
13 | Balanced | 3,50 | 0,50 | 3 | 3 | + | ||||||||
14 | Tempered | 6,70 | 0,40 | 4 | + | |||||||||
15 | Deadly | 8,50 | 0,30 | |||||||||||
16 | Exquisite | 14,50 | 0,30 | |||||||||||
17 | Masterwork | 17,50 | 0,30 | 5 | 4 | 1 | + | |||||||
18 | Heavy | 1,90 | 0,70 | 2 | 1 | -2 | 3 | 10 | 4 | +- | ||||
19 | Strong | 4,90 | 0,40 | 3 | 2 | -3 | +- | |||||||
20 | Powerful | 3,20 | 0,40 | |||||||||||
21 | Tattered | 0,50 | 1,00 | -3 | - | |||||||||
22 | Ragged | 0,70 | 1,00 | -2 | - | |||||||||
23 | Rough | 0,60 | 1,00 | |||||||||||
24 | Sturdy | 1,70 | 0,50 | 1 | + | |||||||||
25 | Thick | 2,60 | 0,35 | 2 | 47 | + | ||||||||
26 | Hardened | 3,90 | 0,30 | 3 | + | |||||||||
27 | Reinforced | 6,50 | 0,25 | 4 | 83 | + | ||||||||
28 | Superb | 2,50 | 0,25 | |||||||||||
29 | Lordly | 11,50 | 0,25 | 6 | 155 | + | ||||||||
30 | Lame | 0,40 | 1,00 | -10 | -5 | - | ||||||||
31 | Swaybacked | 0,60 | 1,00 | -4 | -2 | - | ||||||||
32 | Stubborn | 0,90 | 1,00 | 5 | 1 | +- | ||||||||
33 | Timid | 1,80 | 1,00 | -1 | + | |||||||||
34 | Meek | 1,80 | 1,00 | |||||||||||
35 | Spirited | 6,50 | 0,60 | 2 | 1 | 1 | + | |||||||
36 | Champion | 14,50 | 0,20 | 4 | 2 | 2 | 2 | + | ||||||
37 | Fresh | 1,00 | 1,00 | |||||||||||
38 | Day-old | 1,00 | 1,00 | |||||||||||
39 | Two_Days-old | 0,90 | 1,00 | |||||||||||
40 | Smelling | 0,40 | 1,00 | |||||||||||
41 | Rotten | 0,05 | 1,00 | |||||||||||
42 | Large_Bag_of | 1,90 | 0,30 | 13,00% | + |
Рашифровка
Cost mult — мультипликатор цены
Abd mult — мультипликатор частоты
Dmg(w,a) — Повреждение (оружие, амуниция)
Req(w,d,s) — Требование (оружие, доспехи, щиты)
Spd(w,s) — скорость (оружие, щиты)
Arm(h,s,d) — защита/сопротивление (лошади, щиты, доспехи)
Hp(h,s) — хиты (лошади, щиты)
Spd(h), Mnv(h), Chrg(h), Req(h) — скорость, манёвренность, атака, требования для лошадей
Amnt(f,a) — количество (еда, амуниция)
effect — моя оценка пользы от модификатора.
Примечания
1. Требования разные к разным типам предметов (лошади — навык езды, оружие, доспехи, арбалеты — сила, щиты — владение щитом, луки — сильный выстрел, метательное — бросок).
2. Модификатор меняет требования, только если они есть.
3. У амуниции можно выставить требование, но в этому случае её невозможно будет использовать.
4. Мультипликаторы стоимости и частоты можно править в файле Data/item_modifiers.txt (рекомендуется предварительно скопировать его из общей папки в папку с модулем)
5. Эффект от Large_Bag_of округляется вверх.
6. Влияние на мораль еды и её модификаторов прописаны в модульной системе через скрипты.
7. Требования и эффект от книг тоже заскриптован.
8. Частота определяет вероятность появления предмета при использовании troop_loot_troop,
troop_add_merchandise и troop_add_merchandise_with_faction.
9. Модификатор Lame живёт своей хардкодной жизнью. Лошадь игрока имеет шанс заполучить его, если ёё приложать в бою под игроком. В рюкзаке больные лошади со временем вылечиваются (необходим навык лечение ран (wound treatment), по крайне мере, для обозримого времени лечения). Лошадь с модификатором lame в бою может умереть совсем. Вылечиваясь лошадь получает модификатор plain в том числе, если до этого была Swaybacked. Когда-то похожая жизнь была у щитов с модификатором cracked, но фича попала под нож.
10. Для удобства мою таблицу можно скопировать в Excel или Openoffice. Разделители табы.
header_triggers.py
могу только догадыватся -
ti_question_answered
ti_server_player_joined
ti_on_multiplayer_mission_end
ti_on_player_exit
Trigger Param 1: player_id
ti_on_item_picked_up = -53.0 #can only be used in module_mission_templates triggers
# Trigger Param 1: agent id
# Trigger Param 2: item id
# Trigger Param 3: scene prop id (will be deleted after this trigger)
ti_on_item_dropped = -54.0 #can only be used in module_mission_templates triggers
# Trigger Param 1: agent id
# Trigger Param 2: item id
# Trigger Param 3: scene prop id
ti_on_order_issued = -71.0 #can only be used in module_mission_templates triggers
# Trigger Param 1: order no
# Trigger Param 2: agent id