Skip to content

Logika a dáta: Premenné, podmienky a výrazy

Úvod · Index funkcií · Ťahák

Väčšina tejto stránky je experimental: vydané a v každodennom používaní, ale syntax sa v rámci 1.x ešte môže upraviť. Jedna funkcia tu autorom zatiaľ dostupná nie je — stavové automaty (development). Nesie vlastnú značku.


10. Príkazy

experimentalod 1.0{name attr=value} · {name begin}…{end name}

Pravidlo „vždy buď samouzatvárajúci, alebo párový" a párovanie begin / {end …} sú vydané; jednotlivé príkazy majú vlastný stav.

Príkazy sú jadrovým mechanizmom interaktivity. Uzatvárajú sa do zložených zátvoriek { }.

Každý príkaz je vždy buď samouzatvárajúci, alebo párový — nikdy oboje. Neexistuje nič ako „voliteľné párovanie".

Samouzatvárajúce príkazy

rea
{nazov_prikazu atribut=hodnota}

Párové príkazy

Na otvorenie použite begin, zatvorte pomocou {end nazov_prikazu}:

rea
{nazov_prikazu atribut=hodnota begin}
  Obsah ovplyvnený príkazom.
{end nazov_prikazu}

Obsah vnútri párového príkazu je rovnocenný s atribútom content:

rea
{format color="#00f" begin}formátovaný text{end format}
{format color="#00f", content="formátovaný text"}

Obidva tvary dávajú rovnaký výsledok. Atribút content nastavuje parser na vnútorný text každého párového bloku, čím dáva autorovi voľbu medzi inline a blokovým štýlom bez potreby zvláštnych pravidiel parsera.

experimentalod 1.0You have {player.gold} gold.

Samotný výraz v zložených zátvorkách vytlačí svoju hodnotu; vydané a široko používané, ale okolitá gramatika výrazov sa ešte môže pohnúť.

Samotný výraz v { } sa vytlačí:

rea
Ahoj, {story.player.name}! Máš {story.player.gold} zlata.

Koncepčne je to rovnaké ako vytlačenie hodnoty výrazu.

V texte sa vyhodnotí celá gramatika výrazov — volanie funkcie, aritmetika, ternárny výraz aj indexovanie:

rea
Vyzeráš {story.hrdina.pokoj > 0 ? "pokojne" : "nervózne"}.
Máš {upper(story.hrdina.titul)} a {story.hrdina.zlato + 1} zlatiek po sprepitnom.
Máš {plural(story.hrdina.mince, one="{} mincu", other="{} mincí")}.

Text iba číta; nikdy nezapisuje. Jediný spôsob, ako zmeniť stav, ostáva {set} — výraz v texte, ktorý by mohol zapisovať, by z vykreslenej strany urobil miesto, kde sa mení stav príbehu, a tým by naraz rozbil prehrávanie, návrat aj spoločnú synchronizáciu. Priradenie napísané do textu je chyba (eval/invalid-expression) a nevytlačí sa nič.

Zátvorku, ktorú myslíte doslovne, napíšte s \: \{toto nie je príkaz\} (pozri Escapovanie a doslovný text).

Čo vidí čitateľ

Každá tlačiteľná hodnota má definovaný vykreslený tvar, takže čitateľ nikdy neuvidí ladiaci výpis. Hodnoty sa tlačia v kanonickom tvare nezávislom od jazyka; formát závislý od jazyka je vždy explicitné volanie — formatNumber(), formatDate(), plural(), select().

HodnotaVytlačí sa akoPoznámka
undefined, zmazaná premenná, neúspešná operácianičNikdy nie text undefined
true / falsetrue / falseMalými písmenami, nikdy nie preložené slovo — preklad je select()
Celé číslo11Bez oddeľovača tisícov; ten dáva formatNumber()
Desatinné číslo0.315 platných číslic, koncové nuly odrezané, desatinná bodka — {0.1 + 0.2} vytlačí 0.3
Dlhé desatinné číslo0.333333333333333Ten istý strop; skrátiť si ho viete cez round(x, n)
NaN, ±InfinityničNekonečný výsledok je rovnako netlačiteľný ako undefined
-00
Reťazecjeho text, bez úvodzoviekVytlačí sa doslovne a nikdy sa znova neparsuje — {…} vnútri hodnoty je text, nie príkaz
Prázdne polenič
Polemeč, lanoPrvky spojené cez , , každý podľa tejto tabuľky; reťazce strácajú úvodzovky
Vnorené pole1, [2, 3]Zátvorky len na vnútornej úrovni, aby hranice prvkov zostali čitateľné
Bod48.148600, 17.107700Šesť desatinných miest (~11 cm); desatinná čiarka by sa nedala načítať späť
Trasapath((48.148600, 17.107700), (48.150000, 17.110000))Zložené geografické hodnoty sa tlačia ako platný zdrojový kód Rea
Oblasťarea((48.148600, 17.107700), …)
Kruhcircle((48.148600, 17.107700), 250)
Obalová zónabuffer(path(…), 50)Samotný bod ako argument dostane zátvorky
Zjednotenie / rozdielarea(…) + circle(…) / area(…) - circle(…)
Dátum a čas2026-08-17T20:15:00ZZdrojový tvar ISO; jazyk čitateľa dáva formatDateTime()
TrvaniePT90MZdrojový tvar ISO; ľudská formulácia je práca vstavanej funkcie
Dátum držaný ako reťazec alebo milisekundypodľa riadka reťazec / celé čísloDátumové funkcie pracujú s reťazcami ISO a časovými pečiatkami
Čokoľvek iné — regex, objekt od hostiteľanič a k tomu eval/invalid-expressionPoistka: tvar vytvorený enginom sa na stránku nikdy nedostane

Atribúty

experimentalod 1.0{voice speed=3, emotion="whisper" begin}

Jedna gramatika parametrov oddelených čiarkou, spoločná pre príkazy, funkcie, médiá aj polia.

Príkazy a funkcie zdieľajú jednotnú syntax parametrov. Parametre sa oddeľujú čiarkami.

