Мультисорсы и глобальные переменные

DS XXI

Local Pro
После некоторых размышлений и экспериментов я решил написать эту статейку про использование объектов multisource и про глобальные переменные, так как обычно в руководствах эта тема обходится стороной или рассматривается очень узко.

Статус

Итак, начнём с фундаментального понятия, без которого труднее будет понять работу Мультисорса. Ко многим энтитям, таким как кнопки, двери, лампочки или лучи, уместно будет отнести такую характеристику, как статус. Эти энтити всегда находятся в одном из двух статусов — ON — включена или OFF — выключена. Для них статус энтити очевиден в зависимости от выполняемой функции — например, если лампочка горит, значит она ON; если нет, то OFF. Кнопка в нажатом состоянии включена (имеет статус ON), в отжатом — выключена (OFF). Двери включены, когда открыты, и выключены, когда закрыты, и т.д.

Есть и такие энтити, как, например, scripted_sequence или trigger_relay, для которых статус не имеет никакого смысла. Как правило, они всегда выключены.

Когда какая-то энтитя вызывает другую, то она старается сменить её статус. Например, если мы кнопкой вызываем выключенную лампочку, то она включится, а если включенную, то наоборот, выключится. Но в Халфе есть один триггер, позволяющий непосредственно указать желаемый статус, посылаемый объекту при его вызове.

Этим триггером является trigger_relay. В его параметрах, помимо основных "Name" и "Target" есть ещё один

  • "Trigger state", принимающий одно из трёх значений — ON, OFF или TOGGLE — переключить. Он определяет, какой статус задаст trigger_relay вызванному объекту — включит, выключит или же подействует, как обычный триггер — переключит статус объекта на противоположный.
Например, если trigger_relay задаст статус ON уже включённой лампочке, то с ней ничего не произойдёт.

Вообще, то, как разные энтити реагируют на задание им различных статусов, целиком зависит лишь от самой энтити. Вот лампочки и лучи, скажем, обрабатывают это вполне адекватно. Но вот, например, если открытой двери задать статус ВКЛ., то она всё равно закроется, так как она любой вызов воспринимает как переключение (TOGGLE). Это является лишь недоработкой самой двери, которая, кстати говоря, исправлена в Spirit of Half-Life.



Объект Multisource​



Теперь можно переходить непосредственно к multisource. Он имеет три параметра:

  • Name,
  • Target и
  • Global state master.
Ключевую роль в использовании объекта multisource играет как раз-таки его статус. Энтитя, имя которой указано в поле "target" Мультисорса, будет вызваться каждый раз, когда его статус меняется с Выключен на Включён. Существует два способа влиять на статус Мультисорса — прямо вызывая его имя, или через его параметр "Global state master". Второй разберём несколько позже, а пока что рассмотрим вызов по имени.



Объединение условий​

Выражаясь проще, можно назвать Мультисорс "объеденителем условий", когда каждый из нацеленных на него объектов пошлёт ему вызов, Мультисорс сменит статус с OFF на ON и запустит заданную цель.

Простое описание, которое можно найти в различных руководствах, звучит так: например, у нас есть несколько кнопок, которые после нажатия через несколько секунд отжимаются обратно, и у всех стоит в параметре "target" имя Мультисорса. Мультисорс, в свою очередь, нацелен на некий триггер, например, на ambient_generic, проигрывающий какой-нибудь звук. Чтобы он сработал, надо быстро успеть нажать все кнопки, пока они не отжались обратно, и тогда звук проиграется.

Если вам это показалось слегка странным после предыдущего абзаца, то ничего страшного — мы к этому вернёмся.



Итак, как же функционирует Мультисорс? Первым делом, он создаёт себе список всех энтить, нацеленных на него. Каждой энтите в этом списке он проставляет в соответствие некий мнимый статус, который может принимать такие же значения, как и обычный статус — ON или OFF. Изначально все мнимые статусы выключены.

Мнимый статус энтити переключается, когда она вызывает multisource. Для Мультисорса безразлично, какой статус ему посылается. Например, дверь, достигая своих граничных участков, каждый раз информирует об этом Мультисорс, и тот делает отметку о её статусе (правда тут может произойти глюк, когда дверь окажется чем-то заблокирована, не сможет закрыться, и отъедет назад, а в этом случае она всё равно вызовет Мультисорс, и тот это воспримет, как сигнал о закрытии).

Когда все мнимые статусы примут значение ВКЛ., то сам multisource включится, и вызовет свою цель из поля target. Когда хотя бы один из них выключится, то выключится и Мультисорс.



Примечание: в Spirit of Half-Life у Мультисорса также есть поле "Target on turning off", которое действует похожим образом с target, но срабатывает когда Мультисорс выключается.

Но остается один непонятный момент — почему мнимый статус func_button меняется, когда она отжимается? Ведь обычно автоматически отжимающаяся кнопка вызывает цель только при нажатии, а не отжатии. А дело вот в чём. У кнопок в отношении Мультисорса есть своя специфика — при отжатии они проверяют, является ли их цель Мультисорсом, и в утвердительном случае посылают ему эту специальную активацию. Такое поведение характерно только для func_button.

