Copyright: QSP Help (30.08.2004)


Документация к Quest Soft Player

Version 3.0

Содержание:

I)	О программе

Лицензионное соглашение

Системные требования

Благодарности

II)	Принцип работы

Работа с редактором квестов

Принцип работы QSP

III)	Операторы и функции

Обозначения

Операторы

Многострочные "IF / ACT"

Функции

Системные переменные

Использование массивов

Создание меню для предметов

Использование VB-скриптов при разработке квестов

IV)	Подсказки / Советы

V)	Часто задаваемые вопросы ("FAQ")

VI)	Словарь терминов

VII)	Что нового в этой версии?

PS: Если в описании после какого-либо слова стоит значок "^", то определение этого понятия вы можете найти в словаре терминов.


I) О программе

Лицензионное соглашение

Программа "Quest Soft Player" изготовлена компанией "Byte Soft" и не является лицензионно защищенным программным продуктом. Распространяется на правах "freeware", т.е. абсолютно свободно. При копировании программы разрешается добавлять свои файлы к данному архиву, но ни в коем случае не удалять существующие. При использовании исходного кода "Quest Soft Player" требуется в сопутствующей документации указать, что при разработке были использованы фрагменты программного кода "Quest Soft Player" со ссылкой на автора ("byte@mail.knastu.ru"). Автор не отвечает за какой-либо ущерб, либо упущенную выгоду, полученные в следствии использования программного продукта. Если вы по каким-либо причинам не согласны с этим лицензионным соглашением, то вы должны стереть со всех хранителей информации дистрибутивные пакеты программного продукта и прекратить использование программного продукта. Со всеми жалобами, претензиями и предложениями просьба обращаться по адресу "byte@mail.knastu.ru".

Все, связанное с QSP, просьба присылать на Mail, указанный выше.

Содержание

Системные требования

Для запуска QSP вам потребуется любой компьютер, на котором установлена операционная система "Windows 95" или выше. Желательно, чтобы процессор был не ниже "P100", глубина цвета была не меньше 16 бит, присутствовала мышь.

Без мыши играть можно, но очень неудобно.

Содержание

Благодарности

Выражаю огромную благодарность всем, кто участвовал в разработке QSP. Без ваших советов, тестирования, моральной поддержки QSP не стал бы таким, каковым он сейчас является.

Я благодарен следующим людям:

RipOs'у за его советы / движок (разработал URQ - первую достаточно удобную русскоязычную платформу для написания текстовых квестов);

Зырянову Александру за помощь в тестировании;

Гнедову Павлу за ценные советы и тестирование (сделал очень много для развития QSP);

Чупейкину Андрею за особое внимание к платформе;

Shy за ценные советы и тестирование (ну просто заставил меня сделать достаточно хороший математический движок и нормальное определение текстовых констант);

Nex'у за тестирование;

Игорю Юрину за советы и тестирование;

Бацилле за советы;

Korwin'у, а также всему УРК-сообществу :-)

А также всем, кто присылал свои пожелания и отзывы о программе.

Надеюсь, что этот список будет пополняться.

Еще раз спасибо хотя бы просто за то, что вы есть!

Содержание


II) Принцип работы

Работа с редактором квестов

Программа "Quests Generator" ("QGen.exe") предназначена для создания квестов под платформу "Quest Soft Player" (QSP).

После загрузки редактора вы увидите список существующих локаций^. Пока здесь присутствует лишь одна локация - "Начало". С нее начинается выполнение квеста. Обычно это вступительная часть, в которой указывают название игры, ее автора, ценные советы по прохождению и др.

Щелкните по ее названию два раза. Откроется окно кода локации, условно поделенное на 3 части: описание локации, окно кода "Выполнить при посещении" и 2 поля для быстрой и наглядной вставки возможных действий на локации.

В поле "Описание локации" вводится базовый текст описания для данной локации. Т.е. вывод этого текста состоится в любом случае, независимо от условий игры.

Поле кода локации ("Выполнить при посещении") служит для непосредственного программирования как игровых, так и служебных^ локаций.

2 поля "Действия на локации" служат для вставки базовых (которые будут добавляться независимо от условий игры при переходе на локацию) действий. Левое поле - список. Здесь перечислены названия базовых действий. Справа от списка действий - текстовое поле, код в котором будет выполнен лишь при выборе выделенного действия.

PS: Создание, удаление, переименование локаций и действий происходит посредством выбора соответствующего пункта меню (или с помощью панели инструментов).

Для того, чтобы посмотреть готовый квест, загрузите программу "QSP" и откройте нужный файл (или в опциях QSP выберите "Ассоциировать файлы *.GAM с QSP", чтобы потом можно было открывать GAM-файлы двойным щелчком).

Содержание

Принцип работы QSP

При переходе на новую локацию выполняются следующие действия:

1) Очистка списка действий (от предыдущей локации);

2) Обновление поля описания локации (если нужно);

3) Заполнение списка базовых действий;

4) Выполняются последовательно операторы^, находящиеся в поле "Выполнить при посещении";

5) Если переменная^ локации-счетчика не пуста, то происходит выполнение операторов в поле "Выполнить при посещении" соответствующей локации (2 раза в секунду);

6) Обновление интерфейса (шрифт, цвета, заданные с помощью системных переменных) – также 2 раза в секунду или с помощью оператора "REFINT";

7) Если пользователь выбирает действие, то выполняются операторы, определенные для этого действия;

8) Если пользователь вводит какой-либо текст в поле ввода (внизу окна движка):

1) Этот текст не начинается с символа "#".

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

Затем, если соответствующая вводу строка в операторах "CMD" не найдена, то, если значение системной переменной "$USERCOM" не равно '', происходит выполнение операторов на указанной в "$USERCOM" локации. После этого движок возвращает управление текущей локации (конечно, если не произошел переход с помощью "GOTO / GT, XGOTO / XGT").

2) Этот текст начинается с символа "#" (командный режим^).

Если значение системной переменной "DISABLECOMMODE" равно 0, то движок пытается интерпретировать эту строку (после символа "#") как строку кода. Как это использовать? Просто! Пример: вы пишите игру и обнаружили баг. Разумеется, вы хотите избавиться от него. Вы знаете, от каких переменных зависит то или иное действие. Например, это строковая переменная "$Name". Естественно, возникает желание посмотреть значение этой переменной, а в редакторе искать куда вставить вывод значения, перезапускать квест... Долго. Да и незачем. Вводите в ту самую строку внизу экрана:

