Diskuze o textových hrách

Syrečky

gaspoda

  • Plný člen
  • ***
    • Příspěvků: 141
    • Zobrazit profil
Ještě jsem zkoušel dát pohovce třídu Underside a masku jsem umístil do ní, ale po objevení masky jsem zjistil, že při popisu místnosti se mi zobrazí text: Pod rozvrzanou pohovkou je plynovou masku
Vida, to už jsem před časem opravil. Asi je na čase hodit na web aktuální verzi překladu. Tak si ji kdyžtak stáhni a vyměň.

A mám podivný problém s listerem v inventáři.
Opravil jsem, o téhle chybě jsem nevěděl, díky.


tekket

  • Mladší člen
  • **
    • Příspěvků: 68
    • Zobrazit profil
Paráda, funguje to. Tomu říkám rychlost.


gaspoda

  • Plný člen
  • ***
    • Příspěvků: 141
    • Zobrazit profil
Jinak super a díky za naprogramování příkladu. Trochu jsem ho ještě učesal a dopsal do něj komentáře, příkládám ho níže. Pár opravdu jen drobností, které jsem pozměnil:

  • U postavy otce není potřeba nastavovat isHim a globalParamName. První je automaticky dané rodem postavy a druhé v této malé hře není využito.
  • U kaina máš jeden zbytečný středník.
  • Místo GiveTopic jsem použil GiveShowTopic, který reaguje i na ukázání syrečků otci. Tím se omezují problémy s uhodnutím příkazu.
  • Zapisování akcí pomocí např. actionDobjOpen() { ... } je možné, ale prakticky vždy se používá ta forma s propertysets, tedy dobjFor(Open) { action() { ... }}, ono to pak je přehlednější, když se toho píše více a hlavně to tak budou lidé vídat v jiných ukázkách. Také jsem jeden z testů přehodil do check(), kde by spíše měl být. V této jednouché ukázce to je jedno, ale je to tak lepší z hlediska dobrých návyků.
  • Také <<end>> není potřeba, protože je na konci řetězce automatické.
  • Doplnil jsem k pohovce Underside, o kterém jsi psal. Všimni si, že je přitom potřeba použít už komplexní kontejner, protože jinak by si postava sedala "pod pohovku".
 


tekket

  • Mladší člen
  • **
    • Příspěvků: 68
    • Zobrazit profil
Díky za úpravy, bude zajímavé si porovnat, co jsi změnil.

isHim - zajímavé. globalParamName jsem si nebyl přesně jistý, k čemu je a jestli to npc potřebuje

GiveShowTopic - to dává smysl

actionDobjOpen vs dobjFor(Open) - k téhle verzi jsem se ještě nedopracoval. no vlastně jsem celkově sotva na začátku:) K fázím akcí jako check, verify, action... jsem se ještě ani nedostal.

To mě původně nenapadlo, že na pohovku už je třeba něco složitějšího.

Tu akci to ještě bude chtít změnit. Nyní když se podívám pod pohovku, tak neproběhne ta nakódovaná akce s Textem Nalezl jsi masku.... a místo toho vypíše standardní zprávu pro danou situaci. Také mi došlo, že první část podmínky, kdyby se spustila, zobrazí ten text, i když bych masku nesebral, nebo pod pohovku položil syrečky - to jsem zrovna nedomyslel.

Správněji by tedy akce měla při objevení masky pouze přepsat standardní zprávu pro výpis toho, co je pod pohovkou a dále již nechat Underside kontejner fungovat jako normálně.



tekket

  • Mladší člen
  • **
    • Příspěvků: 68
    • Zobrazit profil
S tím nápadem, že dám masku pod pohovku zdrojový kód nakonec slušně narostl:) Taky lekce.


gaspoda

  • Plný člen
  • ***
    • Příspěvků: 141
    • Zobrazit profil
