Изменения в 5.8.0
Изменение в работе массивов
Это, пожалуй, самое важное из изменений в 5.8.0.
Теперь в массиве будет нельзя под одним индексом хранить и текстовое и числовое значение. Если вы запишете в ячейку числовое значение, а потом запишете в ту же ячейку текстовое значение, текстовое значение затрёт числовое.
При этом, если вы попытаетесь получить из ячейки со строковым значением числовое значение, плеер вернёт значение по умолчанию, то есть 0. И наоборот: если попытаться из ячейки с числовым значением получить строковое, плеер вернёт пустую строку.
Примеры:
! версия 5.7.0
mass[1]=123
$mass[1]='string'
*pl mass[1] & ! выведет число 123
*pl $mass[1] & ! выведет строку 'string'
! версия 5.8.0 и выше
mass[1]=123
$mass[1]='string' & ! затирает числовое значение
*pl mass[1] & ! попытка доступа к числовому значению вернёт 0
*pl $mass[1] & ! выведет строку 'string'
Многомерные массивы
Чтобы организовать многомерный массив, в плеерах версии 5.7.0 (и более ранних) приходилось использовать текстовые индексы. Например:
! работает в плеерах любых версий:
$unit_coords["3,1"]="Пехотинец"
$unit_coords["2,7"]="Артилерист"
$unit_coords["10,0"]="Танк"
Но в новых версиях плеера можно не использовать текстовые индексы, а указывать несколько нужных значений через запятую:
! версия 5.8.0 и выше
$unit_coords[3,1]="Пехотинец"
$unit_coords[2,7]="Артилерист"
$unit_coords[10,0]="Танк"
Это намного упрощает работу с многомерными массивами.
Изменения в работе логических операторов и функций
Все мы знаем, что QSP не поддерживает булевые (логические) типы данных, а вместо них в плеерах версии 5.7.0. использовались числа 0 и -1.
Здесь 0 означало Ложь (False), а -1 означало Правду (True). Соответственно и все логические операции возвращали нам эти значения.
Например:
! версия 5.7.0
*pl (3>2 and 4>3) & ! AND вернёт -1
*pl (3>2 or 4>3) & ! OR вернёт -1
*pl no 0 & ! NO вернёт -1
*pl (3<2 and 4>3) & ! AND вернёт 0
*pl (3<2 or 4<3) & ! OR вернёт 0
*pl no -1 & ! NO вернёт 0
В новых версиях плеера все логические операции будут возвращать 1 в случае Правды (True), и 0 в случае Лжи (False):
! версия 5.8.0 и выше
*pl (3>2 and 4>3) & ! AND вернёт 1
*pl (3>2 or 4>3) & ! OR вернёт 1
*pl no 0 & ! NO вернёт 1
*pl (3<2 and 4>3) & ! AND вернёт 0
*pl (3<2 or 4<3) & ! OR вернёт 0
*pl no -1 & ! NO вернёт 0
Соответственно и различные функции, возвращавшие “логические” значения, будут возвращать либо 1 (Правда, True), либо 0 (Ложь, False):
! версия 5.7.0
addobj "Отвёртка"
*pl obj("Отвёртка") & ! OBJ вернёт -1
*pl obj("Оттка") & ! OBJ вернёт 0
*pl isnum("123") & ! ISNUM вернёт -1
*pl isnum("12d") & ! ISNUM вернёт 0
! версия 5.8.0 и выше
addobj "Отвёртка"
*pl obj("Отвёртка") & ! OBJ вернёт 1
*pl obj("Оттка") & ! OBJ вернёт 0
*pl isnum("123") & ! ISNUM вернёт 1
*pl isnum("12d") & ! ISNUM вернёт 0
Ещё одно изменение в работе логических операций заключается в том, что теперь они на самом деле будут логическими. Да, оказывается в плеерах версий 5.7.0 и старше операции AND, OR, NO не были логическими — они были побитовыми. Это означает, что данные операции могли выполнять сравнение чисел по отдельным битам и возвращать результат этого сравнения.
Например:
! версия 5.7.0
*pl (3 and 2) & ! AND вернёт 2
*pl (4 or 6) & ! OR вернёт 6
*pl no 7 & ! NO вернёт -8
Теперь же, не имеет значения, какое число мы передаём логическому оператору. Если это число отлично от нуля, логический оператор будет воспринимать его как 1, то есть Правду (True).
! версия 5.8.0 и выше
*pl (3 and 2) & ! AND вернёт 1
*pl (4 or 6) & ! OR вернёт 1
*pl no 7 & ! NO вернёт 0
И это логично, ведь именно по такому принципу и работали операторы проверки условия if и elseif. Если этим операторам передавалось значение отличное от 0, то это означало, что условие верно (Правда, True).
! одинаково для всех версий плеера:
if 0:
*pl "условие выполнено"
else
*pl "условие не выполнено"
end
if 3:
*pl "условие выполнено"
else
*pl "условие не выполнено"
end
DISABLESUBEX больше нет
Системная переменная DISABLESUBEX была предназначена для того, чтобы отключать обработку вложенных выражений. Например, если вы хотели вывести строку, в которой присутствуют вложенные выражения, без изменений, вы могли воспользоваться данной переменной:
! в версии 5.7.0
health=100
*pl "Здоровье <<health>>" & ! выведет строку 'Здоровье 100'
disablesubex=1
*pl "Здоровье <<health>>" & ! выведет строку 'Здоровье <<health>>'
disablesubex=0
*pl "Здоровье <<health>>" & ! выведет строку 'Здоровье 100'
В плеерах более новых версий это не сработает:
! в версии 5.8.0 и выше
health=100
*pl "Здоровье <<health>>" & ! выведет строку 'Здоровье 100'
disablesubex=1
*pl "Здоровье <<health>>" & ! выведет строку 'Здоровье 100'
disablesubex=0
*pl "Здоровье <<health>>" & ! выведет строку 'Здоровье 100'
Чтобы вывести строку с подвыражениями без обработки таких вложенных выражений в новых версиях плеера, можно использовать фигурные скобки:
! одинаково работает во всех версиях плеера
health=100
*pl "Здоровье <<health>>" & ! выведет строку 'Здоровье 100'
*pl {Здоровье <<health>>} & ! выведет строку 'Здоровье <<health>>'
*pl "Здоровье <<health>>" & ! выведет строку 'Здоровье 100'
Изменения в работе неявного оператора
Неявный оператор — это оператор, который мы не указываем. В 5.7.0 он делал примерно то же, что делал и оператор *pl. То есть выводил на экран значение, добавляя после этого значения перевод строки:
! работает в плеерах любых версий
*pl 456
*pl "text"
! эквивалентно:
456 & ! здесь для вывода используется неявный оператор
"text" & ! и здесь для вывода используется неявный оператор
Если мы вызывали какую-то функцию, но она не возвращала никакого результата, неявный оператор, как и оператор *pl, выводил на экран пустую строку и добавлял к ней перевод строки:
# loc1
"Строка текста"
func('foo')
"Строка текста"
--loc1
# foo
N=R*L
--foo
Вот что мы увидим на экране в плеерах версии 5.7.0:
Строка текста
Строка текста
В новых версиях плеера, если неявный оператор не получит никакого значения от функции, он просто ничего не будет делать. Вот что мы увидим на экране в плеерах версии 5.8.0 и выше:
Строка текста
Строка текста
Неявный вызов пользовательских функций
В плеерах версии 5.7.0 и более ранних вы могли написать собственную функцию и затем вызвать её без возвращения результата, используя оператор GOSUB, или с возвращением результата, используя функцию FUNC. В плеерах версии 5.8.0 и выше эта возможность конечно же сохраняется.
Пример:
! работает во всех версиях плеера
# start
gosub 'proced' & ! вызов без возвращения результата
*pl func('foo',23,45) & ! вызов с возвращением результата
--start
# proced
act "Action":
*pl 'text'
end
--proced
# foo
result=args[0]+args[1]
--foo
Однако в плеерах версии 5.8.0 и выше вы можете использовать сокращённую запись вызова таких функций:
! работает только в 5.8.0 и выше
# start
@proced & ! вызов без возвращения результата
*pl @foo(23,45) & ! вызов с возвращением результата
--start
# proced
act "Action":
*pl 'text'
end
--proced
# foo
result=args[0]+args[1]
--foo
То есть вместо того, чтобы использовать явное указание оператора gosub или функции func, можно писать символ @, а после него без пробелов записывать название локации. Само название вызываемой таким образом локации/функции так же не должно содержать пробелов.
Если такой функции нужно передать значения, после названия локации ставим скобки и перечисляем нужные аргументы.
Новая функция ARRITEM
Функция ARRITEM возвращает значение указанной ячейки массива. Это новая функция, и введена она по большей части для того, чтобы упразднять подвыражения при использовании DYNAMIC/DYNEVAL.
Примеры:
massive[123]=256
! работает в любой версии плеера:
xvar = massive[123]
! работает только в 5.8.0 и выше:
xvar = arritem('massive',123)
Обе команды присваивают переменной xvar значение из ячейки 123 массива 'massive’, однако во втором случае мы указываем название в виде строкового значения. Таким образом мы, не прибегая к помощи DYNAMIC/DYNEVAL можем динамически формировать названия массива при получении значения.
! $stringarray[345]='text out'
$mass[0]='string'
$mass[1]='array'
*pl $arritem('$'+$mass[0]+$mass[1],345)
Так же ARRITEM позволяет получить значение из ячейки с текстовым индексом:
$mass["text index"]="text string"
*pl $arritem('$mass','text index')
KILLVAR удаляет по текстовому индексу
В плеерах версии 5.7.0 и ниже оператор KILLVAR умел удалять элементы массивов только по числовому индексу:
! работает в плеерах любых версий
$mass[0]='строка 0'
$mass[1]='строка 1'
$mass[2]='строка 2'
$mass["text index"]='строка 3'
$mass[4]='строка 4'
! удаление по числовому индексу
killvar '$mass',2
*pl $mass[2] & ! выведет на экран строку 'строка 3'
В плеерах версии 5.8.0 и выше KILLVAR умеет удалять элементы массивов не только по числовому, но и по текстовому индексу:
! работает только в 5.8.0 и выше
$mass[0]='строка 0'
$mass[1]='строка 1'
$mass[2]='строка 2'
$mass["text index"]='строка 3'
$mass[4]='строка 4'
! удаление по числовому индексу
killvar '$mass','text index'
*pl $mass[3] & ! выведет на экран строку 'строка 4'
Операторы ADDQST и KILLQST переименованы
В плеерах версии 5.7.0 (за исключением Quest Navigator) используются операторы ADDQST и KILLQST. В плеерах более новых версий (5.8.0 и выше) данные операторы заменены на INCLIB и FREELIB соответственно.
INCLIB добавляет локации из подключаемого модуля QSP к основной игре.
FREELIB удаляет все локации ранее подключённых модулей QSP из основной игры.
inclib 'module.qsp'
inclib 'drive.qsp'
inclib 'base.qsp'
freelib
Изменение в работе оператора SET
Для явного объявления переменных в QSP используется оператор SET. В плеерах версии 5.7.0 и ниже с помощью этого оператора вы могли объявить лишь одну переменную:
! работает в плеерах любых версий
set mass=45
Если требовалось объявить несколько переменных, приходилось писать несколько команд SET:
! работает в плеерах любых версий
set mass=45 & set daz=65 & set zaz=79
! эквивалентно:
mass=45 & daz=65 & zaz=79
В плеерах версии 5.8.0. и выше вы можете объявить несколько переменных одной командой:
! работает в 5.8.0 и выше:
set mass, daz, zaz = 45, 65, 79
Обратите внимание на форму записи. Здесь лишь один знак =. Переменные и их значения перечислены через запятую соответственно слева и справа от знака =.
Более того. С помощью оператора SET вы можете не только назначать переменным определённые значения, но и присваивать значения других переменных:
! работает в 5.8.0 и выше:
set a, b, c = x, y, z
В том числе и менять значения переменных местами не прибегая к помощи третьей переменной:
! работает в 5.8.0 и выше:
set j,y=y,j
Само собой, как и в плеерах версии 5.7.0, оператор SET указывать не обязательно:
! работает в 5.8.0 и выше:
mass, daz, zaz = 45, 65, 79
a, b, c = x, y, z
j,y=y,j
Новый оператор LOCAL
В плеерах версии 5.8.0 и выше, а так же в Quest Navigator появился новый оператор, который позволяет объявить указанные переменные локальными для отдельного блока кода (локации, действия, код в DYNAMIC/DYNEVAL). После того, как блок кода выполнен, значения переменных восстанавливаются к предыдущим:
# start
i=99
*pl i
gosub 'foo'
*pl i
--start
# foo
local i
i=45
*pl i
--foo
Можно объявить локальную переменную и сразу присвоить ей значение:
local i=45
Можно объявить сразу несколько локальных переменных:
! объявляем локальные переменные
local i, j, k
! объявляем локальные переменные и присваиваем им значения
local f, d, $g = 123, 45, 'string'
Обратите внимание на последнюю форму записи. Сначала мы перечисляем объявляемые переменные через запятую, затем ставим один знак =, а после него перечисляем через запятую значения, которые хотим присвоить переменным. Неправильно делать такую запись:
! Данная строчка кода вызовет ошибку "Несоответствие типов данных":
local f=123, d=45, $g='string'
Изменения в работе функций INSTR, ARRCOMP, ARRPOS
Необязательные аргументы функций INSTR, ARRCOMP и ARRPOS в плеерах 5.8.0 и выше, а так же в Quest Navigator переставлены в конец. В плеерах версии 5.7.0. и ниже эти аргументы шли в начале.
Примеры для версий плеера 5.7.0 и ниже:
! поиск подстроки в строке, начиная с 7го символа
instr(7,"В корзине 23 красных и 47 синих яблок.", "красн")
! поиск среди элементов массива элемента, который содержит число 23, начиная с 13 элемента
arrpos(13,'mass',23)
! поиск среди элементов массива элемента, который соответствует регулярному выражению, начиная с пятого элемента
arrcomp(5,'$objectbox','\S{2}\s\S{6}')
Те же самые примеры для плееров версии 5.8.0 и выше и Quest Navigatorа:
! поиск подстроки в строке, начиная с 7го символа
instr("В корзине 23 красных и 47 синих яблок.", "красн",7)
! поиск среди элементов массива элемента, который содержит число 23, начиная с 13 элемента
arrpos('mass',23,13)
! поиск среди элементов массива элемента, который соответствует регулярному выражению, начиная с пятого элемента
arrcomp('$objectbox','\S{2}\s\S{6}',5)
Новый оператор цикла LOOP
В плеерах версий 5.7.0 и старше, для организации циклов приходилось использовать метки. Начиная с версии 5.8.0. у нас появляется отдельный оператор циклов LOOP. Вот как он записывается в общем виде:
! многострочная форма:
LOOP [команды 1] WHILE [условие] STEP [команды 2]:
[команды 3]
END
! однострочная форма:
LOOP [команды 1] WHILE [условие] STEP [команды 2]: [команды 3]
Здесь, как вы видите, есть целых три ключевых слова:
-
LOOP— это ключевое слово объявляет, что начинается цикл, оно обязательно. ПослеLOOPмогут идти некоторые однострочные операторы. Например, здесь мы можем объявить локальные переменные, которые будут считаться локальными только для данного цикла. -
WHILE— после этого ключевого слова должно стоять условие, и пока выполняется это условие, цикл тоже будет выполняться. -
STEP— это ключевое слово не является обязательным, однако оно удобно, чтобы перечислить однострочные операторы, не относящиеся напрямую к телу цикла. Например, здесь можно указать изменение счётчика.
Непосредственно тело цикла, то есть его основные команды пишутся после двоеточия. Для однострочной формы — в той же строке, что и loop, а для многострочной формы — в последующих строках сразу после двоеточия. Многострочную форму необходимо завершать ключевым словом END.
Несколько примеров:
! выведет на экран таблицу умножения на 12
loop local i=1 while i<11 step i+=1:
*pl "12 * <<i>> = <<12*i>>"
end
! поиск всех позиций элементов массива, содержащих число 3
loop local i,pos,true=0,-1,1 while true:
pos=arrpos('mass',3,pos+1)
if (pos<>-1 and i<>pos) or pos=0:
i=pos
*pl "mass[<<pos>>] = 3"
else
true=0
end
end
! нарезаем неповторяющиеся символы из строки
$string='long long long string'
loop while len($string)>0:
$a=$mid($string,1,1)
if arrpos('$letters',$a)=-1:
$letters[]=$a
end
if len($string)>1:
$string=$mid($string,2)
else
$string=''
end
end
*pl
! выводим на экран
loop local i,s=0,arrsize('$letters') while i<s step i+=1:
*p $letters[i]+", "
end
Изменения в чтении длинных строк, разбитых на несколько
Для того, чтобы разбивать длинные строки на несколько (для удобства чтения) в QSP используется сочетание символов " _" (пробел и символ нижнего подчёркивания). В плеерах версии 5.7.0 и ниже (кроме Quest Navigator 0.0.28) при разборе данной конструкции движок оставлял строки, как есть. Для примера возьмём такую конструкцию:
if t _
or _
t:
В плеерах версии 5.7.0 символы преформатирования будут исключены, при интерпретации, а строка, разбитая с помощью " _" будет объединена, как есть, то есть будет равнозначна строке:
if tort:
В плеерах же версии 5.8.0 и выше данная строка будет объединена с добавлением пробела вместо каждого сочетания " _", то есть будет равнозначна строке:
if t or t:
Данное отличие в прочтении строк используется, как костыль, чтобы отличить классический плеер версии 5.7.0 от Quest Navigator версии 0.0.28:
t=1
tort=0
if t _
or _
t:
"Игра запущена на Quest Navigator"
else
"Игра запущена на Классике"
end
Изменения в работе функции RAND
В плеерах версии 5.7.0 и ниже второй параметр функции RAND по умолчанию был 0. Например, если вы указывали число 100 в качестве аргумента функции RAND, то эта функция возвращала случайное число от 0 до 100. В плеерах версии 5.8.0 и выше, а так же в Quest Navigator, второй параметр по умолчанию равен 1. То есть если вы укажете лишь одно число, например 100, функция RAND вернёт случайное значение от 1 до 100.
RAND(100) & ! в 5.7.0 вернёт значение от 0 до 100
RAND(100) & ! в 5.8.0 вернёт значение от 1 до 100
RAND(10) & ! в 5.7.0 вернёт значение от 0 до 10
RAND(10) & ! в 5.8.0 вернёт значение от 1 до 10
RAND(5) & ! в 5.7.0 вернёт значение от 0 до 5
RAND(5) & ! в 5.8.0 вернёт значение от 1 до 5
RAND(0) & ! в 5.7.0 вернёт значение 0
RAND(0) & ! в 5.8.0 вернёт значение от 1 до 0
RAND(1) & ! в 5.7.0 вернёт значение от 0 до 1
RAND(1) & ! в 5.8.0 вернёт значение 1
Повышение приоритета функций LOC и OBJ
В плеерах версии 5.7.0 (и ниже) у функций LOC и OBJ приоритет был ниже, чем у операций сравнения. Это могло быть неочевидным для выражений такого рода:
(obj 'Отвёртка'=obj 'Верёвка')
Кажется, что данное выражение должно выполняться так: проверяется наличие предмета “Отвёртка”, проверяется наличие предмета “Верёвка”, и лишь потом значения сравниваются. Однако в 5.7.0 у операции сравнения приоритет выше, чем у OBJ. Поэтому сначала выполняется операция сранения, и лишь потом функция OBJ. Таким образом в плеерах версии 5.7.0 данное выражение всегда возвращает 0.
В плеерах версии 5.8.0 (и выше) приоритет у функций OBJ и LOC выше, чем у операций сравнения, поэтому данное выражение будет вычисляться именно так, как мы предположили: сначала проверяется наличие обоих предметов и лишь потом сравниваются полученные значения. В плеерах 5.8.0 (и выше) данное выражение будет возвращать 1, если оба предмета или отсутствуют, или присутствуют, и 0, если одни предмет присутствует, а другой отсутствует.
Больше аргументов для функций
В плеерах версии 5.7.0 (и ниже) максимальное число аргументов, которое вы могли передавать операторам и функциям, было 10. Таким образом, например функции MAX и MIN могли производить поиск значений лишь среди десяти значений. В плеерах версии 5.8.0 и выше максимальное число аргументов, передаваемых функциям и операторам, — 20.
! работает в плеерах любых версий
max('a','b','c','d','e','f','g','h','i','j')
! работает лишь в плеерах версии 5.8.0 и выше
max('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t')