#pl $Name

и нажимаете "OK". Все! Теперь вы видите значение этой переменной!

Аналогично можно выполнять ЛЮБЫЕ операторы QSP.

Содержание


III) Операторы и функции^

Обозначения

[выражение] - набор констант^, переменных, функций, разделенных знаками "+, -, *, /" - сумма / разность / умножение / деление. Также можно использовать скобки. Например, можно написать:

PL (val('25')*4)/(2*5)

Допустимо использование логических выражений. Например:

PL A=5+6 OR (C=V AND N=8*7)

Одна переменная / элемент массива может содержать два значения: текстовое и числовое.

При использовании текстового значения перед названием переменной ставится знак "$" ("$Player_Name"). Для использования числового значения переменной пишется только ее название.

Числовая константа записывается числом (например 4535), а текстовая берется с двух сторон в апострофы - одинарные кавычки ("'"). Два подряд идущих апострофа считаются апострофом, включенным в текстовую константу. Т.е. после выполнения

PL 'Byte Soft''s QSP'

вы увидите "Byte Soft's QSP".

Складывать с помощью "+" можно не только числа (или числовые переменные), но и объединять текстовые константы / переменные / функции. Но, для объединения текстовых выражений, рекомендуется использовать символ "&". При этом такое объединение должно быть заключено в скобки. Например,

PL 'The '+'door '+'is closed.'

и

PL ('The '&'door '&'is closed.')

выведут одно и то же: "The door is closed.".

Возможна ЛЮБАЯ комбинация констант, переменных, функций вместо [выражение].

Т.е. если, например, вы видите "ADD OBJ [$выражение]", то это значит, что можно написать как

ADD OBJ 'молот'

так и

ADD OBJ $text

а также

ADD OBJ 'молот'+str(a)+$text

и др.

PS: Смотрите раздел "Использование массивов" этой части документации, чтобы получить дополнительную информацию о возможных выражениях.

Если в описании встретите:

[выражение] - выражение может быть как только текстового^, так и только числового^ типа.

[$выражение] - выражение ТОЛЬКО текстового (строкового) типа.

[#выражение] - выражение ТОЛЬКО числового типа.

Содержание

Операторы

ADD OBJ [$выражение] или ADDOBJ [$выражение] - добавление предмета в рюкзак.

DEL OBJ [$выражение] или DELOBJ [$выражение] - удаление предмета из рюкзака, если таковой имеется.

KILLOBJ - очистка рюкзака.

UNSELECT или UNSEL - отмена выбора предмета. При выборе играющим какого-либо предмета, он остается выделенным (т.е. текстовое значение системной переменной "$SELOBJ" чему-то равно). Данная команда отменяет выделение, и, как следствие, очищается переменная "$SELOBJ".

CLEAR или CLR - очистка окна пользователя.

NL - переход на новую строку (перевод каретки) в окне пользователя.

P [выражение] - вывод в окно пользователя текста, значения переменной...

PL [выражение] - вывод в окно пользователя текста, затем переход на новую строку.

*CLEAR или *CLR - очистка основного окна описаний.

*NL - переход на новую строку в основном окне описаний.

*P [выражение] - вывод текста в основное окно описаний.

*PL [выражение] - вывод текста в основное окно описаний, затем переход на новую строку. Аналогичным образом можно вывести текст, просто написав нужное выражение вместо оператора. Например, строки

*PL AAA+VAL('989')

и

AAA+VAL('989')

выполнят одно и то же действие.

COPYARR [$выражение] – копирование содержимого массива в другой массив. Формат строки [$выражение]: [$массив_приемник:массив_источник]. Копируются как текстовые, так и числовые значения массива. Размер массива-приемника при копировании не имеет значения. Примеры:

copyarr '$a:$b'

copyarr 'a:b'

copyarr $arrname1+':'+$arrname2

KILLVAR - удаление всех переменных.

SET [название переменной]=[выражение], LET [название переменной]=[выражение] или [название переменной]=[выражение] - установка значения переменной. Если нужно установить текстовое значение переменной, то перед ее названием ставится "$".

EXIT - завершение выполнения текущего кода (преждевременный выход из подпрограммы / обработчика какого-либо события...).

GOSUB [$выражение] или GS [$выражение] - обработка на заданной локации операторов в поле "Выполнить при посещении", затем возврат на исходную строку (продолжение выполнения программы).

GOTO [$выражение] или GT [$выражение] - переход на локацию с названием [$выражение].

JUMP [$выражение] - переход в текущей локации на метку [$выражение]. Метка на локации обозначается как ":[название метки]". После описания метки (через "&") могут идти операторы. Если интерпретатор находит случайную метку, то он ее просто игнорирует. Например:

jump 'КонеЦ'

p 'Это сообщение не будет выведено'

:конец

p 'А это сообщение пользователь увидит'

С помощью оператора "JUMP" можно строить циклы:

set s=0

:loop

set s=s+1

pl s

if s!9:jump 'LOOP'

p 'Все!'

XGOTO [$выражение] или XGT [$выражение] - отличается от "GOTO / GT" тем, что при переходе не обновляется поле описания локации.

CLOSE [$выражение] - остановка проигрывания звукового файла с заданным названием.

CLOSE ALL - остановка проигрывания всех активных звуковых файлов.

PLAY [$выражение] - проигрывание звукового файла с заданным названием (+путь к файлу относительно папки с квестом). Может одновременно проигрываться большое число файлов. Звук накладывается.

! - оператор комментария. То, что находится в данной строке после оператора комментария, игнорируется.

CALL [$выражение] – вызов процедуры, написанной на VBScript. В выражении-аргументе нужно указать название вызываемой процедуры и список передаваемых значений (через запятую), заключенных в скобки. Пример:

Call 'MyProc("String",1,2,3)'

Call 'MyProc("String'+$S+'",'+str(a+5)+',78)'

Call 'MyProc'

MENU [$выражение] - вызов меню с заданным названием (см. раздел "Создание меню для предметов").

MSG [выражение] - вывод заданного сообщения в окне "MessageBox".

NOSAVE - запрет записи состояния игры (сделать недоступным пункт меню "Сохранение").

OPENGAME [$выражение] - если [$выражение] равно '', то вызов окна загрузки состояния игры, иначе загрузка состояния из указанного файла.

OPENQST [$выражение] - открытие и запуск заданного файла квеста (+путь к файлу относительно папки с квестом).

REFINT – обновление интерфейса (смена цветов, шрифта, назначенных с помощью переменных "BCOLOR, FCOLOR, FSIZE, $FNAME").

SAVE - разрешение записи состояния игры.

SAVEGAME [$выражение] - если [$выражение] равно '', то вызов окна сохранения состояния игры, иначе сохранение состояния в указанный файл.

VIEW [$выражение] - просмотр картинки с заданным названием (+путь к файлу относительно папки с квестом). Если вместо [$выражение] написать пустую строку (''), то это скроет окно с картинкой.

WAIT [#выражение] - остановка выполнения программы на заданное количество миллисекунд (1 секунда = 1000 миллисекунд).

CMD [$выражение]:[оператор] & [оператор] & ... - если играющий вводит [$выражение] в командную строку на данной локации, то выполняются заданные действия.

PS: 1) Оператор "CMD" бессмысленно использовать в условных операторах.

    2) Не рекомендуется пользоваться данным оператором. Вместо этого лучше использовать локацию-обработчик строки ввода (см. раздел "Системные переменные").