(проверить это можно довольно просто — между каждой кнопкой и Мультисорсом вставьте по trigger_relay, чтобы вызовы проходили через них, и проверьте поведение Мультисорса — оно изменится)



Также стоит отметить, что такая специфика саботирует мнимый статус toggle-кнопки (переключаемой) — обычно она посылает активирующие вызовы при нажатии и отжатии, а для Мультисорса получается два при отжатии, что по сути оставляет мнимый статус неизменным. Способом избежать этого как раз и будет вставка trigger_relay на пути данных от кнопки до Мультисорса.

Блокирование​

Таким образом мы разобрали один способ управления статусом объекта multisource, и один способ его использования. Но, само собой, статус преназначен не только для того, чтобы меняться с ВЫКЛ. на ВКЛ. и вызывать этим разнообразные штуки. Второе, можно даже сказать, даже более важное применение Мультисорса заключается в том, чтобы использовать его для блокирования энтить, действие которых можно отключить. Такие энтити имеют параметр Master, в который для блокирования нужно подставить имя некого Мультисорса, и после этого энтитя будет работать только в том случае, если этот Мультисорс находится во включенном состоянии, иначе эта энтитя перестанет реагировать на что-либо вообще. Это практичный способ отключать на некоторое время trigger_once, trigger_multiplie, телепорты и им подобные объекты.

Примечание: в этом случае "master" переводится с английского как "хозяин" (а не в значении умелец), и любой объект с соответствующим именем в параметре Master становится к нему "подчинённым".

Например, как заблокировать телепорт? Ставим телепорт, кнопку, реле и Мультисорс и связываем это таким образом: кнопка вызывает реле, которое в свою очередь вызывает Мультисорс, а у телепорта в Master'е стоит имя этого самого Мультисорса. При том, что интересно, из всех параметров мультисорса в данном примере используется только имя. Блокировать таким образом можно всё, у чего есть поле Master.

Примечание №2: в заблокированном состоянии двери при попытке открыть их будут издавать звук, указаный в свойстве "Locked Sound".

Примечание №3: в Spirit of Half-Life блокирующим "мастером" может быть любая энтитя, не только мультисорс.




Теперь осталось узнать, для чего нужно поле Global state Master. Оно выполняет схожую функцию с Master'ом, о котором мы только что говорили. Но для начала придется разобрать понятие "Глобальная переменная".



Глобальные переменные​

Глобальной переменной называется переменная, принимающая одно из двух значений — ВКЛ. или ВЫКЛ. Значение глобальной переменной передается между уровнями, что позволяет создавать в игре ситуации, когда игроку надо что-то включить или сделать на одной карте, чтобы это повлияло на ситуацию на другой (например, заработали кнопки). Каждая глобальная переменная имеет собственное имя, по которой вы будете к ней обращаться. Для установки статуса глобальной переменной используется энтитя env_global. В принципе, особых хитростей здесь нет, и можно ограничиться простым описанием назначений параметров env_global:

  • Name — Просто имя, используемое для её вызова. Когда env_global вызывается, она изменит значение определенной глобальной переменной.
  • Global state to set — Имя глобальной переменной, значение которой надо изменить. Это имя впоследствии будет использовано другими энтитями для считывания значения переменной.
  • Trigger mode — собственно, само устанавливаемое значение переменной. Как и в trigger_relay, нам предлагается включить, выключить или переключить — ON, OFF или TOGGLE.
  • Initial State — если флаг Set initial state установлен, то значение этого поля определит первоначальный статус глобальной переменной.
Флаг один:

  • 1 = Set initial state — из предыдущего абзаца


Ну вот мы знаем, как установить значение этой переменной. Теперь осталось узнать, как её считать. Считывать глобальные переменные могут только две энтити — это trigger_auto, и multisource. У trigger_auto для этого служит параметр Global State to Read, а у multisource — Global State Master. Для этих двух энтить значение глобальной переменной является чем-то, вроде Master'а для триггеров. Пока глобальная переменная имеет статус выключено — OFF, мультисорс также будет выключен. Вот, кстати, и ещё один способ контролировать статус мультисорса — если на карте нет энтить, нацеленных на мультисорс, то его статус будет зависеть только лишь от статуса глобальной переменной. Получается, что для включения и выключения мультисорса можно использовать два env_global'а — один для включения глобальной переменной, а другой, соответственно, для выключения (или даже один в режиме toggle). Так обычно и делается при создании всяких лифтов, где надо блокировать на время кнопки.

А trigger_auto, как мы знаем, служит для запуска определенных событий сразу после загрузки уровня, и с помощью механизма глобальных переменных можно указать, когда ему надо это делать, а когда — нет.



При отладке полезно бывает узнать значение некой глобальной переменной. Для этого есть команда impulse 104 — она выводит статусы всех глобальных переменных (и работает только если вы запускали Half-Life с параметром -dev).



Вот, пожалуй, и всё, что я могу рассказать про эти вещи. Надеюсь, эта статья не оставила в вас никаких сомнений по поводу работы мультисорсов!