Skutečně jsem toho zase tak moc neměnil, ale neodpustil jsem si opravit odsazení, to opravuji i dětem, když je učím programovat ;-)

V příštím díle seriálu budu právě vysvětlovat provádění akcí a k čemu jsou jednotlivá stádia verify, check, action atd.

globalParamName

Na vlastnost globalParamName jsem se sám musel podívat, protože jsem ji ještě nepoužil. Jde o parametry zpráv. Když píšeš nějaké zprávy, tak se do nich dají dosazovat názvy objektů (a třeba zájmena apod. vztahující se k těm objektům) pomocí parametrů. Ponejvíce toho využívá knihovna, protože ta potřebuje univerzální hlášky, které se hodí pro jakýkoliv objekt. Programátor píšící hru to potřebuje jen tehdy, kdy píše něco obecnějšího, jako fungl novou akci. Pokud už ale píše konkrétní chování jednoho konkrétního objektu, nemusí zprávu parametrizovat, může napsat rovnou ten konkrétní objekt.

Taková zpráva může vypadat třeba následovně: "{Kdoco dobj} už {je} pod {kýmčím iobj}. " V rámci takových zpráv jsou předdefinované názvy "dobj", "iobj" a "actor", které dosadí patřičný objekt. Tak např. {Kdoco dobj} vloží název přímého objektu v prvním pádu a s velkým písmenem na začátku. Když bychom se ve zprávě chtěli odvolat na něco jiného, než přímý či nepřímý objekt resp. postavu provádějící akci, můžeme si nový objekt zaregistrovat. Dělá se to zavoláním gMessageParam(s) s příslušnou proměnnou, která umožní pak použít parametr vztahující se k té dané proměnné, jako třeba ring nebo key:

Kód: [Vybrat]
    foundKeyOnKeyringMsg(ring, key)
    {
        gMessageParams(ring, key);
        return 'Zkusil{a} {jsi} každý klíč na {komčem ring} a zjistil{a} {jsi},
            že {kdoco key} pas{uje|oval[a key]} do zámku. ';
    }

Kromě iobj, dobj a actor (určité parametry, jako {a}, {jsi} apod. se automaticky vztahují k actor, pokud u nich není napsáno něco jiného, proto ve zprávách nemusí být {jsi actor}), které jsou registrované automaticky během zprácování akce, a kromě proměnných, které si uživatel sám ručně zaregistruje pro jednorázové použití pomocí gMessageParam(s), lze kterémukoliv objektu pomocí globalParamName určit nějaký název parametru a ten pak bude dostupný ve zprávách.

Tedy zavedl-li jsi globalParamName = 'otec', znamená to, že pak můžeš použít {komučemu otec} v nějaké zprávě, což se přepíše na "otci". Takhle tedy asi ne moc užitčné, ale třeba u některých postav ve hrách, které hráč nezná a během hry se s nimi seznámí, to může být užitečné. Třeba v Heidi je "uhlíř", který po seznámení je pak představován jako "Joe Black", proto má globalParamName = 'burner' a ve všech rozhovorech, kde je zmíněno jeho jméno, je dosazeno parametrem "Jakmile {jsi} podala prsten {komučemu burner}, jeho oči zaplály nadšením...". Zpráva se pak vytiskne buď s "uhlířovi" nebo "Joe Blackovi" podle toho, zda se s ním Heidi seznámila (příkazy "řekni o sobě" resp. "zeptej se na něj").

Rod

V anglické lokalizaci se rod nastavuje právě pomocí vlastností isHim resp. isHer, ale pro češtinu by to nebylo moc praktické. Angličtina totiž rody používá jinak. V podstatě všechno je "it", dokud to není živý objekt, takže nastavují tyto vlastnosti jen u pár objektů. V češtině jsou ale rody rozprostřeny v podstatě nahodile po všech živých i neživých objektech, a tak jsem pro zkrácení dělal ten zápis s hvězdičkou a číselným vyjádřením. V češtině tedy vlastnosti isHim/isHer/isIt jsou kompletně nahrazeny vlastností gender a z ní pak čerpají další metody, jako canMatchHim a další, které používá parser.

Komplexní kontejnery

Komplexní kontejnery jsou potřeba všude tam, kde určitý objekt potřebuje mít více než jeden druh kontainmentu. Např. stůl, na který i pod který lze položit věci. Nebo kontejner, který může mít uvnitř sebe věci, ale zároveň má i nějaké komponenty z venku. A právě postava sedící na posteli je také vlastně v kontejneru, takže spolu s prostorem pod to jsou dva různé kontejnery v rámci jednoho objektu. Komplexní kontejner je takový dispečer nebo proxy, která rozděluje požadavky na jednotlivé podkontejnery v rámci jednoho objektu a tím obchází limitaci kontejnerové hierarchie.

U té akce by to chtělo ještě pořešit LookUnder, resp. ono je více možností. Teď to funguje zhruba takhle:

Kód: [Vybrat]
>p pohovku
Pamatuje příjezd ruských vojáků do Prahy. Není jisté, zda ten první nebo až ten
druhý. Vypadá to, že pod pohovkou je schovaný nějaký předmět.

>p masku
Nic takového jako „masku“ tu nevidíš.

>podívej se pod pohovku
Pod rozvrzanou pohovkou je plynová maska.

>r
Obývák
Nacházíš se v obýváku. Rozvrzaná pohovka je jediný kus nábytku, který tu
momentálně je.

Pod rozvrzanou pohovkou je plynová maska.

Otec tu stojí.

>p masku
Pochází z dávné minulosti. Je s podivem, že stále drží pohromadě.

Jak je z ukázky vidět, tak neproběhne ta zpráva s objevením masky (a nezavoláš discover), ale když si všimneš, tak se maska odkryje a je vidět. Totiž kontejnery automaticky zviditelňují Hidden objekty, pokud jim to nezakážeš. Ale udělají to jen tak mimochodem, nezobrazí tu zprávu, resp. zobrazí lister, takže to nevypadá tak slavnostně.

Takže jsou dvě možnosti. Buď doplnit akci LookUnder, kde se stane to samé, jako při prozkoumání pohovky dříve a kontrolovat a zprávu vypsat jen tehdy, pokud tam maska je a ještě nebyla objevena a nebo můžeš zprávu nechat vypsat v discover metodě masky. Prostě napíšeš zprávu a zavoláš inherited. Když to zkusíš, zjistíš, že to první je lepší, protože se to odehrává v rámci zpracování akce. Když bys to udělal v discover metodě, bude problém potlačit výpis objektů, který by se připsal ke zprávě o objevení a vypadalo by to divně. Tedy ono to jde potlačit, ale už by se zde ctěnému publiku ježily vlasy, takže mysím ideální varianta:

Kód: [Vybrat]
+ pohovka: ComplexContainer, Bed, Heavy 'rozvrzaná pohovka' 'rozvrzaná pohovka' *3
    "Pamatuje příjezd ruských vojáků do Prahy. Není jisté, zda ten první nebo až ten druhý.
    <<if !maska.discovered>>Vypadá to, že pod pohovkou je schovaný nějaký předmět. "

    gcName = 'rozvrzané pohovky, rozvrzané pohovce, rozvrzanou pohovku, rozvrzané pohovce, rozvrzanou pohovkou'
    gcVocab = 'rozvrzané rozvrzanou pohovky/pohovce/pohovku/pohovkou'

    /*
     *   Pohovka kombinuje dva různé kontejnery. Jednak je to Bed, takže na ní může spočívat postava, druhak má prostor
     *   pod sebou, kde je ukryta maska. Proto musíme pohovku deklarovat jako komplexní kontejner a prostor pod pohovkou
     *   bude subkontejnerem.
     */
    subUnderside: ComplexComponent, Underside
    {
        dobjFor(LookUnder)
        {
            action()
            {
                if(!maska.discovered)
                {
                    "Nalezl jsi masku! A to masku plynovou, nikoliv maškarní. ";
                    maska.discover();
                }
                else inherited;
            }
        }
    }
