Pro úspěšný lov potřebuji mít v ruce nůž a návnadu. I přes můj kód však stačí mít jen jediný předmět, např. nůž
Ty tam máš podmínku:
if(!navnada.isIn(me) && !nuz.isIn(me))
ale to není správně utvořená negace. Ty říkáš, že potřebuješ nůž A ZÁROVEŇ návnadu. Co je tedy opakem, kdy akci nedovolíš? Když nemáš nůž NEBO nemáš návnadu. Zapoměl jsi prohodit tu logickou spojku. Je to stejné, jako když řeknu, že půjdu ven, když budu mít čas A ZÁROVEŇ bude hezky. Čili nepůjdu ven, pokud buď nebudu mít čas, NEBO bude ošklivě. Říká se tomu DeMorganovy zákony a dají se zapsat jako !(A * B) = !A + !B či !(A + B) = !A * !B (hvězdička značí logický součin, tedy "a zároveň", plusko logický součet, tedy "nebo" a vykřičník je negace). Měl bys tedy napsat:
if(!navnada.isIn(me) || !nuz.isIn(me))
a ještě se text opakuje, místo aby hra zobrazila blok uvedený v else. Předměty typu PresentLater se v pořádku objeví:
Ty tam říkáš:
if(!moved)
Ale dej si pozor, koho se ptáš. Protože píšeš přímo vlastnost moved bez určení objektu, tak se ptáš objektu, ve kterém je napsaný if() a to jsou jámy, které se nikdy nepohnou. Možná bys měl testovat např. orliMaso.moved, potom to bude zabírat, dokud se maso nepohne, čili než ho sebereš. (Teď jsi nejsem jistý, jestli makePresent způsobí pohnutí masa, ale myslím, že ano - záleží, jestli chceš změnit text po objevení nebo až po sebrání a podle toho přizpůsobit podmínku. Můžeš také zkoušet testovat if(orliMaso.location != nil))
V referenční knihovně si vyhledám Akce a rozkliknu LieOnAction, pokud dobře chápu, zjišťuji, že se jedná o třídu dědící od tříd TAction a Action a také od BasicProd a Resolver
Ano, od TAction a BasicProd přímo a ty zase od Action a Resolver.
(které jsou však označeny jako objekty, i když po rozkliknutí jako třídy
Třídy poznáš, že zpravidla začínají velkým písmenkem a objekty malým. Nicméně klíčové slovo "object", které v manuálu vidíš napsané poblíž BasicProd a Resolver neznamená, že BasicProd je objekt, je to třída, ale dědí od speciální třídy nazvané "object", což je označení, že třída nemá žádné předky v knihovně, od kterých by dědila vlastnosti.
An object must always have at least one superclass, but you can use the special class name "object" if you want a generic object that is not based on another object that your program defines.
V sumáři vlastností a metod třídy LieOnAction vidím několik akcí xxx dobj xxx (snad se vyjadřuji přesně), nikoliv však akci s názvem dobjFor
(LieOn), kterou potřebuji použít.
V prvé řadě dobjFor(LieOn) bys měl hledat na herním objektu (potomku Thing), kde se definuje chování akce. Třída LieOnAction se přímo o konkrétní chování nestará, všechny akční třídy jsou součastí parseru, starají se o rozpoznání akce v příkazu hráče a pro samotné vykonání pak zavolají preCond, verify, check a nakonec action na herním objektu.
Zde mě zaráží, že jsem nedohledal žádné propojení s třídou LieOnAction, tady něco chápu špatně.
Potřebuji pracovat s věcmi v inventáři, takže se juknu blíže na aplikaci této metody ve spojení s třídou Thing a dostávám předpis:
dobjFor(LieOn)
{
preCond = [touchObj]
verify() { illogical(&cannotLieOnMsg); }
}
Já se však ve svém kódu snažím využít nikoliv preCond a verify (mohu je chápat jako atributy metody?),
Zápis s dobjFor() samo o sobě ještě není ani metoda, ani vlastnost, ale taková zkratka v zápisu, aby vypadal více hierarchicky a méně se opakovalo psaní. Říká se tomu propertyset a je to specialita TADSu. To, co takhle napíšeš, tak se změní na metodu (verify, action,...) či vlastnost (preCond) tak, že se název zkombinuje z obou částí:
preCondDobjLieOn = [touchObj]
verifyDobjLieOn() { illogical(&cannotLieOnMsg); }
Ale jinak ano, teď už hledáš na správném místě. V těchto místech se skrývá chování, které chceš ovlivnit.
ale verify, check a action společně s podmínkou začínající příkazem if a končící else, nakonec se snažím
umožnit hráči nejen si s potřebnými předměty lehnout do jámy, ale také při položení obou věcí dosáhnout
téhož pomocí dobjFor(PutIn) asDobjFor(LieOn).
Tak to ale pozor, o jakou akci se jedná. Když se snažíš jednu akci přesměrovat na jinou, nesmíš míchat různé druhy akcí dohromady. Jednak bys nemohl přesměrovávat akci, co žádné objekty nebere na akci, co bere jen přímý objekt a podobně akci, co bere přímý objekt na akci, která používá přímý i nepřímý objekt. To není kompatibilní. Ve tvém příadě LieOn je akce, kde hráč ulehá na objekt a to není kompatibilní s akcí, kdy objekt se položí na jiný objekt. I když nemůžeš použít asDobjFor, tak můžeš obě možnosti naprogramovat velmi podobně, ale zvlášť.
Pokud dobře chápu, potřebuji rozšířit funkcionalitu metody dobjFor(LieOn) tak, abych mohl využít atributů
verify, check a action. Je nepříjemné, že můj zápis hra nebere jako chybu (syntaktická to pro kompilátor
není, sémantická však ano, pokud dobře rozumím, i tak je chování zvláštní, neměl by TADS při překladu zařvat,
že se snažím volat neexistující atributy?).
Neměl by řvát, je to obráceně. Ty je nevoláš, ty je vytváříš (a máš možnost vytvořit jakoukoliv metodu či proměnnou chceš), volá je akce v knihovně. A nebo pokud se spleteš a nepojmenuješ metodu správně nebo z jiného důvodu ji nikdo nechce, tak ji holt nikdo nezavolá.
Zde se ale už dostáváme dost do teorie a možná většina tvých problémů zmizí, když vyřešíš ty drobné chybky v logice ifů zmíněné na začástku
mé odpovědi.
Něco mi holt uniká, nechápu zatím propojení mezi třídou LieOnAction a metodou dobjFor(LieOn), tuším, že zde
takové propojení bude např. přes třídu Thing a její metody.
Ze strany akční třídy se spouští vykonání akce, např. kdyby sis našel ve třídě TAction metodu verifyAction(), tak tam uvidíš, jak zde akce volá tu verifyDobjLieOn tvé jámy. Ale pointa je, že kód LieOnAction bys ani neměl číst, to jsou ty nízkoúrovňové věci, které sice tvoří jádro zpracování, ale jako autor hry tu nic užitečného nenajdeš.