Статьи по разработке игр на QSP

Что нового в QSP

Пока готовится выход нового плеера версии 5.8.0 (или выше), мы решили рассказать о грядущих нововведениях. Всё (или почти всё), что будет представлено в этой статье, вы уже можете пощупать в плеере "qSpider" от Werewolf`а.

Изменение в работе массивов

Это, пожалуй, самое основное из грядущих изменений, и о нём мы подробно писали в статье "Массивы уже не те". Здесь же изложим кратко.

Теперь в массиве будет нельзя под одним индексом хранить и текстовое и числовое значение. Если вы запишете в ячейку числовое значение, а потом запишете в ту же ячейку текстовое значение, текстовое значение затрёт числовое.

При этом, если вы попытаетесь получить из ячейки со строковым значением числовое значение, плеер вернёт значение по-умолчанию, то есть 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 и выше) можно не использовать текстовые индексы, а указывать несколько нужных значений через запятую:

! версия 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

Аргументы, передаваемые с операторами GOTO и XGOTO

Теперь аргументы (параметры, данные), передаваемые с операторами GOTO и XGOTO, и которые мы можем получить из массива ARGS на локации, однозначно можно будет использовать в действиях, созданных на этой локации.

Раньше это тоже можно было делать, однако в плеере присутствовал досадный баг, который периодически ломал всё это дело. Этот баг исправили, и теперь всё прекрасно работает:

# локация_1
goto "локация_2","текст"
--локация_1


# локация_2

act "Действие":
    *pl $args[0]
end
--локация_2

Обратите внимание, ARGS ведёт себя на текущей локации, как обычный глобальный массив. Т.е., если вы изменяете значения ARGS в одном из действий, эти же значения будут использоваться в других действиях.

# локация_1
goto "локация_2","из аргументов"
--локация_1


# локация_2

act "Действие - 1":
    *pl $args[0]
    $args[0]="Из действия 1"
end
act "Действие - 2":
    *pl $args[0]
    $args[0]="Из действия 2"
end
--локация_2

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<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')

Старые новости, о которых вы могли не знать

Здесь мы осветим пару изменений, которые появились в плеере версии 5.7.0 (или раньше), но которые прошли не очень заметно.

Игнорирование отрицательных индексов

В плеерах версий ниже 5.6.5 отрицательные индексы приводились к нулю, а в плеерах более новых версий, они просто напросто игнорируются:

! версии ниже 5.6.5
mass[0]=123
*pl mass[-1]    ! на экране увидим 123
mass[-1]=456
*pl mass[0]        ! на экране увидим 456
! версии 5.6.5 и выше
mass[0]=123
*pl mass[-1]    ! на экране увидим 0
mass[-1]=456
*pl mass[0]        ! на экране увидим 123

Добавление предмета в определённую позицию

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

! версии 5.6.5 и выше
addobj 'Отвёртка','путь к файлу картинки/картинка.png',4

Индексация предметов в списке начинается с единицы. Можно указать индекс численно больший на один, чем число предметов, тогда предмет добавится в конец списка. Однако, если указать индекс числом больше числа предметов плюс один, или индекс меньше единицы, команда addobj будет проигнорирована:

! версии 5.6.5 и выше
addobj 'Первый предмет'
addobj 'Второй предмет'
addobj 'Третий предмет'
addobj 'Четвёртый предмет'
addobj 'Пятый предмет','',5 ! предмет будет добавлен в конец списка
addobj 'Седьмой предмет','',7 ! предмет не будет добавлен
addobj 'Нулевой предмет','',0 ! предмет не будет добавлен

Копирование части массива в COPYARR

Начиная с версии 5.7.0 вы можете копировать часть массива в другой массив, используя не обязательные параметры: начальный индекс и количество. В следующем примере в массив 'mass' будут скопированы шесть элементов массива 'array', начиная с третьего:

! версии 5.7.0 и выше
copyarr 'mass','array',3,6

Передача аргументов в ONNEWLOC

Начиная с версии 5.7.0 аргументы, которые передаются на локацию при переходе на эту локацию с помощью операторов GOTO или XGOTO, передаются так же и на локацию-обработчик перехода на новую локацию (прописанную в переменной $ONNEWLOC). При этом, даже если значения в массиве args будут изменены на локации, на которую был осуществлён переход, на локацию, прописанную в переменной $ONNEWLOC, будут переданы исходные значения, переданные с GOTO/XGOTO.

# start
$onnewloc='onNewLoc'
goto 'next','old text',345
--start


# next

''
'next:'
! значения, переданные с GOTO
*pl $args[0]
*pl args[1]
! меняем значения на текущей локации
args[1]=678
$args[0]='new text'
! изменённые значения
*pl $args[0]
*pl args[1]
--next


# onNewLoc

''
'onNewLoc:'
! значения, переданные с GOTO
*pl $args[0]
*pl args[1]
--onNewLoc

Что ещё?

Плеер продолжает развиваться и совершенствоваться, а значит мы можем ждать ещё много изменений в работе, которые непременно будут отражены в новых статьях, а так же в онлайн-справке wiki.qsp.org.

P.S.:

Данную статью вы можете найти так же и на других ресурсах: