[[help:objs|Назад: Предметы]]
====== Порядок работы интерпретатора ======
**Несмотря на то, что эта статья обросла некоторыми подробностями, она всё ещё требует серьёзной редактуры, упрощения и расширения. Так что пока что это всё ещё черновой вариант.**
Эта статья подробно рассказывает о порядке работы интерпретатора (плеера) **QSP**. Она может показаться вам довольно сложной, но читать её всю не обязательно. Вернитесь к ней, когда у вас возникнут сложности в понимании того, как ведёт себя плеер. А пока достаточно ознакомиться с общими принципами:
* При запуске игры автоматически воспроизводится только самая первая в игре локация. На остальные локации нужно осуществлять переходы с помощью **''GOTO''** или **''XGOTO''**, или вызывать их с помощью **''GOSUB''**, **''FUNC''**, или иным предусмотренным плеером способом.
* Код действий "прикрепляется" к действию и не выполняется, пока игрок не нажмёт на действие.
* Все команды выполняются последовательно одна за другой, и никогда не выполняются одновременно.
Ниже по тексту будут использоваться следующие определения:
* **Переход на локацию** — это событие в игре, которое происходит при обращении к локации с помощью операторов **''GOTO''** или **''XGOTO''**. При этом локация становится "активной", или "текущей". Функция **''$CURLOC''** возвращает название локации, на которую был совершён переход, а массив **''ARGS[]''** этой локации сохраняет свои значения, пока снова не будет осуществлён переход на локацию (другую, или ту же самую). После добавления текста из поля "Базовое описание" в Окно основного описания, действий из поля "**Базовые действия**" в **Окно действий**, и выполнения кода из поля "**Выполнить при посещении**", плеер "останавливается" и ожидает участия игрока, при этом локация, на которую был осуществлён переход, остаётся "активной" ("текущей"), т.е. функция **''$CURLOC''** в любой момент может вернуть название этой локации, а массив ''ARGS[]'' сохраняет значения.\\ Для переходов существуют только два оператора (подробнее см. статью [[help:goto|"Переходы"]]):
* **''GOTO''** — осуществляет переход на указанную локацию с автоматической очисткой **Окна основного описания** и **Окна действий**.
* **''XGOTO''** — осуществляет переход на указанную локацию с автоматической очисткой **Окна действий**. **Окно основного описания** НЕ очищается.
* **Вызов локации** — это событие в игре, которое происходит при обращении к локации с помощью оператора **''GOSUB''**, функции **''FUNC''**, или в связи с выполнением другого события (например, "**Выделение предмета**", "**Загрузка сохранения**", "**Ввод в поле ввода**", "**Выбор пункта меню**"). В отличие от **перехода на локацию**, при **вызове** локация не становится "активной" ("текущей"), т.е. функция **''$CURLOC''** не возвращает название этой локации, а массив **''ARGS[]''** сохраняет свои значения только пока выполняется код локации. После выполнения кода локации, продолжается выполнение того блока кода, который выполнялся до вызова. Например, если локация была **вызвана** из действия, то после выполнения её кода, продолжится выполнение кода действия, при этом в массив **''ARGS[]''** внутри действия не попадут значения массива **''ARGS[]''** из вызванной локации. При вызове локации в **Окно основного описания** добавляется текст из поля "**Базовое описание**" локации, в **Окно действий** добавляются действия из поля "**Базовые действия**" локации, и выполняется код из поля "**Выполнить при посещении**" локации. Очистка окон при вызове локации НЕ ПРОИСХОДИТ.
act "Действие с вызовом локации":
*pl "Выводим текст до вызова"
gosub 'foo' & ! вызываем локацию foo
*pl "Продолжаем выполнять код после вызова локации foo"
end
Вызвать локацию можно разными способами:
* Оператор **''GOSUB''** вызывает локацию без возвращения результата (подробнее в статье [[help:organizing|"Пользовательские функции и процедуры"]]).
* Оператор **FUNC** вызывает локацию с возвращением результата (подробнее в статье [[help:organizing|"Пользовательские функции и процедуры"]]).
* Нажатием пункта всплывающего меню (см. статью [[help:menu|"Всплывающее меню"]])
* Выполнением какого-либо события в игре, как то: "Выделение предмета", "Выделение действия", "Загрузка сохранения", "Ввод текста в поле ввода" и т.д. (подробнее в статье [[help:service_locations|"Служебные локации"]]).
* **Блок кода** — это выделенный в отдельное целое фрагмент кода игры. Отдельными блоками кода в **QSP** являются:
* Локации сами со себе.
* Код, передаваемый оператору **''DYNAMIC''** или функции **''DYNEVAL''** в виде текста.
* Код, выполняемый при нажатии на гиперссылку.
* Код каждого отдельного Действия (**[[help:acts|ACT]]**).
* Код каждого отдельного Цикла (**[[help:cycle|LOOP]]**)
===== Запуск игры =====
Каждая игра на **QSP** структурно представляет собой набор локаций, последовательно записанных в файл.
Когда мы открываем игру в плеере (интерпретаторе), автоматически запускается чтение самой первой локации в файле (далее **Стартовая локация**), как если бы на неё был совершён переход с помощью оператора **''GOTO''**. То есть:
* В Окно основного описания добавляется текст из поля "**Базовое описание**" локации (поле "**Описание**" в **Quest Generator**).
* В Окно действий добавляются действия из поля "**Базовые действия**" локации (поле "**Базовые действия**" в **Quest Generator**).
* Выполняется код из поля "**Выполнить при посещении**" локации.
* Если на Стартовой локации в переменную **''$ONNEWLOC''** было помещено название локации-обработчика события "**Переход на новую локацию**", произойдёт автоматический вызов этой самой локации-обработчика события "**Переход на новую локацию**" (см. [[help:service_locations|"Служебные локации"]]).
* После того, как Стартовая локация была прочитана, плеер "останавливается" и ожидает действий от игрока. При этом локация остаётся "активной", т.е. функция **''$CURLOC''** в любой момент может вернуть её название, а в массиве **''ARGS[]''** данной локации сохраняются значения, которые на ней были выставлены, и эти значения могут использоваться, например, в действиях, выведенных в **Окно действий**.
Если на Стартовой локации в переменную **''$COUNTER''** было помещено название локации-счётчика, примерно через равные промежутки времени (по умолчанию раз в пол секунды) плеер будет вызывать локацию-счётчик (см. [[help:service_locations|"Служебные локации"]]).
===== Выполнение кода =====
Код в **QSP** всегда выполняется последовательно, команда за командой. Чтение команд происходит сверху вниз и справа налево:
*pl "Первая команда"
*pl "Вторая команда"
*pl "Третья команда"
*pl "Четвёртая команда" & *pl "Пятая команда" & *pl "Шестая команда"
**QSP** не способен выполнить две команды одновременно, или случайно выполнить вторую команду раньше первой. Поэтому в большинстве случаев, если вам кажется, что плеер "забывает" выполнить какую-либо команду, скорее всего эта команда написана в таком месте, где плеер просто не может до неё добраться.
Например, если написано невыполнимое условие, команда никогда не будет выполнена:
if 5>6:
*pl "Данная команда никогда не будет выполнена"
end
Команды, стоящие после **''GOTO''** или **''XGOTO''**, так же никогда не будут выполнены:
*pl "Текст на локации" & ! этот текст будет виден на локации всегда
act "Переход по XGOTO":
*pl "Этот текст виден благодаря тому, что вы перешли с помощью XGOTO"
xgoto $curloc & ! переходим на текущую локацию
*pl "А эта команда никогда не будет выполнена"
end
act "Переход по GOTO":
*pl "Эта команда будет выполнена"
! но при переходе по GOTO Окно основного описания очистится,
! так что эту строчку вы всё равно не увидите.
goto $curloc & ! переходим на текущую локацию
*pl "А эта команда никогда не будет выполнена"
end
Код действий (**''ACT''**) не выполняется сразу, а "прикрепляется" к этим действиям. Он будет выполнен только тогда, когда игрок нажмёт на соответствующее действие.
example=12 & ! присваиваем переменной число 12
! создаём действие
act "Вывести значение переменной example":
*pl example
end
example=37 & ! меняем значение в переменной
То же самое происходит с кодом в гиперссылках. Он не выполняется сразу, когда мы создаём гиперссылку, он выполняется только тогда, когда мы на гиперссылку нажимаем:
usehtml=1 & ! включаем режим распознавание HTML
example=12
! выводим на экран гиперссылку с кодом
*pl "Вывести значение переменной example"
example=37
При выполнении команды, которая содержит строки с вложенными выражениями, сначала раскрываются вложенные выражения, и только затем происходит работа со строкой, например, передача её оператору для вывода на экран:
яблоки = 23
! Сначала в строку подставится значение,
! потом строка выведется на экран:
*pl "Яблок в кармане: <<яблоки>>."
===== Переход на новую локацию =====
Переход на новую локацию может осуществляться с помощью двух операторов **''GOTO''** и **''XGOTO''**. Различие в их работе заключается в следующем:
* При переходе с помощью оператора **''GOTO''** очищаются Окно основного описания и Окно действий.
* При переходе с помощью оператора **''XGOTO''** очищается только Окно действий. Окно основного описания не очищается.
В остальном работа этих операторов схожа:
* В Окно основного описания добавляется текст из поля "Базовое описание" локации (поле "Описание" в **Quest Generator**).
* В Окно действий добавляются действия из поля "Базовые действия" локации (поле "Базовые действия" в **Quest Generator**).
* Выполняется код из поля "Выполнить при посещении" локации.
* Если в переменную **''$ONNEWLOC''** было помещено название локации-обработчика события "Переход на новую локацию", произойдёт автоматический вызов этой самой локации-обработчика события "Переход на новую локацию" (см. [[help:service_locations|"Служебные локации"]]).
* После этого плеер "останавливается" и ожидает действий от игрока. При этом локация остаётся "активной", т.е. функция **''$CURLOC''** в любой момент может вернуть её название, а в массиве **''ARGS[]''** данной локации сохраняются значения, которые на ней были выставлены, и эти значения могут использоваться, например, в действиях, выведенных в **Окно действий**.
Если в переменную **''$COUNTER''** было помещено название локации-счётчика, примерно через равные промежутки времени (по умолчанию раз в пол секунды) плеер будет вызывать локацию-счётчик (см. [[help:service_locations|"Служебные локации"]]).
P.S.: "Переход на новую локацию" — это устоявшееся название события. Технически более правильно называть такие переходы просто "Переход на локацию", поскольку мы можем переходить не только на новые, но и на текущую локацию:
"Счёт: <>"
act "Обновить":
count+=1
goto $curloc & ! перезаходим на текущую локацию
end
Поэтому, столкнувшись с выражением "Переход на новую локацию" помните, что оно может значить в том числе и переход на текущую локацию.
===== Вызов локации =====
Вызов локации может быть выполнен напрямую через оператор [[help:organizing|**GOSUB**]] или функцию [[help:organizing|**FUNC**]] или в привязке к какому-либо [[help:service_locations|событию]].
При вызове:
* В Окно основного описания добавляется текст из поля "Базовое описание" локации (поле "Описание" в **Quest Generator**).
* В Окно действий добавляются действия из поля "Базовые действия" локации (поле "Базовые действия" в **Quest Generator**).
* Выполняется код из поля "Выполнить при посещении" локации.
Дополнительно, при вызове с помощью оператора **''GOSUB''**, или функции **''FUNC''**, а так же с помощью оператора [[help:menu|**MENU**]], осуществляется возврат к тому коду, из которого был осуществлён вызов, и продолжается выполнение этого кода. Например, если локация была вызвана из действия, то произойдёт возврат к выполнению кода действия.
act "Действие с вызовом локации":
*pl "Выводим текст до вызова"
gosub 'foo' & ! вызываем локацию foo
*pl "Продолжаем выполнять код после вызова локации foo"
end
Более подробно работа оператора **''GOSUB''** и функции **''FUNC''** освещена в разделе [[help:organizing|"Пользовтальские функции и процедуры"]].
О работе оператора **''MENU''** более подробно можно почитать в разделе [[help:menu|"Меню"]].
===== Обработка событий =====
События, если смотреть на это понятие с точки зрения работы плеера, — это некое изменение состояния в написанной нами игре. Например, у нас все предметы были не выделены, и вот игрок щёлкает мышью по одному из предметов, и предмет оказывается выделен. То есть предмет изменил своё состояние с "не выделен", на "выделен". Это и есть **событие выделения предмета**.
Конечно, мы могли бы и сами отслеживать некоторые события, например, с помощью локации-счётчика постоянно проверять, какое значение возвращает нам функция **''$SELOBJ''**, и в момент, когда функция изменяет своё значение с одного на другое, мы точно знаем, что произошло выделение нового предмета, или иными словами: событие "Выделение предмета". Однако, для нас это, во-первых, лишний код, а, во-вторых, очень неудобный и неточный инструмент по отслеживанию событий, поскольку локация-счётчик имеет ряд ограничений и на скорость выполнения, и на очерёдность. Мы хотим, чтобы миллисекунда в миллисекунду мы знали, что какое-то событие произошло, и чтобы при этом мы могли выполнить какой-либо код.
Именно для этого в **QSP** введены специальные служебные локации: локации-обработчики событий (и локация-счётчик).
Любая локация, названная как угодно, и написанная каким угодно образом, может быть назначена обработчиком-события или локацией-счётчиком. Для этого название этой локации нужно прописать в специальную системную переменную. Например:
$counter = 'счётчик' & ! назначаем локацию-счётчик
$onobjsel = 'onClick' & ! назначаем локацию-обработчик события "Выделение предмета"
$usercom = 'debugger' & ! назначаем локацию-обработчик события "Нажатие клавиши ввода в Поле ввода"
Как видите, название локации может быть совершенно любым, главное, чтобы она была прописана в нужную системную переменную. И как только это происходит, как только мы прописываем имя локации в нужную переменную, эта локация становится **связана** с указанным событием. Это значит, что как только это событие случится, будет выполнен код на указанной локации.
Подробнее о том, какая системная переменная за **связку** с каким событием отвечает, вы можете прочитать в статье [[help:service_locations|"Служебные локации"]].
Чтобы отвязать локацию от события, достаточно в нужную системную переменную прописать пустое значение:
$counter = '' & ! отключаем локацию-счётчик
$onobjsel = '' & ! отключаем локацию-обработчик события "Выделение предмета"
===== Процессы в настоящем времени =====
Если была назначена локация-счётчик, то с приблизительно равной периодичностью будет происходить вызов указанной локации-счётчика. По умолчанию локация-счётчик вызывается 2 раза в секунду, то есть каждые 500 миллисекунд — это значение можно изменять с помощью оператора **''SETTIMER''**.
settimer 100 & ! устанавливаем период обращения к локации-счётчику в 100 мс
$counter = 'отсчёт_времени' & ! плеер будет вызывать локацию **отсчёт времени** примерно 10 раз в секунду
Так же с заданной периодичностью (по умолчанию 2 раза в секунду) происходит полное обновление интерфейса: шрифт и цвета, заданные с помощью системных переменных.
Подробнее о локации-счётчике и создании игровых событий в реальном времени читайте в статье [[help:realtime|"Реальное время"]].
[[help:variables|Вперёд: Переменные]]