ACT [$выражение]:[оператор] & [оператор] & ... - добавление действия к существующим на локации. К действиям добавляется новое с описанием [$выражение] и при нажатии на него выполняются заданные операторы.

CLA - очистка списка действий на локации.

CLS - эквивалентен конструкции "CLEAR & *CLEAR & CLA & CMDCLEAR".

CMDCLEAR или CMDCLR - очистка строки ввода (и, конечно, значения переменной "$USER_TEXT").

DEL ACT [$выражение] или DELACT [$выражение] - удаляет действие из списка действий на локации (если такое действие существует). Например:

DEL ACT 'Идти вперед'

FIGHTING - вызов окна боя (игры во что-либо, соревнования...).

Переменные, которые нужно заполнять перед боем:

HHealth - здоровье героя

EHealth - здоровье врага

HDefense - защита героя

EDefense - защита врага

HHit - сила удара героя

EHit - сила удара врага

$HName - название героя

$EName - название врага

$HHealthName - название параметра "здоровье героя"

$EHealthName - название параметра "здоровье врага"

$HDefenseName - название параметра "защита героя"

$EDefenseName - название параметра "защита врага"

$HHitName - название параметра "сила удара героя"

$EHitName - название параметра "сила удара врага"

FTimer - время задержки в бою (в миллисекундах). Если значение этой переменной равно 0 или она не существует, то задержка принимается равной 500 (полсекунды).

После заполнения параметров боя, бой вызывается оператором "FIGHTING".

На время боя НЕ ВЫПОЛНЯЮТСЯ операторы, стоящие после этого оператора, но, если нужно, происходит обработка локации-счетчика (можно отключить на время боя, установив переменную локации-счетчика равной '' (пусто)).

Бой идет до тех пор, пока параметр "здоровье" кого-либо не станет меньше 1.

Затем результаты боя остаются в переменных "HHealth" и "EHealth".

В бою присутствует элемент случайности (как герой, так и враг могут промахнуться при ударе). Урон противнику считается по формулам:

Урон_Противнику = Своя_сила_удара - Защита_противника / 2

Если Урон_Противнику < 1, то Урон_Противнику = 1

Пример вызова боя:

set hhealth=100

set ehealth=200

set hdefense=10

set edefense=15

set hhit=7

set ehit=8

set $hname='Вы'

set $ename='Враг'

set $hhealthname='Здоровье'

set $ehealthname='Жизни'

set $hdefensename='Защита'

set $edefensename='Щит'

set $hhitname='Сила удара'

set $ehitname='Удар'

set FTimer=100

FIGHTING

msg 'All OK'

msg 'Здоровье героя:'+str(hhealth)

msg 'Здоровье врага:'+str(ehealth)

PS: Разумеется, можно записывать присвоение значений переменным без слова "SET".

IF [условие]:[оператор1] & [оператор2] & ... ELSE [оператор3] & [оператор4] & ... - если [условие] верно, то выполнить заданные операторы до ключевого слова "ELSE", иначе выполнить операторы после "ELSE".

Если ключевое слово "ELSE" не указано, то при верном условии [условие], выполнить все операторы, находящиеся после знака ":".

При записи условия можно пользоваться следующими операциями (в порядке возрастания приоритета; операции с одинаковым приоритетом находятся на одной строке):

&

OR

AND

OBJ,NO

=,<,>,!,<>,<=,>=,=<,=>

+,-

*,/

- (унарный)

PS: Выражения в скобках имеют наивысший приоритет.

Здесь:

& - операция объединения строковых выражений (см. раздел "Обозначения").

OR – "Или". Если хотя бы одно из рядом стоящих условий верно, то верно и все условие.

AND - "И". Если оба рядом стоящие условия верны, то верно и все условие.

OBJ [$выражение] - Верно, если есть предмет [$выражение].

NO [условие] - Отрицание. Верно, если [условие] ложно (аналогично "NOT" в Basic).

= - Верно, если значения рядом стоящих выражений равны.

< - Верно, если значение выражения слева меньше значения выражения справа.

> - Верно, если значение выражения слева больше значения выражения справа.

! или <> - Верно, если значения рядом стоящих выражений не равны.

<= или =< - Верно, если значение выражения слева меньше или равно значению выражения справа.

>= или => - Верно, если значение выражения слева больше или равно значению выражения справа.

+,-,*,/ - Сложение, вычитание, умножение, деление соответственно.

- (унарный) – Находится перед числовым выражением и меняет знак у значения этого выражения.

Пример:

if ((a+b)/c)=45+54 or (b<5 or c>45) and no obj 'лопата' and $f=$vvv+'RRRRR':p 'OK' & goto 'Next'

KILLALL - эквивалентен конструкции "KILLVAR & KILLOBJ".

Содержание

Многострочные "IF / ACT"

Возможно использование многострочных "IF" и "ACT". Многострочные формы записи отличаются от однострочных тем, что после символа ":" ставится перенос строки, затем идут построчно необходимые операторы, а заканчивается все это словом "END" (можно записывать "END IF / END ACT"). Мнострочные формы "IF" и "ACT" могут содержать внутри себя как однострочные формы, так и многострочные. Каждому "IF" и "ACT" должен соответствовать свой "END". Например:

