Nejprve jsem otevřené závorky zkusil vymazat, debugger ale nepochopil jak interpretovat mříž, takže jsem je vrátil na úroveň objektu, pokud je to takto správně.
Jsou dvě možnosti, jak deklarovat objekt a Eric obě na začátku knížky popisuje. Buď se použije otevírací i uzavírací složená závorka na úrovni objektu, nebo se místo nich použije jen středník označující konec objektu. Druhý způsob je obvyklejší v praxi, protože je úspornější a přehlednější. Je dobré si na něj zvyknout, protože ho najdeš prakticky výhradně v dalších kapitolách knihy a a příkladech a rozšířeních stáhnutých z internetu. Tedy v tvém případě by to znamenalo první otevírací závorku vymazat a zavírací také vymazat a místo ní dát středník.
Pokusil jsem se doplnit skloňování, budu testovat přímo ve hře.
Jen u gcName na rozdíl od gcVocab musíš zadat pády, i když se opakují. Konkrétně v pořadí 2, 3, 4, 6, 7, tedy např. gcName = 'mříže, mříži, mříž, mříži, mříží'.
Při debuggování bych si potřeboval uložit pozici a testovat hru z konkrétní místnosti. Když ale hru ukončím a znovu zkompiluji, uložený soubor není kompatibilní. Je tu nějaká lepší možnost testování ve Workbenchi?
Při zkompilování hry vznikne vlastně "nová hra", která není co se týče uložených pozic kompatibilní s tou původní. Je to nutný důsledek toho, jak ukládání pozic a UNDO v TADSu funguje. Tyto funkce jsou vytvořené na nízké úrovni a pracují s binární reprezentací objektů v paměti virtuálního stroje. Uložená hra je vlastně obrazem paměti (tj. stav objektů), přesněji řečeno je to rozdíl oproti výchozímu stavu hry, který je uložený v samotném souboru s hrou.
Přímo Workbech má funkci, že když hraješ hru, tak nahrává jednotlivé příkazy do souboru a příště jedním dvojklikem můžeš celé sezení přehrát a podívat se, jak se hra změnila. Nebo příkazem >přehraj 'soubor' můžeš interaktivně přímo ve hře nechat přehrát soubor s příkazy. Já osobně ve Workbenchi běžně nepracuji, ale mám udělaný skript, který mi hru tímto způsobem otestuje a rovnou mi zobrazí změny oproti poslednímu průchodu, který považuji za správný:
#!/bin/sh
t3make -d
frob -i plain -k utf8 --no-pause -S -c -e 1000 -R testCommands.txt asteroid.t3 > testOutput.txt
diff -Nur testTranscript.orig testTranscript.txt > testTranscript.diff
kwrite testTranscript.diff
potom mám soubor s příkazy, do nějž postupně doplňuji cokoliv, co chci vyzkoušet, ten vypadá např.:
>zapni zápis
>testTranscript.txt
>restart
>a
>nápověda
>o hře
>kontrola překlepů
>zapni kontrolu překlepů
Na začátku hry jsme ve své kajutě.
>p sebe
>zhasni
>p dozimetr
>p ventily
>přemýšlej
>na 20
>přemýšlej o věčnosti
atd., u Základny má přes 2000 příkazů. Když jsem s výsledkem spokojený, tak překopíruji obsah souboru testTranscript.txt do souboru testTranscript.orig a tím vytvořím novou bázi pro hledání změn. Po každé úprave programu spustím ten výše uvedený skript, hra se přeloží a za chvíli mám před očima rozdíl v kwritu:
@@ -2138,8 +2182,8 @@
>rozsvitit displej tabletu
Zmáčkl jsi tlačítko a displej se rozzářil. Na obrazovce tabletu je zobrazena
hra Dělostřelecký souboj. Na nádherně malované krajině v hyperrealistickém 2D
-zobrazení stojí dvě děla. Hra ukazuje, že děla jsou od sebe 10 km daleko a
-čeká, až zadáš úhel hlavně, pod kterým chceš vystřelit. (např. ZADEJ 45)
+zobrazení stojí dvě děla. Hra čeká, až zadáš úhel hlavně, pod kterým chceš
+vystřelit.
Servisní šachta
Jsi v servisní šachtě. Tudy vedou kabely z přední části lodi s řídicím
Sice je trochu otrava s náhodnými akcemi, ale i tak je to fajn a rychlé řešení, vlastně jsem při vývoji hru interaktivně skoro nikdy nehrál.
Zkoušel jsem použít na mrtovlu direktivu RestrictedContainer a Heavy, právě při použití Heavy není ve hře vidět, ale lze jí prozkoumat, dělám něco špatně? Po vymazání Heavy je zase vše OK.
Heavy je třída poděděná z Immovable a ta zase z NonPortable. Tyto třídy slouží typicky k reprezentaci různých pevných součástí lokace, jako je nábytek, lustr na stropě apod., které se nevypisují v rámci rozhlédnutí v místnosti, protože se předpokládá, že to není běžný objekt, který by si hráč mohl odnést.
Když pracuješ s nějakou třídou, kterou ještě moc neznáš, tak je fajn se podívat na její definici do referenční příručky:
http://www.tads.org/t3doc/doc/libref/index.html Po levé straně vyhledáš Heavy v seznamu tříd, klikneš a podíváš se na vlastnosti a metody, které třída definuje. Úplně nejlépe se pak můžeš prokliknout přímo do zdrojáku kliknutím na číslo řádky v pravém horním rohu, zde objects.t[2054]:
/*
* Heavy: an object that's immovable because it's very heavy. This is
* suitable for things like large boulders, heavy furniture, or the like:
* things that aren't nailed down, but nonetheless are too heavy to be
* carried or otherwise move.
*
* This is a simple specialization of Immovable; the only thing we change
* is the messages we use to describe why the object can't be moved.
*/
class Heavy: Immovable
cannotTakeMsg = &cannotTakeHeavyMsg
cannotMoveMsg = &cannotMoveHeavyMsg
cannotPutMsg = &cannotPutHeavyMsg
;
Vidím, že se zde nastavují jen hlášky, tak zatočím kolečkem a podívám se výše (nebo najdu přes seznam) a podívám se na Immovable. Tam toho je trochu více, upravují se akce, ale když vyhledám ještě dalšího předka, tak najdu:
class NonPortable: Thing
/*
* An immovable objects is not listed in room or container contents
* listings. Since the object is immovable, it's in effect a
* permanent feature of its location, so it should be described as
* such: either directly as part of its location's description text,
* or via its own specialDesc.
*/
isListed = nil
isListedInContents = nil
isListedInInventory = nil
Všimni si, že právě tady mají tyto objekty definováno, že na rozdíl od běžných přenosných objektů třídy Thing se nemají vypisovat ani v místnosti, ani v inventáři atp. A pokud bys chtěl, tak to můžeš zvrátit, nastavit některou z vlastností u své mrtvoly zpátky na true. Druhý mechanismus, který můžeš využít pro popis objektu, který je v místnosti důležitý a je potřeba ho zmínit, tak je nastavení vlastnosti specialDesc, viz příklady v Základně.
Pokusil jsem se pilník definovat jako hidden, ale bez úspěchu, v takovém případě se sice zobrazí při zadání příkazu "koukni se do mrtvoly", ale následně prozkoumat ani sebrat nelze.
Existují dva vzájemně se deoplňující způsoby, jak zacházet se skrytými objekty. Třída Hidden a PresentLater. Nevím, co přesně a jak jsi zkoušel, našel jsem ve zdrojáku zhruba tohle:
+ mrtvola : RestrictedContainer 'mrtvola' 'mrtvola' *3
;
pilnik : Key 'pilník' 'pilník' *2
;
Doporučil bych ti přidat Hidden třídu, tj. deklarovat pilník jako Key, Hidden. Tím způsobem bude objekt skrytý před zraky, jako by ve hře nebyl, dokud nebude objeven. Hidden má ještě jednu vlastnost a sice že takové objekty hráč automaticky nalezne, pokud prohledá kontejner (>podívej se do mrtvoly).
Aby ti to fungovalo, musíš udělat ještě jednu důležitou věc - musíš pilník umístit do mrtvoly. To uděláš tak, že přidáš dvojici znamének plus před deklaraci objektu. Dvě proto, že mrtvola má znaménko jedno a místnost žádné, tedy mrtvola je v místnosti a pilník v mrtvole. Když není znaménko žádné, tak pilník existuje, ale není nikde ve hře umístěn. Podobně by to fungovalo u PresentLater, jen bysis tam musel sám objekt zviditelnit při prohledání. Ale v obou případech platí to o nutnosti psát známénka plus. Podobně na konci zdrojáku nemáš provaz v truhle.
Zahlédl jsem ve zdrojáku také poznámku "nevím, zda má smysl dobjFor(Search) asDobjFor(LookIn)". Kdybys po tom pátral, tak najdeš, že u Thing je právě tohle udělané a Container to trochu mění v tom smyslu, že akce Search (>prohledej něco) na rozdíl od LookIn (>podívej se do něčeho) má malinko upravené podmínky a na rozdíl od nahlédnutí vyžaduje, aby se postava předmětu mohla dotýkat. Ale to je pro tebe nezajímavý detail, takže nemusíš přesměrovávat akci.
Rád bych také místo otrockého příkazu "odemkni mříž" použil "přepiluj mříž". Pokud budeš mít chvilku, prosím koukni se na definici objektů mriz, mrtvola a pilnik, nyní si vůbec nejsem jist, zda tato definice není celá špatně.
To je pak něco jiného. V tom případě by se asi hodilo přepilování modelovat jako samostatnou akci a vůbec nebrat pilník jako klíč ke dveřím. Co se týče "dveří", které se nedají otevírat hráčem jako běžné dveře, ale mají nějakou formu externího ovládání, tak to viz dveře přechodové komory v Základně. Co se týče přepilování, tak viz některou definici nového příkazu, ale to je trochu pakárna, tak bych si to schoval, až budeš jistější.
Stručně chce to definovat akci a k ní VerbRule. Potom modify Thing a definovat základní chování příkazu se všemy objekty (něco jako hlášku Tohle není něco, co bys mohl přepilovat) a selektivně povolit u žádaných objektů. Aby to bylo dokonalé, tak to chce TAction i TIAction, aby reagovalo na >přepiluj mříž, >piluj pilníkem i >přepiluj mříž pilníkem. U té poslední varianty je ještě problém s tím, že ji lze říci v obou pořadích slov, takže musíš pořešit, aby parser nepochpil, že má mříží přepilovat pilník, viz debata s Tekketem.
Slovník předmětů jsem definoval, zatím jsem nepoužil pomnožný tvar.
Pomnožné jsou např. typicky dveře, těm bys měl nastavit isPlural = true. Když to neuděláš, tak bude hra špatně reagovat, když napíšeš příkaz >prozkoumej dveře a vzápětí zkusíš >otevři je, tak parser nebude vědět, že slovem "je" se odvoláváš na dveře.
+ drahokam_1 : Thing 'drahokam č. 1' 'drahokam č. 1' *2
"Je nádherný. "
gcName = 'drahokamu č. 1, drahokamu č. 1, drahokam č. 1'
gcVocab = 'drahokamu č. 1/drahokamu č. 1/drahokam č. 1'
;
Tady pozor, takhle nemůžeš zapsat slovník. Jednak si nejsem jistý, jestli parser rozdejchá tečku za "č", ale hlavně když se zapisuje několik synonym, tak nemůžeš psát delší frázi lomeno delší frází. Vždy to je ve formátu "přídavné přídavné podstatné/podstatné*množné", takže gcVocab = 'drahokamu' a nahoře v šabloně 'drahokam (č.) 1'. Závorky označují nespecifickou část slovníku, tedy slova, která když jsou použita samotná, tak nejsou brány jako shoda, protože jsou moc slabá.
Nicméně vřele bych se doporučil těmto problémům úplně vyhnout např. označením 'první diamant' apod.