Pomenované parametre používajú kľúč=hodnota:

rea
{voice speed=3, pitch=7, emotion="whisper" begin}
Naklonila sa bližšie a vyslovila tajné slovo.
{end voice}

Reťazcové hodnoty s medzerami sa uvádzajú v úvodzovkách:

rea
{button action="show_map", title="Kráľovstvo Arath"}

Logické atribúty možno uviesť bez hodnoty (prítomnosť znamená true):

rea
{video src="intro.mp4", autoplay, loop, muted}

Pozičné parametre predchádzajú pomenovaným. Vo volaniach funkcií idú pozičné argumenty ako prvé:

rea
{plural(story.player.gold, zero="žiadne mince", one="{} minca", other="{} mincí")}
{formatNumber(story.player.score, style="decimal", maximumFractionDigits=0)}
{max(a, b)}

{} vnútri hodnoty pomenovaného parametra vloží hodnotu prvého pozičného argumentu.

Pomenovanie príkazov

Príkazy sa dajú pomenovať pre neskoršie použitie pomocou name=:

rea
{if story.player.gold > 100, name=rich_check begin}
  Predvádzaš svoje bohatstvo.
{end if}

Pomenované príkazy sledujú stav vykonania (pozri Vstavané funkcie).

Vyhradené kľúčové slovo

end je vyhradené kľúčové slovo a nemožno ho použiť ako názov príkazu. Rozpoznáva sa výhradne ako uzáver párových príkazov: {end nazov_prikazu}.

Bežné atribúty príkazov

AtribútPopis
namePriradí názov na odkazovanie
repeattrue (predvolené) alebo false — vyhodnotiť len raz
onceSkratka pre repeat=false — zobraziť len pri prvom stretnutí

11. Premenné a dátové typy

Deklarovanie premenných

experimentalod 1.0{set story.player.gold = 100}

Dostupné od prvého vydania a v reálnom používaní, ale stále v testovacej fáze — priradenie aj povinné pravidlo domény sa môžu pred zmrazením upraviť.

Každá referencia na premennú a každý cieľ {set} musí niesť prefix domény. Holé meno bez bodky v pozícii {set} je chyba (parse/dotless-set). Doména je povinný prvý segment; všetko za ňou je voľný, nedeklarovaný menný priestor autora, usporiadaný do logických kategórií. Neexistuje samostatný „trvalý" a „netrvalý" druh premennej — životnosť premennej určuje výhradne doména (pozri Rozsahy platnosti):

rea
{set story.player.name = "Aiden"}
{set story.player.gold = 100}
{set story.quest.has_key = true}
{set story.player.inventory = ["meč", "fakľa", "mapa"]}

Bežné vzory voľného menného priestoru, pod tou doménou, ktorá zodpovedá životnosti premennej:

VzorPoužitiePríklad
Meno postavyStav postavystory.player.gold, story.elena.location
Kategória objektuPredmety, nástroje, prostrediestory.tool.knife, story.door.state
Pojem príbehuPríznaky, úlohy, postupstory.quest.has_key, story.flag.visited
Viacúrovňové vnorenieJemnejšie členeniestory.role.king.power, story.map.zone.3

Rozsahy platnosti

experimentalod 1.0part. · story. · shared. · context.

Presne štyri povinné domény — part, story, shared, context — každá s vlastnou životnosťou; rozsah nadpisu už neexistuje.

Bez premenovania domén v manifeste (nižšie) existujú presne tieto štyri domény:

DoménaŽivotnosť a účel
part.Lokálny dočasný stav. Vynuluje sa pri každej zmene aktívnej časti (terminálna brána, odkaz medzi časťami alebo akýkoľvek iný prechod medzi súbormi častí) — vrátane opätovného vstupu do už navštívenej časti; obnovenie neexistuje.
story.Pretrváva v celom balíku .reast, naprieč všetkými časťami, po celý čas čítania (a medzi sedeniami cez uloženie/obnovenie).
shared.Pretrváva ako story., ale každý zápis sa replikuje ku každému pripojenému čitateľovi v kooperatívnom sedení (env/shared-write-conflict — vyhráva posledný zápis).
context.Interakcia so svetom, čitateľom, zariadením a bežiacim sedením, len na čítanie — pozri Doména context.
rea
{set story.player.gold = 50}
{set shared.story.player.name = "Aiden"}
{set part.scratch.attempts = 0}

shared. a part. sú domény samy osebe, nie modifikátory nad story.shared.story.player.name znamená „story.player.name pod doménou shared", nie „story.player.name z domény story, zdieľaná".

Rozsah nadpisu už neexistuje. Neexistuje forma premennej bez domény — každý cieľ {set} aj každé čítanie nesie jednu zo štyroch domén vyššie (alebo jej premenovanie z manifestu). Autor, ktorý chce dočasný stav miestny pre sekciu, použije part.: správa sa ako story. (pretrváva cez hranice nadpisov, telá cyklov aj vetvy {if}) s tým rozdielom, že sa vynuluje pri zmene časti, nie na hranici nadpisu.

Premenné cyklu ({for} položka/index, počítadlo {while}) nie sú výnimkou. Sú to bežné premenné s prefixom domény, ktoré si autor volí ako každý iný cieľ {set}part.item je typická voľba pre pracovný stav, ale story.item alebo ktorákoľvek iná doména funguje rovnako. Hlavička cyklu vykoná ekvivalent {set <cesta> = <hodnota>} pri každej iterácii; pozri Cyklus for a Cyklus while. Po skončení cyklu sa premenná nijako nevyprázdňuje — drží poslednú hodnotu tak dlho, ako hovorí jej doména.

Parametre funkcií sú jediná výnimka bez bodky — pozri Vlastné funkcie (rekurzia potrebuje čerstvú väzbu pre každý rámec volania, čo zdieľaná cesta v doméne poskytnúť nevie).

Vyhradené holé slová

neznáma funkcia

Pod identifikátorom reserved-words nie je v súbore .vitepress/data/features.ts zaregistrovaná žiadna funkcia.