if a+b<3 or y=8:

p 'A+B<3 или Y=8'

nl

if j=88:nl & p 'NEXT'

if $h='ooo':

p 'loo' & jump 'lll'

end

act 'Идти к '+$Dest:

pl 'Вы пошли к '+$Dest

goto $Dest

end

end

Кроме этого, в многострочной форме "IF" допускается использование ключевого слова "ELSE".

Например:

if a=0:

'1'

if b=0:'0' else '1'

if j=88:nl & p 'NEXT'

if $h='ooo':

p 'loo' & jump 'lll'

else

p 'sample text'

v=8

end

act 'Идти к '+$Dest:

pl 'Вы пошли к '+$Dest

goto $Dest

end

else

'0'

g=78

end

PS: Количество вложений любых форм "IF" и "ACT" не ограничено.

Содержание

Функции

ARRPOS([#выражение 1],[$выражение 2],[выражение 3]) - возвращает индекс элемента массива [$выражение 2], равного значению выражения [выражение 3]. Поиск начинается с элемента номер [#выражение 1]; индексация элементов массива ведется с нуля. Если указанное значение не найдено, функция возвращает -1. Чтобы найти числовое значение в массиве, нужно в [$выражение 2] подставить лишь название массива (в кавычках), для строкового - название массива с символом "$" перед его названием. Пример:

ARRPOS(0,'$A','This') - найдет строку 'This' в текстовых значениях массива "$A" (или вернет -1, если такого не существует)

ARRPOS(2,'A',65) - найдет число 65 в числовых значениях массива "A" (при этом первые два элемента массива игнорируются)

DESC([$выражение]) - возвращает текст описания локации с заданным в [$выражение] названием.

EVAL([$выражение]) – вычисляет значение VBScript-выражения. Формат вызова функций похож на формат вызова процедур. Т.е. сначала записывается название вызываемой функции, затем, в скобках через запятую, перечисляются передаваемые значения. Пример:

a=eval('MyFunction(2,3,4)')

$b=eval('MyFunc("'+$b+'",'+str(a)+',556)')

$c=eval('MyFunct')

IIF([условие],[выражение_да],[выражение_нет]) - возвращает значение выражения [выражение_да], если [условие] истинно, иначе значение выражения [выражение_нет].

INPUT([выражение]) - выводит окно ввода с приглашением [выражение]. Возвращает введенный играющим текст, либо '' (пусто), если была нажата кнопка "Отмена".

INSTR([#выражение 1],[$выражение 2],[$выражение 3]) - возвращает номер позиции символа, с которого начинается вхождение строки [$выражение 3] в строку [$выражение 2] (или 0, если такой строки нет). Поиск начинается с символа номер [#выражение 1]. Пример:

INSTR(1,'ABCDefgh','BC') равно 2

INSTR(1,'ABCDefgh','Be') равно 0

ISNUM([$выражение]) - функция проверяет, все ли символы в строке являются цифрами (учитывая знак "-" в начале, прилегающие пробелы и символы табуляции). Если в указанной строке есть хотя бы один символ - не-цифра (исключая возможный "-" в начале и прилегающие пробелы / символы табуляции), то функция возвращает 0 (ложь), иначе -1 (истина).

Функция полезна при проверке введенной играющим строки на число. Пример:

ISNUM('9999 ') равно -1

ISNUM('-888') равно -1

ISNUM('777a6') равно 0

ISPLAY([$выражение]) - проверяет, проигрывается ли файл с заданным названием в текущий момент времени и возвращает -1, если файл воспроизводится, иначе 0.

LCASE([$выражение]) - возвращает строку маленьких букв, полученную изменением регистра букв исходной строки [$выражение]. Например,

msg lcase('TExT#')

выведет "text#".

LEN([$выражение]) - возвращает длину строки [$выражение].

MAX([выражение 1],[выражение 2]) - возвращает максимальное из значений выражений-аргументов.

MID([$выражение],[#выражение 1],[#выражение 2]) - вырезает из строки [$выражение] строку, которая начинается с символа номер [#выражение 1] и имеет длину [#выражение 2].

MIN([выражение 1],[выражение 2]) - возвращает минимальное из значений выражений-аргументов.

RAND([#выражение 1],[#выражение 2]) - возвращает случайное число между числами [#выражение 1] и [#выражение 2].

RGB([#выражение 1],[#выражение 2],[#выражение 3]) - возвращает код цвета на основе 3-х числовых аргументов. [#выражение 1], [#выражение 2] и [#выражение 3] определяют соответственно уровни красного, зеленого и синего цветов. Все значения аргументов должны быть в отрезке [0,255]. Данная функция используется совместно с системными переменными "BCOLOR, FCOLOR".

STR([#выражение]) - переводит число (или числовое выражение) [#выражение] в соответствующую строку. Например,

pl str(56)

выведет строку "56".

STRCOMP([$выражение],[$шаблон]) – проводит сравнение строки [$выражение] на соответствие шаблону [$шаблон]. Регистр символов не учитывается. Если строка соответствует шаблону, то функция возвращает -1, иначе 0. Управляющие конструкции в шаблоне:

? – любой символ.

* - 0 или больше любых символов.

# - любая цифра.

[список_символов] – любой символ из списка.

[!список_символов] – любой символ, которого нет в списке.

Примеры:

STRCOMP('aBBBa','a*a') равно -1

STRCOMP('F','[A-Z]') равно -1

STRCOMP('F','[!A-Z]') равно 0

STRCOMP('a2a','a#a') равно -1

STRCOMP('AM5b','a[L-P]#[!c-e]') равно -1

STRCOMP('bAT123khg','B?T*') равно -1

STRCOMP('CAT123khg','B?T*') равно 0

TRIM([$выражение]) – удаляет прилегающие пробелы и символы табуляции из [$выражение]. Затем возвращает полученную строку. Например,

msg trim('     TRIM TEST        ')

выведет "TRIM TEST".

UCASE([$выражение]) - возвращает строку больших букв, полученную изменением регистра букв исходной строки [$выражение]. Например,

msg ucase('TexT#')

выведет "TEXT#".

VAL([$выражение]) - переводит строку цифр [$выражение] в соответствующее число. При [$выражение] равном '' или если оно содержит не-цифры, то возвращается 0.

PS: Перед функциями, возвращающими строковые значения ("DESC, INPUT, LCASE, MID, STR, TRIM, UCASE"), а также перед "EVAL, IIF, MAX, MIN" можно писать знак "$". Т.е. можно написать "pl str(43)" или "pl $str(43)".

Содержание

Системные переменные

Системные переменные - переменные, значения которых устанавливаются или используются интерпретатором. Системные переменные используются как обычные переменные.

COUNTOBJ - имеет значение, равное числу предметов в рюкзаке.

DISABLECOMMODE – если значение переменной не равно 0, то блокирует командный режим.

DISABLESCROLL – если значение переменной не равно 0, то запрещает автопрокрутку текста при его выводе в основное или дополнительное окно описания локации.

DISABLESUBEX – если значение переменной не равно 0, то запрещает использование "подвыражений" в тексте (например, значением '<<5+6>>' будет строка '<<5+6>>', а не '11').

MSECSCOUNT – содержит количество миллисекунд, прошедших с момента запуска Windows.

RND - имеет случайное значение от 1 до 1000.

$CURLOC - содержит название текущей локации.

$QSPVER – содержит версию интерпретатора в формате "X.Y.Z".

$SELOBJ - содержит название выделенного предмета.

$SELACT – содержит название выделенного действия.

$USER_TEXT - содержит текст, находящийся в строке ввода в окне движка.

$USRTXT - дублирует "$USER_TEXT".

$COUNTER - содержит название локации-счетчика. Если значение этой переменной не равно '', то 2 раза в секунду происходит выполнение операторов в поле "Выполнить при посещении" на соответствующей локации. Локация-счетчик полезна для проверки выделенных предметов, введенного текста...

$ONGLOAD – содержит название локации, на которую происходит переход после загрузки состояния игры (если задана эта переменная). Данная локация полезна для установки параметров, которые не сохраняются в файле состояния (переменные VBScript, настройки интерфейса, произведенные с помощью VBScript...).

$ONGSAVE – содержит название локации, на которую происходит переход перед сохранением состояния игры. Возможное применение см. выше.

$USERCOM - содержит название локации-обработчика строки ввода. Если пользователь вводит какой-либо текст, то движок ищет на текущей локации операторы "CMD" и сравнивает введенный текст с тем, который указан в этих операторах. Если находит совпадение (без учета регистра букв и прилегающих пробелов), то выполняет заданные в "CMD" операторы, иначе (если "$USERCOM" чему-то равно) выполняет операторы на локации, указанной в данной переменной. После выполнения оных управление возвращается текущей локации (конечно, если не было совершено перехода по "GOTO / GT, XGOTO / XGT").

BCOLOR - содержит цвет текущего фона. Если равна 0 или не существует, то используется цвет, заданный в настройках программы.

FCOLOR - содержит цвет используемого в данный момент шрифта. Если равна 0 или не существует, то используется цвет, заданный в настройках программы.

FSIZE - содержит размер используемого в данный момент шрифта. Если равна 0 или не существует, то используется размер, заданный в настройках программы.

$FNAME - содержит название используемого в данный момент шрифта. Если равна '' или не существует, то используется шрифт, заданный в настройках программы.

PS: 1) Т.к. при значении переменных "BCOLOR" и "FCOLOR" равном 0 используется стандартный цвет, то, чтобы получить черный цвет, НЕ нужно в качестве аргументов функции "RGB" использовать ВСЕ нули. Вместо этого поставьте где-нибудь единицу. Например "FCOLOR=RGB(0,0,0)" даст стандартный цвет шрифта, а "FCOLOR=RGB(1,0,0)" даст черный цвет, независимо от настроек программы.

    2) Обновление настроек интерфейса происходит 2 раза в секунду (автоматически), либо с помощью оператора "REFINT".

    3) На локации-обработчике строки ввода следует пользоваться системной переменной "$USER_TEXT", чтобы узнать текущую строку. Очистить строку ввода можно в любом месте программы с помощью оператора "CMDCLEAR".

    4) При использовании операторов "KILLALL, KILLVAR" удаляются также системные переменные "DISABLECOMMODE, DISABLESCROLL, DISABLESUBEX, $COUNTER, $ONGLOAD, $ONGSAVE, $USERCOM, BCOLOR, FCOLOR, FSIZE, $FNAME".

Содержание

Использование массивов

QSP поддерживает работу с массивами. Массив - набор значений, имеющих один тип данных и обладающих одним названием. Элементы массива идентифицируются по индексам. Индексация ведется с нуля. Т.е. элемент с индексом 0 - первый элемент массива, 1 - второй и т.д. В зависимости от типа элементов массива он может быть текстовым или числовым. В QSP каждый массив имеет и текстовые, и числовые значения. Если вы хотите обратиться к текстовым элементам массива, нужно перед его названием поставить знак "$", если к числовым - достаточно указать его название. Обращение к элементу массива происходит так: сначала указывается название массива (со знаком "$" или без него), затем в квадратных скобках - числовое выражение, равное индексу элемента, к которому производится обращение. Т.е. "$A[6]" - обращение к текстовому значению элемента с индексом 6 (7-му) массива с названием "A", "NEW[2]" - обращение к числовому значению элемента с индексом 2 (3-му) массива с названием "NEW".

Присваивание и считывание значений массива происходит точно также, как-будто вы работаете с переменной. Пример:

A[2]=89 - присвоить числовому значению 3-го элемента массива "A" значение 89

$B[3]='Cool' - присвоить текстовому значению 4-го элемента массива "B" значение 'Cool'

A=B[5] - присвоить числовому значению переменной "A" числовое значение 6-го элемента массива "B"

$C=$MAS[54] - аналогично

PS: В QSP все переменные являются массивами (если не указывать индекс - он будет равен 0), поэтому обращение "A=AR[5]" полностью эквивалентно такому: "A[0]=AR[5]". Следствие этого - к названиям массивов представляются точно такие же правила записи, как к названиям переменных.

Содержание

Создание меню для предметов

Меню - набор текстовых значений массива, формат записи которых: [$название:название_локации]. Пример создания меню:

$stone[0]='Взять камень:takestone'

$stone[1]='Кинуть камень:throwstone'

$stone[2]='Осмотреть камень:' + $see_stone

Здесь название массива ("stone") - это название меню, а текстовые значения массива - действия, для которых указаны названия и названия локаций-обработчиков выбора пунктов меню. Т.е. при выборе пункта "Взять камень" произойдет временный переход на локацию с названием "takestone", в которой выполнятся операторы на поле "Выполнить при посещении", а затем произойдет возврат (если не было перехода по "GOTO / GT, XGOTO / XGT") на прежнюю локацию (как при переходе с помощью "GOSUB").

Аналогично будет происходить с др. пунктами.

Вызов меню производится с помощью оператора "MENU" из любого места программы квеста. Пример:

menu 'stone'

или

menu '$stone'

Этот оператор покажет меню с названием "stone".

PS: 1) Меню заканчивается на элементе массива со значением '' (пусто). Т.е. если массив меню состоит из элементов 'Взять','Осмотреть','','Бросить', то 2 последних пункта меню не будут созданы.

    2) Чтобы вставить разделитель в меню, вместо соответствующего элемента массива напишите "-:-". Т.е. если нужно поставить разделитель вместо 2-го элемента меню "stone", напишите:

$stone[1]='-:-'

    3) Примеры создания меню можно найти в папке "%AppPath%\Demos\" (файлы "menu.gam", "testact.gam" и "objs.gam").

Содержание

Использование VB-скриптов при разработке квестов

Язык QSP достаточно гибок, чтобы разрабатывать текстовые квесты практически любой сложности. Но он имеет недостатки: например, отсутствие поддержки функций пользователя (таких, которые могли бы использоваться наравне с переменными в числовых и строковых выражениях), а также возможности изменять интерфейс программы прямо из квеста. Эти возможности предоставляют функции и процедуры, написанные на VBScript. Для их описания существует специальное окно "Функции и процедуры пользователя", которое можно вызвать в редакторе, нажав "Ctrl+U". В нем вы можете описать все необходимые функции и процедуры VBScript, а затем вызывать их из программы квеста. Естественно, чтобы осмысленно описать нужные функции, вам необходимо хотя бы поверхностное знакомство с VBScript или Visual Basic.

Вызов функций VBScript осуществляется с помощью функции QSP "EVAL" (см. раздел "Функции"), а операторов – с помощью оператора "CALL" (см. раздел "Операторы").

Для функций / процедур VBScript существуют глобальные объекты:

QSP – имеет 2 метода:

qsp.eval([выражение]) - возвращает значение заданного QSP-выражения.

qsp.execstat [выражение] - выполняет заданный оператор / группу (разделенных &) операторов QSP.

Примеры:

a=qsp.eval("'version:'+$qspver")

b=qsp.eval("6+a+b+78/c")

qsp.execstat "$nxt='next'"

qsp.execstat "$a='A VARIABLE'"

qsp.execstat "pl 'It''s a test. '+$a & act 'Next':goto '"+qsp.eval("$nxt")+"'"

Screen класса "Screen" – объект, с помощью которого можно узнавать параметры настройки рабочего стола Windows.

MainForm класса "Form" – основная форма интерпретатора.

TxtMain класса "TextBox" – основное окно описания локации.

TxtUser класса "TextBox" – окно пользователя.

Objects класса "ListBox" – список предметов.

Actions класса "ListBox" – список действий.

UsrText класса "ComboBox" – строка текстового ввода.

BtnOK класса "CommandButton" – кнопка OK.

ImgForm класса "Form" – форма, на которой находится изображение, выводимое оператором "VIEW".

Image класса "Image" – элемент, в котором выводится изображение.

PS: 1) В модуле, описывающем функции / процедуры VBScript, не рекомендуется пользоваться контейнерными переменными, т.к. их значения не сохраняются в файлах состояний игры.

    2) Пример создания функций пользователя вы можете найти в папке "%AppPath%\Demos" (файл "usrfuncs.gam").

Содержание


IV) Подсказки / Советы

1) Числовое значение переменной / элемента массива может быть в интервале [-2147483648, 2147483647].

2) Все переменные (и элементы массивов) по-умолчанию имеют числовое значение = 0, а текстовое = ''.

