diff --git a/blog/2024-08-15-docs-add-chapters-of-keywords-etc.md b/blog/2024-08-15-docs-add-chapters-of-keywords-etc.md index 9649fc3..bc29fed 100644 --- a/blog/2024-08-15-docs-add-chapters-of-keywords-etc.md +++ b/blog/2024-08-15-docs-add-chapters-of-keywords-etc.md @@ -11,7 +11,7 @@ tags: Поскольку этот раздел был практически полностью написан мной в другом проекте, я решил слегка его отредактировать и перенести сюда. -[Это раздел](../../../../docs/language/qsp-keywords/), в котором собраны все операторы, функции, системные переменные, а так же спецсимволы и синтаксемы языка QSP. +[Это раздел](/docs/language/qsp-keywords/), в котором собраны все операторы, функции, системные переменные, а так же спецсимволы и синтаксемы языка QSP. :::warning[Важно помнить:] Раздел охватывает полностью ключевые слова и т.д. для версий плееров 5.8.0, и частично затрагивает плееры версии 5.9.0. А значит, в будущем требует дополнения. diff --git a/docs/language/qsp-keywords/_category_.yml b/docs/language/qsp-keywords/_category_.yml deleted file mode 100644 index 438662f..0000000 --- a/docs/language/qsp-keywords/_category_.yml +++ /dev/null @@ -1,2 +0,0 @@ -position: 99 -label: Зарезервированные слова, системные переменные, спецсимволы diff --git a/docs/language/qsp-keywords/index.md b/docs/language/qsp-keywords/index.md index 45ec8ce..df32c34 100644 --- a/docs/language/qsp-keywords/index.md +++ b/docs/language/qsp-keywords/index.md @@ -1,4 +1,5 @@ --- +title: Зарезервированные слова, системные переменные, спецсимволы sidebar_position: 6 --- diff --git a/docs/language/qsp-keywords/qsp-keyword-functions.md b/docs/language/qsp-keywords/qsp-keyword-functions.md index d56feb0..a14842a 100644 --- a/docs/language/qsp-keywords/qsp-keyword-functions.md +++ b/docs/language/qsp-keywords/qsp-keyword-functions.md @@ -183,14 +183,14 @@ func('возвести_в_степень', 3, 3) Другие примеры: ```qsp -!Обработка локации "функция" как функции. +!Обработка локации "функция" как функции. !Массив ARGS пуст. яблоки = FUNC('функция') - + !обработка локации с названием лежащим в переменной $name как функции. ARGS[0] равен 1. pl func($name, 1) * 78 - -!обработка локации с названием в $name как функции. + +!обработка локации с названием в $name как функции. !$ARGS[0] содержит строку "строка", ARGS[1] равен 2. msg "text" + func($name, "строка", 2) ``` @@ -301,7 +301,7 @@ $name = $input('Как звать тебя, герой?') Другие примеры: ```qsp -! Вопрос с одним правильным ответом. +! Вопрос с одним правильным ответом. if $input('Что приходит после тьмы?') = 'свет': msg 'Все верно.' else @@ -667,7 +667,7 @@ $strfind('идти к пещере', '\b\w{4}\b') &! на экране увид ``` ```qsp title="Выборка с вложенными группами" -$strfind('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)', 1) &! на экране увидим '671' +$strfind('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)', 1) &! на экране увидим '671' $strfind('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)', 2) &! на экране увидим '-190-23-999' $strfind('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)', 3) &! на экране увидим '-999' ``` @@ -785,8 +785,8 @@ arrcomp('$A', 'This', 0) arrcomp('$A', 'abc\d+', 2) ! аналогично предыдущему примеру, ! но поиск осуществляется по всем элементам массива -arrcomp('$A', '.*string.*', 0) - +arrcomp('$A', '.*string.*', 0) + arrcomp('$A', 'This') & ! эквивалентно 1му варианту ``` @@ -945,13 +945,13 @@ ARRTYPE([$имя_массива], [индекс]) ```qsp $ddd = 'text' arrtype('ddd') & ! '$' - + $g = 'text' & g = 13 arrtype('g') & ! '#' - + %tuple['index'] = [12, 'string'] arrtype('tuple', 'index') & ! '%' - + ! $empty not exist arrtype('$empty') & ! '' ``` @@ -1098,7 +1098,7 @@ if i < 100000: end new_time = msecscount pl "Скорость работы старого цикла: " + $str(new_time - old_time) - + old_time = msecscount loop i = 0 while i < 100000 step i += 1: b[i] = i diff --git a/docs/language/qsp-keywords/qsp-keyword-operacion.md b/docs/language/qsp-keywords/qsp-keyword-operacion.md index cad7517..98bce6d 100644 --- a/docs/language/qsp-keywords/qsp-keyword-operacion.md +++ b/docs/language/qsp-keywords/qsp-keyword-operacion.md @@ -149,7 +149,7 @@ sidebar_position: 1 %tuple = [4, 10, 16] %a = %tuple * 2 ! %a будет равно [8, 20, 32] - + [4, 10] * 'b' & ! ошибка о несоответствии типов данных ``` @@ -352,7 +352,7 @@ number += [4,5] & ! ошибка о несоответствии типов да %tuple = [4, 10, 16] %a = %tuple - 2 ! %a будет равно [2, 8, 14] - + [4, 10] - 'b' & ! ошибка о несоответствии типов данных ``` @@ -494,7 +494,7 @@ number -= [4,5] & ! ошибка о несоответствии типов да %tuple = [4, 10, 16] %a = %tuple / 2 ! %a будет равно [2, 5, 8] - + [4, 10] / 'b' & ! ошибка о несоответствии типов данных ``` @@ -1231,7 +1231,7 @@ elseif obj("Пустой кувшин") = 1: addobj "Полный кувшин" delobj "Пустой квушин" goto $curloc - end + end end ``` @@ -1253,7 +1253,7 @@ end ! одна часть выражения верна, значит всё выражение верно (2 <> 2) or (3 <> 2) & ! выражение вернёт 1 (правда) ! обе части выражения не верны, значит и всё выражение не верно -(2 <> 2) or (3 = 2) & ! выражение вернёт 0 (ложь) +(2 <> 2) or (3 = 2) & ! выражение вернёт 0 (ложь) ``` :::note[5.7.0] diff --git a/docs/language/qsp-keywords/qsp-keyword-operators.md b/docs/language/qsp-keywords/qsp-keyword-operators.md index cf022b3..e2ceed4 100644 --- a/docs/language/qsp-keywords/qsp-keyword-operators.md +++ b/docs/language/qsp-keywords/qsp-keyword-operators.md @@ -93,7 +93,7 @@ end ```qsp ! строка до кавычек " текст внутри кавычек может переходить на другие строки " а так же { -можно использовать другие группы символов, чтобы +можно использовать другие группы символов, чтобы продолжать многострочный комментарий } и комментарий не кончится, пока не кончится строка ``` @@ -426,7 +426,7 @@ $code = ' *pl "<<$args[0]>>" *pl $args[0] ' - + dynamic $code, 'asdfg' ``` @@ -504,8 +504,8 @@ gosub 'ход' !Передаётся один параметр - args[0] равен 1. gosub $location,1 -!обработка локации "ход" с передачей 3-х параметров. -! $args[0] = $var (значению), args[1] = 2, +!обработка локации "ход" с передачей 3-х параметров. +! $args[0] = $var (значению), args[1] = 2, ! $args[2] = "данные". Обратите внимание на символы '$'. gosub 'ход',$var,2,'данные' ``` @@ -657,8 +657,8 @@ end &! ключевое слово end - просто игнорируется ```qsp if a+b<3 or y=8: p 'A+B<3 или Y=8' - nl - if j=88: nl & p 'NEXT' + nl + if j=88: nl & p 'NEXT' if $h='ooo': p 'loo' & jump 'lll' end @@ -711,7 +711,7 @@ if abcd=3: k1=34 else k1=25 end ```qsp ! однострочная форма записи IF [#выражение]: {команда д1} & {команда д2} & ... ELSE {команда н1} & {команда н2} & ... - + ! в многострочном IF: ! многострочная форма ELSE @@ -819,8 +819,8 @@ ELSE {последний набор команд} ... END - -! однострочная в многострочном условии + +! однострочная в многострочном условии IF [#выражение 1]: {набор команд 1} ... @@ -835,7 +835,7 @@ END Особенности записи `ELSEIF`: - Может использоваться вариант написания `ELSE IF`. Работает точно так же. -- Если в многострочной конструкции `IF` после `ELSEIF` операторы идут в той же самой строке (однострочная форма), то все последующие строки игнорируются до следующего `ELSEIF`, либо до `ELSE` или `END`. +- Если в многострочной конструкции `IF` после `ELSEIF` операторы идут в той же самой строке (однострочная форма), то все последующие строки игнорируются до следующего `ELSEIF`, либо до `ELSE` или `END`. - В конструкции `IF` c `ELSEIF` может как присутствовать, так и отсутствовать часть с `ELSE`. Примеры: @@ -850,7 +850,7 @@ ELSEIF ОЧКИ>99: ELSE GOTO 'КОН5' END - + if money mod 10=1 and money mod 100<>11: *pl "У вас <> монета." elseif money mod 10>1 and money mod 10<5 and (money mod 100<5 or money mod 100>20): @@ -1133,7 +1133,7 @@ i = 99 & ! объявляем глобальную переменную gosub 'foo' *nl i & ! на экране увидим число 99 --- start --- - + # foo ! на этой локации объявляем локальную переменную local i = 0 @@ -1146,7 +1146,7 @@ loop while i < 10 step i += 1: end *nl i & ! на экране увидим число 10 --- foo --- - + # undo ! в эту локацию из цикла с локации foo ! транслируется всё та же локальная переменная @@ -1179,7 +1179,7 @@ if i = 0: i = 99 & ! значение переменной i задаётся л *pl "Глобальное i = <>" act "На локацию 2": goto 'локация 2' --- локация 1 --- - + # локация 2 *pl "Глобальное i = <>" local i = 137 & ! значение переменной i задаётся лишь раз @@ -1324,7 +1324,7 @@ menu '%stone' %usr_menu[2] = ['Уничтожить предмет','del_item', $icon_file] ! пункт меню задан 3-мя переменными %usr_menu[3] = [$name, $location, $icon_file] - + menu 'usr_menu' &! покажет меню из 4-х пунктов ``` @@ -1421,7 +1421,7 @@ $usr_menu[1] = 'Положить предмет:put_item:images/put_item.gif' $usr_menu[2] = 'Осмотреть предмет:look_item:<<$icon_file>>' ! пункт меню задан 3-мя переменными $usr_menu[3] = '<<$name>>:<<$location>>:<<$file>>' - + menu 'usr_menu' &! покажет меню из 4-х пунктов ``` @@ -1647,12 +1647,12 @@ SCANSTR [$имя_массива], [$текст_для_разбора], [$рег $text = 'Шла Саша по шоссе, а Грека через реку.' scanstr '$words', $text, '\b\w+\b' !В массиве $words окажутся значения: 'Шла', 'Саша', 'по', 'шоссе', 'а', 'Грека', 'через', 'реку' - + ! разбиваем строку по разделителю: $text = 'утро|день|вечер|ночь' scanstr '$words', $text, '[^|]+' !В массиве $words окажутся значения: 'утро', 'день', 'вечер', 'ночь' - + ! вытаскиваем из строки все слова, помещённые в квадратные скобки, но без квадратных скобок: $text = '[first] ignoredtext [second][third] also ignored' scanstr '$words', $text, '\[(.*?)\]', 1 diff --git a/docs/language/qsp-keywords/qsp-keyword-syntaxems.md b/docs/language/qsp-keywords/qsp-keyword-syntaxems.md index 58bbaa4..469dd47 100644 --- a/docs/language/qsp-keywords/qsp-keyword-syntaxems.md +++ b/docs/language/qsp-keywords/qsp-keyword-syntaxems.md @@ -417,9 +417,9 @@ health = 150 ```qsp !обработка локации "ход". Массив args[] пуст. @ход() - -!обработка локации "ход" с передачей 3-х параметров. -! $args[0] = $var (значению), args[1] = 2, + +!обработка локации "ход" с передачей 3-х параметров. +! $args[0] = $var (значению), args[1] = 2, ! $args[2] = "данные". Обратите внимание на символы '$'. @ход($var, 2, 'данные') ``` diff --git a/docs/syntax-highlighting.md b/docs/syntax-highlighting.md index ac862f1..13c2fc0 100644 --- a/docs/syntax-highlighting.md +++ b/docs/syntax-highlighting.md @@ -15,9 +15,9 @@ VS Code есть два способа подсветки: ### Готовые решения {#vscode-text-solutions} -* TextMate формат - * `glife/src/master/tools/syntax/VSCode/qsrc/syntaxes/QSP.tmLanguage.json` - * [LangQSP от некого slanon](https://git.tfgames.site/slanon/LangQSP/src/master/qsrc/syntaxes/QSP.tmLanguage.json) +* TextMate Формат + * `glife/tools/syntax/VSCode/qsrc/syntaxes/QSP.tmLanguage.json` + * [Формат TextMate от некого Xorgroth](https://gitlab.com/kevinsmartstfg/girl-life/-/raw/master/tools/syntax/VSCode/qsrc/syntaxes/QSP.tmLanguage.json) * семантическая подсветка * Связка `Qsp.FSharp.Parser`, `Qsp.FSharp.ServerLanguage` и `Qsp.FSharp.VsCode` diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 172e7f0..0ade03b 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -26,8 +26,20 @@ const config: Config = { // useful metadata like html lang. For example, if your site is Chinese, you // may want to replace "en" with "zh-Hans". i18n: { - defaultLocale: 'en', - locales: ['en'], + defaultLocale: 'ru', + locales: ['ru', 'en'], + localeConfigs: { + ru: { + label: 'Русский', + direction: 'ltr', + htmlLang: 'ru-RU', + }, + en: { + label: 'English', + direction: 'ltr', + htmlLang: 'en-US', + }, + }, }, presets: [ @@ -82,7 +94,11 @@ const config: Config = { position: 'left', label: 'Docs', }, - {to: '/blog', label: 'Blog', position: 'left'}, + { to: '/blog', label: 'Blog', position: 'left' }, + { + type: 'localeDropdown', + position: 'right', + }, { href: 'https://github.com/QSPFoundation/qspfoundation.github.io', label: 'GitHub', diff --git a/i18n/en/docusaurus-plugin-content-docs/current/all-together.md b/i18n/en/docusaurus-plugin-content-docs/current/all-together.md new file mode 100644 index 0000000..29d13d3 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/all-together.md @@ -0,0 +1,138 @@ +# All Together + +This section briefly outlines various thorny paths from starting QSP game development (using various tools and instruments) to implementing and launching the game for the end player. + +## Writing Games + +```mermaid +graph TD + GameDev[Game Developer] --> |writes game in| Editor + + Editor --> |can be| QGen[QGen] + QGen --> |compiles| BinaryFile[Binary game file .qsp] + + Editor --> |can be| VSCode[VS Code] + VSCode --> |edits and checks code| Qsp.FSharp.VsCode[Qsp.FSharp.VsCode] + + VSCode --> |generates| RawSource + + Editor --> |can be| AnyTextEditor[Any text editor] + AnyTextEditor --> |generates| RawSource[Raw source files .qsps .qsrc] + + Editor --> |can be| Sublime[Sublime Text] + Sublime --> |generates| RawSource + Sublime --> |edits and checks code| JAD_for_QSP[JAD_for_QSP] + + RawSource --> QSP_CLI[qsp-cli] + QSP_CLI --> |compiles| BinaryFile + RawSource --> TXT2GAM[TXT2GAM] + TXT2GAM --> |compiles| BinaryFile + + RawSource --> QSPGame[QSP Game] + BinaryFile --> QSPGame +``` + +QSP game developers write games in: + +* QGen +* Editors + * Sublime Text + * VS Code + * Any text editor + +If using Sublime Text, the JAD_for_QSP extension is used for code checking. + +If using VS Code, the Qsp.FSharp.VsCode extension is used when writing code. + +QGen converts source code into a binary game file. + +Raw source files written in editors are either left as-is or converted to binary using one of the utilities: + +* QSP CLI +* TXT2GAM + +Some utilities allow converting binary game files back to text format. + +## Playing Games + +```mermaid +flowchart TD + QSPGame --> RawSource + RawSource --> |played in| Player + QSPGame --> BinaryFile + BinaryFile --> |played in| Player + + Player --> |can be| Classic[Classic] + Classic --> |interprets game code in| QSPLib[QSPLib] + + Player --> |can be| Navigator[Navigator] + Navigator --> |interprets game code in| QSPLib + + Player --> |can be| QSpider[QSpider] + QSpider --> |uses| qsp-wasm-engine + qsp-wasm-engine --> |interprets game code in| QSPLib +``` + +Raw source files or binaries are played in players: + +* Classic +* Navigator +* QSpider + +Classic and Navigator use the QSPLib interpreter. + +QSpider uses qsp-wasm-engine, which is a wrapper around the QSPLib interpreter. + +## Game Distribution + +```mermaid +flowchart TD + QSPGame --> QSPCatalog[Catalog on https://qsp.org/] + QSPGame --> |wrapped in| QSpiderStandalone[QSpider Standalone] + QSpiderStandalone --> |published on| GitHubPages + QSpiderStandalone --> |published on| ItchIo[itch.io] +``` + +Later, the game developer publishes game resources to: + +* QSP catalog +* GitHub Pages using QSpider Standalone + +Now the player can: + +* Download the game from the [QSP catalog](https://qsp.org/index.php?option=com_sobi2&Itemid=55) and play it in players +* Launch the game with [QSpider](https://dev.qsp.org/qspider) + + There you can either: + + * Open a .qsp file from your device + * Add a game from the library and run it + * Run a game via direct link + + * Game from catalog + + If you know the game ID (for example, 285 — "Ballad of the Hero"), you can run it like this: + + ```text + https://qspfoundation.github.io/qspider/?catalogId=285 + ``` + + * From a separate source + + For example, there's a game "Ballad of the Hero" located at the following link: + + ```text + https://aleksversus.github.io/QSP-storage/game/heroballad/heroballad.qsp + ``` + + This link can be loaded into QSpider: + + ```text + https://qspfoundation.github.io/qspider/?config=https://aleksversus.github.io/QSP-storage/game/heroballad/heroballad.qsp + ``` + + And [go to it](https://qspfoundation.github.io/qspider/?config=https://aleksversus.github.io/QSP-storage/game/heroballad/heroballad.qsp) + +* Go to a link on GitHub, itch.io, etc., and just start playing + +The best option to make life easier for both the game developer and player is to upload the game to a website and give the player a direct link to the game. This way you can avoid +100500 problems. \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/co-development/branches.png b/i18n/en/docusaurus-plugin-content-docs/current/co-development/branches.png new file mode 100644 index 0000000..6e8fd12 Binary files /dev/null and b/i18n/en/docusaurus-plugin-content-docs/current/co-development/branches.png differ diff --git a/i18n/en/docusaurus-plugin-content-docs/current/co-development/create-pull-request.png b/i18n/en/docusaurus-plugin-content-docs/current/co-development/create-pull-request.png new file mode 100644 index 0000000..555a204 Binary files /dev/null and b/i18n/en/docusaurus-plugin-content-docs/current/co-development/create-pull-request.png differ diff --git a/i18n/en/docusaurus-plugin-content-docs/current/co-development/index.md b/i18n/en/docusaurus-plugin-content-docs/current/co-development/index.md new file mode 100644 index 0000000..08024c3 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/co-development/index.md @@ -0,0 +1,161 @@ +# Collaborative Development + +The main purpose of collaborative development is to avoid stepping on each other's toes. To achieve this, we need to follow some rules: + +* We coordinate in [#qsp_platform_dev](https://discord.com/channels/373163463842725891/749965798038306866) ([IF Discord invitation](https://discord.gg/bbbdxhE9M2)) about what we're going to write +* We don't touch the `main` branch at all +* We create and use our own branches +* We merge all branches through pull requests +* We delete our branches when they're no longer needed + +## Example + +For instance, someone decided to write about syntax highlighting. To do this, they need to: + +* Set up the development environment: + * Clone the repository: + + ```bash + git clone https://github.com/QSPFoundation/qspfoundation.github.io.git + ``` + + * Go to the repository folder and install packages: + + ```bash + cd qspfoundation.github.io + npm install + ``` + + * Start the live server: + + ```bash + npm run start + ``` + + * Open the link in a browser + + Now the documentation page in the browser will automatically update with every change made. + +* Create a `syntax-highlight` branch + + ```bash + git checkout -b syntax-highlight + ``` + + You can do this through your editor tools — doesn't matter. + +* Create a file `docs/syntax-highlighting.md` and start writing the article in it +* Add the file to git and commit: + + ```bash + git add docs/syntax-highlighting.md + git commit -m "wip: I was too lazy to give it a proper name" + ``` + + You can give a meaningful message, but it doesn't always work out that way, so this is fine too. More about meaningfulness below. + +* Push the branch to GitHub: + + ```bash + git push -u origin syntax-highlight + ``` + + That's it, now the branch is there. We don't touch other people's branches, or we'll get confused. + +* Continue writing the article in `docs/syntax-highlighting.md` +* Add the file changes to git and commit: + + ```bash + git add . + git commit -m "wip: finally finished writing the article!" + ``` + +* Push: + + ```bash + git push + ``` + +* Create a pull request from this branch through GitHub: + + * Go to the creation page using one of two methods: + * Through the main repository page: + + ![create-pull-request](./create-pull-request.png) + + * Through branches + * Click on [branches](https://github.com/QSPFoundation/qspfoundation.github.io/branches) + + ![branches](./branches.png) + * Select the branch you're interested in, click on `...` and in the dropdown menu select "New Pull Request" + + ![select-and-pull-request.png](./select-and-pull-request.png) + + * Give the pull request a meaningful name in the "Add a title" field + + By meaningful name, we mean something like: + + ```bash + docs: write the syntax highlighting article + ``` + + The repository uses a [common commit naming convention](https://www.conventionalcommits.org/en/v1.0.0/). + +* As soon as the pull request is created, tests will run (they are defined in `.github/workflows/test-deploy.yml`). They will check if everything is in order with your changes + +* Let people know in the IF Discord, so someone can approve your Pull Request, and wait + +Once your Pull Request is approved, your branch will merge with the `main` branch, deployment will automatically start (this is configured in `.github/workflows/deploy.yml`), and after some time you'll be able to see the changes on the documentation site. + +After the branch is merged, it becomes unnecessary and should be deleted so it doesn't get in the way: + +* Delete the branch from GitHub: + + ```bash + git push -d origin syntax-highlighting + ``` + +* Delete the branch on your computer: + + ```bash + git branch -d syntax-highlighting + ``` + +* Delete all local branches that no longer exist on GitHub: + + ```bash + git fetch -p && git branch -vv | awk '/: \w+]/{print $1}' | xargs git branch -d --force + ``` + +## Pull Request Approval + +If you have the rights, you can approve a Pull Request in three ways: + +* `squash` — all commits from your branch are combined into one commit (*if you're not sure, use this method*) + + This is needed to turn this stream of consciousness: + + ```text + wip: I was too lazy to give it a proper name + wip: finally finished writing the article! + ``` + + Into one meaningful commit: + + ```bash + docs: write syntax highlighting article + ``` + +* `rebase` — this merges new commits into `main` + + Can be used if you have meaningful commits, like: + + ```text + docs(syntax-highlighting): start writing an article + docs(syntax-highlighting): write short description of what syntax highlighting is + ... + ``` + + Then it's not embarrassing to put all this directly into `main` in this form. + +* something else that merges the branch through a commit. I forgot what it's called \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/co-development/pull-request-creation-form.png b/i18n/en/docusaurus-plugin-content-docs/current/co-development/pull-request-creation-form.png new file mode 100644 index 0000000..1724a86 Binary files /dev/null and b/i18n/en/docusaurus-plugin-content-docs/current/co-development/pull-request-creation-form.png differ diff --git a/i18n/en/docusaurus-plugin-content-docs/current/co-development/select-and-pull-request.png b/i18n/en/docusaurus-plugin-content-docs/current/co-development/select-and-pull-request.png new file mode 100644 index 0000000..4cef3a1 Binary files /dev/null and b/i18n/en/docusaurus-plugin-content-docs/current/co-development/select-and-pull-request.png differ diff --git a/i18n/en/docusaurus-plugin-content-docs/current/intro.md b/i18n/en/docusaurus-plugin-content-docs/current/intro.md new file mode 100644 index 0000000..913c7a9 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/intro.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 1 +--- + +# QSP Foundation + +QSP Foundation is the QSP ecosystem, that is, everything we know about the [language](./language/), its [parsers](./parsers/index.md), interpreters and compilers, players, development environments, and useful tools. \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/language/index.md b/i18n/en/docusaurus-plugin-content-docs/current/language/index.md new file mode 100644 index 0000000..824b5e3 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/language/index.md @@ -0,0 +1,6 @@ +--- +sidebar_position: 1 +--- + + +# QSP Language diff --git a/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/index.md b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/index.md new file mode 100644 index 0000000..5c3aad1 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/index.md @@ -0,0 +1,183 @@ +--- +title: Reserved Words, System Variables, Special Characters +sidebar_position: 6 +--- + +# Index + +:::warning[Attention!] +Crossed out commands do not work in players version 5.8.0 and above. +::: + +- [Implicit operator](qsp-keyword-operators#implicit-operator) +- [`!` (comment)](qsp-keyword-operators.md#-comment) +- [`!` (not equal)](qsp-keyword-operacion.md#-not-equal-1) +- [`&` (concatenation)](qsp-keyword-operacion.md#-concatenation) +- [`&` (command enumeration)](qsp-keyword-syntaxems.md#ampersand-) +- [`:` (labels)](qsp-keyword-syntaxems.md#labels-) +- [`,` (argument separator)](qsp-keyword-syntaxems.md#comma-) +- [`""` (quotes)](qsp-keyword-syntaxems.md#quote-) +- [`''` (apostrophes)](qsp-keyword-syntaxems.md#apostrophe-) +- [`{}` (Curly braces)](qsp-keyword-syntaxems.md#curly-braces-) +- [`()` (round brackets)](qsp-keyword-syntaxems.md#round-brackets-) +- [`[]` (square brackets)](qsp-keyword-syntaxems.md#square-brackets-) +- [`@` (commercial "at")](qsp-keyword-syntaxems#commercial-at-symbol-) - 5.8.0 +- [`$` (dollar sign)](qsp-keyword-syntaxems#dollar-sign-symbol-) +- [`%` (percent sign)](qsp-keyword-syntaxems#percent-sign-symbol-) - 5.9.0 +- [`*`](qsp-keyword-operacion.md#-multiplication) +- [`*=`](qsp-keyword-operacion.md#-multiplication-assignment) +- [`+`](qsp-keyword-operacion.md#-addition) +- [`+=`](qsp-keyword-operacion.md#-addition-assignment) +- ~~[`+` (unary)](qsp-keyword-operacion.md#--unary-minus)~~ +- [`-`](qsp-keyword-operacion.md#--subtraction) +- [`-=`](qsp-keyword-operacion.md#--subtraction-assignment) +- [`-` (unary)](qsp-keyword-operacion.md#--unary-minus) +- [`/`](qsp-keyword-operacion.md#-division) +- [`/=`](qsp-keyword-operacion.md#-division-assignment) +- [`<`](qsp-keyword-operacion.md#-less-than) +- [`<=`](qsp-keyword-operacion.md#-less-than-or-equal) +- [`<>`](qsp-keyword-operacion.md#-not-equal) +- [`=` (equal)](qsp-keyword-operacion.md#-equal) +- [`=` (assignment)](qsp-keyword-operacion.md#-assignment) +- [`=<`](qsp-keyword-operacion.md#-equal-or-less) +- [`=>`](qsp-keyword-operacion.md#-equal-or-greater) +- [`>`](qsp-keyword-operacion.md#-greater-than) +- [`>=`](qsp-keyword-operacion.md#-greater-than-or-equal) +- [`ACT`](qsp-keyword-operators.md#act) +- ~~[`ADDLIB`](qsp-keyword-operators.md#inclib)~~ +- [`ADDOBJ`](qsp-keyword-operators.md#addobj) +- ~~[`ADDQST`](qsp-keyword-operators.md#inclib)~~ +- [`AND`](qsp-keyword-operacion.md#and) +- [`ARGS`](qsp-keyword-sys-var.md#args) +- [`ARRCOMP`](qsp-keyword-functions.md#arrcomp) +- [`ARRITEM`](qsp-keyword-functions.md#arritem) - 5.8.0 +- [`ARRPACK`](qsp-keyword-functions.md#arrpack) - 5.9.1 +- [`ARRPOS`](qsp-keyword-functions.md#arrpos) +- [`ARRTYPE`](qsp-keyword-functions.md#arrtype) - 5.9.1 +- [`ARRSIZE`](qsp-keyword-functions.md#arrsize) +- [`$BACKIMAGE`](qsp-keyword-sys-var.md#backimage) +- [`BCOLOR`](qsp-keyword-sys-var.md#bcolor) +- [`CLA`](qsp-keyword-operators.md#cla) +- [`CLEAR`](qsp-keyword-operators.md#clear-1) +- [`*CLEAR`](qsp-keyword-operators.md#clear) +- [`CLOSE`](qsp-keyword-operators.md#close) +- [`CLOSE ALL`](qsp-keyword-operators.md#close-all) +- [`CLR`](qsp-keyword-operators.md#clear-1) +- [`*CLR`](qsp-keyword-operators.md#clear) +- [`CLS`](qsp-keyword-operators.md#cls) +- [`CMDCLEAR`](qsp-keyword-operators.md#cmdclear) +- [`CMDCLR`](qsp-keyword-operators.md#cmdclear) +- [`COPYARR`](qsp-keyword-operators.md#copyarr) +- [`$COUNTER`](qsp-keyword-sys-var.md#counter) +- [`COUNTOBJ`](qsp-keyword-functions.md#countobj) +- [`$CURACTS`](qsp-keyword-functions.md#curacts) +- [`$CURLOC`](qsp-keyword-functions.md#curloc) +- [`$CUROBJS`](qsp-keyword-functions.md#curobjs) - 5.9.0 +- [`DEBUG`](qsp-keyword-sys-var.md#debug) +- [`DELACT`](qsp-keyword-operators.md#delact) +- ~~[`DELLIB`](qsp-keyword-operators.md#freelib)~~ +- [`DELOBJ`](qsp-keyword-operators.md#delobj) +- [`$DESC`](qsp-keyword-functions.md#desc) +- [`DISABLESCROLL`](qsp-keyword-sys-var.md#disablescroll) +- ~~[`DISABLESUBEX`](qsp-keyword-sys-var.md#disablesubex)~~ +- [`DYNAMIC`](qsp-keyword-operators.md#dynamic) +- [`DYNEVAL`](qsp-keyword-functions.md#dyneval) +- [`ELSE`](qsp-keyword-operators.md#else) +- [`ELSEIF`](qsp-keyword-operators.md#elseif) +- [`END`](qsp-keyword-syntaxems.md#end) +- [`EXIT`](qsp-keyword-operators.md#exit) +- [`FCOLOR`](qsp-keyword-sys-var.md#fcolor) +- [`$FNAME`](qsp-keyword-sys-var.md#fname) +- [`FREELIB`](qsp-keyword-operators.md#freelib) - 5.8.0 +- [`FSIZE`](qsp-keyword-sys-var.md#fsize) +- [`FUNC`](qsp-keyword-functions.md#func) +- [`$GETOBJ`](qsp-keyword-functions.md#getobj) +- [`GOSUB`](qsp-keyword-operators.md#gosub) +- [`GOTO`](qsp-keyword-operators.md#goto) +- [`GS`](qsp-keyword-operators.md#gosub) +- [`GT`](qsp-keyword-operators.md#goto) +- [`IF`](qsp-keyword-operators.md#if) +- [`IIF`](qsp-keyword-functions.md#iif) +- [`INCLIB`](qsp-keyword-operators.md#inclib) - 5.8.0 +- [`$INPUT`](qsp-keyword-functions.md#input) +- [`INSTR`](qsp-keyword-functions.md#instr) +- [`ISNUM`](qsp-keyword-functions.md#isnum) +- [`ISPLAY`](qsp-keyword-functions.md#isplay) +- [`JUMP`](qsp-keyword-operators.md#jump) +- [`KILLALL`](qsp-keyword-operators.md#killall) +- [`KILLOBJ`](qsp-keyword-operators.md#killobj) +- ~~[`KILLQST`](qsp-keyword-operators.md#freelib)~~ +- [`KILLVAR`](qsp-keyword-operators.md#killvar) +- [`$LCASE`](qsp-keyword-functions.md#lcase) +- [`LCOLOR`](qsp-keyword-sys-var.md#lcolor) +- [`LEN`](qsp-keyword-functions.md#len) +- [`LET`](qsp-keyword-operators.md#let) +- [`LOC`](qsp-keyword-operacion.md#loc) +- [`LOCAL`](qsp-keyword-operators.md#local) - 5.8.0 +- [`LOOP`](qsp-keyword-operators.md#loop) - 5.8.0 +- [`$MAINTXT`](qsp-keyword-functions.md#maintxt) +- [`MAX`](qsp-keyword-functions.md#max) +- [`MENU`](qsp-keyword-operators.md#menu) +- [`$MID`](qsp-keyword-functions.md#mid) +- [`MIN`](qsp-keyword-functions.md#min) +- [`MOD`](qsp-keyword-operacion.md#mod) +- [`MSECSCOUNT`](qsp-keyword-functions.md#msecscount) +- [`MSG`](qsp-keyword-operators.md#msg) +- [`NL`](qsp-keyword-operators.md#nl-1) +- [`*NL`](qsp-keyword-operators.md#nl) +- [`NO`](qsp-keyword-operacion.md#no) +- [`NOSAVE`](qsp-keyword-sys-var.md#nosave) +- [`OBJ`](qsp-keyword-operacion.md#obj) +- [`$ONACTSEL`](qsp-keyword-sys-var.md#onactsel) +- [`$ONGLOAD`](qsp-keyword-sys-var.md#ongload) +- [`$ONGSAVE`](qsp-keyword-sys-var.md#ongsave) +- [`$ONNEWLOC`](qsp-keyword-sys-var.md#onnewloc) +- [`$ONOBJADD`](qsp-keyword-sys-var.md#onobjadd) +- [`$ONOBJDEL`](qsp-keyword-sys-var.md#onobjdel) +- [`$ONOBJSEL`](qsp-keyword-sys-var.md#onobjsel) +- [`OPENGAME`](qsp-keyword-operators.md#opengame) +- [`OPENQST`](qsp-keyword-operators.md#openqst) +- [`OR`](qsp-keyword-operacion.md#or) +- [`P`](qsp-keyword-operators.md#p-1) +- [`*P`](qsp-keyword-operators.md#p) +- [`PL`](qsp-keyword-operators.md#pl-1) +- [`*PL`](qsp-keyword-operators.md#pl) +- [`PLAY`](qsp-keyword-operators.md#play) +- [`$QSPVER`](qsp-keyword-functions.md#qspver) +- [`RAND`](qsp-keyword-functions.md#rand) +- [`REFINT`](qsp-keyword-operators.md#refint) +- [`$REPLACE`](qsp-keyword-functions.md#replace) +- [`RESULT`](qsp-keyword-sys-var.md#result) +- [`RGB`](qsp-keyword-functions.md#rgb) +- [`RND`](qsp-keyword-functions.md#rnd) +- [`SAVEGAME`](qsp-keyword-operators.md#savegame) +- [`SCANSTR`](qsp-keyword-operators.md#scanstr) - 5.9.0 +- [`$SELACT`](qsp-keyword-functions.md#selact) +- [`$SELOBJ`](qsp-keyword-functions.md#selobj) +- [`SET`](qsp-keyword-operators.md#set) +- [`SETTIMER`](qsp-keyword-operators.md#settimer) +- [`SETVAR`](qsp-keyword-operators.md#setvar) - 5.9.1 +- [`SHOWACTS`](qsp-keyword-operators.md#showacts) +- [`SHOWINPUT`](qsp-keyword-operators.md#showinput) +- [`SHOWOBJS`](qsp-keyword-operators.md#showobjs) +- [`SHOWSTAT`](qsp-keyword-operators.md#showstat) +- [`SORTARR`](qsp-keyword-operators.md#sortarr) - 5.9.0 +- [`$STATTXT`](qsp-keyword-functions.md#stattxt) +- [`$STR`](qsp-keyword-functions.md#str) +- [`STRCOMP`](qsp-keyword-functions.md#strcomp) +- [`$STRFIND`](qsp-keyword-functions.md#strfind) +- [`STRPOS`](qsp-keyword-functions.md#strpos) +- [`$TRIM`](qsp-keyword-functions.md#trim) +- [`$UCASE`](qsp-keyword-functions.md#ucase) +- [`UNPACKARR`](qsp-keyword-operators.md#unpackarr) - 5.9.1 +- [`UNSEL`](qsp-keyword-operators.md#unselect) +- [`UNSELECT`](qsp-keyword-operators.md#unselect) +- [`USEHTML`](qsp-keyword-sys-var.md#usehtml) +- [`$USERCOM`](qsp-keyword-sys-var.md#usercom) +- [`$USER_TEXT`](qsp-keyword-functions.md#user_text) +- [`$USRTXT`](qsp-keyword-functions.md#user_text) +- [`VAL`](qsp-keyword-functions.md#val) +- [`VIEW`](qsp-keyword-operators.md#view) +- [`WAIT`](qsp-keyword-operators.md#wait) +- [`XGOTO`](qsp-keyword-operators.md#xgoto) +- [`XGT`](qsp-keyword-operators.md#xgoto) \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-functions.md b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-functions.md new file mode 100644 index 0000000..ceda974 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-functions.md @@ -0,0 +1,1540 @@ +--- +sidebar_position: 3 +--- + +# Functions + +## `$CURACTS` + +`$CURACTS` — this function returns actions displayed on screen as QSP code, as a text value. + +Actions are saved as a set of `act` operators with corresponding parameters and operations. + +By writing the value returned by the function to a variable, actions can be restored using the `dynamic` operator. Example: + +```qsp +! write current actions to variable +$actlist = $curacts +! restore actions from variable +dynamic $actlist +``` + +## `$CURLOC` + +`$CURLOC` — function returns the name of the current location, i.e., the location where the player "is". + +Technically, this should be understood as follows. When the game starts, the player begins executing code of the very first location in the game, and when the code is executed, the player "stops" and waits for player participation. The player can press various buttons in the game, links and select menu items, which leads to execution of other code blocks (for example, actions) and transitions to new locations via `goto` or `xgoto`. During such transitions, the player again executes code of other locations and, when code is executed, "stops". + +So, when a direct transition to a location is made (i.e., via `goto` or `xgoto`, or it's the very first location in the game), `$curloc` begins returning the name of this location, — throughout the time while code is executing and when the player "stops". If no transition via `goto`/`xgoto` occurs after stopping, the value returned by `$curloc` doesn't change. + +Usage example: + +```qsp +*pl $curloc & ! output current location name to Main Description Window +*pl "Times re-entered: <>" +act "Re-enter current location": + re_entered += 1 + goto $curloc +end +``` + +## `$CUROBJS` + +`$CUROBJS` - this function returns the list of objects displayed on screen as QSP code. +Objects are saved as a set of `ADDOBJ` operators with corresponding parameters and operations. + +By writing the value returned by the function to a variable, objects can be restored using the `DYNAMIC` operator. Example: + +```qsp +! save object list as QSP code: +$old_objects = $CUROBJS +! remove all objects from objects window: +KILLOBJ +! restore all objects in objects window: +DYNAMIC $old_objects +``` + +## `$DESC` + +`$DESC` — returns the base description text of a location with the specified name. General syntax: + +```qsp +$DESC([$location]) +``` + +, where `[$location]` — the name of the location we're interested in. For example: + +```qsp +! return base description of location "cupboard_under_stairs" +$desc('cupboard_under_stairs') +!return base description of current location +$desc($curloc) +``` + +If sub-expressions are present in the base description, the function automatically expands them. + +:::warning[Pay attention!] +The function returns text written only in the "Description" field (**Base description**) of the **Quest Generator** editor. When working in a text editor, this field is unavailable to you and the function will always return an empty string. +::: + +## `$DYNEVAL` + +`DYNEVAL` — executes code passed as a text string and returns the result if it exists. General syntax: + +```qsp +$DYNEVAL([$code], [argument 0], [argument 1], ... , [argument 18]) +DYNEVAL([$code], [argument 0], [argument 1], ... , [argument 18]) +``` + +, where `[$code]` — regular QSP code written as text. Executing such code is analogous to executing `FUNC` function code. Arguments `[argument 0]`, `[argument 1]`, etc. can be used inside `[$code]`, their values are automatically placed in variables `args[0]`, `args[1]`, etc. respectively. + +Inside the code executed by `dyneval`, its own `ARGS` array is used, its values don't intersect with `ARGS` values at the location from which `dyneval` was called. + +After executing the code passed to the `dyneval` function, calculation of the expression in which `dyneval` is located continues. + +For `dyneval` to return a result, you need to assign this result to the `result` variable inside `[$code]`. + +Examples: + +```qsp +dyneval('result = 3 + 4') +*pl $dyneval('$result = mid("abcd", 2, 1) + "qwerty"') +pass = dyneval("result = ($args[0] <> 'text')", 'string') +``` + +- For `DYNEVAL` to return multiple values, the result must be written to `%RESULT`. +- For `DYNEVAL` to return a string value, the result must be written to `$RESULT`. +- For `DYNEVAL` to return a numeric value, the result must be written to `RESULT`. +- `%RESULT`, `$RESULT` and `RESULT` are the same variable but with different data types. Remember that a new value assignment overwrites the previous one, regardless of the data type of that value. + +If `dyneval` doesn't return values during execution (`result` is not initialized), and is the only element of an expression passed to the implicit operator, the player will output nothing to screen. I.e., `dyneval` will work like `DYNAMIC`. Example: + +```qsp +! implicit operator will output 123 to screen: +123 +! code in dyneval will execute, but we won't see +! anything on screen: +dyneval("code = 123 + 890") +! implicit operator will output 1013 to screen: +code +``` + +See also [operator `DYNAMIC`](qsp-keyword-operators.md#dynamic). + +## `$FUNC` + +`FUNC` — executes code of the specified location without direct transition to it with value return. + +General syntax: + +```qsp +FUNC([$location], [argument 0], [argument 1], ... , [argument 18]) +$FUNC([$location], [argument 0], [argument 1], ... , [argument 18]) +``` + +, where `[$location]` — the name of the location whose code we want to execute without direct transition to it. Arguments `[argument 0]`, `[argument 1]`, etc. can be used at this location, their values are automatically placed in variables `args[0]`, `args[1]`, etc. respectively. + +For `FUNC` to return: + +- multiple values or a tuple, at the specified location you need to assign the result to variable `%RESULT`; +- a string result, at this location you need to assign this result to variable `$RESULT`; +- for returning a numeric result, it must be assigned to variable `RESULT`. + +Remember that `%RESULT`, `$RESULT` and `RESULT` are the same variable but of different types, so if you defined both `%RESULT`, `$RESULT`, and `RESULT` at the location, the function will return the value that was written to this variable last. + +If no value was assigned to the `RESULT` variable, the function returns nothing. And here there are two player behavior variants. + +- If the `FUNC` function is in some expression, the default value will be substituted instead of the function (empty tuple, empty string, or zero depending on the expression type). +- If the `FUNC` function stands right after the implicit operator, such operator will be ignored, and nothing will be output to screen. Example: + +```qsp title="location_N" +N = 23 * 13 +! no value is assigned to result variable +``` + +```qsp title="Other location" +'string 1' +func('location_N') &! nothing will be output to screen +'string 2' +56 + func('location_N') &! function is in expression. Its value = 0 +``` + +:::note[Recommendation:] +It's not mandatory, but recommended, to use the type prefix (`$` or `%`) with the `FUNC` keyword if the function should return a string value or tuple, and — without type prefix if the function should return a numeric value: + +```qsp +$func('string_slice', 'We left the house when lights went out in all windows.', 3, 7) +func('raise_to_power', 3, 3) +``` + +::: + +**Order of operation.** + +When calling the specified location using `FUNC`, the following happens: + +- The player interrupts execution of current code (for example, current location code) and calls the specified location. +- Base description and action list of the specified location are added to the description and actions of the current location. +- Code from the **Execute on visit** field is executed +- Then the player returns to executing the code it interrupted. I.e., to calculating the expression in which this function stands. + +Separate unique `ARGS` and `RESULT` arrays are automatically created at each location, so values in these arrays will be separate for each location. After executing the location code called by `FUNC`, the `ARGS` and `RESULT` arrays of this location are destroyed. + +Other examples: + +```qsp +!Processing location "function" as function. +!ARGS array is empty. +apples = FUNC('function') + +!processing location with name in variable $name as function. ARGS[0] equals 1. +pl func($name, 1) * 78 + +!processing location with name in $name as function. +!$ARGS[0] contains string "string", ARGS[1] equals 2. +msg "text" + func($name, "string", 2) +``` + +```qsp +! location code for function getting sum of series of numbers from one to specified value +# summ +! args[0] will contain the number we specify as [argument 0] +loop while args[0]>0 step args[0] -= 1: + result += args[0] +end +---summ--- + +! example of calling location "summ" as function +*pl func("summ", 19) & ! will output 190 to screen +! example of call with location name written to variable +$name_loc = "summ" +*pl func($name_loc, 23) & ! will output 276 to screen +``` + +Also see ["Implicit `FUNC` function call"](qsp-keyword-syntaxems#commercial-at-symbol-). + +## `$GETOBJ` + +`$GETOBJ` — returns the name of an item in the *Objects Window* located at the specified position. General syntax: + +```qsp +$GETOBJ([#item_number]) +``` + +Indexing (numbering) of items in the *Objects Window* starts from 1. If an item with index `[#item_number]` doesn't exist, an empty string (`''`) is returned. + +Examples: + +```qsp +$getobj(1) & ! returns name of first item in backpack + +$getobj(countobj) & ! returns name of last added item +``` + +Code counting the number of items with identical names in the `OBJECTS` array: + +```qsp +loop local i = 1 while i <= countobj step i += 1: + objects[$getobj(i)] += 1 +end +``` + +## `$QSPVER` + +`$QSPVER` - returns the interpreter version in the format "X.Y.Z Player". For example, classic player version 5.8.0 returns the value "5.8.0 (classic)", and qSpider simply "5.8.0". Usage example: + +```qsp +if $qspver < "5.8.0": + *pl "Your player version is not suitable for this game." + *pl "Install player version 5.8.0 or higher." +end +``` + +This function can also return the platform on which the game is running if you specify "platform" as an argument: + +```qsp +$qspver('platform') +``` + +:::note[5.7.0] + +In older player versions, the function returned only the interpreter version (libqsp library). + +::: + +## `$SELACT` + +`$SELACT` — returns the name of the selected action anywhere in the game. + +Remember that action selection occurs when hovering the mouse pointer over it, not when directly clicking. + +Most often this function is used to remove the current action: + +```qsp +act "Eat apple": + *pl "It was a very tasty apple. Too bad it was wormy." + health += 100 + delact $selact +end +``` + +Also see usage examples in the [`$onactsel`](qsp-keyword-sys-var.md#onactsel) section + +## `$SELOBJ` + +`$SELOBJ` — returns the name of the selected object anywhere in the game. Object selection occurs when clicking (mouse click on object) and is not removed until the `unselect` command is applied. + +Usage examples can be found in the [`$onobjsel`](qsp-keyword-sys-var.md#onobjsel) section + +## `$STATTXT` + +`$STATTXT` — returns text output to the additional description window. Can be useful for replacing part of text in the additional description window. + +Example: + +```qsp +p 'The Ship Carried Caramel' +nl 'The Ship Hit a Shoal' +$string = $stattxt +``` + +## `$USER_TEXT` + +`$USER_TEXT` — anywhere in the game returns text that is in the input line (input field). Has the short form `$usrtxt`. + +Example of an action that will output text entered in the input line to the additional description window when clicked: + +```qsp +act "What did I write?": pl 'I wrote: "<<$user_text>>".' +``` + +A more common example is presented in the [`$usercom`](qsp-keyword-sys-var.md#usercom) section. + +## COUNTOBJ + +`COUNTOBJ` — returns the number of items in inventory. + +The number of the last item in the list numerically matches the number of items, so you can always get the name of the last item like this: + +```qsp +$getobj(countobj) +``` + +## MSECSCOUNT + +`MSECSCOUNT` — returns the number of milliseconds elapsed since the game started. This function, when used at the counter location, allows organizing various events occurring in real time. Also, with this function you can measure performance of various code sections in your game: + +```qsp +i = 0 +old_time = msecscount +:for +if i < 100000: + d[i] = i + i += 1 + jump 'for' +end +new_time = msecscount +pl "Old loop performance: " + $str(new_time - old_time) + +old_time = msecscount +loop i = 0 while i < 100000 step i += 1: + b[i] = i +end +new_time = msecscount +pl "New loop performance: " + $str(new_time - old_time) +``` + +:::note +The maximum number this function can return is `2147483647`. It's not hard to calculate that this is enough for more than **550** hours of gameplay. +::: + +## RND + +`RND` - returns a random value from `1` to `1000`. Analogous to the command: + +```qsp +rand(1, 1000) +``` + +## `$IIF` + +`IIF` — returns a value depending on expression truth. + +General syntax: + +```qsp +IIF([#expression], [#expression_yes], [#expression_no]) +$IIF([#expression], [$expression_yes], [$expression_no]) +``` + +If `[#expression]` is true, returns the value of expression `[expression_yes]`, otherwise returns the value of expression `[expression_no]`. + +Only one of the expressions `[expression_yes]` and `[expression_no]` will be calculated, depending on whether the condition is met. + +Examples: + +```qsp +!Absolute value of number +abs_x = iif(x>0, x, -x) + +!And the following construct will NOT cause division by zero error: +x = 0 +y = iif(x = 0, 0, 1/x) + +! typical solution for outputting time so as not to lose zero on hours: +$iif(hour>9, $str(hour), "0"+$str(hour)) + ":"+$iif(minute>9, $str(minute), "0"+$str(minute)) +``` + +Equivalence of conditional constructs with `IF` operator and `IIF` function: + +```qsp +if number mod 2 = 0: + *pl "Number is even" +else + *pl "Number is odd" +end +! equivalent to +*pl $iif(number mod 2 = 0,"Number is even","Number is odd") +``` + +## `$INPUT` + +`$INPUT` — returns to the interpreter the text entered by the player, or `''` (empty string) if the "Cancel" button was pressed. General syntax: + +```qsp +$INPUT([$text]) +``` + +, where `[$text]` — the prompt in the dialog box that the player sees. For example: + +```qsp +$name = $input('What is your name, hero?') +``` + +When this command is executed, a dialog box with the text "What is your name, hero?" will appear on screen, and execution of the rest of the code will pause until the player interacts with the dialog box. + +The player can enter or not enter text, and press the "OK" or "Cancel" button. If the player entered text and pressed the "OK" button, the `$input` function will return the text entered by the player to the `$text` variable. In all other cases, after closing the dialog box, the function will return an empty string (`''`). + +Other examples: + +```qsp +! Question with one correct answer. +if $input('What comes after darkness?') = 'light': + msg 'Correct.' +else + msg 'Wrong answer.' +end + +! Example implementation of question with multiple answer variants where any will be correct. +$answer = $trim($lcase($input('Answer'))) +if instr($answer, 'red') or instr($answer, 'yellow') or instr($answer, 'green'): gt 'win' +! Entering red or green or yellow will transition to 'win' location +``` + +:::warning[Be careful!] +It's acceptable but not approved to use the function for returning numeric values: + +```qsp +INPUT([$prompt]) +``` + +This can lead to various game errors if the player enters not only digits in the dialog box. For example: + +```qsp +age = input('How old are you?') +``` + +If the player enters the string "24 years old" instead of a number, the player will give error **101** "Data type mismatch". + +Such situations should be anticipated by the game author, which means it's correct to check the entered value after the `$input` function is executed. + +```qsp +loop local $text while 1: + ! ask player to answer question + ! and assign entered text to variable + $text = $input('How old are you?') + ! if entered text contains not only digits + ! or player didn't enter answer + if isnum($text) and $text <> "": + ! player entered number + age = val($text) & ! set age + jump 'break' & ! break loop + else + ! player entered nothing or incorrect value + ! loop continues + end +end +:break +``` + +::: + +## `$LCASE` + +`$LCASE` — returns a lowercase string obtained by changing the case of letters in the original string. General syntax: + +```qsp +$LCASE([$text]) +``` + +, where `[$text]` — any text string. + +Examples: + +```qsp +$lcase('TExT#') & ! returns 'text#' +$lcase('Hello, Alice!') & ! returns 'hello, alice!' +$lcase('I DON\'T WANT TO SHOUT AT YOU.') & ! returns 'i don\'t want to shout at you.' +``` + +## `$MAINTXT` + +`$MAINTXT` — returns text output to the main description window. + +This function can be useful for replacing part of text in the main description window, or other text processing. Example: + +```qsp +! initially we output a string +*pl "We output a string to screen and in this string there's a piece we want to remove." + +! get text from main description window +$text = $maintxt +! cut out extra piece +$text_new = $replace($text, " and in this string there's a piece we want to remove") +! clear main description window +*clr +! output new text +*p $text_new +``` + +## `$MID` + +`$MID` — allows cutting a part from a string. General syntax: + +```qsp +$MID([$string], [#start], [#length]) +``` + +, where `[$string]` — text string from which the function cuts a part, starting from character number `[#start]`, and with length of `[#length]` characters. Character numbering starts from 1. + +- If the `[#length]` parameter is absent, the part is cut to the end of the string. +- The `[#start]` parameter is mandatory and can take any values. +- If the `[#start]` value exceeds the string length, an empty string is returned. + +```qsp +$mid('abcdef', 1, 2) & ! 'ab' +$mid('abcdef', 2, 3) & ! 'bcd' +$mid('abcdef', 2) & ! 'bcdef' +$mid('abcdef') & ! 'error [120] — incorrect number of operator/function arguments' +$mid('abcdef', 0) & ! 'abcdef' +$mid('abcdef', 8) & ! '' +``` + +## `$REPLACE` + +`$REPLACE` — general syntax: + +```qsp +$REPLACE([$string], [$search], [$replacement], [#num_replacements]) +``` + +This function replaces several occurrences of string `[$search]` with string `[$replacement]` in string `[$string]` and returns the result. Replacement is performed left-to-right and only for non-overlapping occurrences. The `[#num_replacements]` parameter shows how many occurrences should be replaced. If the parameter is not specified, all occurrences are replaced. If `[$replacement]` is absent or an empty string is specified, then all occurrences of the searched string are removed from the original string. Examples: + +```qsp +$replace('test', '12', '4') & ! will output 'test' to screen +$replace('test', 'e', 's') & ! will output 'tsst' to screen +$replace('test', 't', '34') & ! will output '34es34' to screen +$replace('test', 't') & ! will output 'es' to screen + +$replace('test', 't', 'qu', 1) &! 'quest' +$replace('test my test', 't', 'q', 3) &! 'qesq my qest' +``` + +```qsp +! you can assign value to variable +$text = "Text string with different letters." +! and write new value to another variable +$text_new = $replace($text, "st", "st") +*pl $text +*pl $text_new +``` + +## `$STR` + +`$STR` — returns a text string obtained by converting a number to string. General syntax: + +```qsp +$STR([#number]) +``` + +Example: + +```qsp +$str(56) & ! converts number 56 to string "56" and outputs to screen +``` + +## `$STRFIND` + +`$STRFIND` — returns a substring matching a regular expression from the specified string. General syntax: + +```qsp +$STRFIND([$string], [$pattern], [#number]) +``` + +, where `[$string]` — source string in which we search for an occurrence matching regular expression `[$pattern]`, or group number `[#number]` in the regular expression. If substring with specified number is absent, an empty string is returned. Group numbering starts from 1. If parameter `[#number]` is absent or equals 0, the substring matching the entire regular expression `[$pattern]` is returned. + +For example, let's take the regular expression: + +```regex +^(\S+)\s(\S+)\s(\S+)$ +``` + +The `\S` metacharacter means any non-whitespace character, and the `+` quantifier indicates that non-whitespace characters must be present one or more times. Thus the notation `\S+` can be conditionally matched to a word. Each word is enclosed in separate groups using parentheses `()`, and whitespace characters `\s` are present between groups. The `^` and `## `$IIF` + +`IIF` — returns a value depending on expression truth. + +General syntax: + +```qsp +IIF([#expression], [#expression_yes], [#expression_no]) +$IIF([#expression], [$expression_yes], [$expression_no]) +``` + +If `[#expression]` is true, returns the value of expression `[expression_yes]`, otherwise returns the value of expression `[expression_no]`. + +Only one of the expressions `[expression_yes]` and `[expression_no]` will be calculated, depending on whether the condition is met. + +Examples: + +```qsp +!Absolute value of number +abs_x = iif(x>0, x, -x) + +!And the following construct will NOT cause division by zero error: +x = 0 +y = iif(x = 0, 0, 1/x) + +! typical solution for outputting time so as not to lose zero on hours: +$iif(hour>9, $str(hour), "0"+$str(hour)) + ":"+$iif(minute>9, $str(minute), "0"+$str(minute)) +``` + +Equivalence of conditional constructs with `IF` operator and `IIF` function: + +```qsp +if number mod 2 = 0: + *pl "Number is even" +else + *pl "Number is odd" +end +! equivalent to +*pl $iif(number mod 2 = 0,"Number is even","Number is odd") +``` + + metacharacters mean the beginning and end of string respectively. Thus our regular expression matches any string of three words separated by spaces. + +Then: + +```qsp +! in this case the string doesn't match the regular expression +! because according to the regular expression the string should start +! with a group of non-whitespace characters. The command will return empty string '' +$strfind(' go to cave','^(\S+)\s(\S+)\s(\S+)) +``` + +```qsp +! in this case the string fully matches the regular expression +! so the command will return the string entirely 'go to cave' +$strfind('go to cave','^(\S+)\s(\S+)\s(\S+)) = '' +``` + +```qsp +! in the next three examples the string matches the regular expression +! but the third argument specifies which group from this +! regular expression we want to get, so each command will return +! the first, second and third words from the string respectively +$strfind('go to cave','^(\S+)\s(\S+)\s(\S+), 1) & ! returns 'go' +$strfind('go to cave','^(\S+)\s(\S+)\s(\S+), 2) & ! returns 'to' +$strfind('go to cave','^(\S+)\s(\S+)\s(\S+), 3) & ! returns 'cave' +``` + +```qsp +! here the last group of non-whitespace characters is combined into one +! group with the last whitespace character. The "?" quantifier indicates +! that this group may or may not be present in the string: +$strfind('go to cave', '^(\S+)\s(\S+)(\s(\S+))?, 4) & ! returns 'cave' +$strfind('go to cave', '^(\S+)\s(\S+)(\s(\S+))?, 3) & ! returns ' cave' +! this regular expression also matches this string +$strfind('search key', '^(\S+)\s(\S+)(\s(\S+))?, 1) & ! returns 'search' +! but this string no longer matches the regular expression +$strfind('search', '^(\S+)\s(\S+)(\s(\S+))?, 1) & ! returns '' +``` + +The following examples show how `$strfind` returns part of string matching the regular expression: + +```qsp +$strfind('go to house', 'to\s(\S+)') & ! returns 'to house' +$strfind('go to house', 'to\s(\S+)', 1) & ! returns 'house' +$strfind('go to my house', 'to\s(\S+)', 1) & ! returns 'my' +``` + +Other examples: + +```qsp title="four-letter word" +$strfind('go to cave', '\b\w{4}\b') &! we'll see 'cave' on screen +``` + +```qsp title="Selection with nested groups" +$strfind('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)', 1) &! we'll see '671' on screen +$strfind('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)', 2) &! we'll see '-190-23-999' on screen +$strfind('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)', 3) &! we'll see '-999' on screen +``` + +```qsp title="searching for numbers in string without numbers" +$strfind('Eight green apples in basket','\d+') &! empty string will be on screen +``` + +## `$TRIM` + +`$TRIM` — returns the specified string without adjacent tab and space characters. General syntax: + +```qsp +$TRIM([$expression]) +``` + +For example: + +```qsp +$trim(' trim test ') & ! returns 'trim test' +``` + +## `$UCASE` + +`$UCASE` — returns an uppercase string obtained by changing the case of letters in the original string. General syntax: + +```qsp +$UCASE([$text]) +``` + +, where `[$text]` — any text string. + +Examples: + +```qsp +$ucase('TExT#') & ! returns 'TEXT#' +$ucase('Hello, Alice!') & ! returns 'HELLO, ALICE!' +$ucase('I want to shout at you.') & ! returns 'I WANT TO SHOUT AT YOU.' +``` + +## INSTR + +`INSTR` — returns the character number from which the substring occurrence begins in the string. General syntax: + +```qsp +INSTR([$string], [$substring], [#start]) +``` + +, where `[#start]` — the character number from which to start the search, `[$string]` — text value (string) in which to search, and `[$substring]` — value we're looking for in the specified string. Character numbering starts from `1`. The `[#start]` parameter can be absent, in which case it's taken as 1. + +Examples: + +```qsp +instr('abcdefabcdef', 'bc', 3) & ! returns number 8 +instr('abcdefghijklm', 'abc') & ! returns number 1 +``` + +If no occurrence of the specified substring is found in the string, `instr` returns `0`. + +Example: + +```qsp +instr('Vasya left the house.', 'go') & ! returns 0 +``` + +:::note[5.7.0] +In older player versions, the `[#start]` parameter was specified first: + +```qsp +INSTR([#start], [$string], [$substring]) +``` + +::: + +## ISNUM + +`ISNUM` — function returns `1` (true) if the passed string is a number, and `0` if the string is not a number. General syntax: + +```qsp +ISNUM([$string]) +``` + +, where `[$string]` — any text string. + +The check takes into account the `-` sign at the beginning, adjacent spaces and tab characters, but if at least one character turns out not to be a digit, the function will return `0` (false). + +Examples: + +```qsp +isnum(' 9999 ') & ! returns 1 +isnum(' -888') & ! returns 1 +isnum('777a6') & ! returns 0 +isnum('') & ! returns 0, since empty string contains no number +``` + +## ISPLAY + +`ISPLAY` — function checks if a file with the specified name is currently playing, and if it is, returns `1`. Otherwise the function returns `0`. General syntax: + +```qsp +ISPLAY([$file_path]) +``` + +, where `[$file_path]` — path to sound file relative to game file. + +Example: + +```qsp +if isplay('music/mountsound.mp3'): + *pl 'Music is playing.' +else + *pl 'Music is not playing.' +end +``` + +## LEN + +`LEN` — returns the length of the specified text string (number of characters). General syntax: + +```qsp +LEN([$text]) +``` + +, where `[$text]` — any text value. + +Examples: + +```qsp +len("abc") & ! returns value 3 +len("thousand-nine-hundred-eighty-nine-millimeter") & ! returns value 46 +len("") & ! returns value 0 +``` + +## STRCOMP + +`STRCOMP` — compares a string with a regular expression and, if the string matches the regular expression, returns `1` (true), and if it doesn't match — `0` (false). General syntax: + +```qsp +STRCOMP([$string], [$pattern]) +``` + +, where `[$string]` — any text value, `[$pattern]` — regular expression to compare with. + +For example, we need to check if the specified string consists of three words. Each word, roughly speaking, is a set of non-whitespace characters, so we can use the `\S` metacharacter with the `+` quantifier. Words are usually separated by whitespace characters, for which we use the `\s` metacharacter. We get this regular expression: + +```regex +\s?\S+\s+\S+\s+\S+\s? +``` + +Now we can check which strings match this regular expression: + +```qsp +strcomp('go along road', '\s?\S+\s+\S+\s+\S+\s?') & ! returns 1 +strcomp(' go home', '\s?\S+\s+\S+\s+\S+\s?') & ! returns 0 +strcomp(' go to forest ', '\s?\S+\s+\S+\s+\S+\s?') & ! returns 1 +strcomp('oneword', '\s?\S+\s+\S+\s+\S+\s?') & ! returns 0 +``` + +## STRPOS + +`STRPOS` — returns the position of the character from which the substring occurrence matching the regular expression begins in the specified string. General syntax: + +```qsp +STRPOS([$string], [$pattern], [#number]) +``` + +, where `[$string]` — source string in which we search for an occurrence matching regular expression `[$pattern]`, or group number `[#number]` in the regular expression. Group numbering in regular expression starts from 1. If substring with specified number is absent, `0` is returned. + +If parameter `[#number]` is absent or equals `0`, the position of the character from which the substring occurrence matching the entire regular expression begins is returned. + +For example, we need to find out in which part of the text the phrase "green apple" occurs, but the case of this adjective shouldn't matter. + +To write a regular expression for this task, we need to account for all cases: + +```plain +green apple +green apple +green apple +green apple +green apple +green apple +``` + +As we can see, only word endings change in all forms. Therefore we can compose this regular expression: + +```regex +green(oe|ogo|omu|ym|om)\s+apple(o|a|u|om|e) +``` + +Possible ending variants are listed through a vertical bar in parentheses. And now let's find out from which character in the string the possible phrase "green apple" begins: + +```qsp +! for convenience we put the regular expression in a variable +$regexp = "green(oe|ogo|omu|ym|om)\s+apple(o|a|u|om|e)" +strpos("I have a green apple", $regexp) & ! returns 13 +strpos("You threw a green apple at him!", $regexp) & ! returns 19 +strpos("full box of green apples", $regexp) & ! returns 0, because we didn't account for this form +``` + +If we don't just want to know from which character the phrase occurrence begins in the string, but specifically where the word "apple" from this phrase begins, we need to put the word "apple" with ending variants in a separate group and use the `[#number]` parameter: + +```qsp +$regexp = "green(oe|ogo|omu|ym|om)\s+(apple(o|a|u|om|e))" +strpos("I have a green apple", $regexp, 2) & ! returns 21 +strpos("You threw a green apple at him!", $regexp, 2) & ! returns 27 +strpos("full box of green apples", $regexp, 2) & ! returns 0, because we didn't account for the form +``` + +Other examples: + +```qsp title="Working with groups" +!------'----5--8------15--' +STRPOS('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)',1) &! we'll see 5 on screen +STRPOS('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)',2) &! we'll see 8 on screen +STRPOS('+33-671-190-23-999', '\+\d{1,2}-(\d{3})((-\d+)+)',3) &! we'll see 15 on screen +``` + +```qsp title="Searching for number in string without number" +STRPOS('Eight green apples in basket','\d+') &! 0 will be on screen +``` + +```qsp +STRPOS('go to cave', '^(\S+)\s(\S+)\s(\S+), 0) &! 1 +STRPOS(' go to cave', '^(\S+)\s(\S+)\s(\S+), 0) &! 0 +STRPOS('go to cave', '^(\S+)\s(\S+)\s(\S+), 1) &! 1 +STRPOS('go to cave', '^(\S+)\s(\S+)\s(\S+), 2) &! 6 +STRPOS('go to cave', '^(\S+)\s(\S+)\s(\S+), 3) &! 8 +STRPOS('go to cave', '^(\S+)\s(\S+)(\s(\S+))?, 4) &! 8 +STRPOS('go to house', 'to\s(\S+)', 0) &! 6 +STRPOS('go to house', 'to\s(\S+)') &! 6 +STRPOS('go to house', 'to\s(\S+)', 1) &! 8 +STRPOS('go to my house', 'to\s(\S+)', 1) &! 8 +``` + +## VAL + +`VAL` — converts the specified digit string to corresponding number. General syntax: + +```qsp +VAL([$expression]) +``` + +, where `[$expression]` — any text string. + +The check takes into account the `-` sign at the beginning, adjacent spaces and tab characters, but if at least one character turns out not to be a digit, the function will return `0`. Also if `[$expression]` equals `''` (empty string), `0` is returned. + +Examples: + +```qsp +apples = val($apples) + +val('123') & ! we'll see 123 +val('') & ! we'll see 0 +val('sand') & ! we'll see 0 +``` + +## `$MAX` + +`MAX` — returns the maximum of expression-argument values. You can pass from one to twenty values/arguments. If one argument is passed, it's considered that an array name is specified. General syntax: + +```qsp +MAX([#expression 1], [#expression 2], ... , [#expression 20]) +$MAX([$expression 1], [$expression 2], ... , [$expression 20]) + +MAX([$array_name]) +$MAX([$array_name]) +``` + +Note, when passing one argument, the search for maximum element occurs among string (if array name is specified with `$` sign) or among numeric values of array elements. For example: + +```qsp +max('a') & ! returns maximum of numeric values of "a" array elements +$max('$b') & ! returns maximum of string values of "b" array elements +``` + +You can't write like this and expect search among array `a` values: + +```qsp +max(a) +``` + +You can do this: + +```qsp +$b = 'a' +max($b) & ! search for maximum value among elements of "a" array will occur +``` + +Other examples: + +```qsp +max(1, 2, 5, 2, 0) &! returns 5 +max(a, b, c) &! returns maximum of variable values a,b,c +$max('aa', 'ab', 'zz') &! returns 'zz' +``` + +## `$MIN` + +`MIN` — returns the minimum of expression-argument values. You can pass from one to twenty values/arguments. If one argument is passed, it's considered that an array name is specified. General syntax: + +```qsp +MIN([#expression 1], [#expression 2], ... , [#expression 20]) +$MIN([$expression 1], [$expression 2], ... , [$expression 20]) +``` + +```qsp +MIN([$array_name]) +$MIN([$array_name]) +``` + +Note, when passing one argument, the search for minimum element occurs among string (if array name is specified with `$` sign) or among numeric values of array elements. For example: + +```qsp +min('a') & ! returns minimum of numeric values of "a" array elements +$min('$b') & ! returns minimum of string values of "b" array elements +``` + +You can't write like this: + +```qsp +min(a) +``` + +You can do this: + +```qsp +$b = 'a' +min($b) & ! search for maximum value among elements of "a" array will occur +``` + +Other examples: + +```qsp +min(1, 2, 5, 2, 0) & ! returns 0 +min(a, b, c) & ! returns minimum of variable values a,b,c +$min('aa', 'ab', 'zz') & ! returns 'aa' +``` + +## RAND + +`RAND` — returns a random number between two specified numbers. General syntax: + +```qsp +RAND([#expression 1], [#expression 2], [#mode]) +``` + +, where `[#expression 1]` and `[#expression 2]` — any two numbers or numeric expressions. + +The `[#mode]` parameter allows specifying a number that should occur more frequently than others. The frequency distribution will smoothly change for all other numbers, decreasing from mode to the limits of the selected interval. If the 3rd parameter is not specified, the function returns a random number in the specified range with uniform/equiprobable number distribution. + +The `[#expression 2]` parameter can be absent, in which case it's taken as `1`. + +:::note[5.7.0] +In older player versions, this parameter defaults to zero. +::: + +Examples: + +```qsp +rand(1, 4) &! returns random value from 1 to 4 +rand(4, 1) &! returns random value from 1 to 4 +rand(1000) &! returns random value from 1 to 1000 +rand 1000 &! returns random value from 1 to 1000 + +x = RAND(1, 1000, 500) & ! 500 will occur more often +x = RAND(1, 1000, 1) & ! 1 will occur more often +x = RAND(1, 1000, 1000) & ! 1000 will occur more often +x = RAND(-1000, 0, -500) & ! -500 will occur more often +x = RAND(1, 1000, 5000) & ! 1000 will occur more often +x = RAND(-1000, -100, -5000) & ! -1000 will occur more often +``` + +## RGB + +`RGB` — returns the numeric color code based on three numeric arguments, each corresponding to a component of the required color. General syntax: + +```qsp +RGB([#red], [#green], [#blue], [#alpha]) +``` + +, where `[#red]`, `[#green]` and `[#blue]` — numeric expression of three color components respectively red, green and blue; `[#alpha]` — transparency component; should take values from 0 to 255. + +This function is usually used together with system variables `bcolor`, `fcolor`, `lcolor`. Example: + +```qsp +! light yellow hyperlinks +lcolor = rgb(255, 255, 100) +! dark gray background +bcolor = rgb(25, 25, 25) +! light green text +fcolor = rgb(100, 255, 100) +``` + +Example of semi-transparent link color: + +```qsp +lcolor = rgb(0, 255, 255, 128) +``` + +:::note[Note.] + +Don't rely on the `[#alpha]` parameter as many players don't support it. + +::: + +## ARRCOMP + +`ARRCOMP` — returns the index of array element matching a regular expression. Search starts from element with specified number; array element indexing starts from zero. If the specified value is not found, the function returns -1. General syntax: + +```qsp +ARRCOMP([$array_name], [$pattern], [#start]) +``` + +, where `[#start]` — array element number from which to start search, `[$array_name]` — array name to search in, `[$pattern]` — regular expression to compare the searched element with. + +- The `[#start]` parameter can be absent, in which case its value is taken as 0. +- Search works only on text arrays (the `$` symbol in array name can be omitted). + +For example, let's take this array: + +```qsp +$mass[0] = "stomp forward" +$mass[1] = " go to cave" +$mass[2] = "don't go to cave" +$mass[3] = "stomp to house" +``` + +We need to find an element whose value consists of three words. Roughly speaking, a word is a set of one or more non-whitespace characters `\S+`, which can be surrounded by whitespace characters `\s`, so we can compose this regular expression: + +```regex +\s?\S+\s\S+\s\S+\s? +``` + +Now we just need to find out which array element matches the pattern: + +```qsp +arrcomp('$mass', '\s?\S+\s\S+\s\S+\s?') & ! the first element matches this expression +``` + +If we want to ignore the first element and start search from the second: + +```qsp +arrcomp('$mass', '\s?\S+\s\S+\s\S+\s?', 2) & ! the third element matches this expression +``` + +And this is how we can output all element values containing the word "go": + +```qsp +loop local pos, index = 0, 0 while 1: + index = arrcomp('$mass', '(.*\s|^)go(\s.*|$)', pos) + if index <> -1: + $mass[index] + pos = index + 1 + else: + jump 'break' + end +end +:break +``` + +Other examples: + +```qsp +! Search for string 'This' among elements of array "$A" +arrcomp('$A', 'This', 0) +! Search for string matching regular expression "abc\d+" +! (first two array elements are ignored) +arrcomp('$A', 'abc\d+', 2) +! similar to previous example, +! but search is performed on all array elements +arrcomp('$A', '.*string.*', 0) + +arrcomp('$A', 'This') & ! equivalent to 1st variant +``` + +:::warning[Attention!] +The function returns only the numeric index of the element. String or multi-dimensional index cannot be obtained with this function. +::: + +## ARRITEM + +`ARRITEM` — returns the value of array element at specified index. General syntax: + +```qsp +ARRITEM([$array_name], [element_index]) +``` + +, where `[$array_name]` — the name of the array whose element we want to get, and `[element_index]` — numeric, text, or multi-dimensional index. + +In other words, the function extracts a value from the specified array cell. Examples: + +```qsp +! output value of element with index 3 +*pl $arritem('$mass', 3) +! output value of element with text index +*pl $arritem('$mass', 'Pete') +! output value of element with multi-dimensional index +*pl $arritem('$mass', [-2, 9, 0]) +``` + +This function can be useful for extracting values when the array name is not known in advance. Example: + +```qsp title="Output contents of several arrays without using DYNAMIC" +$array_name[] = 'mass_1' +$array_name[] = 'mass_2' +$array_name[] = 'mass_3' +$array_name[] = 'mass_4' +$array_name[] = 'mass_5' +! outer loop iterates through array names +loop local j = 0 while j < arrsize('$array_name') step j += 1: + ! inner loop outputs array contents + loop local i = 0 while i < arrsize($array_name[j]) step i += 1: + *pl arritem($array_name[j], i) + end +end +``` + +## %ARRPACK + +`ARRPACK` — returns a tuple into which values from the specified array are packed. + +General syntax: + +```qsp +%ARRPACK([$array_name], [#start_index], [#count]) +``` + +, where `[#start_index]` - the number of array element `[$array_name]` from which to start selecting elements for packing; `[#count]` — the number of elements to be packed into the tuple. + +This function allows shortening the command for extracting arguments from `args`: + +```qsp +! instead of: +local type, name = args[0], args[1] +! you can write like this: +local type, name = arrpack('args') +``` + +It can also be convenient if you need to quickly view array contents or part of it: + +```qsp +! view values in array without using loop: +*pl %arrpack('massive', 11, 10) & ! we'll see ten elements starting from 11th, as a tuple on screen +``` + +## ARRPOS + +`ARRPOS` — returns the index of array element equal to specified value. Search starts from element with specified number; array element indexing starts from zero. If the specified value is not found, the function returns -1. + +General syntax: + +```qsp +ARRPOS([$array_name], [value], [#start]) +``` + +, where `[#start]` — array element number from which to start search, `[$array_name]` — array name to search in, `[value]` — number or string (depending on array type) to find in the array. + +For example, let's take this array: + +```qsp +$color[0] = 'red' +$color[1] = 'yellow' +$color[2] = 'green' +$color[3] = 'blue' +$color[4] = 'yellow' +``` + +We need to find element with value "yellow": + +```qsp +arrpos('$color', 'yellow') & ! returns value 1 +``` + +If we want to ignore the first two elements: + +```qsp +arrpos('$color', 'yellow', 2) & ! returns value 4 +``` + +If we want to find element with value that doesn't exist in the array: + +```qsp +arrpos('$color','light blue') & ! returns value -1 +``` + +Other examples: + +```qsp +! search for string 'this' in text array "$a" +arrpos('$a', 'this', 0) +! search for number 65 in array "a" (two array elements are ignored) +arrpos('a', 65, 2) +! search for string 'test' among values of array "$b" +arrpos('$b', 'test') +``` + +:::warning[Attention!] +The function returns only the numeric index of the element. String or multi-dimensional index cannot be obtained with this function. +::: + +:::note[5.7.0] +In older player versions, the `[#start]` parameter was specified first: + +```qsp +ARRPOS([#start], [$array_name], [$pattern]) +``` + +::: + +## ARRTYPE + +`ARRTYPE` — returns the type of value stored in a variable or specified array cell. The type is returned as one of the following values: +- `''` (empty string) — value not defined (for example, for uninitialized variables); +- `'#'` — variable contains number; +- `'` — variable contains string; +- `'%'` — variable contains tuple. + +General syntax: + +```qsp +ARRTYPE([$array_name], [index]) +``` + +, where `[$array_name]` — array name (type prefix doesn't matter, better not to specify); `[index]` — cell index whose value type we want to get. + +Examples: + +```qsp +$ddd = 'text' +arrtype('ddd') & ! ' + +$g = 'text' & g = 13 +arrtype('g') & ! '#' + +%tuple['index'] = [12, 'string'] +arrtype('tuple', 'index') & ! '%' + +! $empty not exist +arrtype('$empty') & ! '' +``` + +## ARRSIZE + +`ARRSIZE` — function returns the number of array elements. General syntax: + +```qsp +ARRSIZE([$array_name]) +``` + +, where `[$array_name]` — the name of the array whose size we want to get. + +It doesn't matter whether you specify **`## `$MAX` + +`MAX` — returns the maximum of expression-argument values. You can pass from one to twenty values/arguments. If one argument is passed, it's considered that an array name is specified. General syntax: + +```qsp +MAX([#expression 1], [#expression 2], ... , [#expression 20]) +$MAX([$expression 1], [$expression 2], ... , [$expression 20]) + +MAX([$array_name]) +$MAX([$array_name]) +``` + +Note, when passing one argument, the search for maximum element occurs among string (if array name is specified with `$` sign) or among numeric values of array elements. For example: + +```qsp +max('a') & ! returns maximum of numeric values of "a" array elements +$max('$b') & ! returns maximum of string values of "b" array elements +``` + +You can't write like this and expect search among array `a` values: + +```qsp +max(a) +``` + +You can do this: + +```qsp +$b = 'a' +max($b) & ! search for maximum value among elements of "a" array will occur +``` + +Other examples: + +```qsp +max(1, 2, 5, 2, 0) &! returns 5 +max(a, b, c) &! returns maximum of variable values a,b,c +$max('aa', 'ab', 'zz') &! returns 'zz' +``` + +## `$MIN` + +`MIN` — returns the minimum of expression-argument values. You can pass from one to twenty values/arguments. If one argument is passed, it's considered that an array name is specified. General syntax: + +```qsp +MIN([#expression 1], [#expression 2], ... , [#expression 20]) +$MIN([$expression 1], [$expression 2], ... , [$expression 20]) +``` + +```qsp +MIN([$array_name]) +$MIN([$array_name]) +``` + +Note, when passing one argument, the search for minimum element occurs among string (if array name is specified with `$` sign) or among numeric values of array elements. For example: + +```qsp +min('a') & ! returns minimum of numeric values of "a" array elements +$min('$b') & ! returns minimum of string values of "b" array elements +``` + +You can't write like this: + +```qsp +min(a) +``` + +You can do this: + +```qsp +$b = 'a' +min($b) & ! search for maximum value among elements of "a" array will occur +``` + +Other examples: + +```qsp +min(1, 2, 5, 2, 0) & ! returns 0 +min(a, b, c) & ! returns minimum of variable values a,b,c +$min('aa', 'ab', 'zz') & ! returns 'aa' +``` + +## RAND + +`RAND` — returns a random number between two specified numbers. General syntax: + +```qsp +RAND([#expression 1], [#expression 2], [#mode]) +``` + +, where `[#expression 1]` and `[#expression 2]` — any two numbers or numeric expressions. + +The `[#mode]` parameter allows specifying a number that should occur more frequently than others. The frequency distribution will smoothly change for all other numbers, decreasing from mode to the limits of the selected interval. If the 3rd parameter is not specified, the function returns a random number in the specified range with uniform/equiprobable number distribution. + +The `[#expression 2]` parameter can be absent, in which case it's taken as `1`. + +:::note[5.7.0] +In older player versions, this parameter defaults to zero. +::: + +Examples: + +```qsp +rand(1, 4) &! returns random value from 1 to 4 +rand(4, 1) &! returns random value from 1 to 4 +rand(1000) &! returns random value from 1 to 1000 +rand 1000 &! returns random value from 1 to 1000 + +x = RAND(1, 1000, 500) & ! 500 will occur more often +x = RAND(1, 1000, 1) & ! 1 will occur more often +x = RAND(1, 1000, 1000) & ! 1000 will occur more often +x = RAND(-1000, 0, -500) & ! -500 will occur more often +x = RAND(1, 1000, 5000) & ! 1000 will occur more often +x = RAND(-1000, -100, -5000) & ! -1000 will occur more often +``` + +## RGB + +`RGB` — returns the numeric color code based on three numeric arguments, each corresponding to a component of the required color. General syntax: + +```qsp +RGB([#red], [#green], [#blue], [#alpha]) +``` + +, where `[#red]`, `[#green]` and `[#blue]` — numeric expression of three color components respectively red, green and blue; `[#alpha]` — transparency component; should take values from 0 to 255. + +This function is usually used together with system variables `bcolor`, `fcolor`, `lcolor`. Example: + +```qsp +! light yellow hyperlinks +lcolor = rgb(255, 255, 100) +! dark gray background +bcolor = rgb(25, 25, 25) +! light green text +fcolor = rgb(100, 255, 100) +``` + +Example of semi-transparent link color: + +```qsp +lcolor = rgb(0, 255, 255, 128) +``` + +:::note[Note.] + +Don't rely on the `[#alpha]` parameter as many players don't support it. + +::: + +## ARRCOMP + +`ARRCOMP` — returns the index of array element matching a regular expression. Search starts from element with specified number; array element indexing starts from zero. If the specified value is not found, the function returns -1. General syntax: + +```qsp +ARRCOMP([$array_name], [$pattern], [#start]) +``` + +, where `[#start]` — array element number from which to start search, `[$array_name]` — array name to search in, `[$pattern]` — regular expression to compare the searched element with. + +- The `[#start]` parameter can be absent, in which case its value is taken as 0. +- Search works only on text arrays (the `$` symbol in array name can be omitted). + +For example, let's take this array: + +```qsp +$mass[0] = "stomp forward" +$mass[1] = " go to cave" +$mass[2] = "don't go to cave" +$mass[3] = "stomp to house" +``` + +We need to find an element whose value consists of three words. Roughly speaking, a word is a set of one or more non-whitespace characters `\S+`, which can be surrounded by whitespace characters `\s`, so we can compose this regular expression: + +```regex +\s?\S+\s\S+\s\S+\s? +``` + +Now we just need to find out which array element matches the pattern: + +```qsp +arrcomp('$mass', '\s?\S+\s\S+\s\S+\s?') & ! the first element matches this expression +``` + +If we want to ignore the first element and start search from the second: + +```qsp +arrcomp('$mass', '\s?\S+\s\S+\s\S+\s?', 2) & ! the third element matches this expression +``` + +** before the array name or not. The total number of cells with both string and numeric values is counted. For example: + +```qsp +n = ARRSIZE('a') +n = ARRSIZE('$a') +! The result will be the same +``` + +:::warning[Attention!] + +If an array was declared using the `LOCAL` operator, but no value was assigned to any array element, `ARRSIZE` of such array will return `0`. + +::: \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-operacion.md b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-operacion.md new file mode 100644 index 0000000..6fe3d5a --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-operacion.md @@ -0,0 +1,1261 @@ +--- +sidebar_position: 1 +--- + +# Operations + +List of operations for player version 5.8.0 in ascending order of priority: + +- `OR` +- `AND` +- `NO` +- `=`, `<`, `>`, `!`, `<>`, `<=`, `>=`, `=<`, `=>` (comparison operations) +- `OBJ`, `LOC` +- `&` (concatenation) +- `+`, `-` (addition, subtraction) +- `MOD` +- `*`, `/` (multiplication, division) +- `-` (unary minus) +- `([expr])` - expressions in brackets + +Operations written on one line have equal priority and are executed in order from left to right if present at the same level in an expression. + +Operations in brackets have priority over other operations. + +Function value calculation has priority over all operations. + +A numeric expression whose value is not `0` is considered true. When the value is `0`, the expression is considered false. For the "true" value, it's strongly recommended to use `1` for compatibility with logical operations and functions returning logical values. + +:::note[5.7.0] +In older player versions, the priority order was different. + +- `&` +- `OR` +- `AND` +- `OBJ`, `LOC`, `NO` +- `=`, `<`, `>`, `!`, `<>`, `<=`, `>=`, `=<`, `=>` +- `+`, `-` +- `MOD` +- `*`, `/` +- `+`, `-` (unary) + +::: + +**Some features of comparison operations:** + +- Comparison operations return `1` (true) or `0` (false) depending on the comparison result. +- When comparing numbers, everything is simple: + - of two positive numbers, the positive number with greater magnitude will be considered greater; + - a negative number is always less than a non-negative (positive and zero); + - a positive number is always greater than a non-positive (negative and zero); + - of two negative numbers, the negative number with greater magnitude will be considered smaller. +- When comparing strings, character-by-character comparison occurs from left to right: + - the character that comes later in the character table is considered greater. You can rely on alphabetical sequence of characters to understand which string will be greater. Then character '`z`' will be greater than character '`a`'. Examples: + + ```qsp + 'z' > 'a' & ! returns 1 + 'z' > 'az' & ! returns 1 + 'akz' > 'akk' & ! returns 1 + ``` + + - when comparing any non-empty string with an empty string, the empty string will be considered smaller: + + ```qsp + ' ' > '' & ! returns 1 + 'a' > '' & ! returns 1 + 'z' > '' & ! returns 1 + 'akzakz' > 'akzak' & ! returns 1 + ``` + + :::tip[You can consider] + that missing characters in a string are empty characters (empty strings), which when compared with any other character turn out to be smaller. + ::: + + - when comparing a string with a number, the player will try to convert both values to numbers. If successful, numbers will be compared. If unsuccessful — the number will be converted to a string, and strings will be compared. + + ```qsp + 'zzz' > 123 & ! returns 1 + '123' > 92 & ! returns 1 + '123' > '92' & ! returns 0 + ``` + +- When comparing tuples, element-by-element comparison occurs from left to right: + - the tuple whose element turned out to be greater will be considered greater: + + ```qsp + [1, 2, 3] > [1, 2, 2] & ! returns 1 + [2, 2, 3] > [1, 2, 3] & ! returns 1 + ``` + + - when comparing any non-empty tuple with an empty tuple, the empty tuple will be considered smaller: + + ```qsp + [1] > [] & ! returns 1 + [''] > [] & ! returns 1 + [0] > [] & ! returns 1 + [1, 2] > [1] & ! returns 1 + [1, 2] < [9] & ! returns 1 + ``` + + :::tip[You can consider] + that missing elements in a tuple are empty elements, which when compared with any other element turn out to be smaller. + ::: + + - when comparing tuples with numbers or strings, the number or string will be compared as a tuple of one element. For easier understanding, you can consider that the number or string is converted to a tuple when compared: + + ```qsp + [8] < 9 & ! returns 1 + [9, 8] > 9 & ! returns 1 + [0, 0] > 9 & ! returns 0 + + [8, 9] > '8,9' & ! returns 0 + ['a', 'z'] < 'az' & ! returns 1 + ['a', 'z'] > 'a' & ! returns 1 + (['az'] = "az") & ! returns 1 + ``` + +:::warning[We recommend:] +Not to compare values of different types to avoid confusion. +::: + +## `*` (multiplication) + +`*` — arithmetic operation "MULTIPLICATION". Multiplies two numbers. General syntax: + +```qsp +[#expression 1] * [#expression 2] +``` + +, where `[#expression 1]` and `[#expression 2]` — any two numeric values or expressions. The operation result is the product of two numbers. + +Examples: + +```qsp +2 * 2 & ! returns 4 +4 * 2 & ! returns 8 +17 * 5 & ! returns 85 +37 * 100 & ! returns 3700 +``` + +Can be used with tuples whose values are numbers and/or other tuples containing numbers. General syntax: + +```qsp +[%tuple] * [#number] +``` + +In this case, each tuple element will be multiplied by the specified number. Examples: + +```qsp +%tuple = [4, 10, 16] +%a = %tuple * 2 +! %a will equal [8, 20, 32] + +[4, 10] * 'b' & ! data type mismatch error +``` + +Note the last example. A data type mismatch error occurs because it's impossible to apply multiplication to a string value. The same error will occur if the tuple contains string values. However, you can multiply tuples containing only numeric values: + +```qsp +*pl [2, 3] * [4, 5] +! [2 * [4,5], 3 * [4,5]] +! [[8,10],[12,15]] +``` + +In this case, each element of the first tuple is multiplied by the second tuple. This gives us a new tuple of two tuples as a result. + +## `*=` (multiplication-assignment) + +`*=` — "MULTIPLICATION-ASSIGNMENT" operation. Combines assignment and multiplication operations. Multiplies the specified variable value by a certain number and returns the result to the same variable. General syntax: + +```qsp +ARRAY_NAME *= [#expression 1] +``` + +, where `ARRAY_NAME` — variable name (without quotes) or array name with cell specification, and `[#expression 1]` — any numeric value or expression. + +Analogous to: + +```qsp +ARRAY_NAME = ARRAY_NAME*[#expression 1] +``` + +Example: + +```qsp +! we replace two operations: assignment and multiplication +warrior = warrior * 2 +! with multiplication-assignment (identical action) +warrior *= 2 +``` + +If the `ARRAY_NAME` variable value is a tuple, each tuple element will be multiplied by the specified number, and the resulting tuple will be assigned to the variable. Example: + +```qsp +%tuple = [4, 10, 16] +%tuple *= 2 +! %tuple will equal [8, 20, 32] +``` + +You cannot multiply by a string type value; this will lead to a data type mismatch error. Also, tuple values (and all nested tuples) should not contain string values when performing this operation. However, you can perform multiplication-assignment with another tuple: + +```qsp +%tuple = [2, 3] +%tuple *= [4, 5] +! %tuple will equal [[8,10],[12,15]] +``` + +:::warning[Note] +Multiplication-assignment with a tuple will cause a data type mismatch error if the variable type is not a tuple: + +```qsp +number = 4 +number *= [4,5] & ! data type mismatch error +! this way there will be no error, but the variable will contain an empty tuple: +%number *= [4,5] +``` + +::: + +## `+` (addition) + +`+` — arithmetic operation "ADDITION". Adds two numbers. General syntax: + +```qsp +[expression 1]+[expression 2] +``` + +, where `[expression 1]` and `[expression 2]` — any two values or expressions. The operation result is the sum of two values. + +Examples: + +```qsp +2+2 & ! returns 4 +4+2 & ! returns 6 +17+5 & ! returns 22 +37+100 & ! returns 137 +``` + +When "adding" string values, [concatenation](qsp-keyword-operacion.md#-concatenation) is performed, i.e., "gluing" strings together: + +```qsp +! the string "2627" will be output to screen +"26"+"27" +``` + +If values are "added" to a tuple, each tuple element is summed with the specified value: + +```qsp +%tuple = [4, 10, 16] +%a = %tuple + 2 +! %a will equal [6, 12, 18] +``` + +If two tuples are added, the second tuple is added to the values of each element of the first tuple: + +```qsp +[4, 10] + ['b', 'x'] +! [4 + ['b', 'x'], 10 + ['b', 'x']] +! [['4b','4x'], ['10b','10x']] +``` + +## `+=` (addition-assignment) + +`+=`, `(increment)` — "INCREMENT" operation, combining assignment and addition operations. Adds the specified value to the current variable value. General syntax: + +```qsp +ARRAY_NAME += [expression 1] +``` + +, where `ARRAY_NAME` — variable name (without quotes) or array name with cell specification, and `[expression 1]` — any value or expression. + +Analogous to: + +```qsp +ARRAY_NAME = ARRAY_NAME + [expression 1] +``` + +Example: + +```qsp +! we replace two operations: assignment and addition +warrior = warrior + 15 +! with increment (identical action) +warrior += 15 +``` + +It's also possible to perform increment with string values, works like [concatenation](qsp-keyword-operacion.md#-concatenation): + +```qsp +$text += " (maybe something is written here)" +``` + +If the `ARRAY_NAME` variable value is a tuple, each tuple element will be summed with the specified value, and the resulting tuple will be assigned to the variable. Example: + +```qsp +%tuple = [4, 10, 16] +%tuple += 2 +! %tuple will equal [6, 12, 18] +``` + +You can perform addition-assignment with another tuple: + +```qsp +%tuple = [2, 3] +%tuple += [4, 5] +! %tuple will equal [[6,7],[7,8]] +``` + +:::warning[Note] +Addition-assignment with a tuple will cause a data type mismatch error if the variable type is not a tuple: + +```qsp +number = 4 +number += [4,5] & ! data type mismatch error +! this way there will be no error, but the variable will contain an empty tuple: +%number += [4,5] +``` + +::: + +:::tip[Note] +Increment — in many programming languages this is an operation that performs variable increase. Most often, increment means increasing a variable by `1`. +::: + +## `-` (subtraction) + +`-` — arithmetic operation "SUBTRACTION". Subtracts one number from another. General syntax: + +```qsp +[#expression 1] - [#expression 2] +``` + +, where `[#expression 1]` and `[#expression 2]` — two numeric values or expressions. The operation result is the difference of two values. + +Examples: + +```qsp +2 - 2 & ! returns 0 +4 - 2 & ! returns 2 +17 - 5 & ! returns 12 +37 - 100 & ! returns -63 +``` + +Can be used with tuples whose values are numbers and/or other tuples containing numbers. General syntax: + +```qsp +[%tuple] - [#number] +``` + +In this case, the specified number will be subtracted from each tuple element. Examples: + +```qsp +%tuple = [4, 10, 16] +%a = %tuple - 2 +! %a will equal [2, 8, 14] + +[4, 10] - 'b' & ! data type mismatch error +``` + +Note the last example. A data type mismatch error occurs because it's impossible to apply subtraction to a string value. The same error will occur if the tuple contains string values. However, you can subtract one tuple from another if both tuples contain only numeric values: + +```qsp +*pl [2, 3] - [4, 5] +! [2 - [4,5], 3 - [4,5]] +! [2 + ([4,5] * -1), 3 + ([4,5] * -1)] +! [[-4, -5] + 2, [-4,-5] + 3] +! [[-2,-3],[-1,-2]] +``` + +In this case, the second tuple is subtracted from each element of the first tuple. If you sequentially expand brackets and perform all necessary mathematical operations, you get a new tuple containing other tuples with results. + +## `-=` (subtraction-assignment) + +**`-=`, `(decrement)`** — "DECREMENT" operation, combining assignment and subtraction operations. Subtracts the specified value from the current variable value. General syntax: + +```qsp +ARRAY_NAME -= [#expression 1] +``` + +, where `ARRAY_NAME` — variable name (without quotes) or array name with cell specification, and `[#expression 1]` — any numeric value or expression. + +Analogous to: + +```qsp +ARRAY_NAME = ARRAY_NAME - [#expression 1] +``` + +Example: + +```qsp +! we replace two operations: assignment and subtraction +warrior = warrior - 15 +! with decrement (identical action) +warrior -= 15 +``` + +If the `ARRAY_NAME` variable value is a tuple, the specified number will be subtracted from each tuple element, and the resulting tuple will be assigned to the variable. Example: + +```qsp +%tuple = [4, 10, 16] +%tuple -= 2 +! %tuple will equal [2, 8, 14] +``` + +You cannot subtract a string type value; this will lead to a data type mismatch error. Also, tuple values (and all nested tuples) should not contain string values when performing this operation. However, you can perform subtraction-assignment with another tuple: + +```qsp +%tuple = [2, 3] +%tuple -= [4, 5] +! %tuple will equal [[-2,-3],[-1,-2]] +``` + +:::warning[Note] +Subtraction-assignment with a tuple will cause a data type mismatch error if the variable type is not a tuple: + +```qsp +number = 4 +number -= [4,5] & ! data type mismatch error +! this way there will be no error, but the variable will contain an empty tuple: +%number -= [4,5] +``` + +::: + +:::tip[Note] +Decrement — in many programming languages this is an operation that performs variable decrease. Most often, decrement means decreasing a variable by `1`. +::: + +## `-` (unary minus) + +**unary `-`** — unary operation. General syntax: + +```qsp +-[#expression] +``` + +, where `[#expression]` — any numeric value or expression. The result of this operation is the same value but with opposite sign. + +Examples: + +```qsp +-2 & ! returns -2 +-(3+6) & ! returns -9 +-(-27) & ! returns 27 +``` + +Unary minus can be used before a tuple containing only numeric values. This expression will return a new tuple where the sign of each element is changed to opposite: + +```qsp +- [2, 3, -1, -17, 5] +! [-2, -3, 1, 17, -5] +``` + +:::note[5.7.0] + +In earlier player versions, there was a "unary plus" operation: + +```qsp ++(6+7) +``` + +Essentially, it did nothing, so it was decided to abandon it. +::: + +## `/` (division) + +`/` — arithmetic operation "DIVISION". General syntax: + +```qsp +[#expression 1] / [#expression 2] +``` + +, where `[#expression 1]` and `[#expression 2]` — any two numeric values or expressions. The value `[#expression 2]` must not equal zero. The operation result is the quotient of dividing two numbers. + +Since QSP supports only integer values, division is also performed as integer division, without rounding, with truncation of the fractional part. + +Examples: + +```qsp +2 / 2 & ! returns 1 +4 / 2 & ! returns 2 +17 / 5 & ! returns 3 +37 / 100 & ! returns 0 +``` + +Can be used with tuples whose values are numbers and/or other tuples containing numbers. General syntax: + +```qsp +[%tuple] / [#number] +``` + +In this case, each tuple element will be divided by the specified number. Examples: + +```qsp +%tuple = [4, 10, 16] +%a = %tuple / 2 +! %a will equal [2, 5, 8] + +[4, 10] / 'b' & ! data type mismatch error +``` + +Note the last example. A data type mismatch error occurs because it's impossible to apply division to a string value. The same error will occur if the tuple contains string values. However, you can divide tuples containing only numbers: + +```qsp +*pl [30, 60] / [2, 6] +! [30 / [2,6], 60 / [2,6]] +! [[15,5],[30,10]] +``` + +In this case, each element of the first tuple is "divided" by the second tuple. This gives us a new tuple of two tuples as a result. + +## `/=` (division-assignment) + +`/=` — "DIVISION-ASSIGNMENT" operation. Combines assignment and division operations. Divides the specified variable value by a certain number and returns the result to the same variable. General syntax: + +```qsp +ARRAY_NAME /= [#expression 1] +``` + +, where `ARRAY_NAME` — variable name (without quotes) or array name with cell specification, and `[#expression 1]` — any numeric value or expression. + +Analogous to: + +```qsp +ARRAY_NAME = ARRAY_NAME / [#expression 1] +``` + +Example: + +```qsp +! we replace two operations: assignment and division +warrior = warrior / 2 +! with division-assignment (identical action) +warrior /= 2 +``` + +If the `ARRAY_NAME` variable value is a tuple, each tuple element will be divided by the specified number, and the resulting tuple will be assigned to the variable. Example: + +```qsp +%tuple = [4, 10, 16] +%tuple /= 2 +! %tuple will equal [2, 5, 8] +``` + +You cannot divide by a string type value; this will lead to a data type mismatch error. Also, tuple values (and all nested tuples) should not contain string values when performing this operation. However, you can perform division-assignment with another tuple: + +```qsp +%tuple = [10, 30] +%tuple /= [5, 2] +! %tuple will equal [[2,5],[6,15]] +``` + +:::warning[Note] +Division-assignment with a tuple will cause a data type mismatch error if the variable type is not a tuple: + +```qsp +number = 4 +number /= [4,5] & ! data type mismatch error +! this way there will be no error, but the variable will contain an empty tuple: +%number /= [4,5] +``` + +::: + +## MOD + +`MOD` — operation calculates the remainder from dividing two numbers. General syntax: + +```qsp +[#expression 1] MOD [#expression 2] +``` + +, where `[#expression 1]` — dividend, `[#expression 2]` — divisor. + +Examples: + +```qsp +! 4 divides by 2 evenly +4 mod 2 & ! returns 0 +! 5 doesn't divide by 2 evenly +5 mod 2 & ! returns 1 +! 13 doesn't divide by 10 evenly +13 mod 10 & ! returns 3 +``` + +The remainder from dividing a negative number will be a negative number. + +## `<` (less than) + +`<` — comparison operation "LESS THAN". General syntax: + +```qsp +[expression_1] < [expression_2] +``` + +If the value of expression `[expression_1]` is less than the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns `0`. In other words: true if the first is less than the second. + +Examples: + +```qsp +! 2 is less than 4 — returns 1 +2 < 4 +! 5 is not less than 5 — returns 0 +5 < 5 +! 7 is not less than 3 — returns 0 +7 < 3 +``` + +You can compare text values: + +```qsp +"a" < "z" & ! true +"z" < "zz" & ! true +"aaaaaa" < "z" & ! true +``` + +And you can compare tuples: + +```qsp +[1, 2, 3] < [1, 2, 9] & ! true +[1, 2, 3] < [2, 2, 3] & ! true +[1, 2] < [1, 2, 3] & ! true +``` + +## `<=` (less than or equal) + +`<=` — comparison operation "LESS THAN OR EQUAL". General syntax: + +```qsp +[expression_1] <= [expression_2] +``` + +If the value of expression `[expression_1]` is less than or equal to the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns `0`. In other words: true if the first is less than the second, or equal to it. + +Examples: + +```qsp +! 2 is less than 4 — returns 1 +2 <= 4 +! 5 equals 5 — returns 1 +5 <= 5 +! 7 is not less than three and not equal to it +7 <= 3 & ! returns 0 +``` + +Analogous to "`=<`" and constructs: + +```qsp +([expression_1] < [expression_2]) or ([expression_1] = [expression_2]) + +no [expression_1] > [expression_2] +``` + +You can also compare text values: + +```qsp +"a" <= "z" & ! true +"z" <= "zz" & ! true +"aaaaaa" <= "z" & ! true +"z" <= "z" & ! true +``` + +And tuples: + +```qsp +[1, 2, 3] <= [1, 2, 9] & ! true +[1, 2, 3] <= [2, 2, 3] & ! true +[1, 2] <= [1, 2, 3] & ! true +[1, 2, 3] <= [1, 2, 3] & ! true +``` + +## `<>` (not equal) + +`<>` — comparison operation "NOT EQUAL". General syntax: + +```qsp +[expression_1] <> [expression_2] +``` + +If the value of expression `[expression_1]` is not equal to the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns `0`. In other words: true if the expressions are not equal. + +Analogous to "`!`", or construct: + +```qsp +no [expression_1] = [expression_2] +``` + +Examples: + +```qsp +! 2 is not equal to 4 — returns 1 +2 <> 4 +! 5 equals 5 — returns 0 +5 <> 5 +``` + +You can compare string values: + +```qsp +"abc" <> "def" & ! returns 1 +"abc" <> "abc" & ! returns 0 +``` + +You can compare tuples: + +```qsp +[1, 2, 3] <> [4, 6, 7] & ! returns 1 +[1, 2, 3] <> [1, 2, 3] & ! returns 0 +``` + +## `=` (equal) + +`=` — comparison operation "EQUAL". General syntax: + +```qsp +[expression_1] = [expression_2] +``` + +If the value of expression `[expression_1]` equals the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns `0`. In other words: true if the expressions are equal. + +Analogous to construct: + +```qsp +no [expression_1] <> [expression_2] +``` + +Examples: + +```qsp +! 2 is not equal to 4 — returns 0 +(2 = 4) +! 5 equals 5 — returns 1 +(5 = 5) +``` + +You can compare string values: + +```qsp +("abc" = "def") & ! returns 0 +("abc" = "abc") & ! returns 1 +``` + +You can compare tuples: + +```qsp +([1, 2, 3] = [4, 6, 7]) & ! returns 0 +([1, 2, 3] = [1, 2, 3]) & ! returns 1 +``` + +:::warning[Attention!] +Don't confuse with the [assignment operation](#-assignment). +::: + +## `=` (assignment) + +`=` — assignment operation. General syntax: + +```qsp +ARRAY_NAME = [value] +``` + +, where `ARRAY_NAME` — variable name (not in quotes) or array name with cell specification (not in quotes), `[value]` — any value or expression. + +Examples: + +```qsp +! assign value 13 to variable BOX +BOX = 13 +! assign value "Text string" to variable $text +$text = "Text string" +! assign value 365 to zero cell of array day +day[0] = 365 +! assign tuple [1, 'unit', 3] to variable tuple: +%tuple = [1, 'unit', 3] +``` + +String variable/array names must start with the `$` symbol. + +Variable/array names containing tuples must start with the `%` symbol. + +:::warning[Attention!] +The assignment operation should not be confused with the "EQUAL TO" comparison operation, although they look very similar: + +```qsp +! assignment operation +alukard = 1000 +! comparison operation +(alukard = 1000) +``` + +In this case, the player understands that inside the brackets is a comparison operation because brackets are used for writing expressions. The notation: + +```qsp +"abc" = "abc" +``` + +is syntactically incorrect. The player will give an error: invalid variable/array name. Since in this case it doesn't understand that this is a comparison operation. + +If an operator explicitly precedes the comparison operation, brackets can be omitted: + +```qsp +if alukard = 150: *pl "Not enough strength" +*pl "abc" = "abc" +``` + +::: + +### Multiple Assignment + +Multiple assignment allows assigning values to several variables or array cells with one `=` command. General syntax: + +```qsp +ARRAY_NAME_1, ARRAY_NAME_2, ... , ARRAY_NAME_N = [VALUE_1], [VALUE_2], ... , [VALUE_N] +``` + +, where variable names (or array names with cell index specification in square brackets) are written to the left of the `=` sign, and values to be assigned to variables or array cells are listed to the right of the `=` sign. + +:::warning[Important to remember!] +There must be as many variables to the left of the equals sign as there are values to the right. The number of variables and the number of assigned values must match. + +This rule is not followed when unpacking tuples. +::: + +Examples: + +```qsp +apples_in_pocket, apples_in_basket, apples_at_lyoshka = 58, 11, 19 +$string_1, $string_2 = 'Grekha rode across the river', 'Grekha sees a crab in the river' +$name, count = 'Old sword', 2 +``` + +Instead of directly specifying values, you can assign values of other variables, expressions, functions: + +```qsp +! three variables = three values +red, green, blue = rand(0,255), rand(0,255), rand(0,255) +! two variables = two values +apples_in_pocket, apples_in_basket = apples_at_lyoshka, apples_on_tree+15 +``` + +Thanks to the ability to simultaneously assign values to several variables, you can swap data in two variables without using a third: + +```qsp +! assign variables x and y values 12 and 99 +x, y = 12, 99 +! swap values. Now x contains number 99, and y — 12 +x, y = y, x +``` + +### Tuple Unpacking + +Since tuples contain several values at once, the notation for assigning values to variables from tuples can differ from the usual: + +```qsp +! %unit = [187, 94, 'steel', [0, 2]] +height, weight, $material, %coordinates = %unit +``` + +As you can see, here we have four variable names on the left, but only one tuple variable name on the right. Such assignment is called unpacking — values are extracted from the tuple and placed in the specified variables. + +A tuple not placed in a variable is unpacked the same way: + +```qsp +height, weight, $material, %coordinates = [187, 94, 'steel', [0, 2]] +``` + +Such notation differs little from multiple assignment, so external square brackets are not required: + +```qsp +height, weight, $material, %coordinates = 187, 94, 'steel', [0, 2] +``` + +It should be emphasized that **multiple assignment is essentially tuple unpacking**. + +Since if there are more variables to the left of the equals sign than values in the tuple, default values for those variables will be written to the "extra" variables, the same will happen with multiple assignment. + +```qsp +r, g, b, a = [255, 188, 19] +! r = 255, g = 188, b = 19, a = 0 +raz, dva, tri, chetyre = 137, 61 +! raz = 137, dva = 61, tri = 0, chetyre = 0 +``` + +At the same time, if there are fewer variables to the left of the equals sign than values to the right in multiple assignment, this will cause a data type mismatch error: + +```qsp title="Data type mismatch" +coords = 23, 34 +age, weight, material = 27, 94, 'steel', 'biorobot' +``` + +If the type of the last listed variable is a tuple, such assignment won't cause an error: + +```qsp +age, weight, %type = 27, 94, 'steel', 'biorobot' +! age = 27, weight = 94, %type = ['steel', 'biorobot'] +``` + +## `=<` (equal or less) + +:::warning[Attention!] +This notation, although acceptable in QSP, is not recommended for use. Use "`<=` (less than or equal)" instead. +::: + +`=<` — comparison operation "EQUAL OR LESS". General syntax: + +```qsp +[expression_1] =< [expression_2] +``` + +If the value of expression `[expression_1]` is less than or equal to the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns 0. In other words: true if the first is less than the second, or equal to it. + +Examples: + +```qsp +! 2 is less than 4 — returns 1 +2 =< 4 +! 5 equals 5 — returns 1 +5 =< 5 +! 7 is not less than three and not equal to it +7 =< 3 & ! returns 0 +``` + +Analogous to "`<=`" and constructs: + +```qsp +([expression_1] < [expression_2]) or ([expression_1] = [expression_2]) + +no [expression_1] > [expression_2] +``` + +## `=>` (equal or greater) + +:::warning[Attention!] +This notation, although acceptable in QSP, is not recommended for use. Use "`>=` (greater than or equal)" instead. +::: + +`=>` — comparison operation "EQUAL OR GREATER". General syntax: + +```qsp +[expression_1] => [expression_2] +``` + +If the value of expression `[expression_1]` is greater than or equal to the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns 0. In other words: true if the first is greater than the second, or equal to it. + +Examples: + +```qsp +! 2 is not greater than and not equal to 4 — returns 0 +2 => 4 +! 5 equals 5 — returns 1 +5 => 5 +! 7 is greater than 3 +7 => 3 & ! returns 1 +``` + +Analogous to "`>=`" and constructs: + +```qsp +([expression_1] > [expression_2]) or ([expression_1] = [expression_2]) +no [expression_1] < [expression_2] +``` + +## `>` (greater than) + +`>` — comparison operation "GREATER THAN". General syntax: + +```qsp +[expression_1] > [expression_2] +``` + +If the value of expression `[expression_1]` is greater than the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns `0`. In other words: true if the first is greater than the second. + +Examples: + +```qsp +! 2 is not greater than 4 — returns 0 +2 > 4 +! 5 is not greater than 5 — returns 0 +5 > 5 +! 7 is greater than 3 — returns 1 +7 > 3 +``` + +You can compare text values, where characters are compared sequentially, and the character closer to the end of the alphabet is considered greater. + +```qsp +"z" > "a" & ! true +"zz" > "z" & ! true +"z" > "aaaaaa" & ! true +``` + +And you can compare tuples: + +```qsp +[1, 2, 9] > [1, 2, 3] & ! true +[1, 2, 3] > [2, 2, 3] & ! false +[1, 2, 3] > [1, 2] & ! true +``` + +## `>=` (greater than or equal) + +`>=` — comparison operation "GREATER THAN OR EQUAL". General syntax: + +```qsp +[expression_1] >= [expression_2] +``` + +If the value of expression `[expression_1]` is greater than or equal to the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns 0. In other words: true if the first is greater than the second, or equal to it. + +Examples: + +```qsp +! 2 is not greater than and not equal to 4 — returns 0 +2 >= 4 +! 5 equals 5 — returns 1 +5 >= 5 +! 7 is greater than 3 +7 >= 3 & ! returns 1 +``` + +Analogous to "`=>`" and constructs: + +```qsp +([expression_1] > [expression_2]) or ([expression_1] = [expression_2]) +no [expression_1] < [expression_2] +``` + +You can compare text values, where characters are compared sequentially, and the character closer to the end of the alphabet is considered greater. + +```qsp +"z" >= "a" & ! true +"zz" >= "z" & ! true +"z" >= "aaaaaa" & ! true +"z" >= "z" & ! true +``` + +And tuples: + +```qsp +[1, 2, 9] >= [1, 2, 3] & ! true +[1, 2, 3] >= [2, 2, 3] & ! false +[1, 2] >= [1, 2, 3] & ! false +[1, 2, 3] >= [1, 2, 3] & ! true +``` + +## `!` (not equal) + +:::warning[Attention!] +Don't confuse with the comment operator. + +For better code readability, we recommend using `<>`. +::: + +`!` — comparison operation "NOT EQUAL". General syntax: + +```qsp +[expression_1]![expression_2] +``` + +If the value of expression `[expression_1]` is not equal to the value of expression `[expression_2]`, the operation returns `1`, otherwise it returns `0`. In other words: true if the expressions are not equal. + +Analogous to "`<>`", or construct: + +```qsp +no [expression_1] = [expression_2] +``` + +Examples: + +```qsp +! 2 is not equal to 4 — returns 1 +2 ! 4 +! 5 equals 5 — returns 0 +5 ! 5 +``` + +## `&` (concatenation) + +`&` — concatenation, operation for combining string expressions or tuples. General syntax: + +```qsp +([$expression 1] & [$expression 2]) +([%expression 1] & [%expression 2]) +``` + +:::warning[Attention!] +Concatenation must always be enclosed in brackets! +::: + +If you try to combine numeric values, they will be converted to strings, and then the strings will be combined. + +Examples: + +```qsp +*pl ('hello, ' & 'World!') +! we'll see the string 'hello, World!' on screen +*pl ([1, 2, 3] & [4, 5, 6]) +! we'll see the tuple [1, 2, 3, 4, 5, 6] on screen +``` + +:::warning[Attention!] +Don't confuse with the command enumeration symbol: + +```qsp +! in this case, strings "26" and "27" will be +! output to screen sequentially +"26" & "27" +! and here the string "2627" will be output to screen +("26" & "27") +``` + +::: + +:::tip +It's not recommended to use this operation for combining strings, since strings can be combined through [`+`](qsp-keyword-operacion.md#-addition): + +```qsp +! the string "2627" will be output to screen +"26"+"27" +``` + +Such notation creates less confusion when reading code and works similarly. + +You can't join two tuples into one using the `+` operation: + +```qsp +[2, 5] + [3, 7] +! the tuple [[5,9],[8,12]] will be on screen +``` + +::: + +## AND + +`AND` — logical "AND". General syntax: + +```qsp +[#expression 1] AND [#expression 2] +``` + +The entire expression will be true if both `[#expression 1]` and `[#expression 2]` are true. + +Examples: + +```qsp +! both parts of expression are true, so entire expression is true +(2 = 2) and (3 <> 2) & ! expression returns 1 (true) +! one part of expression is not true, so entire expression is false +(2 <> 2) and (3 <> 2) & ! expression returns 0 (false) +! both parts of expression are not true, so entire expression is not true +(2 <> 2) and (3 = 2) & ! expression returns 0 (false) +``` + +:::note[5.7.0] +In older player versions, the operation was bitwise. +::: + +## LOC + +`LOC` — operation checks for location existence and returns `1` if location exists, and `0` if location doesn't exist. General syntax: + +```qsp +LOC([$location]) +``` + +, where `[$location]` — location name whose existence needs to be checked in the game. Expression is true if location exists in the game. + +Examples: + +```qsp +! checks if location "start" exists in game +loc("start") & ! if location exists, returns 1 + +! if location "street" is not added to game +if loc("street") = 0: + act "Go outside": *pl "I can't go outside, the door won't open." +end +``` + +## NO + +`NO` — negation operation. General syntax: + +```qsp +NO [#expression] +``` + +If `[#expression]` is true, then the entire expression is false, and vice versa. In other words, returns `0` if the expression value is not zero, and returns `1` if the expression value equals `0`. + +Example: + +```qsp +! 4 equals 4 is true, so entire expression is false +no (4 = 4) & ! returns 0 (false) +! can be read as question: four does not equal four? No — false. + +! that 5 equals 3 is false, so entire expression is true +no (5 = 3) & ! returns 1 (true) +! can be read as question: five does not equal three? Yes — true. +``` + +:::note[5.7.0] +In older player versions, the operation was bitwise. +::: + +## OBJ + +`OBJ` — operation checks for item presence in inventory and returns `1` if item exists, and `0` if item doesn't exist. General syntax: + +```qsp +OBJ([$name]) +``` + +, where `[$name]` — item name whose presence needs to be checked in the objects window. Expression is true if item is added to the objects window. + +Examples: + +```qsp +! checks if "Screwdriver" item is added to objects window +obj("Screwdriver") & ! if item exists, returns 1 + +! depending on presence of this or that item +! this or that action is output +if obj("Full jug") = 1: + act "Empty jug": + delobj "Full jug" + addobj "Empty jug" + goto $curloc + end +elseif obj("Empty jug") = 1: + act "Fill jug": + addobj "Full jug" + delobj "Empty jug" + goto $curloc + end +end +``` + +## OR + +`OR` — logical "OR". General syntax: + +```qsp +[#expression 1] OR [#expression 2] +``` + +The entire expression will be true if at least one of expressions `[#expression 1]` and `[#expression 2]` is true. + +Examples: + +```qsp +! both parts of expression are true, so entire expression is true +(2 = 2) or (3 <> 2) & ! expression returns 1 (true) +! one part of expression is true, so entire expression is true +(2 <> 2) or (3 <> 2) & ! expression returns 1 (true) +! both parts of expression are not true, so entire expression is not true +(2 <> 2) or (3 = 2) & ! expression returns 0 (false) +``` + +:::note[5.7.0] +In older player versions, the operation was bitwise. +::: \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-operators.md b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-operators.md new file mode 100644 index 0000000..12d436d --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-operators.md @@ -0,0 +1,2023 @@ +--- +sidebar_position: 2 +--- + +# Operators + +## Implicit operator + +The implicit operator is an operator that is not written in QSP code but outputs values to the screen. It is implied wherever an expression without an operator is present in a command. The implicit operator outputs values to the **Main Description Window** in the same way as if you used explicit specification of the `*pl` operator, i.e., it outputs the value and makes a line break. Examples: + +```qsp +$AAA + '989' +'You are in the park' +'Preformatted + + string' +$curloc & ! will output the location name to the screen +``` + +Unlike the `*pl` operator, the implicit operator does not output an empty line with a line break to the screen if no value is passed to it. This means that if a function returns no value, the implicit operator is simply ignored. Example: + +```qsp +# start +! this is the code of a location calling a location-function +$curloc +$func('foo') +$func('foo') +$curloc +- start + +# foo +! this is the code of the location-function +local i = 0 +- foo +``` + +In this case, the location-function `foo` returns nothing, so we will see two lines with the word "start" on the screen, with no empty lines between them, since the implicit operator in the lines with `$func` at location `start` will be simply ignored. Compare with: + +```qsp +# start +! this is the code of a location calling a location-function +*pl $curloc +*pl $func('foo') +*pl $func('foo') +*pl $curloc +- start + +# foo +! this is the code of the location-function +local i=0 +- foo +``` + +## `!` (comment) + +`!` — comment operator. What is in the line after the comment operator and until the end of the line is ignored by the interpreter. The comment operator allows you to "comment out" (disable) an unnecessary operator/function temporarily during game debugging. In addition, writing comments to program code is one of the signs of good programming style. + +It is necessary to clearly understand that this is an operator, so if you are commenting some line of code, then `!` should come after `&`: + +```qsp +*pl "Hello, world!" & ! comment +``` + +Comments can be single-line, i.e., end on the same line where the comment operator is located: + +```qsp +! single-line comment +*pl "text string" & ! also a single-line comment +``` + +:::tip[Exception] +The only exception to this rule is writing a comment after a colon in multi-line operators: + +```qsp +act "Multi-line action": ! comment + *pl "Text on screen" +end +``` + +::: + +Comments can be multi-line. For this, after the comment operator, you need to write quotes, apostrophes, or curly braces. For example: + +```qsp +! "this is the first line of the comment + this is the second line of the comment + this is the third line of the comment +" +``` + +Multi-line comments can take various forms: + +```qsp +! line before quotes " text inside quotes +can move to other lines " as well as { +you can use other character groups to +continue the multi-line comment +} and the comment won't end until the line ends +``` + +## `*CLEAR` + +`*CLEAR` — clears the main description window. Has a short form `*clr`. + +## `*NL` + +`*NL` — line break, then text output in the main description window. General syntax: + +```qsp +*NL [$text] +``` + +where `[$text]` is any text string, number, or expression of any type. If `[$text]` is absent, a simple line break occurs. Example: + +```qsp +*p "Text without line break." +*nl "Line break + text output." +*p "Text without line break." +``` + +## `*P` + +`*P` — text output to the main description window without line break. Text output by any other operator immediately after `*p` will add new text immediately after the current text. General syntax: + +```qsp +*P [$text] +``` + +where `[$text]` is any text string, number, or expression of any type. `[$text]` can be an empty string `''`, but should not be absent. Example: + +```qsp +*p "Text without line break." +*p "Text without line break." +*p "" +*p "Text without line break." +``` + +## `*PL` + +`*PL` — text output to the main description window, then line break. General syntax: + +```qsp +*PL [$text] +``` + +where `[$text]` is any text string, number, or expression of any type. `[$text]` can be absent, then just a line break. Example: + +```qsp +*pl "Text output, then line break." +*pl "Text output, then line break." +*p "Text without line break." +*pl "Text output, then line break." +``` + +You can output text in the same way by simply writing the needed expression instead of this operator. For example, the lines: + +```qsp +*pl $AAA + '989' +*pl 'You are in the park' +*pl 'Preformatted + + string' +``` + +and: + +```qsp +$AAA + '989' +'You are in the park' +'Preformatted + + string' +``` + +will work identically. + +## ACT + +`ACT` — creates and outputs a new action to the actions window. + +General syntax in single-line form: + +```qsp +ACT [$name], [$path to image file]: [operator] & [operator] & [operator] +``` + +General syntax in multi-line form: + +```qsp +ACT [$name], [$path to image file]: + [operator] + [operator] + [operator] +END +``` + +A new action with name `[$name]` and image located at `[$path to image file]` is added to the actions list in the actions window. When the action is clicked, the specified operators are executed. + +The `[$path to image file]` parameter can be absent, in which case the action is added without an image. + +Examples: + +```qsp +! action in single-line form +act "Pick apple from birch": apple += 1 & *pl "You picked a ripe white apple." + +! action in multi-line form, with image +act "Pick watermelon from bush", "img/watermelon.png": + watermelon += 1 + *pl "You picked a watermelon from the bush" +end +``` + +If there is already an action with the specified name in the actions list, no new action is created, and it does not replace the existing one, the player simply ignores the `act` command. Thus, you cannot output actions with identical names. Example: + +```qsp +act "Action 1": *pl "Old action." +act "Action 1": *pl "New action." +``` + +However, you can simulate actions with identical names in HTML recognition mode by adding HTML tags to action names: + +```qsp +usehtml = 1 +act 'Action 1': *pl "Old action." +act 'Action 1': *pl "New action." +``` + +## ADDOBJ + +`ADDOBJ` — adding a new object to the objects window. General syntax: + +```qsp +ADDOBJ [$name], [$path to image file], [#position] +``` + +where `[$name]` is the object name, `[$path to image file]` is the path to the object's image file (displayed next to the object name), and `[#position]` is the position in the inventory where the object is added. The `[#position]` parameter can be absent. By default, objects are added to the end of the list. Object numbering in the inventory starts from `1`. The `[$path to image file]` parameter can be absent, default value is `''`, in which case the object is added without an image. + +:::note[Allowed but not recommended, deprecated form:] + +```qsp +ADD OBJ [$name],[$path to image file],[#index] +``` + +::: + +You can add objects with the same name, but if you plan to add many identical objects, it's better to use an additional variable to count these objects and add one object to the objects window to avoid cluttering the inventory with a list of 137 Ruble / Cartridge objects: + +```qsp +if obj('Cartridges'): +! if object "Cartridges" is already added, just increase their number + cartridges += 10 +else +! if object "Cartridges" is not yet added, add it and increase the number + addobj 'Cartridges' + cartridges += 10 +end +``` + +You can use arrays indexed by strings to store object counts: + +```qsp +objects['money'] = 12 +objects['cartridges'] = 137 +'Quantity: <>' +``` + +Example of adding an object to the very top of the list (all other objects will shift down): + +```qsp +addobj "Screwdriver", "", 1 +``` + +## CLA + +`CLA` - clearing the list of current actions (removing all actions from the actions window). + +## CLEAR + +`CLEAR` — clears the additional description window. Has a short form `clr`. + +## CLOSE + +`CLOSE` — stops playing the specified sound file. General syntax: + +```qsp +CLOSE [$path to sound file] +``` + +where `[$path to sound file]` is the path to the sound file relative to the game file. If the `[$path to sound file]` parameter is not specified, all sound files stop playing. + +## CLOSE ALL + +`CLOSE ALL` — stops playing all active sound files. Has a short form `close`. + +## CLS + +`CLS` — clears all windows except the objects list. Equivalent to the construction: + +```qsp +clear & *clear & cla & cmdclear +``` + +## CMDCLEAR + +`CMDCLEAR` — clearing the input line. Has a short form `cmdclr`. + +## COPYARR + +`COPYARR` — copying the contents of one array to another. General syntax: + +```qsp +COPYARR [$receiver], [$source], [#start], [#count] +``` + +where: `[$receiver]` is the array to which copying is performed, size and content don't matter; `[$source]` is the array from which copying is performed; `[#start]` is the element number from which to start copying; `[#count]` is how many elements to copy. The `[#count]` parameter is optional; by default — until the end of the source array. The `[#start]` parameter is optional; by default — 0. + +Examples: + +```qsp +! copy all elements of array '$b' to array '$a' +copyarr '$a', '$b' +! at the same time, all elements of array 'b' were also copied to array 'a' + +! copy elements of array 'd' starting from the sixth to array 'c' +copyarr 'c', 'd', 6 + +! copy the first six elements of array 'd' to array 'c' +copyarr 'c', 'd', 0, 6 +``` + +Due to player peculiarities, when copying, for example, numeric array `mass1` to `mass2`, text array `$mass1` is also copied to `$mass2`. + +Other examples: + +```qsp +copyarr $arrname1, $arrname2, 10, 5 +copyarr 'a<<$arrname1>>', 'a<<$arrname2>>' +``` + +## DELACT + +`DELACT` — removes an action from the actions list (if such action exists). General syntax: + +```qsp +DELACT [$name] +``` + +where `[$name]` is the name of the action we want to remove. + +Examples: + +```qsp +! remove action with specific name +delact 'Go forward' +! remove selected action +delact $selact +``` + +:::note[Allowed but not recommended, deprecated form:] + +```qsp +DEL ACT [$name] +``` + +::: + +## DELOBJ + +`DELOBJ` — removing an object from inventory by name (if such object exists). General syntax: + +```qsp +DELOBJ [$name] +``` + +where `[$name]` is the name of the object we want to remove. + +If there are identical objects in the inventory, the command will remove the topmost one with the specified index. + +Examples: + +```qsp +! remove object with specific name +delobj "Screwdriver" +! remove selected object +delobj $selobj +``` + +:::note[Allowed but not recommended, deprecated form:] + +```qsp +DEL OBJ [$name] +``` + +::: + +## DYNAMIC + +`DYNAMIC` — executes code passed as a text string. General syntax: + +```qsp + DYNAMIC([$code], [argument 0], [argument 1], ... , [argument 18]) +``` + +where `[$code]` is regular QSP code written as text. Execution of such code is similar to executing `GOSUB` operator code. Arguments `[argument 0]`, `[argument 1]`, etc. can be used inside `[$code]`, their values are automatically placed in variables `args[0]`, `args[1]`, etc. respectively. After execution, old `args` parameters are restored, then code execution continues from the next command after `dynamic`. + +Examples: + +```qsp +dynamic '$a = "string<<$b>>"' +dynamic '$a' +dynamic 'if $a = "string": "text!"' +dynamic " + $args[0] + addobj $args[1] +", 'Text', 'Fork' +``` + +The following information is also true for the [`dyneval`](qsp-keyword-functions.md#dyneval) function. + +**Important!** If code is specified using apostrophes (`''`) or quotes (`""`), sub-expressions are evaluated in the text: + +```qsp +$args[0] = 'qwerty' +$code = ' + *pl "<<$args[0]>>" + *pl $args[0] +' + +dynamic $code, 'asdfg' +``` + +In this case, when setting the `$code` variable, the sub-expression will be evaluated, so the first line will output 'qwerty', the second line will output 'asdfg'. + +Curly braces are the third type of quotes used specifically for writing dynamic code. Here, bracket nesting is supported, and sub-expressions are not evaluated before code execution: + +```qsp +$args[0]='qwerty' +$code = { + *pl "<<$args[0]>>" + *pl $args[0] +} + +dynamic $code, 'asdfg' +``` + +In this case, two lines 'asdfg' will be output. + +## EXIT + +`EXIT` — termination of the current code block execution (premature exit from subroutine, function, event handler, etc.). + +A code block can be a location, action, code passed to `dynamic` or `dyneval`, or code in a hyperlink. + +Example: + +```qsp +if args[1] = 0: + exit +else + if args[0] mod args[1] = 0: + result = 1 + else + result = 0 + end +end +``` + +:::warning[Attention!!!] +In players version 5.8.0, the `loop` operator appeared. + +The loop body is also considered a separate code block, but the `exit` operator interrupts not only the loop itself, but also the code block in which the loop is located. +::: + +## FREELIB + +`FREELIB` — removes all locations added with the `inclib` operator. + +:::note[5.7.0] +In older player versions, the command was called `dellib` and `killqst`. +::: + +## GOSUB + +`GOSUB` — executing code of the specified location without directly going to it. + +General syntax: + +```qsp +GOSUB [$location],[argument 0],[argument 1], ... ,[argument 8] +``` + +where `[$location]` is the name of the location whose code we want to execute without directly going to it. Arguments `[argument 0]`, `[argument 1]`, etc. can be used on this location, their values are automatically placed in variables `args[0]`, `args[1]`, etc. respectively. After processing the location, previous `args` values are restored. Using arguments is not mandatory. + +When accessing a location via `gosub`, the base description of the location is added to the current description, base actions are added to current actions, and operators in the "Execute on visit" field are executed, then return to the original line (continuing code execution after `gosub`). + +Examples of calling locations via `gosub`: + +```qsp +!processing location "move". The args[] array is empty. +gosub 'move' + +!processing location with name from variable $location +!One parameter is passed - args[0] equals 1. +gosub $location,1 + +!processing location "move" with passing 3 parameters. +! $args[0] = $var (value), args[1] = 2, +! $args[2] = "data". Note the '$' symbols. +gosub 'move',$var,2,'data' +``` + +Another example: + +```qsp +! this is the code for calling location "transition" +gosub 'transition', 'location' + +! and this is the code of the location "transition" itself +# transition +*pl $args[0] & ! the text 'location' will be output to the screen +! a new action will appear in the actions window: +act 'go': + goto "street" +end +- transition +``` + +The operator has a short form `gs`: + +```qsp +GS [$location], [argument 0], [argument 1], ... , [argument 18] +``` + +## GOTO + +`GOTO` — transition to the specified location. General syntax: + +```qsp +GOTO [$location], [argument 0], [argument 1], ... , [argument 18] +``` + +where `[$location]` is the name of the location to which the transition should be made. Arguments `[argument 0]`, `[argument 1]`, etc. can be used on this location, their values are automatically placed in variables `args[0]`, `args[1]`, etc. respectively. Using arguments is not mandatory. + +When transitioning to a new location using `goto`, the main description window is cleared, as well as the list of current actions, then the base description text is output to the main description window, base actions to the actions window, and code from the "Execute on visit" field of location `[$location]` is executed. Also, when transitioning to a new location, the value returned by the `$curloc` function changes. + +Examples: + +```qsp +! transition to location "house". +! The args array at location "house" will be empty. +goto 'house' + +! transition to location "street" with passing 2 parameters. +! at location "street" args[0] equals 1, +! $args[1] contains string "data". +goto 'street',1,'data' +``` + +The operator has a short form `gt`: + +```qsp +GT [$location],[argument 0],[argument 1], ... ,[argument 8] +``` + +## IF + +`IF` — the main operator for writing conditional constructions. Constructions written using this operator (let's call them "simple conditions") have two forms: single-line and multi-line, and generally look like this: + +General form: + +```qsp +! single-line form +IF [#expression]: {command 1} & {command 2} & ... + +! multi-line form +IF [#expression]: + {command 1} + {command 2} + ... +END +``` + +In this case, if condition `[#expression]` is true, commands `{command 1}`, `{command 2}`, etc. are executed. + +- For **single-line form**, these will be only those commands that are on the same line as the `IF` operator until the end of the line; +- and for **multi-line form**, these will be those commands that are in subsequent lines after the colon and until the special keyword `END`. + +Comparison operations, logical operations, and other expressions returning numeric values can serve as conditions. + +The `END` keyword in multi-line form must be on a separate line. + +If condition `[#expression]` is not true, commands will not be executed. + +Examples of single-line conditional forms: + +```qsp +! if the sum of a and b equals two, +! variable c is assigned value 30 +if a + b = 2: c = 30 +! If there's no orange in inventory, text is output +if no obj("Orange"): pl "You don't have an orange." +! this is also a simple single-line form +if ((a+b)/c)=45+54 or (b<5 or c>45) and no obj 'shovel' and $f=$vvv+'RRRRR': p 'OK' & goto 'Next' +``` + +Examples of multi-line conditional forms: + +```qsp +if library = 0: + learned_about_party = 0 + library_returned = 1 + gt 'library' +end +if a+b=2: + c=30 +end +``` + +:::warning[Pay attention!!!] + +In multi-line form, after the colon on the same line where the IF operator is located, there should be no commands, otherwise the player will consider such a conditional operator single-line, and commands in subsequent lines will be executed in any case, regardless of whether the condition turns out to be true or not. Example of such erroneous notation: + +```qsp +if library = 0: learned_about_party = 0 + library_returned = 1 &! this line will be executed regardless of the condition's truth + gt 'library' &! and this one too +end &! the end keyword is simply ignored +``` + +The exception is the comment operator written after the colon: + +```qsp +if library = 0: ! if haven't visited library + learned_about_party = 0 + library_returned = 1 + gt 'library' +end +``` + +But if the comment is separated by an ampersand, the condition will be considered single-line: + +```qsp +if library = 0: & ! such a comment makes the condition single-line! + learned_about_party = 0 & ! this line will be executed regardless of the condition's truth + library_returned = 1 & ! and this one + gt 'library' &! and this one too +end &! the end keyword is simply ignored +``` + +::: + +For multi-line forms, unlimited depth nesting is allowed. Each nesting level must end with its own `end` line. + +Examples: + +```qsp +if a+b<3 or y=8: + p 'A+B<3 or Y=8' + nl + if j=88: nl & p 'NEXT' + if $h='ooo': + p 'loo' & jump 'lll' + end +end +``` + +```qsp +if a=0: + 'abc1234' + 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 + 1234 +else + '01234' + g=78 +end +``` + +Several examples of incorrect notation: + +```qsp {4} +! in this case, if the condition is not met, +! the player will ignore only the command `k1=34` +! since it will consider this a single-line condition +if abcd=3: k1=34 + k2=35 & ! this command will always be executed + k3=36 & ! this command will always be executed +end & ! this end will be ignored +``` + +```qsp {3,9} +! this line will output an error unknown action +! since single-line forms should not end with end +if abcd=3: k1=34 else k1=25 end +``` + +## ELSE + +`ELSE` — keyword used together with the `IF` operator, which serves to provide an alternative if the condition is not met. The `ELSE` keyword also has two forms: single-line and multi-line. + +- Multi-line form of `ELSE` can only be used in multi-line construction of the `IF` operator, +- single-line form can be used both in single-line and multi-line constructions of the `IF` operator. General form: + +```qsp +! single-line form +IF [#expression]: {command y1} & {command y2} & ... ELSE {command n1} & {command n2} & ... + +! in multi-line IF: + +! multi-line form of ELSE +IF [#expression]: + {command y1} + {command y2} + ... +ELSE + {command n1} + {command n2} + ... +END + +! single-line form of ELSE +IF [#expression]: + {command y1} + {command y2} + ... +ELSE {command n1} & {command n2} & ... + ! commands in following lines + ! until END are ignored +END +``` + +Here, if condition `[#expression]` is true, commands from the colon to the `ELSE` keyword are executed, and if condition `[#expression]` is not true, commands from the `ELSE` keyword to the end of the conditional construction are executed. + +After `ELSE` you can put or not put a colon. + +**For single-line form:** + +- both commands and the `ELSE` keyword must be written on one line +- the end of the alternative command list is the end of the line. +- if single-line form of `ELSE` is used in multi-line form of `IF`, all commands that follow in subsequent lines after `ELSE` until `END` are ignored. + +Examples of single-line notation: + +```qsp +! if the sum of a and b equals two, variable c is assigned value 30 +! otherwise (i.e., if the sum of a and b does not equal two) +! variable c is assigned value 10 +if a+b=2: c=30 else c=10 + +! depending on whether there's an orange in inventory +! corresponding text is output +if obj("Orange"): pl "You have an orange." else pl "You don't have an orange." + +! single-line form of else inside multi-line if +if $left_hand = 'Great sword': + gosub 'atack', 300 + gosub 'health.prove' + gosub 'win.prove' +else gosub 'atack', atack_power +end +``` + +**For multi-line form:** + +- all commands must be in subsequent lines after `ELSE`; + +Examples of multi-line notation: + +```qsp +if a+b=2: + c=30 +else + c=10 +end + +if obj("Orange"): + pl "You have an orange." +else + pl "You don't have an orange." +end + +if len($curtoken) > 0: + $tokens[curtoken_num] = $curtoken tokens_count = curtoken_num + 1 +else + tokens_count = curtoken_num +end +``` + +## ELSEIF + +`ELSEIF` — keyword used together with the `IF` operator and allows defining sequentially-exclusive conditions at one nesting level. Has single-line and multi-line forms. + +- Multi-line form can only be used in multi-line constructions with the `IF` operator, +- single-line form can be used in both multi-line and single-line constructions with the `IF` operator. + +General forms: + +```qsp +! single-line in single-line condition +IF [#expression 1]: {command set 1} ELSEIF [#expression 2]: {command set 2} ELSE {last command set} + +! multi-line in multi-line condition +IF [#expression 1]: + {command set 1} + ... +ELSEIF [#expression 2]: + {command set 2} + ... +ELSEIF ... : + ... +ELSE + {last command set} + ... +END + +! single-line in multi-line condition +IF [#expression 1]: + {command set 1} + ... +ELSEIF [#expression 2]: {command set 2} +ELSEIF ... : ... +ELSE {last command set} +END +``` + +This works as follows. If `[#expression 1]` is true, commands `{command set 1}` are executed. If `[#expression 1]` is false, but `[#expression 2]` is true, commands `{command set 2}` are executed, and so on. And only if all expressions in the current conditional construction are false, commands after `ELSE` will be executed. The truth of expression `[#expression 1]` does not exclude the truth of expression `[#expression 2]`, but the truth of expression `[#expression 2]` excludes the truth of expression `[#expression 1]`. + +Features of `ELSEIF` notation: + +- The variant `ELSE IF` can be used. Works exactly the same. +- If in multi-line `IF` construction after `ELSEIF` operators are on the same line (single-line form), then all subsequent lines are ignored until the next `ELSEIF`, or until `ELSE` or `END`. +- In `IF` construction with `ELSEIF`, the part with `ELSE` can be either present or absent. + +Examples: + +```qsp +if obj('Health potion'): health += 100 esleif obj('Apple'): health += 15 else *pl 'Nothing to restore strength!' + +IF POINTS>124: + GOTO 'END3' +ELSEIF POINTS>99: + GOTO 'END4' +ELSE + GOTO 'END5' +END + +if money mod 10=1 and money mod 100<>11: + *pl "You have <> coin." +elseif money mod 10>1 and money mod 10<5 and (money mod 100<5 or money mod 100>20): + *pl "You have <> coins." +elseif money mod 10=0 or money mod 10>4 or (money mod 100>10 and money mod 100<21): + *pl "You have <> coins." +end +``` + +Example of `ELSEIF` notation with operators on the same line: + +```qsp +! implementing switch/case in QSP +if r = 0: + 'Option 0' + elseif r = 1: 'Option 1' + elseif r = 2: 'Option 2' + elseif r = 3: 'Option 3' + else: 'No options' +end +``` + +:::tip[Note:] + +For better code readability, it's recommended to use constructions with `elseif` only in multi-line form of the `if` operator. + +::: + +## INCLIB + +`INCLIB` — from the specified game file, adds all locations whose names are absent among the current game locations. Loaded locations are fully equivalent to locations from the main game file. General syntax: + +```qsp +INCLIB [$path to game file] +``` + +Example: + +```qsp +inclib "lib/easy.math.qsp" +inclib "lib/easy.title.qsp" +inclib "res/drive.qsp" +inclib "res/base.qsp" +inclib "res/intro.qsp" +``` + +:::note[5.7.0] +In older player versions, the command was called `addqst` and `addlib`. +::: + +## JUMP + +`JUMP` — jump in the current code block to the specified label. General syntax: + +```qsp +JUMP [$label] +``` + +where `[$label]` is a label below or above in the code (see section ["Labels"](qsp-keyword-syntaxems.md#labels-)). + +`jump` finds a label only within the current code block, i.e., labels are local. + +Separate code blocks in QSP are: + +- "Execute on visit" code of a specific location (each location is a separate code block), +- action code even if the action is added programmatically, +- code in a hyperlink, +- `DYNAMIC`/`DYNEVAL` code + +Example: + +```qsp +jump 'End' +p 'This message will not be output' +:end +p 'But this message the user will see' +``` + +:::note[5.7.0] +Using the `jump` operator in older player versions, you could organize loops: + +```qsp +:loop +if s<9: + s=s+1 + pl s + jump 'loop' +end +p 'Done!' +``` + +Double loop with one label: + +```qsp +:loop +if y<9: + if x<9: + *p "<> - " + x=x+1 + jump 'loop' + end + *pl ":<>" + y=y+1 + x=0 + jump 'loop' +end +``` + +Starting from version 5.8.0, the `loop` operator was introduced for loops. +::: + +## KILLALL + +`KILLALL` — destroys all variables and removes all objects from the objects window. Equivalent to the construction: + +```qsp +killvar & killobj +``` + +:::warning[Attention!] +Remember that `killall` is not equivalent to the construction: + +```qsp +killobj & killvar +``` + +since in this case variable values are deleted after object deletion, meaning the object deletion handler location code has time to execute (see `$onobjdel`). +::: + +Usually `killall` is used at the beginning of the game if there's a "Start over" action at the end of the game. + +## KILLOBJ + +`KILLOBJ` — removing an object located at the specified position. General syntax: + +```qsp +KILLOBJ [#number] +``` + +where `[#number]` is the object number in the inventory window. Object numbering starts from 1. If the `[#number]` parameter is not specified, all objects are removed. When removing each object using `killobj`, the object deletion handler location code is executed (see `$onobjdel`). + +Example: + +```qsp +! remove the topmost object in the list +killobj 1 +! remove the bottommost object in the list +killobj countobj +! remove all objects +killobj +``` + +## KILLVAR + +`KILLVAR` — removing the specified array element. General syntax: + +```qsp +KILLVAR [$array name], [element index] +``` + +where `[$array name]` is the name of the array from which we want to remove an element, and `[element index]` is the number, text index, or multi-dimensional index of the array element we want to remove. Array element numbering starts from 0. + +If the element index is not specified, the entire array is cleared. If the operator is called without arguments, all variables and arrays are deleted. + +Examples: + +```qsp +killvar 'a', 3 & ! will delete element with index 3 from array 'a'. +killvar 'unit', 'Paratrooper' & ! deletes element with index 'Paratrooper' from array +killvar 'a' & ! deletes array 'a' +killvar & ! deletes all variables, arrays +killvar '$map_cell', (3, 4) & ! deletion by multi-dimensional index +``` + +When deleting an element, all elements following it shift up one position. + +Example: + +```qsp +a[0] = 4 +a[1] = 3 +a[2] = 23 +a[3] = 15 +KILLVAR 'a', 1 +! now the array looks like this: +! a[0] = 4 +! a[1] = 23 +! a[2] = 15 +``` + +## LET + +`LET` — deprecated operator for setting variable value. General syntax: + +```qsp +LET [variable name] = [expression] +``` + +where `[variable name]` is a valid variable name, `[expression]` is a valid value for this variable. + +- Numeric variable names are written without `$` and `%` symbols at the beginning. +- Text variable names are written with `$` symbol at the beginning. +- Variable names containing tuples are written with `%` symbol at the beginning. + +Examples: + +```qsp +! set text variable +let $text = "text string" +! set numeric variable +let abs = 123 +! set tuple +let %tuple = [123, "text string"] +``` + +:::tip +This operator is considered deprecated. Use the `set` operator instead, and only in cases when it improves code readability. + +```qsp +! assignment can be done without set or let operators: +$text = "text string" +``` + +::: + +## LOCAL + +`LOCAL` — declares a local variable (or several variables) in the current code block. + +General syntax: + +```qsp +LOCAL [variable 1], [variable 2], ... +LOCAL [variable 1], [variable 2], ... = [value 1], [value 2], ... +``` + +where `[variable 1]`, `[variable 2]`, etc. are variable/array names written directly (not in quotes), and `[value 1]`, `[value 2]`, etc. are any values, constants, expression values, functions, or other variables. + +The number of variables and values must match (except for unpacking cases). + +```qsp +! declare one local variable +local tempora = 12 +! declare several local variables +local x, y, $item = 11, 19, "Old sword" +! declaration with unpacking +local i, j = %map_cell +local z, $a = [13, '37'] +``` + +Unlike `set` and `let` operators, you can declare a variable but not assign it a value. + +```qsp +local tempora +local x, y, $item, %map_cell +``` + +However, despite the variable being created, `arrsize` will return `0` for it. I.e., you cannot check if a variable is declared. + +```qsp +local arr +*pl arrsize('arr') & ! will output 0 +``` + +You can create your own local variables in the following code blocks: + +- Locations themselves. +- Code passed to the `DYNAMIC` operator or `DYNEVAL` function as text. +- Code executed when clicking on a hyperlink. +- Code of each separate Action ([ACT](qsp-keyword-operators.md#act)). +- Code of each separate Loop ([LOOP](qsp-keyword-operators.md#loop)) + +:::warning[**Attention!**] +Local variables have one feature that needs to be very clearly understood. The value of a local variable declared in a given code block is translated to all nested or called code blocks from this one. For example, if a local variable is declared on a location, its value is translated to all locations called using `GOSUB` or `FUNC`, to code blocks for `DYNAMIC`/`DYNEVAL`, to loop blocks, and so on. Example: + +```qsp +# start +! from this location we will call location foo +i = 99 & ! declare global variable +gosub 'foo' +*nl i & ! we'll see number 99 on screen +--- start --- + +# foo +! on this location we declare a local variable +local i = 0 +! local variable is translated to the loop +loop while i < 10 step i += 1: + ! in the loop we call location undo + gosub 'undo' + ! and also in the loop we work with the variable + ! declared on location foo +end +*nl i & ! we'll see number 10 on screen +--- foo --- + +# undo +! to this location from the loop on location foo +! the same local variable declared on location foo is translated +i+=1 & ! increase variable value, affecting the value in foo +*p 'undo:<>, ' & ! numbers 1,3,5,7,9 with prefix undo: will appear on screen +--- undo --- +``` + +**However!** Local variable values are not translated to actions (unlike `ARGS` array values at the current location): + +```qsp +$args[0] = 'current location' +local $var = 'local variable' +*pl $args[0] +*pl $var +act "Output values": + *pl $args[0] + *pl $var +end +``` + +::: + +### Examples of local variable assignment + +```qsp title="Two locations, each with its own variable i" +# location 1 +if i = 0: i = 99 & ! variable i value is set only once +*pl "Global i = <>" +act "To location 2": goto 'location 2' +--- location 1 --- + +# location 2 +*pl "Global i = <>" +local i = 137 & ! variable i value is set only once +*pl "Local i = <>" +act "To location 1": goto 'location 1' +--- location 2 --- +``` + +```qsp title="Another example with two locations" +! this code will sequentially output numbers 12, 549 and 99, 549 +# start +x = 99 +z = 4608 +gosub 'foo' +*pl x & *pl z & ! numbers 99 and 549 will be output to screen +--- start --- + +# foo +local x & ! declare variable x local for this location +x = 12 & ! change variable x value +z = 549 +*pl x & *pl z & ! numbers 12 and 549 will be output to screen +--- foo --- +``` + +```qsp title="Example of declaring local variables in DYNEVAL code and in loop" +$chkObjWord = { + ! this is code written as text in variable $chkObjWord + ! in local variable $word we write the word + ! by which we search + local $word = $args[0] + loop local i = 1 while no i > countobj step i += 1: + ! use local variable i inside the loop + ! loop executes while counter doesn't exceed number of objects + if instr($getobj(i), $word) <> 0: + ! as soon as the considered word is found + ! in the name of the next object + result = i & ! return position + exit & ! close function + end + end +} +object_position = dyneval($chkObjWord, 'grenade') +``` + +```qsp title="Local variables can also be declared inside actions" +i=99 +act "Action with local i": + local i = 449933 + *pl i +end +act "Action with global i": + *pl i +end +``` + +## LOOP + +`LOOP` — loop operator. Necessary for organizing cyclic calculations. General syntax of single-line form: + +```qsp +LOOP {commands before loop start} WHILE [condition] STEP {commands at end of iteration}: {loop body operators} +``` + +General syntax of multi-line form: + +```qsp +LOOP {commands before loop start} WHILE [condition] STEP {commands at end of iteration}: + {loop body operators} +END +``` + +where: + +- `{commands before loop start}` — these are commands executed before the loop is started. These commands belong to the loop block but don't fall into iterations (passes), i.e., are executed only once. Here you can, for example, declare a loop counter. And here you can write multiple commands, listing them with the `&` (ampersand) separator. +- `[condition]` — this is an expression by whose value the condition is checked. Comparison operations and logical operations in any combinations can be used here. If the value of expression `[condition]` equals zero, the loop is interrupted. +- `{commands at end of iteration}` — these are commands executed at the end of each loop pass. Commands that don't directly relate to the loop body but nevertheless should be executed on each iteration can be placed here. Here you can, for example, change the loop counter value. And here you can actually write multiple commands, listing them with the `&` (ampersand) separator. +- `{loop body operators}` — these are commands that need to be executed on each pass and are the main ones for the loop. I.e., we make the loop specifically for these commands. + +The loop in QSP is a separate code block, which means we can declare local variables inside this code block. This is very convenient because we can declare a local variable for the counter, and this won't affect other variables at the location: + +```qsp +i = 99 +*pl "i before loop <>" +loop local i = 0 & *p "i in loop: " while i < 6 step i += 1: + *p "<>, " +end +*nl "i after loop <>" +``` + +Loops are very convenient for iterating through arrays. For example, you can use a loop to add all numbers stored in an array: + +```qsp +summ=0 & ! here we'll write the sum of numbers +! our numbers are in array **mass** +loop local i, size = 0, arrsize('mass') while i < size step i += 1: + summ += mass[i] +end +*pl 'Sum of all elements in array mass: <>' +``` + +## MENU + +`MENU` — displays a popup menu anywhere in the game, whose items are written in the specified array. General syntax: + +```qsp +MENU [$array name] +``` + +Before using this operator, you need to fill the array based on whose contents the menu items will be formed. Menu items are tuples of three values, sequentially placed in consecutive array cells starting from zero. The contents of each tuple should be approximately like this: + +```qsp +["menu item name", "location name", "path to icon file"] +``` + +Menu item name is what we'll see on screen when the menu is displayed; location name is the name of the location whose code will be executed when clicking on the corresponding menu item; path to icon file is the path to the image file that will be displayed next to the menu item name. + +Knowing this, we can fill the array to create our menu items: + +```qsp +%stone[0] = ['Take stone', 'takestone'] +%stone[1] = ['Throw stone', 'throwstone'] +%stone[2] = ['Examine stone', 'lookstone'] +``` + +Here the array name (`%stone`) is the menu name, and the tuples are actions for which item names and handler location names for menu item selection are specified. When selecting the "Take stone" item, the location named "takestone" will be called. Similarly for other items. + +To display the menu on screen, use the `MENU` operator: + +```qsp +menu '%stone' +``` + +Example of creating a menu with icons: + +```qsp +! no icon +%usr_menu[0] = ['Take item', 'take_item'] +! icon specified by gif file +%usr_menu[1] = ['Put item', 'put_item', 'images/put_item.gif'] +! icon specified by $icon_file value +%usr_menu[2] = ['Destroy item','del_item', $icon_file] +! menu item specified by 3 variables +%usr_menu[3] = [$name, $location, $icon_file] + +menu 'usr_menu' &! will show menu of 4 items +``` + +The menu ends on an array element with an empty tuple, or with a tuple missing a value for the menu item name or item handler location. + +Examples where the last two menu items won't be created: + +```qsp +%usr_menu[0]=['Take item','take_item'] & ! we'll see this item on screen +$usr_menu[1]=['Examine item','look_item'] & ! and we'll see this item on screen +$usr_menu[2]=[] & ! empty tuple, player will consider menu ended +$usr_menu[3]=['Put item','put_item'] & ! we won't see this item +``` + +```qsp +%usr_menu[0]=['Take item','take_item'] & ! we'll see this item on screen +$usr_menu[1]=['Examine item','look_item'] & ! and we'll see this item on screen +$usr_menu[2]=['destroy item', ''] & ! no handler location specified, won't see item +$usr_menu[3]=['Put item','put_item'] & ! and we won't see this item +``` + +```qsp +%usr_menu[0]=['Take item','take_item'] & ! we'll see this item on screen +$usr_menu[1]=['Examine item','look_item'] & ! and we'll see this item on screen +$usr_menu[2]=['', 'del_item'] & ! no name specified, won't see item +$usr_menu[3]=['Put item','put_item'] & ! and we won't see this item +``` + +To insert a separator in the menu, use a tuple with "-" values. I.e., if you need to put a separator instead of the 3rd element: + +```qsp +%usr_menu[0]=['Take item','take_item'] +$usr_menu[1]=['Examine item','look_item'] +$usr_menu[2]=['-', '-'] & ! separator instead of menu item +$usr_menu[3]=['Put item','put_item'] +``` + +An argument (`args[0]`) - the position of the selected item - is passed to the menu item selection handler location. Menu item positions are numbered from 1. + +:::note[Deprecated array filling variant. Strings] + +This variant can be used both in players version 5.9.0 and in earlier versions. + +Here menu items are string values of an array with a special format: + +```qsp +"menu item name:location name:path to icon file" +``` + +- Menu item name is what we'll see on screen when the menu is displayed; +- location name is the name of the menu item handler location whose code will be executed when clicking on the corresponding menu item; +- path to icon file is the path to the image file that will be displayed next to the menu item name. If the path to icon file is not specified or the specified file is unavailable, the menu item will be displayed without an icon. + +The search for ":" symbols starts from the end of the string, meaning the menu item name can contain colons, but then there must be a colon after the location name, even if you don't use icons for menu items. + +```qsp +$stone[0]='Stone: take:takestone:' +$stone[1]='Stone: throw:throwstone:' +$stone[2]='Stone: examine:lookstone:' +``` + +If the path to icon file is not specified or the specified file is unavailable, the menu item will be displayed without an icon. + +Thus we should fill the array to create our menu items: + +```qsp +$stone[0]='Take stone:takestone' +$stone[1]='Throw stone:throwstone' +$stone[2]='Examine stone:lookstone' +``` + +Here the array name (`$stone`) is the menu name, and the text array values are actions for which names and handler location names for menu item selection are specified. When selecting "Take stone", the location named "takestone" will be processed. Similarly for other items. + +To call the menu on screen, use the `menu` operator: + +```qsp +menu '$stone' +``` + +Menus can be called anywhere in the game, for example, from hyperlinks: + +```qsp +'Stone' +``` + +Example of creating a menu with icons: + +```qsp +! no icon +$usr_menu[0] = 'Take item:take_item' +! icon specified by gif file +$usr_menu[1] = 'Put item:put_item:images/put_item.gif' +! icon specified by $icon_file value +$usr_menu[2] = 'Examine item:look_item:<<$icon_file>>' +! menu item specified by 3 variables +$usr_menu[3] = '<<$name>>:<<$location>>:<<$file>>' + +menu 'usr_menu' &! will show menu of 4 items +``` + +The menu ends on an array element with value `''` (empty string). I.e., if the menu array consists of elements 'Take', 'Examine', '', 'Throw', then the last 2 menu items won't be created: + +```qsp +$usr_menu[0] = 'Take item:take_item' & ! we'll see this item on screen +$usr_menu[1] = 'Examine item:look_item' & ! and we'll see this item on screen +$usr_menu[2] = '' & ! empty value here, player will consider menu ended +$usr_menu[3] = 'Put item:put_item' & ! we won't see this item +``` + +To insert a separator in the menu, write `"-:-"` instead of the corresponding array element. I.e., if you need to put a separator instead of the 3rd element: + +```qsp +$usr_menu[0] = 'Take item:take_item' +$usr_menu[1] = 'Examine item:look_item' +$usr_menu[2] = '-:-' +$usr_menu[3] = 'Put item:put_item' +``` + +::: + +## MSG + +`MSG` — displays the specified message in a dialog box. General syntax: + +```qsp +MSG [message] +``` + +where `[message]` is any text string, number, expression of any type. Examples: + +Examples: + +```qsp +! simple message output. +msg 'Many ripe pears.' +! we get a window with message 'Many ripe pears' +``` + +```qsp +! Example of message in ACT action. +act 'Eat pears': + msg 'Mmm pears are very tasty.' +end +! We get message output when clicking on action "Eat pears" +``` + +```qsp +!Example with condition. +if breadready = 1: + msg 'Looks like the bread is ready.' +end +! We get message output when condition breadready = 1 +``` + +## NL + +`NL` — line break, then text output in the additional description window. General syntax: + +```qsp +NL [$text] +``` + +where `[$text]` is any text string, number, or expression of any type. If `[$text]` is absent, a simple line break occurs. Example: + +```qsp +p "Text without line break." +nl "Line break + text output." +p "Text without line break." +``` + +## OPENGAME + +`OPENGAME` — loading the specified game state file. General syntax: + +```qsp +OPENGAME [$path] +``` + +where `[$path]` is the path to the saved game state file. If the `[$path]` parameter is absent, the game state loading window is called. + +Example: + +```qsp +! load state from file 1.sav +opengame "1.sav" +! open state loading window +opengame +``` + +See also the game state loading event handler location ([$ongload](qsp-keyword-sys-var.md#ongload)). + +## OPENQST + +`OPENQST` — opening and running the specified game file. General syntax: + +```qsp +OPENQST [$path] +``` + +where [$path] is the path to the game file to be run. Example: + +```qsp +openqst "gamespool/cubesgame.qsp" +``` + +When using this operator, variables are not deleted, inventory objects are not removed, the additional description and input line are not cleared, and playing files are not stopped. If you need to clear the screen and all variable values, you can write such commands at the beginning of the loaded game file: + +```qsp +killall & cls & close all +``` + +## P + +`P` — text output to the additional description window without line break. Text output by any other operator immediately after p will add new text immediately after the current text. General syntax: + +```qsp +P [$text] +``` + +where `[$text]` is any text string, number, or expression of any type. `[$text]` can be an empty string `''`, but should not be absent. Example: + +```qsp +p "Text without line break." +p "Text without line break." +p "" +p "Text without line break." +``` + +## PL + +`PL` — text output to the additional description window, then line break. General syntax: + +```qsp +PL [$text] +``` + +where `[$text]` is any text string, number, or expression of any type. `[$text]` can be absent, then just a line break. Example: + +```qsp +pl "Text output, then line break." +pl & ! line break without text output +pl "Text output, then line break." +p "Text without line break." +pl "Text output, then line break." +``` + +## PLAY + +`PLAY` — playing the specified sound file with given volume. General syntax: + +```qsp +PLAY [$path to sound file],[#volume] +``` + +where `[$path to sound file]` is the path to the sound file relative to the game file, `[#volume]` is playback volume as percentage from 0 to 100. The `[#volume]` parameter can be absent, in which case volume is taken as 100%. Examples: + +```qsp +!Volume 100% +play 'sound/music.mp3' +!Volume 50% +play 'sound/music.mp3', 50 +!Volume 0% (no sound) +play 'sound/music.mp3', 0 +``` + +```qsp +!Playing file by address from variable $file +! with extension 'mid' +! and volume volume +$file = "melody" +play '<<$file>>.mid', volume +! similarly: +$file = "melody.mid" +play $file, volume +``` + +If the file is already playing, the volume changes without "restarting" it. Multiple audio formats are supported and simultaneous playback of up to 32 compositions. + +## REFINT + +`REFINT` — forced interface update (including color and font changes assigned using system variables). + +By default, interface update occurs 2 times per second (every 500 ms). See also the [`settimer`](#settimer) operator. + +## SAVEGAME + +`SAVEGAME` — saving game state to the specified file. General syntax: + +```qsp +SAVEGAME [$path] +``` + +where `[$path]` is the path to the created game state save file. If the `[$path]` parameter is absent, the game state save window is called. + +Example: + +```qsp +! save state to file 1.sav +savegame "1.sav" +! open state save window +savegame +``` + +See also [game state save event handler location ($ongsave)](qsp-keyword-sys-var.md#ongsave). + +## SCANSTR + +`SCANSTR` — searching for non-overlapping occurrences in a string that match a pattern, and placing these occurrences in an array. General syntax: + +```qsp +SCANSTR [$array_name], [$text_to_parse], [$regexp], [#group_number] +``` + +where `[$array_name]` is the array where strings matching the regular expression `[$regexp]` are placed. The search is performed on string `[$text_to_parse]`. If parameter `[#group_number]` is specified, not the entire string matching the regular expression will be placed in the array, but only the part corresponding to the specified group in this regular expression. + +Examples: + +```qsp +! extract all words from string: +$text = 'Sasha walked down the highway, and Greka across the river.' +scanstr '$words', $text, '\b\w+\b' +!The $words array will contain values: 'Sasha', 'walked', 'down', 'highway', 'and', 'Greka', 'across', 'river' + +! split string by delimiter: +$text = 'morning|day|evening|night' +scanstr '$words', $text, '[^|]+' +!The $words array will contain values: 'morning', 'day', 'evening', 'night' + +! extract all words placed in square brackets from string, but without square brackets: +$text = '[first] ignoredtext [second][third] also ignored' +scanstr '$words', $text, '\[(.*?)\]', 1 +!The $words array will contain values: 'first', 'second', 'third' +``` + +## SET + +`SET` — operator for setting variable value. General syntax: + +```qsp +SET [variable name] = [expression] +``` + +where `[variable name]` is a valid variable name, `[expression]` is a valid value for this variable. + +Numeric variable names are written without the `$` symbol at the beginning. Text variable names are written with the `$` symbol at the beginning. Examples: + +```qsp +! set text variable +set $text = "text string" +! set numeric variable +set abs = 123 +! set tuple +set %tuple = [27, 184, 'steel'] +``` + +:::note[Recommendation:] +Since assignment can be done without the `set` operator, we recommend using this operator only for cases when it improves code readability. For example, with multiple assignment: + +```qsp +set apples_in_pocket, apples_in_basket, apples_at_Lyosha = 58, 11, 19 +set $string_1, $string_2 = 'Greka Rode Across River', 'Greka Sees Crab In River' +``` + +::: + +## SETTIMER + +`SETTIMER` — sets the interval for accessing the counter location. General syntax: + +```qsp +SETTIMER [#expression] +``` + +where `[#expression]` is the period of accessing the counter location in milliseconds. By default, the player accesses the counter location every 500 ms, i.e., 2 times per second. + +Setting the counter location access period also affects the frequency of automatic interface settings update. + +Examples: + +```qsp +! counter location will be launched every 2 seconds: +settimer 2000 +``` + +```qsp +! counter location will be launched 4 times per second: +settimer 250 +``` + +```qsp +! if we set frequency of access (times per second) +frequency=10 & ! ten times per second +settimer 1000/frequency +``` + +```qsp +! if we set access period (after how many seconds) +period=2 & ! every two seconds +settimer 1000*period +``` + +The minimum period value can thus be 1 millisecond: + +```qsp +settimer 1 +``` + +However, in practice, the minimum value is limited by your computer's power, and it's usually higher than 1 millisecond. + +## SETVAR + +`SETVAR` — assigns a value to a variable or array cell. + +This function allows avoiding the use of `dynamic` in cases where you need to assign a value to a variable whose name is not known in advance. + +General syntax: + +```qsp +SETVAR [$array_name], [value], [index] +``` + +where `[$array_name]` is the name of the array or variable to which the value should be assigned; `[value]` is a value of any type: string, number, tuple — however, the type of value that will be placed in the variable is determined by the type prefix before the variable name; `[index]` is if the value is assigned to an array cell, you need to specify the cell index with this parameter (can be of any type). + +Examples: + +```qsp +SETVAR 'A', 65 +SETVAR '$X', 'name', 4 +SETVAR '$X', 'name', 'string index' +SETVAR '%Q', ['example', 'tuple'], 3 +SETVAR '%Q', ['example', 'tuple'], [x, y] + +$arr_pref = '%' +$arr_name = 'tuple' +SETVAR $arr_pref+$arr_name, ['tuple', 1], 3 +``` + +## SHOWACTS + +`SHOWACTS` — controls the display of the actions window on screen. General syntax: + +```qsp +SHOWACTS [#expression] +``` + +where `[#expression]` is a number. Usually values `0` and `1` are used. If the value of expression `[#expression]` is not zero, the actions window is displayed. If the value of expression `[#expression]` equals zero, the actions window is hidden. Examples: + +```qsp +showacts 1 & ! shows actions list +showacts 0 & ! hides actions list +``` + +For code readability, you can pre-define `on` and `off` variables and use them: + +```qsp +on = 1 +off = 0 +showacts on & ! shows actions list +showacts off & ! hides actions list +``` + +## SHOWINPUT + +`SHOWINPUT` — controls the display of the input line on screen. General syntax: + +```qsp +SHOWINPUT [#expression] +``` + +where `[#expression]` is a number. Usually values `0` and `1` are used. If the value of expression `[#expression]` is not zero, the input line is displayed. If the value of expression `[#expression]` equals zero, the input line is hidden. Examples: + +```qsp +showinput on & ! shows input line +showinput off & ! hides input line +``` + +## SHOWOBJS + +`SHOWOBJS` — controls the display of inventory on screen. General syntax: + +```qsp +SHOWOBJS [#expression] +``` + +where `[#expression]` is a number. Usually values 0 and 1 are used. If the value of expression `[#expression]` is not zero, inventory is displayed. If the value of expression `[#expression]` equals zero, inventory is hidden. Examples: + +```qsp +showobjs 1 & ! shows inventory +showobjs 0 & ! hides inventory +``` + +For code readability, you can pre-define `on` and `off` variables and use them: + +```qsp +on = 1 +off = 0 +showobjs on & ! shows inventory +showobjs off & ! hides inventory +``` + +## SHOWSTAT + +`SHOWSTAT` — controls the display of the additional description window on screen. General syntax: + +```qsp +SHOWSTAT [#expression] +``` + +where `[#expression]` is a number. Usually values `0` and `1` are used. If the value of expression `[#expression]` is not zero, the additional description window is displayed. If the value of expression `[#expression]` equals zero, the additional description window is hidden. Examples: + +```qsp +showstat 1 & ! shows additional description window +showstat 0 & ! hides additional description window +``` + +For code readability, you can pre-define `on` and `off` variables and use them: + +```qsp +on = 1 +off = 0 +showstat on & ! shows additional description window +showstat off & ! hides additional description window +``` + +## SORTARR + +`SORTARR` — sorting the specified array. General syntax: + +```qsp +SORTARR [$array_name], [#order] +``` + +Here `[$array_name]` is the name of the array to be sorted. The `[#order]` parameter can be omitted. If not specified or equals `0`, sorts the array in ascending order (from smaller to larger). If equals `1`, sorts the array in descending order (from larger to smaller). + +Can sort arrays of any types (numbers, strings, tuples), but mixing values of different types in one array is not allowed. + +To specify the type of sorted values, you need to specify the type prefix as part of the array name (`$`, `%`). + +Example of sorting a text array: + +```qsp +$a[] = 'nn' +$a[] = 'zz' +$a[] = 'aa' +sortarr '$a' + +!check sorting result: +loop local i=0 while i>: i=<>" +end +``` + +Each multi-line construct must end with the `end` keyword. However, the same rules apply here as for HTML tags or brackets: if we nest one construct inside another, we must first close the last opened construct: + +```qsp +! open condition +if obj "Empty pitcher": + ! code that belongs to the condition + *pl "You have an empty pitcher." + ! open action + act "Fill pitcher": + ! code that belongs to the action + delobj "Empty pitcher" + addobj "Full pitcher" + ! close ACTION + end + *pl "The pitcher can be filled from the well." +! close CONDITION +end +``` + +You can use not just `end`, but also `end if`, `end act`, and `end loop`: + +```qsp +! open action +act "Buy 10 arrows at 5 rubles each": + ! open condition level 1 + if money >= 10 * 5: + arrow += 10 + money -= 10 * 5 + ! open condition level 2 + if no (obj "Arrows"): + addobj "Arrows" + ! close condition level 2 + end if + else + *pl "You don't have enough money." + ! close condition level 1 + end if +! close action +end act +``` + +Generally, after the `end` keyword, any text is allowed but not recommended. All text until the next command is ignored. If a command is written on the same line as `end`, then this command must come after an ampersand (`&`): + +```qsp +! open action +act "Take apple": + apple += 1 + addobj "Apple" +! close action +end presence of this text after end is not recommended & *pl "New command" +``` + +## Labels `:` + +Labels are special syntactic constructs (or rather, less than constructs — syntaxemes) that mark a specified line of code and serve for quick movement to such lines using the [`JUMP`](qsp-keyword-operators.md#jump) operator. General syntax: + +```qsp +:[label name] +``` + +where `[label name]` is theoretically any combination of characters, but in practice it's advisable to use only letters, numbers, underscores, and spaces. Space and tab characters can precede the colon in any quantity. Adjacent space and tab characters around the label name are also ignored (however, it's not recommended to place them for code readability). + +```qsp +! recommended way to use labels +jump 'label' +! ... +:label +``` + +```qsp +! working variant with ignored adjacent spaces in label +jump "label with adjacent spaces" +! ... +: label with adjacent spaces +``` + +```qsp +! working variant with ignored adjacent spaces in jump +jump " label with adjacent spaces " +! ... +:label with adjacent spaces +``` + +Immediately after a label, on the same line, any other commands can follow after an ampersand (`&`), but this is not recommended. + +```qsp +! label with commands after it +jump 'markdown' +! ... +:markdown & *pl "output text" & ! comment +``` + +Labels are case-insensitive: + +```qsp +jump "FoR" +! ... +:for +``` + +The `jump` operator "sees" labels only within the current code block. In other words, labels are local. + +Labels with the same names can be located on different locations (in different code blocks). + +If labels with the same names are located in the same code block, all duplicate labels except the very first one are ignored by the player. + +Separate code blocks for labels are considered: + +* "Execute on visit" code of a specific location (each location is a separate code block), +* action code even if the action was added programmatically, +* code in a hyperlink, +* code passed to `DYNAMIC`/`DYNEVAL`. + +Labels inside loops belong to the same code block where the loop is located. + +If an action is added programmatically, labels placed in this action become available from the code block where this action was created. However, it's impossible to jump from an action to a label located outside the action. + +Random labels, i.e., labels that have no jump to them via `jump` in the current code block, are simply ignored by the interpreter. + +## Ampersand `&` + +`&` — the ampersand symbol serves to enumerate commands on one line. General syntax: + +```qsp +[command 1] & [command 2] & ... +``` + +This symbol should not be confused with the [string concatenation operation](qsp-keyword-operacion.md#-concatenation), and should be used carefully. + +Examples: + +```qsp +*pl "I picked an apple from the branch." & addobj "Apple" & apple+=1 + +a = 3 & b = 7 & g = rand(1, 6) & ("26" & "27") & ! in parentheses — concatenation +``` + +## Comma `,` + +The comma `,` in QSP is used to enumerate arguments passed to various operators and functions: + +```qsp +rgb(25, 67, 250) + +max(12, 45, 67, 89, 90, 122, 135, 168, 90) + +addobj "Screwdriver", "img/screwdriver.png" + +gosub "add_object", "Orange", 2, "Food", 37 +``` + +The comma is also used to enumerate values in a tuple: + +```qsp +%personage = [26, 192, 85, 'Peter', 'boxer'] +``` + +## Round Brackets `()` + +Round brackets `()` in QSP are used in three cases: + +1. In various expressions, brackets increase operation priority (operations in brackets are executed first): + + ```qsp + ! increasing priority of arithmetic operations + (256 + 789) * (789 - 256) + ! increasing priority of comparison operations + if A = (A <> B): ... + ``` + +2. If you need to pass more than one argument to a function, you should place the entire group of arguments in brackets: + + ```qsp + rgb(25, 67, 250) + max(12, 45, 67, 89, 90, 122, 135, 168, 90) + rand(1, 1000) + ``` + + It would be good practice to place even a single function argument in brackets: + + ```qsp + rand(999) + ``` + + It won't be criticized, although it's not usually done, to place groups of arguments to operators in brackets: + + ```qsp + showinput(0) + + addobj("Screwdriver", "img/screwdriver.png") + + gosub("add_object", "Orange", 2, "Food", 37) + gosub("add_object", "Rec", rand(23, 45), "Artifact", max(36, 67, 90, a)) + ``` + +3. If you need to organize a tuple of values: + + ```qsp + %tuple = (123, 234, 'string') + %mass[23] = ('Petrov', 'Peter', 'Petrovich') + ``` + +:::warning[Recommendation!] +For organizing tuples, it's recommended to use square brackets. + +```qsp +%tuple = [123, 234, 'string'] +%mass[23] = ['Petrov', 'Peter', 'Petrovich'] +``` + +::: + +## Square Brackets `[]` + +Square brackets `[]` in QSP are used to specify the index of an array cell: + +```qsp +! assign a value to the seventh cell of the $mass array +$mass[7] = "textstring" +``` + +String values can be used for array cell indexing: + +```qsp +$mass["x:4,y:6"] = "map-dot" +``` + +Tuples can also be used for array cell indexing. Duplicating brackets is not mandatory: + +```qsp +$mass[4, 6] = "map_cell" +! equivalent to +$mass[[4, 6]] = "map_cell" +``` + +If square brackets don't follow the array name, it means we're working with the zero cell of the array: + +```qsp +$mass = "text" +! equivalent to +$mass[0] = "text" +``` + +If the index in square brackets is not specified, it means we're working with the last cell of the array: + +```qsp +! create a new cell at the end of the array and assign it a value +$mass[] = "last_cell" + +! get value from the last array cell: +$mass[] +``` + +Square brackets are also used to create tuples: + +```qsp +%tuple = [123, 234, 'string'] +%mass[23] = ['Petrov', 'Peter', 'Petrovich'] +``` + +## Curly Braces `{}` + +Curly braces `{}` in QSP act as special symbols marking the beginning and end of string values. In other words, by the presence of such braces, the player can understand where a string value begins and ends: + +```qsp +*pl {Text that will be displayed on screen.} +``` + +A special feature of specifying text values using curly braces is that sub-expressions are not expanded in such strings: + +```qsp +health = 150 +*pl {Health: <>} +! the text 'Health: <>' will be displayed on screen +*pl "Health: <>" +! the text 'Health: 150' will be displayed on screen +``` + +For better compatibility with different player versions, as well as for reading convenience, curly braces should be used mainly for writing code intended for the `dynamic` operator or `dyneval` function: + +```qsp +*pl $dyneval({$result = $mid("abcd", 2, 1) + "qwerty"}) +dynamic { + $args[0] + addobj $args[1] +}, 'Text', 'Fork' +``` + +Curly braces can also be used for writing multi-line comments: + +```qsp +! { + multi-line + comment +} +``` + +Any number of curly braces can be nested within each other. + +## Quote `"` + +Quotes `"` (double apostrophe) in QSP act as special symbols marking the beginning and end of string values. In other words, by the presence of quotes, the player can understand where a string value begins and ends: + +```qsp +*pl "Text that will be displayed on screen." +``` + +A special feature of specifying text values using quotes is that sub-expressions are expanded in such strings: + +```qsp +health = 150 +*pl "Health: <>" +! the text 'Health: 150' will be displayed on screen +``` + +Quotes inside a string can be escaped by doubling: + +```qsp +*pl "At the tavern ""At Mo's"" it's cheerful and noisy today." +``` + +Quotes can also be used for writing multi-line comments: + +```qsp +! " + multi-line + comment +" +``` + +## Apostrophe `'` + +The apostrophe `'` in QSP acts as a special symbol marking the beginning and end of string values. In other words, by the presence of apostrophes, the player can understand where a string value begins and ends: + +```qsp +*pl 'Text that will be displayed on screen.' +``` + +A special feature of specifying text values using apostrophes is that sub-expressions are expanded in such strings: + +```qsp +health = 150 +*pl 'Health: <>' +! the text 'Health: 150' will be displayed on screen +``` + +Apostrophes inside a string can be escaped by doubling: + +```qsp +*pl 'Rug''Sta''Rag said: — What do you want, mora? Do you want a fly agaric?' +``` + +Apostrophes can also be used for writing multi-line comments: + +```qsp +! ' + multi-line + comment +' +``` + +## Commercial "At" Symbol `@` + +The commercial "at" symbol `@` is used to organize implicit calling of location-functions, simplifying syntax and replacing the `gosub` operator or `func` function. General syntax: + +```qsp +@[$location]([argument 0], [argument 1], ... , [argument 18]) +``` + +where `[$location]` is the name of the location whose code we want to execute without directly going to it. Arguments `[argument 0]`, `[argument 1]`, etc. can be used on this location, their values are automatically placed in variables `args[0]`, `args[1]`, etc. respectively. After processing the location, previous `args` values are restored. Using arguments is not mandatory; in this case, brackets can be omitted. + +When accessing a location using `@`, the base description of the location is added to the current description, base actions are added to current actions, and operators in the "Execute on visit" field are executed, then return to the original line (continuing code execution after the command with `@`). + +The location name in implicit calling should not contain special characters, otherwise this may lead to non-functional code. You can use letters, numbers, underscores, and periods. + +Examples: + +```qsp +!processing location "move". The args[] array is empty. +@move() + +!processing location "move" with passing 3 parameters. +! $args[0] = $var (value), args[1] = 2, +! $args[2] = "data". Note the '$' symbols. +@move($var, 2, 'data') +``` + +```qsp +! this is the code for calling location "transition" +@transition('location') + +! and this is the code of the location "transition" itself +# transition +*pl $args[0] & ! the text 'location' will be displayed on screen +! a new action will appear in the actions window: +act 'go': + goto "street" +end +- transition +``` + +```qsp +! location code for a function that gets the sum of a series of numbers from one to the specified value +# summ +! args[0] will contain the number we specify as [argument 0] +loop while args[0] > 0 step args[0] -= 1: + result += args[0] +end +- summ + +! example of calling location "summ" as a function +*pl @summ(19) & ! will display 190 on screen +``` + +:::warning[Note!] +Implicit location-function calling replaces both `gosub` and `func`, therefore: + +1. if your location-function returns a result, implicit calling of such a location will work exactly the same as explicit calling through `func`; +2. if the location-function doesn't return a result, then when using it with the **[implicit operator](qsp-keyword-operators.md#implicit-operator)** it will work like explicit calling through `gosub`. + +::: + +## Dollar Sign Symbol `$` + +Acts as a type prefix for naming variables and functions of string type. It must be specified if you want to assign a string value to a variable: + +```qsp +$string = 'This is so long string. Very very long string' +``` + +If you don't specify the dollar sign before the string type variable name during assignment, this will cause error #101: "Data type mismatch": + +```qsp title="Don't do this!" +string = 'Short string' +``` + +If you assigned a variable a value of another type and try to get a string, this won't cause a data type mismatch error, but the variable will return a value corresponding to the default value for string values, i.e., an empty string (`''`). + +```qsp +number = 123 +*pl 'Number ' + $number + '.' +! we'll see 'Number .' on screen because $number will return an empty string. +``` + +## Percent Sign Symbol `%` + +Acts as a type prefix for naming variables and functions containing or returning tuples. It must be specified if you want to assign a tuple to a variable: + +```qsp +%tuple = [13, 37, 'string'] +``` + +If you don't specify the percent sign before the tuple type variable name during assignment, this will cause error #101: "Data type mismatch": + +```qsp title="Don't do this!" +tuple = [13, 37, 'string'] +``` + +If you assigned a variable a value of another type and try to get a tuple, this won't cause a data type mismatch error, but the variable will return a value corresponding to the default value, i.e., empty strings (`''`) if a text value is extracted, or zeros (`0`) if a numeric value is extracted. + +```qsp +number = 123 +$var[0], $var[1] = %number +*pl '[<<$var[0]>>,<<$var[1]>>]' +! We'll see '[,]' on screen +``` \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-sys-var.md b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-sys-var.md new file mode 100644 index 0000000..828830f --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/language/qsp-keywords/qsp-keyword-sys-var.md @@ -0,0 +1,517 @@ +--- +sidebar_position: 4 +--- + +# System Variables + +## $BACKIMAGE + +`$BACKIMAGE` — contains the path to the background image file for the main description window. The background in the main description window is displayed if the value of this variable is not `''` (i.e., not an empty string) and the image file was successfully loaded. + +Example: + +```qsp +$backimage = "img/bg.png" & ! set background image located in "img" folder. +``` + +```qsp +$backimage = "" & ! remove image from main description window background. +``` + +## $COUNTER + +`$COUNTER` — contains the name of the counter location. The counter location can be used for real-time events (i.e., events occurring in real time); for example, smooth background color change, gradual text output to screen, playlist for continuous music playback, and others. + +The counter location is called at equal time intervals, by default every 500 ms, i.e., 2 times per second. Automatic interface updates trigger at the same frequency. Intervals are set by the `settimer` operator in milliseconds. + +If your counter location is called "Counter", you need to write on the very first location in the game: + +```qsp +$counter = 'Counter' +``` + +As a rule, to avoid confusion, the location is named the same as the service variable — "Counter": + +```qsp +$counter = 'Counter' +``` + +To disable counter location execution, you need to set an empty value for the `$COUNTER` variable: + +```qsp +$counter = "" +``` + +:::note[< 5.7.0] + +In older player versions, the counter location was used to automate everything possible, but now we recommend using it only where interface work is required or actions requiring some reaction speed from the player. + +You shouldn't tie health restoration algorithms or checks for whether the character died to the counter location, and especially shouldn't do object or action selection checks through the counter location. QSP provides several handler locations that more than cover most code automation needs. + +::: + +## $FNAME + +`$FNAME` — contains the name of the currently used font. If equal to `''` (empty string), then the font specified in the program settings is used. + +Example: + +```qsp +! set Courier New font for entire game +$fname = "Courier New" +``` + +## $ONACTSEL + +`$ONACTSEL` — contains the name of the "action selection" event handler location (hereinafter "*action selection handler*"). In other words, this variable specifies the name of the location whose code triggers when one of the actions displayed on screen is selected. + +Remember that action selection occurs when hovering the mouse pointer over it, not when directly clicking. + +Assign the "on_mouse" location as *action selection handler*: + +```qsp +$onactsel = "on_mouse" +``` + +This location is useful, for example, for displaying images or playing sounds when selecting actions. You can get the selected action name through the `$selact` function. + +```qsp +if instr($selact, 'go', 1): play 'sounds\walk.mp3' +``` + +To disable the *action selection handler*, you need to set the `$onactsel` variable to an empty value: + +```qsp +$onactsel = "" +``` + +## $ONGLOAD + +`$ONGLOAD` — contains the name of the "*game state loading*" event handler location (hereinafter "*load state handler*"). In other words, this variable contains the name of the location whose code will be executed every time after a game state save file ("save file") is loaded using the `opengame` command. + +Assign the "on_game_load" location as load state handler: + +```qsp +$ongload = "on_game_load" +``` + +To disable the load state handler, you need to set the `$ongload` variable to an empty value: + +```qsp +$ongload = "" +``` + +## $ONGSAVE + +`$ONGSAVE` - contains the name of the "*game state saving*" event handler location (hereinafter "*save state handler*"). In other words, this variable contains the name of the location whose code will be executed every time before the game state is written to a new or existing game state save file ("save file") using the `savegame` command. + +Assign the "on_game_save" location as *save state handler*: + +```qsp +$ongsave = "on_game_save" +``` + +To disable the *save state handler*, you need to set the `$ongsave` variable to an empty value: + +```qsp +$ongsave="" +``` + +## $ONNEWLOC + +`$ONNEWLOC` — contains the name of the new location transition handler (analog of "common" location in URQ; hereinafter "*new location transition handler*"). In other words, this variable contains the name of the location whose code is executed every time after executing the code of the location that was transitioned to using `goto` or `xgoto` operators. Game control is passed to the player only after executing code at this handler location. + +Assign the "on_goto_newloc" location as new location transition handler: + +```qsp +$onnewloc = "on_goto_newloc" +``` + +You can get the name of the location that was transitioned to using the `$curloc` function. + +```qsp +if $curloc = 'house': cat = 1 +``` + +To disable the new location transition handler location, you need to set the `$onnewloc` variable to an empty value: + +```qsp +$onnewloc = "" +``` + +## $ONOBJADD + +`$ONOBJADD` — contains the name of the "*item addition*" event handler location (hereinafter "*item addition handler*"). In other words, this variable contains the name of the location whose code is executed every time after adding an item to the objects window using the `addobj` command. + +When adding an item, two arguments are passed to this handler location, whose values can be obtained from `$args[0]` and `$args[1]` respectively: + +* `$ARGS[0]` - name of the added item +* `$ARGS[1]` - path to the image of the added item + +This location is useful, for example, for limiting backpack capacity. + +Assign the "on_object_add" location as *item addition handler*: + +```qsp +$onobjadd = "on_object_add" +``` + +To disable the *item addition handler*, you need to set the `$onobjadd` variable to an empty value: + +```qsp +$onobjadd = "" +``` + +## $ONOBJDEL + +`$ONOBJDEL` — contains the name of the "*item removal*" event handler location (hereinafter "*item removal handler*"). In other words, this variable contains the name of the location whose code is executed every time when removing an item using the `delobj` command. If you use the `killobj` command, this will be equivalent to a series of `delobj` commands, so the handler location will be called as many times as items are removed with `killobj`. + +When using the `killall` command, the item removal handler location is not called since the `$onobjdel` system variable is destroyed before item removal. + +When removing an item, an argument is passed to this handler location, whose value can be obtained from `$args[0]`: + +* `$ARGS[0]` - name of the removed item + +Assign the "on_object_del" location as *item removal handler*: + +```qsp +$onobjdel = "on_object_del" +``` + +This location is useful, for example, for checking the possibility of item removal: + +```qsp +! for example there's an item we'll need for the plot +if $args[0] = "Important artifact": + ! restore the item + addobj $args[0] +end +``` + +To disable the *item removal handler*, you need to set the `$onobjdel` variable to an empty value: + +```qsp +$onobjdel = "" +``` + +## $ONOBJSEL + +`$ONOBJSEL` — contains the name of the "*item selection*" event handler location (hereinafter "*item selection handler*"). In other words, this variable specifies the name of the location whose code is executed every time when selecting an item. Item selection occurs directly when "clicking" on an item (mouse click on item). + +Assign the "on_object_select" location as *item selection handler*: + +```qsp +$onobjsel = "on_object_select" +``` + +This location is useful, for example, for displaying item information or item menu. You can get the selected item name through the `$selobj` function. + +```qsp +if $selobj = 'teapot': + p 'The most ordinary cast iron teapot.' +end +``` + +When a player selects any item, it remains selected. You can remove selection with the `unselect` command. + +To disable the *item selection handler*, you need to set the `$onobjsel` variable to an empty value: + +```qsp +$onobjsel = "" +``` + +## $USERCOM + +`$USERCOM` — contains the name of the input line (input field) handler location (hereinafter "*input line handler*"). The code of this handler location is executed if the cursor is in the input line when the "Enter" key is pressed. + +Assign the "user_command_line" location as *input line handler*: + +```qsp +$usercom = "user_command_line" +``` + +Useful for organizing a parser (game control through input line) or for organizing a debugger. Example code for handler location: + +```qsp +! if entered text corresponds to existing location name +if loc($user_text): + ! transition to this location + goto $user_text +end +``` + +To disable the *input line handler*, you need to set the `$usercom` variable to an empty value: + +```qsp +$usercom = "" +``` + +## ARGS + +`ARGS` — specific system array in which argument values passed by the user when calling a location or code written as text are placed. + +Example: + +```qsp +gosub "em.arr.sort", "$mass", "rug", "$time_ar" +``` + +Here, three arguments will be passed to the "`em.arr.sort`" location, which will be placed in the first three cells of the `$args` array respectively. I.e., at the moment of starting code execution at the "`em.arr.sort`" location, `$args[0]` will already contain the value "`$mass`", `$args[1]` — the value "`rug`", `$args[2]` — the value "`$time_ar`". + +When using `gosub`, `goto`, `xgoto`, `dynamic` operators and `dyneval`, `func` functions, you can specify up to nineteen such arguments, and they will all be placed in `args` array cells from zero to eighteenth. However, since `args` is still an array, you can work with it like a regular array, i.e., use more than nineteen cells, assign text indices, etc. + +A distinctive feature of the `args` array is that a separate `args` array is created for each separate code block. I.e., if you call location "2" from location "1", then location "1" has its own `args` array, and location "2" has its own, and values in these arrays don't intersect. + +Example: + +```qsp +# location_1 +args[0]=23 +gosub "location_2", 34 +*pl args[0] +- + +# location_2 +*pl args[0] +- +``` + +Running this code, you'll see that first the number `34` will be output, and only then `23`. + +Moreover, if you make a recursive call of a location from itself, a separate array will be created for each location call. Thus, the `args` array is local for each separate code block call by default. + +Separate code blocks in QSP are considered: + +* location code +* code passed to `dynamic`/`dyneval` +* code in hyperlinks +* loop code +* action code + +In the first three cases, the player will create a separate `args` array for each separate session of such code blocks. + +**However:** + +* loops will use the `args` array created in the code block from which the loop was called. +* actions will use the `args` array created at the location that was transitioned to using `goto` or `xgoto` operators. + +## BCOLOR + +`BCOLOR` — contains the current background color. If equal to `0`, then the color specified in the program settings is used. Examples: + +```qsp +! black background color +bcolor = -16777216 +! red background color +bcolor = -16776961 +! white background color +bcolor = -1 +``` + +Since background color is encoded by a special number, and calculating this number manually is inconvenient, you should use the `rgb` function, which takes three color components as arguments: + +```qsp +! set background color through rgb(red,green,blue) function +! blue background +bcolor = rgb(0, 0, 255) +! yellow background +bcolor = rgb(255, 255, 0) +! orange background +bcolor = rgb(255, 130, 0) +! cyan background +bcolor = rgb(0, 255, 255) +! magenta background +bcolor = rgb(255, 0, 255) +``` + +## DEBUG + +`DEBUG` — if the variable value is not zero, game identifier checking is disabled when loading state. Otherwise, every time the game file changes, you won't be able to use save files made before changing the game. + +:::tip[Tip:] +during game development and testing, the `debug` variable value should always be non-zero, and when you release the final game version (release), you need to set the `debug` variable to `0` so players can't load save files from other games. +::: + +## DISABLESCROLL + +`DISABLESCROLL` — if the variable value is not zero, auto-scrolling of text in main and additional description windows is disabled. + +:::note[**What this means**] +Suppose we output a large amount of text to the screen, and then when clicking an `action` we output another text fragment. If `DISABLESCROLL = 0`, this text fragment will force the screen to scroll down when output. If we don't want the screen to scroll down in this case, we assign `1` to the `DISABLESCROLL` variable. +::: + +Quite murky behavior in the classic player — under some circumstances, text doesn't scroll anyway. + +:::note[**Note from Byte:**] + +Supposedly `disablescroll` is used when updating the window. if at the moment of update the value is 0 and there was no transition to a new location (`GT/XGT`), then the description scrolls to the end of the text + +Window update occurs in different cases - for example, after the player performed some action (selected action / object), or the game called `refint` or some modal window (`input` / `msg` / `menu` - what I can remember off the top of my head) + +I.e., imho, there are 2 conditions for text scrolling that must be met. if at least one is not fulfilled, then there will be no scrolling regardless of disablescroll value +::: + +## DISABLESUBEX + +:::warning[Be careful!] +In players version 5.8.0 and higher, this variable is no longer used. +::: + +`DISABLESUBEX` — if the variable value is not zero, sub-expression calculation in strings is disabled. Example: + +```qsp +var = 123 +$text = '<>' & ! variable $text will be assigned string '123' +*pl 'string <>' & ! string 'string 123' will be output to screen +*pl '<<5+6>>' & ! string '11' will be output to screen + +disablesubex = 1 & ! disable sub-expression calculation +$text = '<>' & ! variable $text will be assigned string '<>' +*pl 'string <>' & ! string 'string <>' will be output to screen +*pl '<<5+6>>' & ! string '<<5+6>>' will be output to screen +``` + +## FCOLOR + +`FCOLOR` — contains the color of the currently used font. If equal to `0`, then the color specified in the program settings is used. Changing the variable value changes the color of all game text except hyperlinks and text whose color is reassigned through HTML. Example: + +```qsp +! black text color +fcolor = -16777216 +! red text color +fcolor = -16776961 +! white text color +fcolor = -1 +``` + +Since font color is encoded by a special number, and calculating this number manually is inconvenient, you should use the `rgb` function, which takes three color components as arguments: + +```qsp +! set text color through rgb(red,green,blue) function +! black text +fcolor = rgb(0, 0, 0) +! white text +fcolor = rgb(255, 255, 255) +! red text +fcolor = rgb(255, 0, 0) +! green text +fcolor = rgb(0, 255, 0) +``` + +## FSIZE + +`FSIZE` — contains the size of the currently used font. If equal to `0`, then the size specified in the program settings is used. Font sizes of the HTML `` tag are calculated relative to this value in HTML mode. Example: + +```qsp +fsize = 18 +``` + +Font size is set for all text in the game except text whose size is reassigned through HTML. + +## LCOLOR + +`LCOLOR` — contains the current hyperlink font color. If equal to `0`, then the color specified in the program settings is used. Changing the variable value changes the text color of all hyperlinks except those whose color is reassigned through HTML. Example: + +```qsp +! black hyperlink color +lcolor = -16777216 +! red hyperlink color +lcolor = -16776961 +! white hyperlink color +lcolor = -1 +``` + +Since color in QSP is encoded by a special number, and calculating this number manually is inconvenient, you should use the `rgb` function, which takes three color components as arguments: + +```qsp +! set hyperlink color through rgb(red,green,blue) function +! blue hyperlinks +lcolor = rgb(0, 0, 255) +! yellow hyperlinks +lcolor = rgb(255, 255, 0) +! orange hyperlinks +lcolor = rgb(255, 130, 0) +! cyan hyperlinks +lcolor = rgb(0, 255, 255) +! magenta hyperlinks +lcolor = rgb(255, 0, 255) +``` + +## NOSAVE + +`NOSAVE` — if the value of this variable is not `0`, the player menu item "Save game state" becomes unavailable to the player, i.e., the player cannot save the game independently. At the same time, the `savegame` operator continues to work at the QSP code level. Example: + +```qsp +! disable game saving possibility +nosave = 1 +act "Roll dice": + cubes = rand(1, 6) + ! enable saving possibility back + nosave = 0 + delact $selact +end +``` + +## RESULT + +`RESULT` — specific system variable intended for getting a value in the current code block and passing this value to the `func` or `dyneval` function. In other words, for `func` or `dyneval` functions to return some value, you need to assign a value to the `result` variable in the code block they call. + +For example: + +```qsp +$dyneval { + if args[0] mod 2 = 0: + $result = 'even number' + else + $result = 'odd number' + end +}, 279 +``` + +A separate `result` variable is created for each separate code block by the player. I.e., if you call location "2" from location "1", then location "1" creates its own `result` variable, and location "2" creates its own, and values in these variables don't intersect. Thus, the `result` variable is local for each separate code block call. + +If both `result`, `$result`, and `%result` were set during code block processing, the value written to the variable last will be returned as the result. + +:::note +In players version 5.7.0, a small problem with value intersection in `result` on different locations may be observed. It's recommended to use the `result` variable only at the end of location code. + +In newer player versions, this problem was fixed and `result` can be used alongside `args`. +::: + +## USEHTML + +`USEHTML` — if the value of this variable is not zero, HTML recognition mode is enabled. In this case, HTML markup can be used in action names, object names, in text output to main and additional description windows, as well as in dialog boxes called by the `msg` operator and `$input` function. + +```qsp +! enable HTML +usehtml = 1 +! output text with HTML markup +*pl "Red text." +``` + +:::note[qSpider] +In **qSpider**, recognition is always enabled and is not disabled by changing the `usehtml` variable value. +::: + +## Notes for the Curious + +1. It's possible to define any system variable as local for a separate code block, and then this system variable can be used as a regular local variable, i.e., it won't affect player operation. However, it's **strongly** not recommended to do this to avoid possible errors. +2. Like all other variables in QSP, system variables are also arrays. + * Interface setting variables allow using any cells except zero without consequences; this won't affect player operation, but it's still not recommended unless it's some necessary technical solution. + * But system variables that specify event handler location names give a very peculiar effect when filling cells sequentially. If you write location names in several cells in a row, each location entered in the array will be called sequentially. This way you can unload code from event handler locations. For example, the counter location: + + ```qsp + $counter[] = 'playlist' + $counter[] = 'animation' + $counter[] = 'time.acts' + ``` + + It's very important that location names are listed consecutively in the array. If there are empty cells between location names, only those locations that are in the array before the first encountered empty cell will be executed: + + ```qsp + ! only 'playlist' and 'animation' locations will be executed + $counter[] = 'playlist' + $counter[] = 'animation' + $counter[] = '' + $counter[] = 'time.acts' + ``` \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/parsers/index.md b/i18n/en/docusaurus-plugin-content-docs/current/parsers/index.md new file mode 100644 index 0000000..f468c80 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/parsers/index.md @@ -0,0 +1,5 @@ + + +# Parsers + +The task of a syntax analyzer (i.e., parser) is to take source code written in the [QSP language](../language/) and transform it into a form that can be conveniently worked with later (interpreted, compiled, used for analysis, etc.) \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/parsers/qsp-fsharp-parser.md b/i18n/en/docusaurus-plugin-content-docs/current/parsers/qsp-fsharp-parser.md new file mode 100644 index 0000000..8cb887c --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/parsers/qsp-fsharp-parser.md @@ -0,0 +1,21 @@ + + +# Qsp.FSharp.Parser + +[Qsp.FSharp.Parser](https://github.com/QSPFoundation/Qsp.FSharp/tree/master/src/Qsp.FSharp.Core) is developed for development environments that support LSP (for example, VS Code, for whose [extension](https://github.com/QSPFoundation/Qsp.FSharp.VsCode) all this was started). + +Qsp.FSharp.Parser parses the entire source code at once (which differs from the [parser in QSPLib](./qsplib-parser.md)) and simultaneously collects: + +* tokens and their locations (it seems this should be done by a *lexical* analyzer, not a syntactic one, but everything is not so simple there) +* semantic meaning of tokens +* builds a syntax tree + +The main humor is that the syntax tree is not needed at all for the LSP server, but the parser still stubbornly builds it and then discards it. However, it is used for code formatting (which is called, for example, from the LSP server, so it is still needed!) and other not yet documented things. + +Technically, nothing prevents writing an interpreter that could be fed a syntax tree as input, but let QSPLib handle this since it's designed for this purpose. + +Qsp.FSharp.Parser tries to honestly follow the specification, but there are also plenty of personal interpretations and shortcomings. + + + +Written in F#, which, on one hand, ties it to the .Net platform, and on the other hand, allows it to be compiled to JS and other languages using Fable. If there was a desire, as they say. \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/parsers/qsplib-parser.md b/i18n/en/docusaurus-plugin-content-docs/current/parsers/qsplib-parser.md new file mode 100644 index 0000000..d882081 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/parsers/qsplib-parser.md @@ -0,0 +1,11 @@ + + +# QSPLib Parser + +[QSPLib](https://github.com/QSPFoundation/qsp/tree/master/qsp) was parsing source files long before it became fashionable, and continues to do so to this day. + +It is the parser closest to the language specification (actually, the specification is written from it), and others align with it with varying degrees of success. + +It works on a "lazy" principle: it parses the source line by line and immediately interprets it. Thus, syntax errors are caught only when the parser encounters them. + + \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-docs/current/syntax-highlighting.md b/i18n/en/docusaurus-plugin-content-docs/current/syntax-highlighting.md new file mode 100644 index 0000000..d473d77 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/syntax-highlighting.md @@ -0,0 +1,36 @@ +# Syntax Highlighting + +Syntax highlighting in editors and other environments is achieved through quite specific means, for which, unfortunately, there is no common solution. And since there is no common solution, difficulties arise with maintaining code for each individual solution. + + + +## Highlighting in VS Code + +VS Code has two highlighting methods: + +* TextMate format +* Semantic highlighting + + + +### Ready-made Solutions {#vscode-text-solutions} + +* TextMate format + * `glife/tools/syntax/VSCode/qsrc/syntaxes/QSP.tmLanguage.json` + * [TextMate format by someone called Xorgroth](https://gitlab.com/kevinsmartstfg/girl-life/-/raw/master/tools/syntax/VSCode/qsrc/syntaxes/QSP.tmLanguage.json) + +* Semantic highlighting + * Combination of `Qsp.FSharp.Parser`, `Qsp.FSharp.ServerLanguage` and `Qsp.FSharp.VsCode` + +## Highlighting in Sublime Text + +### Ready-made Solutions {#sublime-text-solutions} + +* [JAD_for_QSP](https://github.com/AleksVersus/JAD_for_QSP/blob/master/QSP.sublime-package/qsp.sublime-syntax) + +## Highlighting in Other Environments + +* [highlighting on wiki.qsp.org](https://wiki.qsp.org/lib/plugins/syntaxhighlighter3/sxh3/scripts/shBrushQsp.js) +* highlighting in [howdo_faq](https://github.com/AleksVersus/howdo_faq) by Aleks Versus + + The function that converts QSP code is [here](https://github.com/AleksVersus/howdo_faq/blob/7aea086c17ac34171f785f2ef3fc500dc132af6b/res/%5Bconverters%5D/nodes.py#L1204-L1271) \ No newline at end of file