begin, end, else, elseif, true, false, undefined sú vyhradené ako:

  • Názov domény (iba prvý segment): {set begin.x = 1} je chyba, aj keď je s bodkou — segment domény je jediné miesto, kde je holé kľúčové slovo naozaj nejednoznačné.
  • Názov funkcie: {function true(...) ...} je chyba.
  • Názov atribútu: {image end="..."} je chyba.

Za prvým segmentom cesty vyhradené byť nemusia (story.quest.true je v poriadku) a mimo týchto troch pozícií nemusia byť vyhradené ani ako lexikálne identifikátory.

Premenovanie domén

neznáma funkcia

Pod identifikátorom domain-renaming nie je v súbore .vitepress/data/features.ts zaregistrovaná žiadna funkcia.

Manifest MÔŽE premenovať štyri domény na identifikátory podľa voľby autora:

json
{
  "domains": {
    "context": "okolie",
    "story": "pribeh"
  }
}
  • Kľúče sú vždy kanonické anglické názvy (part, story, shared, context) — lokalizuje sa iba identifikátor v príbehu.
  • Cieľ premenovania nesmie kolidovať s vyhradeným holým slovom (vyššie) ani s názvom inej domény (kanonickým či premenovaným). Obe kontroly bežia pri načítaní manifestu, ešte pred spracovaním ktoréhokoľvek súboru .rea.
  • Cieľ premenovania musí byť platný identifikátor Rea podľa pravidla Unicode (nižšie).
  • Vynechanie domains alebo jednotlivých kľúčov ponechá kanonický anglický názov — čiastočné premenovanie je povolené.
  • Nerozpoznaný kľúč vnútri domains sa riadi konvenciou pkg/manifest-unknown-key (info, bez dôsledku pre čitateľa), nie tvrdým zlyhaním.

Doména context

neznáma funkcia

Pod identifikátorom context-domain nie je v súbore .vitepress/data/features.ts zaregistrovaná žiadna funkcia.

context. je okno platformy na čitateľa, zariadenie, svet a bežiace sedenie, určené len na čítanie. Predvolená tabuľka schopností:

CestaTypPoznámky
context.reader.namestring
context.reader.languagestring
context.reader.ageinteger
context.story.titlestringMetadáta platformy — nie vyhradený podstrom story.meta.*.
context.story.chapterstring
context.story.progressfloat
context.time.nowdatetime
context.time.datestring
context.time.hour / .minuteinteger
context.time.day / .month / .yearinteger
context.time.weekdaystringNázov dňa, malými písmenami.
context.time.seasonstringPodľa pologule.
context.weatherstringclear, rain, snow, fog, storm.
context.temperature / .wind / .humidityfloatStupne Celzia, m/s, percentá.
context.locationpointTestujte proti oblasti operátorom matches — pozri Literály súradníc.
context.location.lat / .lng / .alt / .accfloat
context.heading / .speedfloatKurz kompasu 0–360, rýchlosť v m/s.
context.orientationfloatOtočenie zariadenia, 0–360.
context.tilt.x / .yfloatNáklon dopredu/dozadu a doľava/doprava.
context.acceleration.x / .y / .zfloat
context.lightfloatOkolité svetlo v luxoch.
context.device.camera / .gps / .vibrationboolean
context.group.sizeinteger
context.group.readersarray
context.group.rolestring

Toto nahrádza staré vstavané menné priestory reader.*, world.*, device.*, group.* — nekompatibilná zmena bez prechodovej vrstvy; príbeh, ktorý sa odvoláva na world.location, dostane link/unknown-domain. Naskenovaná či vyslovená hodnota ({scan}/{listen}) zostáva lexikálnou väzbou event.kind/event.value, nie cestou context.* — neexistuje „posledný výsledok skenu", ktorý by sa dal priebežne čítať. Dva vstavané prvky, ktoré viseli na mennom priestore, sa stávajú obyčajnými globálnymi funkciami v štýle max()/length(): world.has(feature) je has(feature) a group.readers_in_role(role) je readers_in_role(role).

To, čo čitateľ nesie, nie je context.{give}/{take} a peňaženka zapisujú do story.reader.inventory, story.reader.pocket a story.reader.coins, teda pod story., pretože sú dôsledkom príbehu a uloženie ich musí niesť so sebou. context. je len to, čo platforma pozoruje a príbeh zmeniť nemôže.

Manifest MÔŽE premenovať jednotlivé cesty context.* nezávisle od premenovania domény:

json
{
  "domains": { "context": "okolie" },
  "context": { "location": "poloha" }
}

Zapisovateľnosť: context. je celá len na čítanie — {set context.* = ...} na ktorejkoľvek ceste je chyba (eval/context-write-refused). Každú súčasnú cestu napĺňa platforma, nikdy {set}.