3) В названиях переменных / массивов допускаются любые символы, кроме ":,&,=,<,>,+,-,*,/,',(,),!,[,]", запятых, пробелов и символов табуляции. Также не допускается в начале названия ставить цифры и использовать ключевые слова (названия функций / операторов) в качестве названий переменных. Не рекомендуется использовать длинные названия (более 20-25 символов).

4) Вместо пробелов в названиях переменных / массивов используйте символ подчеркивания ("_").

5) Перед интерпретированием строки происходит удаление пробелов и символов табуляции в ее начале, поэтому можете форматировать код локации.

6) В названиях локаций, переменных, действий и предметов не важен регистр букв, т.е. "ДеньГи" и "деньги" - одна и та же локация.

7) Операторы разделяются либо символом "&", либо символом переноса строки. Пример:

d=8 & goto 'PPP'

8) Максимальный индекс элемента массива - 2147483647. Не рекомендуется использовать большие индексы.

9) Любой не оператор (если это не метка и не одна из форм "END") является выражением для вывода в основное окно описаний. Например, можно записать

'COOL!!!'+$A

вместо

*pl 'COOL!!!'+$A

10) В строковые константы, в базовые описания локаций и в названия базовых действий можно вставлять значения выражений. Такие "подвыражения" должны находиться между двойных угловых скобок: "<<" и ">>", до и после которых может идти любой текст, включая подобные "подвыражения".

