Описание движка URQ 1.22 (в моем понимании) --------------------------------------------- Последние изменения внесены Feb 06 2001 ¦ Ограничение на длину строки ¦ Комментарии ¦ Пробелы, регистр, разделители ¦ Переменные ¦ Метки ¦ Локации ¦ Выражения ¦ Присваивание ¦ Операторы print p println pln btn cls end inv+ inv- invkill perkill goto if proc save play pause ¦ Локация :common Язык URQ 1.22 очень простой (проще бейсика), так что если Вы уже владеете каким-либо языком программирования, то освоите его без проблем. Документация, написанная самим RipOs'ом, содержит ряд неточностей и недомолвок, поэтому я решил написать этот документ, чтобы пояснить, каким образом URQ_DOS интерпретирует инструкции URQ. Расхождения с документацией RipOs'а отмечаются так: [* <описание расхождения>] ¦ Ограничение на длину строки ================================= [* в URQ этого ограничения, по видимому, нет] Частями строки кода считаются ключевые слова (операторы), числа (константы) и строки текста (включая пробелы, то есть действительно строки, а не слова). Таких частей в каждой строке должно быть не больше 255. Это ограничение обусловлено чисто техническими соображениями (таким образом существенно память экономится) и, на мой взгляд, оно вполне разумно. Действительно, более длинную строку можно написать, только используя if с огромным числом условий и отладка такого "ифа" может оказаться очень сложной задачей. ¦ Комментарии ================= Любая часть строки после символа ; игнорируется. Многострочные комментарии пока не поддерживаются. ¦ Пробелы, регистр, разделители =================================== При обработке ключевых слов, имен переменных и меток регистр игнорируется. Пробелы являются значащими символами только в именах переменных и при обработке операторов печати. [* В URQ логика обработки пробелов немного другая - любые два пробела в строке заменяются на один. По-моему, это немного ограничивает возможности языка (приходится использовать странные конструкции, чтобы вывести несколько пробелов подряд), поэтому я не стал этого делать.] Поддерживаются разделители строк двух типов: просто конец строки (последовательность CR-LF) и символ &. Разделителем & можно пользоваться не всегда (смотри далее). ¦ Переменные ================ Существуют две разновидности переменных: инвентарь (вещи в рюкзаке) и внутренние переменные (игроку не показываются). И те и другие имеют тип double, диапазон значений от 1.7*(10^-308) до 1.7*(10^+308). Все константы интерпретируются как целые числа типа long, диапазон значений от -2147483648 до 2147483647. Кроме того, существует зарезервированная внутренняя переменная rnd, которая при каждом обращении к ней принимает случайное значение в диапазоне от 0 до 1. Чтобы сравнивает ее значение с целыми константами, нужно умножать ее на 10 или на соответствующее число (например, rnd>0.7 будет выглядеть как rnd*10>7). Никакого описания переменной не требуется. Если происходит обращение к несуществующей переменной, то в случае чтения значения возвращается 0, а в случае записи - переменная создается. Если переменная имеет тип инвентарь (см. оператор inv), то действует дополнительное правило: если значение меньше либо равно 0, то переменная уничтожается (см. оператор invkill). Пока не поддерживается преобразование типов инвентарь <=> внутренняя переменная. В именах переменных недопустимо использование ключевых слов (то есть операторов). Начинаться имя переменной должно обязательно с буквы. Использование пробелов в именах переменных допустимо, но не рекомендуется (заменяйте пробел на символ _. Например, Ржавый_мечь). Размер имени не лимитирован, но не рекомендуется выходить за пределы 32-ух символов. Этим правилам подчиняются так же имена меток. ¦ Метки =========== Описание метки имеет следующий формат: : <метка> (здесь и везде далее если в формате присутствует пробел, то это означает, что пробелы в этой части строки игнорируются). Где <метка> - строка, подчиняющаяся правилам, описанным выше. Не рекомендуется использовать разделитель & для окончания данной инструкции [* URQ вообще это запрещает. Там метка должна располагаться на отдельной строке]. Количество меток в квесте ограничено только объемом доступной свободной основной памяти в момент выполнения квеста. ¦ Локации ============= Локации - это просто участи кода, начинающиеся с метки и заканчивающиеся оператором end. Переходом в новую локацию считается переход только по нажатию кнопки. Переходы с использованием goto и proc считаются внутренними для данной локации. ¦ Выражения =============== Обычное арифметическое выражение, состоящее из внутренних переменных, констант и действий + сложение; - вычитание; * умножение; / деление. Кроме того существует специальный формат проверки значений переменных типа инвентарь: [const] <переменная>. Значение такого выражение 1 (истина), если значение инвентарной переменной больше либо равно const (если const опущена, то сравнивается с 1). 0 (ложь) - в противоположном случае. Другими словами, таким образом можно проверять наличие или отсутствие нужного количества какого-либо предмета в рюкзаке. Поддержку скобок реализовать очень просто, но так как в URQ 1.22 ее пока нет, то в моей проге эта функция пока скрыта (напишите мне, если Вы хотели бы узнать, как ее активизировать). ¦ Присваивание ================== <внутренняя переменная> = <выражение> Думаю, комментарии излишни. Отмечу, что присвоить таким образом значение инвентарной переменной нельзя. ¦ Операторы =============== print <текст> p <текст> println <текст> pln <текст> Эти операторы выводят <текст> на экран [* В окно информации]. При выводе учитываются границы экрана (то есть происходит автоматическое выравнивание по левому краю) и последовательности # <выражение> $. Такие последовательности в <тексте> будут заменены на значения <выражения> (а точнее, на это значение, преобразованное в текстовый формат). Ситуация с пробелами при использовании #$ довольно запутанная и пока что моя программа просто заменяет и # и $ на пробел (то есть значение оказывается окаймленным пробелами с двух сторон). btn <метка> , <имя> В список пунктов меню [* кнопок] (чтобы не путаться, я дальше буду их тоже кнопками называть) добавляется новый, с надписью <имя> и указывающий на метку <метка>. При выборе этого пункта игроком будет осуществлен переход на соответствующую метку. Если эта метка не существует, то добавления не происходит (то есть кнопка не отображается). Длина строки <имя> не должна превышать 80-и символов. Общее количество кнопок не должно превышать 25-и. cls Очистка списка кнопок и информации, выведенной на экран при выполнении текущей локации. end Завершение исполнения текущей локации. Кнопки выводятся на экран и игроку предлагается осуществить очередной переход. Если список кнопок пуст, то игра прекращается. [* в URQ end должен быть расположен на отдельной строке] end используется мною еще и для определения того, что тот файл, который Вы пытаетесь исполнить, вообще является qst-файлом. Файл признается "посторонним", если при делении на отрезки по 64 Kb (начиная с начала файла) в каком-либо из этих отрезков end не встречается ни разу. inv+ [const , ]<предмет (переменная типа инвентарь - здесь и везде далее)> inv- [const , ]<предмет> Эти операторы добавляют или вычитают const экземпляров <предмета> в(из) инвентаря (если const опущена, то она считается равной 1). Еще раз напомню о дополнительном правиле, действующем для инвентарных переменных (см. переменные). Кроме него никаких дополнительных проверок не производится. invkill [<предмет>] Удалить <предмет> из инвентаря. Если предмет не указан - удалить из инвентаря все предметы. perkill Удаляет все созданные на данный момент внутренние переменные. Эти два оператора рекомендуется использовать в самом начале квеста и при прохождении игроком существенных частей игры (чтобы не засорять память лишними переменными). goto <метка> Если <метка> существует, то просто происходит переход, без дополнительных действий (то есть ни экран, ни кнопки не очищаются). if <условие> then <инструкция> <условие> - это логическое выражение в обычном понимании этого слова :) Действиями в нем являются логические операции and, or, not, а аргументами - либо выражения вида [const] <предмет> (см. выше), либо <выражение> <знак> <выражение>, где <знак>ом может быть =, >, <, >=, <=, <>. Порядок выполнения and, or, not: not может быть применен только непосредственно к логическом выражению (так как скобок пока нет), а чтобы понять, в каком порядке выполняются and и or, нужно просто себе представить, что and - это аналог операции умножения, а or - операции сложения. Правила порядка действий для них те же самые. Если <условие> не выполнено, то выполняется следующая за if строка квеста (точнее - строка, следующая после разделителя CR-LF). Если же оно выполнено, то исполняется <инструкция>, причем как раз в ней рекомендуется использовать разделитель &. proc <метка> Выполнение подпрограммы. Отличие этого перехода от goto состоит в том, что после окончания выполнения локации <метка> (то есть когда там будет обнаружен оператор end) анализируется, не вызвала ли эта локация дальнейшего перехода. Если вызвала - то о команде proc интерпретатор забывает и переходит туда, куда затребовала эта локация (это вызвано скорее логическими, а не техническими соображениями). Если же перехода нет, то происходит возврат к строке кода исходной локации, следующей за proc. Крайне не рекомендуется использовать в той локации, куда происходит переход по proc, любые дальнейшие переходы, и особенно - переход по proc. Скорее всего интерпретатор правильно выпутается из этой цепочки переходов, но вот правильно ли он это сделает с точки зрения разработчика - сказать сложно. [* Возможно, URQ обрабатывает команду proc по-другому. В документации об этом ничего не сказано] save [<метка>] Сохраняет в qsv-файл значения всех переменных и инвентаря, а также инструкцию - на какую локацию переходить при загрузке. Если <метка> присутствует, то переход будет осуществлен на нее. Если нет - то на ту локацию, в которой находится этот оператор. [* URQ по-другому интерпретирует отсутствие метки. Там в этом случае будет (цитирую) "сохраняются переменные, предметы и вид локации (Окно Информации и кнопки) ко времени сохранения". Это, конечно, замечательно, но куда же произойдет переход при загрузке ?? Ну, допустим, никуда - будет просто исполнена эта локация. Но ведь это же то же самое, что перейти на ту локацию, из которой был сделан save. Ну, можно, наверное, придумать такой пример, когда это не совсем тоже самое, но на мой взгляд такая конструкция может только запутать как игрока, так и разработчика] play <файл> Моей прогой этот оператор не поддерживается. [* Цитирую документацию к URQ: проигрывает мультимедиа файл (wav) например "play ding.wav" сыграет файл ding.wav из каталога квеста] pause <количество миллисекунд> [1 секунда = 1000 миллисекундам] Это - весьма интересный оператор, описание которого появилось только в документации к URQ 1.22. Значит так. Когда интерпретатор встречает pause, происходит вывод всех кнопок на экран и игроку предоставляется выбор перехода. Но ! Выбор этот можно делать только в течение заданного количества миллисекунд. Если игрок успел нажать на кнопку, то происходит переход и о паузе интерпретатор забывает. Если же нет - то происходит выполнение инструкций квеста после оператора pause (при этом, естественно, игрок уже не может ничего выбирать до следующего pause или end). Если же pause встретился, когда никаких кнопок еще не было - то просто происходит задержка на то самое количество миллисекунд. Смысл использования заключается в том, чтобы ограничить время раздумий игрока на выбор следующего перехода (например, если нужно пробежать по падающему мосту, оббегая при этом лежащие на нем камни). В документации RipOs'а этот оператор описан довольно неясно, и вполне возможно, что я понимаю его не так, как RipOs. Кажется, в его проге если игрок успел нажать на кнопку, то "забывания" о паузе не происходит. Но на мой взгляд это может вызвать трудно отлавливаемые баги и может иметь смысл только в том случае, когда возможна обработка нескольких пауз одновременно. Теперь, чтобы приступить к созданию собственных квестов, Вам осталось узнать только о ... ¦ Локация :common ===================== Это - специальная локация, выполнение которой происходит каждый раз при переходе в новую локацию (то есть при переходе по кнопке). Этот вызов аналогичен вызову командой proc, поэтому для локации :common справедливы рекомендации, данные при описании этого оператора. Сложный вопрос - исполнять ее или нет в самом начале игры, то есть когда исполнение инструкций вообще еще не началось. Моя прога не исполняет, а вот URQ - не знаю. Смысл использования заключается в организации всяческих счетчиков (например, сколько уже было переходов по локациям), времени суток (например, если переходов больше 20-и, то считаем, что день прошел), физических параметров героя (например, голод, усталость ...), мыслей героя (например, организовать случайный вывод мысли из списка при заходе в каждую пятую локацию), каких-то автоматических действий (например, если в локации обнаружен враг, то автоматически выхватить кинжал, если друг - то автоматически поздороваться) ... Этот список можно и дальше продолжать, но я думаю, что основная идея ясна. Ну что ... Вот, пожалуй, и все, что есть на данный момент в URQ 1.22. Конечно же, многие моменты пока еще оставляют желать лучшего (в том числе и это описание :) ), но разработка сейчас все еще идет полным ходом, так что вполне возможно, что это - всего лишь исходный вариант окончательного URQ ... С вопросами и предложениями по поводу URQ_DOS и URQ обращайтесь ко мне и к RipOs'у (ripos@mail.ru). Спасибо за внимание и приятной Вам работы :) Корянов Виктор 06 февраля 2001 года