;

/*
 *   Plynová maska musí být třídy Wearable, aby si ji hráč mohl nasadit. To je třída, která se používá pro oblečení
 *   a podobné věci. Zároveň ji kombinujeme pomocí vícenásobné dědičnosti se třídou Hidden, která zajistí, že objekt
 *   bude na začátku hry skrytý, tedy jako by neexistoval. Ve hře se objeví až po zavolání jeho metody discover().
 */
++ maska: Hidden, Wearable 'plynová maska' 'plynová maska' *3
    "Pochází z dávné minulosti. Je s podivem, že stále drží pohromadě. "

    /* Maska se nachází v subkontejneru. */
    subLocation = &subUnderside

    gcName = 'plynové masky, plynové masce, plynovou masku, plynové masce, plynovou maskou'
    gcVocab = 'plynové plynovou masky/masce/masku/maskou'
;

Což povede k snad už správnému textu:

Kód: [Vybrat]
>p pohovku
Pamatuje příjezd ruských vojáků do Prahy. Není jisté, zda ten první nebo až ten
druhý. Vypadá to, že pod pohovkou je schovaný nějaký předmět.

>podívej se pod pohovku
Nalezl jsi masku! A to masku plynovou, nikoliv maškarní.

>podívej se pod pohovku
Pod rozvrzanou pohovkou je plynová maska.

>r
Obývák
Nacházíš se v obýváku. Rozvrzaná pohovka je jediný kus nábytku, který tu
momentálně je.

Pod rozvrzanou pohovkou je plynová maska.

Otec tu stojí.

>vem ji
Hotovo.

>podívej se pod pohovku
Pod rozvrzanou pohovkou nic nevidíš.

Akorát jsem při tom našel ještě jednu chybu v knihovně, v souboru msg_neu.t se musí opravit tahle metoda:

Kód: [Vybrat]
class LookWhereContentsLister: DescContentsLister
    showListEmpty(pov, parent)
    {
        /* show a default message indicating the surface is empty */
        gMessageParams(parent);
        defaultDescReport('\^' + parent.objInName + ' {|[jsi]} nic
            nevid{[íš]|ěl[a]}. ');
    }
;
« Poslední změna: 1. Listopad 2015 - 11:29 od gaspoda »


tekket

  • Mladší člen
  • **
    • Příspěvků: 68
    • Zobrazit profil
Jo, teď to funguje jak má, včetně opravené chyby ve zprávě v knihovně.

Díky za vysvětlení.


Sylfir

  • Mladší člen
  • **
    • Příspěvků: 73
    • Zobrazit profil
Nestalo by za to u tej tads verzie este v pripade zjedenia syreckov hru ukoncit? Aby hrac nemal pocit ze stale musi este nieco urobit. To je najhorsie na tych hrach ze sa tvaria ze vsetko je OK a pritom je to uz nedohratelne.

Dobre toto riesil Kain v svojich textovkach. Pri save vyhodil hlasku ze hrac vykonal taku akciu ktora znemoznuje dohranie hry. Fungovalo to aspon ako hint ze sa nemam trapit dalej.

Pripadne by sa item syrecky dal nastavit ako bezny objekt ktory nieje urceny na jedenie aby to posobilo ako povodna verzia dema od Kaina.

PS:Thumbs up pred ludmi co v tadse tvoria zlozite textovky.
-::<< Programator TextGame2 enginu v jave (R.I.P.). >>::-
a StoryPlayeru v lua/love2D
a najnovsi je ABEL engine v lua/love2D


gaspoda

  • Plný člen
  • ***
    • Příspěvků: 141
    • Zobrazit profil
To už by bylo triviální, prostě u syrečků bys dal do dobjFor(Eat) metodu action() s nějakým textem a voláním finishGameMsg. Ale stále vycházím z toho, že u Syrečků jde o ukázání programování, ne o hru jako takovou. Ve skutečné hře by autor vůbec neměl dopustit, aby se hráč ocitl v bezvýchodné situaci. Tedy alespoň v takové hře, kterou autor doufá, že někdo bude hrát.


tekket

  • Mladší člen
  • **
    • Příspěvků: 68
    • Zobrazit profil
Ano klidně by stačilo v dané situaci nechat syrečky jako Thing místo Food - nedávalo by z hlediska simulace moc smysl, že je nelze sníst, ale bylo by to blíže původní verzi syrečků, která také podobné detaily neřešila.

Kdyby to měla být plnohodnotná hra, tak souhlasím, že by situace, které můžou hru dostat do mrtvého bodu měly být ošetřeny. Také nejsem úplně fanoušek her, kde lze dostat hru do stavu, že nejde dohrát, aniž by mi to alespoň hra dala jasně vědět. To je přitom případ valné většiny her z 80tých let, včetně těch komerčních. Z dnešního hlediska jsou to prostě hardcore hry - bludiště, mrtvé konce, čtení autorovy mysli, nelogické puzzle, nutnost znalosti konkrétních vědomostí, nedosažitelných v rámci hry - např. puzzle založené na znalosti baseballu:)