Например, вместо оператора

pl 'i='+str(i)

можно написать

pl 'i=<<i>>'

Другой пример:

pl 'Вас зовут <<$PlayerName>>, вы находитесь в <<$curloc>>.'

Примеры использования вложенных "подвыражений":

pl val('<<val(''<<i>>'')>><<j>>')

pl val('<<str(val(''<<i>>''))>>')

PS: 1) Если "подвыражение" с 2-х сторон ограничено скобками ("(), []") или апострофами ("'" - помимо тех апострофов, между которых заключена строковая константа), то оно игнорируется, т.е. не заменяется на свое значение.

Пример:

pl len('(<<23+5>>)') - выведет 10, а не 4

pl len('[<<23+4>>]') - выведет 10

pl len('''<<23+4>>''') - также выведет 10

pl len('*<<23+4>>*') - выведет 4

    2) Если нужно вывести последовательность "<<" на экран, то используйте следующую конструкцию (нужно сделать так, чтобы текст "<<" в строке явно не встречался, а получался при объединении текстовых выражений):

pl '<'+'<Text>>' – выведет "<<Text>>"

Можно сделать это немного другим способом (сначала присвоить некоторой переменной значение "<<", а потом это использовать):

$a='<'+'<'

pl $a+'Text>>' – также выведет "<<Text>>"

    3) См. пример "%AppPath%\Demos\subexpr.gam".