Redakcia: hodnota žiadnej cesty context. sa nikdy nesmie objaviť v diagnostickom zázname, pri žiadnej závažnosti — názov typu sa uviesť smie, hodnota nikdy. Bez výnimiek podľa cesty (context.time.hour nie je „len hodina, to je v poriadku" — redaguje sa rovnako ako context.location).

Metadáta príbehu

neznáma funkcia

Pod identifikátorom story-metadata nie je v súbore .vitepress/data/features.ts zaregistrovaná žiadna funkcia.

meta je vyhradený ako prvý voľný segment iba pod story.:

rea
story.meta.title
story.meta.chapter
story.meta.progress

part.meta.*, shared.meta.* a context.meta.* sú bežný menný priestor autora — nie sú vyhradené. {set story.meta.* = ...} na ktorejkoľvek ceste v tomto podstrome je chyba: eval/story-meta-write-refused.

Identifikátory Unicode

neznáma funkcia

Pod identifikátorom unicode-identifiers nie je v súbore .vitepress/data/features.ts zaregistrovaná žiadna funkcia.

Identifikátory Rea (segmenty domén po prípadnom premenovaní z manifestu a všetko vo voľnom mennom priestore autora) sú definované nad znakmi Unicode Identifier and Pattern Syntax (ID_Start/ID_Continue, podľa UAX #31) plus _ a číslice v pokračovacej pozícii, s výnimkou tej ASCII interpunkcie, ktorú si gramatika Rea už vyhradzuje (., ,, =, zátvorky, úvodzovky). 周囲.位置 je presne tak platné ako context.location.

Každý identifikátor sa porovnáva a ukladá v NFC (Normalization Form C), normalizovaný hneď pri načítaní, pred akýmkoľvek porovnaním, uložením či diagnostikou — predkomponovaný zápis a zápis s kombinujúcimi znakmi toho istého viditeľného identifikátora sú vždy tá istá premenná.

Miešanie zameniteľných písiem je diagnostika, nie chyba: identifikátor, ktorý mieša znaky z dvoch alebo viacerých písiem {latinka, cyrilika, gréčtina} zameniteľné navzájom podľa tabuľky Unicode confusables, dostane style/confusable-identifier (info) s uvedením zmiešaných písiem. Spoločné a zdedené znaky (číslice, _, kombinujúce znaky) sa do počtu písiem nerátajú, takže identifikátor v jedinom nelatinskom písme (周囲.位置, context.météo) sa neoznačí nikdy — kontrola je zámerne úzka: zachytáva zámenu homoglyfom, ktorá má vyzerať identicky, nie bežné lokalizované identifikátory.

Mazanie cez undefined

neznáma funkcia

Pod identifikátorom deletion nie je v súbore .vitepress/data/features.ts zaregistrovaná žiadna funkcia.

{set story.x = undefined} premennú zmaže — ďalšie čítanie story.x je nerozoznateľné od stavu, keď nikdy nastavená nebola. Priradenie undefined uzlu s potomkami zmaže celý podstrom. Príkaz na vyčistenie celej domény neexistuje — zmazanie všetkého pod doménou je {set domena.koren = undefined} na najplytkejšom spoločnom predkovi, keďže mazanie podstromu to už pokrýva.

Dátové typy

experimentalod 1.0string · integer · float · boolean · array · regex · undefined

Množina typov je vydaná vrátane pravidla o vždy dvojito uvádzaných reťazcoch, ktoré udržiava holé slová jednoznačné.

TypPríkladPopis
string"ahoj"Textová hodnota, vždy v dvojitých úvodzovkách
integer42Celé číslo
float3.14Desatinné číslo
booleantrue, falseLogická hodnota
array[1, 2, "adam"]Usporiadaná kolekcia
regex/^[a-z]+$/iRegulárny výraz — literál napravo od matches. Zatiaľ nie hodnota, ktorú by premenná mohla držať: uloženie je JSON a uložený vzor by ho neprežil.
undefinedundefinedPrázdna hodnota

Reťazce vždy vyžadujú dvojité úvodzovky — neexistujú reťazcové literály bez úvodzoviek. Holé slovo vo výraze je vždy odkaz na premennú, nikdy nie reťazec. Tým sa odstraňuje nejednoznačnosť:

rea
{set story.player.name = "Aiden"}
{set story.player.weapon = "sword"}
{if story.player.weapon = "sword" begin}

Tu je "sword" reťazcová hodnota a story.player.weapon premenná — jediné, čo ich odlišuje, sú úvodzovky, a tie nie sú nikdy voliteľné.

V atribútoch príkazov reťazcové hodnoty takisto vyžadujú úvodzovky. Holé hodnoty atribútov sa interpretujú ako čísla, logické hodnoty alebo odkazy na identifikátory — nie ako reťazce:

rea
{voice speaker="elena", emotion="whisper", speed=3 begin}
{input name=guess, type="number", placeholder="Zadajte číslo"}

speed=3 je číslo (bez úvodzoviek), name=guess je naviazanie identifikátora (názov premennej, kam sa uloží vstup) a emotion="whisper" je reťazcová hodnota (v úvodzovkách).

Polia

experimentalod 1.0["sword", "map"] · [hp=100, dex=8]

Jediný kolekčný typ, s pozičnými aj pomenovanými položkami v jedinom literáli; indexovanie od nuly je ustálené.

Polia sú univerzálnym kolekčným typom. Položky sa oddeľujú čiarkami a môžu byť pozičné (indexované podľa poradia), pomenované (indexované kľúčom) alebo oboje:

rea
{set story.player.inventory = ["meč", "fakľa", "mapa"]}
{set story.stats = [strength=10, dexterity=8, wisdom=12]}
{set story.mixed = ["prvá pozičná", 12.345, shift=true]}

K pozičným položkám sa pristupuje indexom od nuly (prvá položka je .0, druhá .1 atď.), k pomenovaným kľúčom:

rea
{story.player.inventory.0}
{stats.strength}
{mixed.0}
{mixed.shift}

Pri miešaní pozičných a pomenovaných položiek musia pozičné predchádzať pomenované — v súlade s parametrami funkcií. Pomenované položky sa dajú preusporiadať voľne.

Pomenované položky nie sú implementované [strength=10, dexterity=8] sa rozparsuje ako test rovnosti, takže pole vyjde ako [false, false] a story.stats.strength sa číta ako nenastavené. Dnes fungujú iba pozičné polia:

rea
{comment ZLE — vyjde [false, false]}
{set story.stats = [strength=10, dexterity=8]}

{comment DOBRE}
{set story.stats.strength = 10}
{set story.stats.dexterity = 8}

Hodnoty dátumu, času a trvania

experimentalod 1.0datetime("2026-06-15T10:30") · duration("P1DT2H")

Konštruktory podľa ISO 8601 vrátane zástupných znakov * pre vzory dennej doby.

Konštruktorové typy (typy počas behu bez literálovej syntaxe):

KonštruktorPopis
datetime("2026-06-15T10:30:00")Časová značka ISO 8601, podporuje zástupné *
duration("P1DT2H30M")Trvanie podľa ISO 8601

Literály súradníc

experimental@(lat, lng) · circle(p, m) · area(p1, p2, p3) · path(...) · buffer(shape, m) · distance(a, b) · bearing(a, b) · a + b · a - b

Bod je literál, pretože príbeh zasadený do reálneho miesta ich píše veľmi veľa; všetko, čo má rozlohu, je bežné volanie nad bodmi, takže sa tvary skladajú bez vlastnej syntaxe. Oba argumenty @(lat, lng) sú výrazy, matches sa pýta, či bod leží v oblasti, a + a - sú zjednotenie a rozdiel. Najprv je zemepisná šírka, polomery sú v metroch.

Geografický bod sa zapisuje ako @(lat, lng)najprv zemepisná šírka, potom dĺžka, v poradí, ktoré používa každá mapová služba aj každé meranie GPS. Oba argumenty sú bežné výrazy, takže bod vznikne z premenných rovnako ľahko ako z čísel:

rea
{set story.home = @(48.14, 17.10)}
{set story.here = @(story.lat, story.lng)}

Bod je jediný literál. Všetko, čo má rozlohu, vzniká z bodov bežnou funkciou, takže sa tvary skladajú rovnako ako ktorákoľvek iná hodnota:

KonštruktorPopis
path(p1, p2, …)Usporiadaná reťaz aspoň dvoch bodov. Trasa nemá vnútro.
area(p1, p2, p3, …)Uzavretý prstenec aspoň troch bodov. Prstenec sa uzatvára sám.
circle(stred, metre)Všetko do vzdialenosti metre od bodu.
buffer(tvar, metre)Všetko do vzdialenosti metre od trasy, oblasti, kruhu alebo bodu.
oblast1 + oblast2Zjednotenie — všetko v ktorejkoľvek z oblastí.
oblast1 - oblast2Rozdiel — všetko v prvej, čo nie je v druhej.

Každý polomer je v metroch. area() si prstenec uzatvára sama, takže zopakovanie prvého bodu na konci nič nemení: area(p1, p2, p3) a area(p1, p2, p3, p1) je ten istý trojuholník. Vnútro dáva trase až buffer() — trasa sa stane miestom, kde čitateľ môže byť, až keď dostane šírku:

rea
{set story.park = circle(@(48.14, 17.10), 500)}
{set story.forest = area(@(48.14, 17.10), @(48.15, 17.10), @(48.15, 17.11), @(48.14, 17.11))}
{set story.corridor = buffer(path(@(48.14, 17.10), @(48.15, 17.11)), 50)}
{set story.donut = circle(@(48.14, 17.10), 1000) - circle(@(48.14, 17.10), 200)}

Či bod leží v oblasti, sa pýtame operátorom matches — tým istým, ktorý testuje reťazec proti vzoru:

rea
{if context.location matches story.park begin}
  Cítiš zvláštnu rezonanciu. Toto je to miesto z príbehu!
{end if}

Dvojica bodov odpovedá aj na otázky o priestore medzi nimi — vďaka tomu vie príbeh povedať ako ďaleko a ktorým smerom, nielen či čitateľ dorazil:

MeraniePopis
distance(a, b)Vzdialenosť dvoch bodov po veľkej kružnici, v metroch.
bearing(a, b)Počiatočný smer z a do b, v stupňoch od severu v smere hodinových ručičiek, 0360.
rea
{if distance(context.location, story.tower) > 400 begin}
  Veža je ešte {round(distance(context.location, story.tower))} m ďaleko, smer {round(bearing(context.location, story.tower))}°.
{end if}

Bod sa vypisuje ako lat, lng na šesť desatinných miest — asi 11 cm, jemnejšie než ktorékoľvek meranie GPS. Tvar je vo všetkých jazykoch rovnaký: jazyk, ktorý vykresľuje desatinný oddeľovač ako čiarku, by vypísal hodnotu, ktorú by nič neprečítalo späť.

Mená vstavaných funkcií

path, area, circle, buffer, distance a bearing sú jadrové vstavané funkcie a vstavanú funkciu nemožno predefinovať. Vlastná {function area() begin} sa ohlási ako link/redefines-builtin a naďalej beží vstavaná — alternatíva, teda tichá výhra deklarácie, by bez slova rozbila každé geografické volanie v dokumente.

Zástupné znaky v dátume a čase

Zástupné znaky umožňujú vzory podľa času pomocou reťazcov konštruktora datetime():

rea
{if context.time.now matches datetime("*-12-24T*") begin}
  Veselé Vianoce, {context.reader.name}!
{end if}

{if context.time.now matches datetime("*-*-*T22:*:*") begin}
  Noc sa okolo teba prehlbuje…
{end if}

12. Výrazy a operátory

experimentalod 1.0+ - * / % = != < > and or ! matches in

Celá tabuľka priorít je vydaná; jednoduché = pre rovnosť je ustálené rozhodnutie, nie dočasná náhrada.

Výrazy sa môžu objaviť kdekoľvek vnútri { }. Riadia sa štandardnými pravidlami priority.

Atómy výrazu

Výraz sa skladá z týchto atomárnych prvkov:

AtómPríkladPopis
Literál42, "text", true, [1, 2, 3]Číslo, reťazec, logická hodnota či pole
Premennástory.player.gold, story.quest.has_keyCesta k premennej s prefixom domény
Volanie funkciemax(a, b), length(inv.items)Volanie s argumentmi oddelenými čiarkou
Zoskupený výraz(story.player.gold + bonus) * 2Zátvorky prebijú prioritu

Priorita operátorov (od najvyššej po najnižšiu)

PrioritaOperátorPopis
1( )Zoskupenie
2.Prístup k vlastnosti
3f()Volanie funkcie
4-, !Unárne mínus, logické NIE
5*, /, %Násobenie, delenie, zvyšok
6+, -Sčítanie, odčítanie, spájanie reťazcov
7matches, !matchesZhoda so vzorom, negovaná
8in, !inTest členstva, negovaný
9<, <=, >, >=Porovnanie
10=, !=Rovnosť, nerovnosť
11andLogické A
12orLogické ALEBO
13? :Ternárna podmienka

Testy vzoru a členstva

experimentalod 1.0matches /regex/ · "x" in array

Operátory ako kľúčové slová namiesto symbolov, každý s negáciou pomocou prefixu !.

matches testuje hodnotu proti regulárnemu výrazu a in testuje členstvo v poli. Oba sú kľúčové slová, nie symboly, a oba sa negujú prefixom !:

rea
{if story.player.name matches /^[A-Z]/ begin}
{if "sword" !in story.player.inventory begin}

Ternárna podmienka

experimentalod 1.0{gold > 0 ? "hopeful" : "dejected"}

Inline podmienené hodnoty s najnižšou prioritou, takže vnáranie vyžaduje explicitné zátvorky.

Ternárny operátor poskytuje inline podmienené hodnoty:

rea
{set story.mood = story.player.health < 50 ? "zúfalý" : "odhodlaný"}
Hrdina vyzerá {gold > 0 ? "nádejne" : "skleslo"}.

Najprv sa vyhodnotí podmienka; ak je pravdivá, vráti sa výraz pred :, inak výraz za :. Ternárny operátor má najnižšiu prioritu — pri vnáraní použite zátvorky:

rea
{(is_night ? 2 : 1) * base_damage}

Poznámky:

  • = vo výrazoch je rovnosť (nie priradenie). Priraďuje sa príkazom {set}.
  • and a or používajú skrátené vyhodnocovanie.
  • Unárne - neguje číslo: -story.player.gold, -(a + b).
  • + s reťazcovým operandom spája: "Ahoj, " + story.player.name
  • Reťazce prístupov k vlastnostiam sa vyhodnocujú zľava doprava: context.group.readers.0.name

Správanie reťazcov

Reťazce sú nepriehľadné hodnoty — syntax {výraz} sa vnútri reťazcových literálov NEinterpretuje. Dynamické reťazce sa skladajú spájaním:

rea
{set msg.greeting = "Ahoj, " + context.reader.name + "!"}

Syntax {výraz} funguje len v naratívnom texte (mimo reťazcových literálov), kde sa vyhodnotí a jej výsledok sa vloží priamo do textu.

Pretypovanie vo výrazoch

experimentalod 1.0number(x) · string(x) · boolean(x) · integer(x)

Implicitné pretypovanie vnútri výrazov plus štyri explicitné konverzné funkcie; pravidlo „reťazec + čokoľvek = reťazec" je ustálené.

Keď majú operandy rôzne typy, Rea uplatní implicitné pretypovanie:

  • Sčítanie a spájanie (+): ak je čo len jeden operand reťazec, výsledkom je reťazec (spojenie). Inak číselné sčítanie
  • Aritmetika (-, *, /, %): operandy sa pretypujú na čísla. Nečíselné reťazce dajú undefined
  • Porovnanie (<, >, <=, >=): oba sa podľa možnosti pretypujú na čísla, inak sa porovnávajú ako reťazce
  • Rovnosť (=, !=): bez pretypovania — typy sa musia zhodovať, okrem "", ktoré sa rovná false (oboje nepravdivé)
  • Logický kontext (if, and, or, !): nepravdivé hodnoty sú false, 0, "", undefined a prázdne pole []

Základné pravidlo: reťazec + čokoľvek = reťazec. Keď + narazí na reťazcový operand, druhý operand sa prevedie na svoju reťazcovú podobu a výsledok sa spojí.

VýrazVýsledokPrečo
"zlato: " + 42"zlato: 42"Reťazec + číslo → spojenie
"má kľúč: " + true"má kľúč: true"Reťazec + logická hodnota → spojenie
42 + 850Číslo + číslo → sčítanie
"3" + "7""37"Reťazec + reťazec → spojenie
"3" * 26Aritmetika pretypuje na číslo
"ahoj" * 2undefinedNečíselný reťazec → aritmetika zlyhá

Explicitná konverzia typov

Na explicitný prevod medzi typmi slúžia konverzné funkcie:

FunkciaPopis
number(x)Prevod na číslo. number("42")42, number("abc")undefined
string(x)Prevod na reťazec. string(42)"42", string(true)"true"
boolean(x)Prevod na logickú hodnotu. Nepravdivé hodnoty → false, všetko ostatné → true
integer(x)Prevod na celé číslo (oreže). integer(3.7)3
rea
{set total = number(reader_input) + story.player.gold}
{set label = "Skóre: " + string(story.player.score)}
{set has_items = boolean(length(story.player.inventory))}

Príklady

rea
{story.player.gold * 2 + combat.bonus}
{story.player.level >= 10 and story.quest.has_key}
{story.player.name matches /^[A-Z]/}
{"sword" in story.player.inventory}
{!door.is_locked or story.quest.has_master_key}
{story.player.health < 50 ? "utekaj" : "bojuj"}
{-combat.penalty + combat.bonus}
{context.reader.name + " — " + upper(story.player.class)}

13. Riadenie toku

If / Else if / Else

experimentalod 1.0{if cond begin} … {else} … {end if}

Najpoužívanejší príkaz jazyka; vydaný a v praxi stabilný, formálne stále experimentálny spolu so zvyškom vrstvy príkazov.

rea
{if story.player.gold > 100 begin}
  Kupec sa chamtivo usmeje.
{else if story.player.gold > 50}
  Kupec zdvorilo prikývne.
{else}
  Kupec sa na teba pozrie s ľútosťou.
{end if}

Podmienka napísaná na jednom riadku môže zdieľať riadok s textom — pred ňou, za ňou alebo z oboch strán: Lampáš je ťažký.{if story.card.lantern.weight > 2 begin} Ťahá ti opasok nadol.{end if} vypíše prvú vetu vždy a druhú len vtedy, keď podmienka platí. To isté platí pre {set}, {goto} a {label}. Ak ich chceš zapísať ako text a nie spustiť, escapuj zátvorku (\{if ...}) alebo ich daj do inline kódu.

Switch / Case

experimentalod 1.0{switch expr begin} {case "x"} … {end switch}

Viaccestné vetvenie so záložnou vetvou {default}.

rea
{switch story.player.class begin}
{case "warrior"}
  Vytasíš meč.
{case "mage"}
  Zdvihneš palicu.
{case "rogue"}
  Roztopíš sa v tieňoch.
{default}
  Zostaneš stáť na mieste.
{end switch}

Cyklus for

experimentalod 1.0{for item in list, index begin} … {end for}

Prechádza polia s voliteľnou premennou indexu počítanou od nuly.

rea
{for item in story.player.inventory begin}
  Máš: {item}
{end for}

S premennou indexu (definovanou za čiarkou pred begin):

rea
{for item in story.player.inventory, index begin}
  {index + 1}. {item}
{end for}

Premenná indexu začína na 0 a s každou iteráciou sa zvyšuje.

Cyklus while

experimentalod 1.0{while cond, n begin} … {end while}

Opakovanie riadené podmienkou s voliteľným počítadlom iterácií; runtime ho ohraničuje proti nekonečným cyklom.

rea
{while lock.attempts > 0 begin}
  Znova skúsiš zámok…
  {set lock.attempts = lock.attempts - 1}
{end while}

S počítadlom iterácií (definovaným za čiarkou pred begin):

rea
{while lock.attempts > 0, tryNumber begin}
  Pokus {tryNumber + 1}: znova skúsiš zámok…
  {set lock.attempts = lock.attempts - 1}
{end while}

Premenná počítadla začína na 0 a s každou iteráciou sa zvyšuje.

Počítadlo {while} nie je implementované Parser neoddelí , part.pokus od podmienky — pohltí ho, takže sa počítadlo nikdy nenaviaže a podmienka je pokazená. Indexová premenná v {for} funguje správne, počítadlo vo {while} nie. Dovtedy počítajte obyčajným {set}:

rea
{set part.pokus = 0}
{while story.zamok.pokusy > 0 begin}
  Pokus {part.pokus + 1}: znova skúsiš zámok…
  {set part.pokus = part.pokus + 1}
  {set story.zamok.pokusy = story.zamok.pokusy - 1}
{end while}

Break a continue

draft{break} · {continue}

Špecifikované spolu s cyklami, ale neimplementované — cyklus dnes beží po svoj prirodzený koniec. Autori namiesto toho odchádzajú skôr pomocou podmienky.

rea
{for item in story.player.inventory begin}
  {if item = "cursed_ring" begin}
    {continue}
  {end if}
  Prezrieš si {item}.
  {if item = "golden_key" begin}
    Toto je ono! {break}
  {end if}
{end for}

Stavové automaty

development{state_machine door, initial="locked" begin}

Parser prijíma stavy, prechody aj strážne podmienky a runtime sleduje aktuálny stav; perzistencia a zdieľanie medzi čitateľmi sa ešte stavajú, takže autorom to zatiaľ nie je ponúknuté.

Formálne stavové automaty modelujú entity, ktoré prechádzajú medzi pomenovanými stavmi na základe udalostí a podmienok. Hodia sa na dvere, postavy, systémy počasia či akúkoľvek entitu s odlišnými režimami správania:

rea
{state_machine door, initial="locked" begin}
  {state locked begin}
    Dvere sú pevne zamknuté.
  {end state}

  {state closed begin}
    Dvere sú zatvorené, ale odomknuté.
  {end state}

  {state open begin}
    Dverný otvor stojí pred tebou dokorán.
  {end state}
{end state_machine}

{on unlock machine="door", state="locked" when has_key begin}
  Otočíš kľúčom. Cvak!
  {-> closed}
{end on}

{on open machine="door", state="closed" begin}
  Dvere sa rozletia.
  {-> open}
{end on}

{on lock machine="door", state="closed" begin}
  Zamkneš za sebou.
  {-> locked}
{end on}

{on close machine="door", state="open" begin}
  Pritiahneš dvere.
  {-> closed}
{end on}

Blok {state} nesie to, čo čitateľ vidí, kým je automat v danom stave. Každý prechod je vrcholový blok {on <udalosť> machine="...", state="..." begin} — tá istá plochá forma, akú má každá iná udalosť v jazyku — a nesie svoju stráž, svoj obsah aj odbočku {-> cieľ}, ktorá automat posunie ďalej. Blok bez machine= platí pre každý automat, ktorý daný stav deklaruje.

Atribúty stavového automatu:

AtribútPopis
initialPočiatočný stav (povinný)
persisttrue na uloženie stavu medzi reláciami
sharedtrue na zdieľanie stavu medzi čitateľmi

Prístup k stavu a spúšťanie prechodov:

Aktuálny stav automatu sa dá čítať na story.<id>.state — je to bežný stav príbehu, len ho zapisuje automat, nie {set}:

rea
{if story.door.state = "locked" begin}
  Potrebuješ kľúč.
{end if}

{trigger door.unlock}

Strážne podmienky na prechodoch bránia neplatným zmenám stavu:

rea
{on unlock when story.quest.has_key and !alarm.active begin}
  {-> closed}
{end on}

14. Funkcie

experimentalod 1.0{function greet(name) begin} … {end function}

Definícia, volania, predvolené parametre aj {return} fungujú; štyri klasifikácie kontextu volania sú vydané, ale môžu pribudnúť pravidlá kontroly.

Vlastné funkcie definované pomocou {function}…{end function} — klasifikácie čistá, šablónová, hybridná a s vedľajším účinkom, správanie podľa kontextu volania, parametre s predvolenými hodnotami a to, ktoré klasifikácie smie exportovať súbor .rext — majú teraz vlastnú stránku: pozri Vlastné funkcie.


15. Udalosti

experimentalod 1.0{on story_start begin} … {end on}

Blok {on …} a udalosti životného cyklu sú vydané; udalosti riadené senzormi závisia od funkcií, ktoré sú stále vo vývoji alebo v návrhu.

Udalosti reagujú na spúšťače platformy. Definujú sa pomocou {on nazov_udalosti begin}:

rea
{on story_start begin}
  {set story.player.gold = 100}
  {set story.player.health = 100}
{end on}

{on chapter_start begin}
  Začína sa ďalšia kapitola tvojej cesty…
{end on}

{on shake begin}
  Zem sa ti chveje pod nohami!
{end on}

Vstavané udalosti

UdalosťSpúšťač
story_startPríbeh sa otvoril prvýkrát
story_resumePríbeh sa znovu otvoril po zatvorení
chapter_startZačína nová kapitola
chapter_endKapitola je dokončená
timerČasovač dosiahol nulu
shakeZariadením sa zatriaslo
screenshotČitateľ urobil snímku obrazovky
idleČitateľ je istý čas nečinný
proximityNeďaleko je iný čitateľ (kooperatívne)
location_enterČitateľ vstúpil do geografickej oblasti
location_exitČitateľ opustil geografickú oblasť
time_matchReálny čas zodpovedá vzoru
weather_matchPoveternostná podmienka zodpovedá vzoru
scanČitateľ naskenoval QR alebo čiarový kód

Parametrizované udalosti

Niektoré udalosti prijímajú parametre, ktoré filtrujú, kedy sa spustia:

rea
{on time_match datetime("*-12-25T*") begin}
  Veselé Vianoce!
{end on}

{on weather_match "snow" begin}
  Za oknom sa znášajú snehové vločky.
{end on}

{on shake, intensity=3 begin}
  Zem sa prudko otriasa!
{end on}

Parameter spúšťač zužuje. Bez parametrov sa udalosť spustí pri akejkoľvek zhode (napr. {on scan begin} sa spustí pri každom skenovaní, {on scan "CODE-42" begin} len vtedy, keď sa naskenuje „CODE-42").

Uloženie a kontrolné body

draft{checkpoint name="before_boss"} · {restore name=…}

Automatické ukladanie postupu funguje už dnes. Kontrolné body deklarované autorom, {restore} a {save enabled=false} sú špecifikované, ale nepostavené, a kooperatívne pravidlo „všetci čitatelia musia súhlasiť" si najprv vyžaduje návrhové kolo.

Platforma automaticky ukladá postup čitateľa po každej voľbe. Autori môžu definovať pomenované kontrolné body ako výslovné miesta uloženia a obnovenia:

rea
{checkpoint name="before_boss"}

Čitatelia sa môžu vrátiť ku ktorémukoľvek kontrolnému bodu cez rozhranie platformy. Autori môžu kontrolné body obnoviť aj programovo:

rea
{restore name="before_boss"}

Čo snímka zachytáva

Snímka (či už automatické uloženie, alebo pomenovaný kontrolný bod) zachytáva kompletný stav čitateľa:

KategóriaČo sa ukladá
PremennéVšetky hodnoty {set} vrátane vnorených vlastností a premenných v rozsahu nadpisu
PozíciaAktuálna pasáž, posun v riadku, zásobník aktívnych volieb
Počty návštevKoľkokrát bola každá kotva či nadpis navštívená
Atribúty čitateľaJazyk, meno, rola, vlastné metadáta
Stavové automatyAktuálny stav každého {state_machine}
Príznaky blokov onceKtoré bloky {once} sa už spustili
Indexy cyklovAktuálna pozícia v každom {cycle}
Text návestíAktuálny text každého {label} (po prípadnom {replace})
Inventár karietPredmety pridané a odobrané cez {give} / {take}
Stav balíčkaKtoré storylety už boli vytiahnuté a čo ostáva vo výbere
Stav časovačovAktívne časovače sa pri uložení pozastavia a pri obnovení pokračujú
Prehrávanie médiíPozície zvuku a videa sa neukladajú — médiá sa pri obnovení spustia odznova

Pri kooperatívnom čítaní snímka navyše zachytáva:

KategóriaČo sa ukladá
Zdieľané premennéVšetky hodnoty shared.*
Stav jednotlivých čitateľovIndividuálny stav každého čitateľa (premenné, pozícia, inventár)
Priradenie rolíAktuálne naviazania {define role}
Stav zámkovKtoré bloky {lock} sú aktívne a kto ich drží
Výsledky hlasovaní a pretekovDokončené výsledky hlasovaní a pretekov

Kontrolné body v kooperatívnom čítaní vyžadujú pred obnovením súhlas všetkých pripojených čitateľov. Ak je čitateľ odpojený, jeho súhlas potrebný nie je — platforma mu stav obnoví, keď sa znovu pripojí.

Ručné uloženie

Čitatelia môžu ručne uložiť kedykoľvek počas čítania (nielen v kontrolných bodoch definovaných autorom). Ručné uloženia zachytávajú tie isté údaje ako kontrolné body. Autori môžu ručné ukladanie pre konkrétne sekcie vypnúť:

rea
{save enabled=false}
{comment Automatické ukladanie stále beží, ale čitateľ nemôže ručne uložiť ani načítať}

Keď je {save enabled=false} aktívne, rozhranie platformy skryje tlačidlo uloženia. Automatické ukladanie pri voľbách pokračuje, aby sa postup nestratil pri páde aplikácie.

Prenositeľnosť uložení medzi verziami príbehu

Uloženia sú viazané na konkrétnu verziu príbehu (pole metadát version). Keď sa príbeh aktualizuje:

  • Zmena verzie patch (napr. 1.0.01.0.1): uloženia sa načítajú normálne. Chýbajúce nové premenné použijú svoje predvolené hodnoty. Odstránené premenné sa ticho ignorujú.
  • Zmena verzie minor (napr. 1.01.1): platforma sa pokúsi uloženie načítať. Ak aktuálna pozícia čitateľa už neexistuje (pasáž bola odstránená alebo premenovaná), platforma sa vráti k najbližšiemu platnému kontrolnému bodu alebo na začiatok aktuálnej kapitoly.
  • Zmena verzie major (napr. 1.x2.x): uloženia sú nekompatibilné. Platforma to čitateľovi oznámi a ponúkne začať odznova.

Platforma ukladá uloženia ako JSON. Schéma obsahuje pole spec_version (verzia jazyka Rea) a pole story_version (verzia autora), vďaka čomu runtime dokáže zistiť kompatibilitu.