[[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|Вперёд: Переменные]]