11) Не обязательно записывать операторы, функции, выражения в одной строке. Чтобы перейти на др. строку, нужно лишь в конце строки дописать " _" (пробел и символ подчеркивания). При этом группа таких строк считается ОДНОЙ строкой:

Строки

if a<5 and n-b>4+5+h/7*2 or t=4: p 'TTTTTTTTT' & cla & $f='Text Variable' & goto 'FFFF'

и

if a<5 and n-b> _

4+5+h/7*2 or  _

t=4: p 'TTTTTTTTT' _

& cla & $f='Text Variable' _

& goto 'FFFF'

ЭКВИВАЛЕНТНЫ, т.е. воспринимаются движком одинаково.

PS: После "OR" стоит не один, а ДВА пробела - первый пробел воспринимается движком как пробел, а второй - как часть " _". Это сделано для того, чтобы движок правильно обрабатывал операцию "OR" - не как "4+5+h/7*2 ort=4", а как "4+5+h/7*2 or t=4".

12) Перед тем, как выложить вашу игру в интернете, не забудьте установить значение системной переменной "DISABLECOMMODE" отличным от 0 (чтобы не облегчать жизнь читерам :).

13) Если вы разрабатываете квесты не с помощью поставляемого с программой редактора, а, например, в блокноте, то настоятельно рекомендую установить значение системной переменной "DISABLESCROLL" отличным от 0.

Содержание


V) Часто задаваемые вопросы (FAQ)

Я пишу такое условие "if a=8 or 9 or 10:..." , а происходит ошибка. Почему?

Как и во всех языках программирования, подобная запись недопустима. Нужно писать так:

if a=8 or a=9 or a=10:...

Как сделать плэйлист (чтобы при окончании одной мелодии воспроизводилась другая, затем еще одна и т.д.)?

См. примеры в папке "%AppPath%\Demos" (файлы "playlist1.gam, playlist2.gam, playlist3.gam").

Как сделать, чтобы при выборе предмета в списке происходило нужное мне действие?

На локации-счетчике в поле "Выполнить при посещении" введите:

if $selobj='[предмет]':[нужные операторы через &]

[если нужно, то вставьте подобные условия]

unselect

Как сделать показ анимации в игре (последовательно с паузой вывести картинки)?

1) В нужном месте локации введите:

view '[картинка 1 (название файла)]'

wait 500

view '[картинка 2]'

wait 500

view '[картинка 3]'

2) С помощью цикла:

set a=0

:loop

wait 500

view 'pic'+str(a)+'.jpg'

set a=a+1

if a<10:jump 'loop'

Как сделать в игре голод / увеличение числа жизней со временем...?

На локации-счетчике введите:

set голод=голод-1

if голод<10:pl 'Вы голодны!'

Как проверить, был ли герой на какой-либо локации?

На той локации, которую нужно проверить, введите:

set был_здесь=1

А на локации, где нужно это проверить:

if был_здесь=1:[операторы]

или:

if был_здесь:[операторы]

У меня в квесте локация-счетчик загромождена до предела. Как я могу облегчить ввод кода?

Разбейте код на процедуры, поместите их на разных локациях в поля "Выполнить при посещении", а затем вызывайте таким образом:

gosub 'LOC1'

gosub 'LOC2'

и т.д.

В игре заметно торможение, подвисание. Почему? Как исправить?

Скорее всего, это из-за огромного количества операторов на локации-счетчике. Уберите ненужное, отредактируйте код.

Я создавал квесты на платформе URQ. А как здесь сделать деньги?

В начале игры введите команду:

add obj 'Деньги'

Затем, когда нужно, изменяйте переменную "Money". Например, так:

set Money=Money+1

И на локации-счетчике сделайте обработку выбора предмета "Деньги":

if $selobj='Деньги':pl 'У вас '+str(money)+' монет.'

unselect

Почему я пишу "set a=4.676", а происходит ошибка?

Все числовые переменные должны быть целочисленного типа.

Как ограничить вместительность рюкзака?

Для этого используйте системную переменную "COUNTOBJ".

1) Проверяйте перед добавлением нового предмета кол-во предметов в рюкзаке, а затем решайте: добавлять ли этот предмет, или сделать что-либо еще.

2) Можете написать подпрограмму добавления предмета. И, например, через переменную "$OBJ4ADD" передавать ей название нужного предмета. На этой локации такой код:

if COUNTOBJ=10:

! Код обработки исключения

! ...

exit

end

addobj $obj4add

Тогда, чтобы добавить какой-либо предмет (например, "ложка"), нужно будет писать:

$OBJ4ADD='ложка' & gosub 'ADDOBJECT'

3) Можете написать процедуру добавления предмета на VBScript:

sub AddObject(obj)

count=Objects.ListCount

if count=20 then ' Максимальное число предметов – 20.

' Обработка исключения

' ...

else

Objects.AddItem obj

end if

end sub

Для добавления предмета (например, "ложка"), нужно будет писать:

Call 'AddObject("ложка")'

Как сделать меню предмета?

Существует несколько способов задания различных действий для предметов:

1) Дополнительные действия.

Вы обрабатываете выбор предмета на локации-счетчике, добавляя (с помощью оператора "ACT") новые действия.

2) С помощью строки ввода.

На локации-обработчике строки ввода проверяются какие-либо команды и, если нужно, выполняются необходимые действия.

3) С помощью меню пользователя.

См. раздел "Создание меню для предметов".

При выполнении моего квеста происходит вывод сообщения об ошибке, но на указанной локации ошибки нет. Почему?

Скорее всего, это происходит при вызове подпрограмм (через оператор "GOSUB") или при выполнении операторов на локации-счетчике. Дело в том, что при таком "переходе" реально движок не совершает никакого перехода, поэтому переменная, содержащая название текущей локации, не изменяется, и в сообщении об ошибке указывается "старая" локация.

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

Если сообщение об ошибке циклично повторяется, то, скорее всего, ошибка на локации-счетчике.