Sylfir

  • Mladší člen
  • **
    • Příspěvků: 73
    • Zobrazit profil
Este by som poprosil k prispevku tads ako je main.t prilozit aj skompilovany subor.

Malo by to byt v IDE pod projects/build release ZIP package a vysledok uklada do adresara s projektom ako menoProjektu.zip a bude obsahovat t3 subor ktory uz mozeme spustit aj bez IDE cez nejaky interpreter tadsu. Dik.
-::<< Programator TextGame2 enginu v jave (R.I.P.). >>::-
a StoryPlayeru v lua/love2D
a najnovsi je ABEL engine v lua/love2D


tekket

  • Mladší člen
  • **
    • Příspěvků: 68
    • Zobrazit profil
Verze upravená Gaspodou v příloze.

Spustit lze:
Windows - HTML Tads Player Kit. Pokud máte TADS 3 Author's Kit, tak v něm již tento interpretr je.
Linux a Mac - QTads







severak

  • Nováček
  • *
    • Příspěvků: 28
    • Zobrazit profil
    • Můj web
Ha! Člověk se chvíli nekouká na fórum a oni se tu objevují implementace syrečků. No, taky večer přispěju se svou troškou do mlýna...
-- Severák, nositel pohrabáče


severak

  • Nováček
  • *
    • Příspěvků: 28
    • Zobrazit profil
    • Můj web
Tak tady je ta verze, kvůli které toto téma vlastně začalo. Syrečky v jazyce ALAN (2). V příloze je zdroják i aplikace pro DOS.

Pracuju na Syrečkách pro INSTEAD (v kterém v současnosti vyvíjím něco jiného).
-- Severák, nositel pohrabáče


tekket

  • Mladší člen
  • **
    • Příspěvků: 68
    • Zobrazit profil
Tak tady je ta verze, kvůli které toto téma vlastně začalo. Syrečky v jazyce ALAN (2). V příloze je zdroják i aplikace pro DOS.

Pracuju na Syrečkách pro INSTEAD (v kterém v současnosti vyvíjím něco jiného).

ALAN se mi líbí, někdy v roce 2008 jsem v něm něco zkoušel(zkusím projít stará cd, jestli se něco zachovalo), ale nikdy jsem se nepřenesl přes nemožnost používat diakritiku. Dodnes kompiler i interpretr natvrdo jedou v ISO-8859-I (otázka je nakolik by bylo složité upravit a zkompilovat třeba pro ISO-8859-II ... no pro mě příliš:))