Как сделать набор локаций (например, повышение уровня героя) подпрограммой?

Нужно в обработке выбора действия, после которого происходит возврат к основной программе, поставить "GOTO $S", и перед вызовом такой "подпрограммы" написать "$S=$CURLOC".

Т.е. вам, например, нужно сделать универсальную подпрограмму, в которой играющий распределяет очки навыков по умениям. Вы описываете соответствующую локацию (например "Points"), одним из базовых действий на которой является пункт "Далее". В описании реакции на выбор этого действия, вы пишите

GOTO $S

и когда вызываете такую подпрограмму

$S=$CURLOC & GOTO 'Points'

Вызов такой подпрограммы можно сделать в реакции на выделение какого-либо "предмета".

Содержание


VI) Словарь терминов

Текстовый квест/адвентюра - жанр игр. Эти игры основаны обычно на текстовом вводе команд играющим и реакции программы на них - выводом различного текста в зависимости от условий игры.

Локация - одно из базовых понятий текстовых адвентюр. Локация - элементарная единица игрового мира. Это может быть комната, пещера, ее часть, дом... Играющий исследует игровой мир посредством перемещений между локациями.

Служебная локация - локация, не предназначенная для явного перехода на нее. Т.е. она используется лишь как контейнер для группы операторов. Это локация-счетчик, локация-обработчик строки ввода, локации-обработчики событий загрузки и сохранения игры, а также локации, на которые происходит переход с помощью оператора "GOSUB" (подпрограммы). На служебных локациях заполняется только поле "Выполнить при посещении".

Локация-счетчик - служебная локация, название которой записано в переменной "$COUNTER". Выполнение операторов на ней происходит 2 раза в секунду.

Локация-обработчик строки ввода - локация, на которой происходит выполнение операторов после нажатия пользователем кнопки "OK" в строке ввода (если переменная "$USERCOM" не равна '' и на текущей локации движок не нашел нужного оператора "CMD").

Переменная - именованная "ячейка памяти". Переменная имеет название и 2 значения - текстовое и числовое. Для использования текстового значения переменной нужно перед ее названием ставить знак "$". Для использования числового значения переменной достаточно указать ее название.

Массив - именованный типизированный список значений. См. раздел "Использование массивов".

Константа - фиксированное значение. Это может быть текстовая константа (заключается в апострофы ("'"): 'Text constant'), а может и числовая (записывается числом: 8888).

Оператор - ключевое слово, выполняющее какое-либо действие. Часто операторы имеют аргументы. Например, оператор "SET" имеет 2 аргумента: название переменной и ее значение.

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

Командный режим - режим, в котором движок выполняет команды, введенные в поле ввода (внизу окна движка).

Содержание


VII) Что нового в этой версии?

QSP еще жив!!!

После ну очень дООООлгого перерыва я выпускаю 3-ю версию. Надеюсь, в ней вы найдете все, что так долго ждали :-)

Итак, изменения в версии 3.0:

1) (QSP) Поддержка ключевого слова "ELSE" в однострочных / многострочных формах оператора "IF";

2) (QSP) Возможность вызывать функции / выполнять операторы QSP из VBScript (см. раздел "Принцип работы > Использование VB-скриптов при разработке квестов");

3) (QSP) Возможность вставлять в строковые константы, в базовые описания локаций и в названия базовых действий значения выражений (см. раздел "Подсказки / Советы > Совет №10");

4) (QSP) Новый оператор "REFINT" (см. раздел "Операторы и функции > Операторы");

5) (QSP) Новый оператор "COPYARR" (см. раздел "Операторы и функции > Операторы");

6) (QSP) Новая функция "STRCOMP" (см. раздел "Операторы и функции > Функции");

7) (QSP) Новая функция "UCASE" (см. раздел "Операторы и функции > Функции");

8) (QSP) Новая системная переменная "$ONGLOAD" (см. раздел "Операторы и функции > Системные переменные");

9) (QSP) Новая системная переменная "$ONGSAVE" (см. раздел "Операторы и функции > Системные переменные");

10) (QSP) Новая системная переменная "DISABLECOMMODE" (см. раздел "Операторы и функции > Системные переменные");

11) (QSP) Новая системная переменная "DISABLESCROLL" (см. раздел "Операторы и функции > Системные переменные");

12) (QSP) Новая системная переменная "DISABLESUBEX" (см. раздел "Операторы и функции > Системные переменные");

13) (QSP) Новая системная переменная "MSECSCOUNT" (см. раздел "Операторы и функции > Системные переменные");

14) (QSP) Новая системная переменная "$SELACT" (см. раздел "Операторы и функции > Системные переменные");

15) (QSP) В командном режиме теперь можно пользоваться операторами "ADD OBJ, ADDOBJ, SAVE, SAVEGAME";

16) (QSP) Изменен формат файлов сохранений состояния игры;

17) (QSP) Две новых опции, отвечающие за безопасность VB-скриптов;

18) (QSP) При просмотре переменных не отображаются "[ ]" для элементов с индексом 0;

19) (QSP) Пункт "Настройки / Другое / Не запускать два экземпляра QSP одновременно" теперь по-умолчанию включен;

20) (QSP) Размер изображений, показываемых с помощью оператора "VIEW", теперь можно изменять;

21) (QSP) Размеры полей описаний, а также списков предметов и действий теперь можно изменять;

22) (QGen) Наконец-то объединены 3 утилиты: "QGen, MultiQuest, Txt2Gam";

23) (QGen) Улучшен механизм работы с файлом подсказок "syntax.txt";

24) (QGen) Исправлен баг с "запаздыванием" изменения высоты списка локаций при восстановлении окна из свернутого состояния;

25) (QGen) Сортировка локаций стала работать заметно быстрей;

26) (QGen) Улучшен механизм поиска текста;

27) (QGen) Возможность получения подсказки по ключевому слову при наведении на него курсора мыши;

28) (QGen) Локации теперь сохраняются в том порядке, в котором находятся в списке;

29) (QGen) Локации в списке можно перемещать перетаскиванием;

30) (QGen) Действия на локации можно перемещать также как локации;

31) (QGen) Пункт меню "Окна / Закрыть все окна";

32) (QSP, QGen) Почти полностью переписан код;

33) (QSP, QGen) Куча мелких изменений;

34) (QSP, QGen) Исправлено множество мелких багов.

Содержание