Programování pro hračičky/Krok 9

Z Wikiverzity
Skočit na navigaci Skočit na vyhledávání
Jak používat klasifikační nálepkuTato stránka je součástí kurzu:
středoškolská
Příslušnost: skupinová

Spouštění akcí[editovat]

Už jsme si všimli, že s různými objekty ve hře můžeme provádět různé akce. Například sušenku můžeme sníst, pochodeň můžeme rozsvítit nebo zhasnout, dveře můžeme otevřít nebo zavřít.

Každá takováto akce je navenek definována jednak množinou řetězců, kterými je možno ji vyvolat (jedná se vždy o první slovo, případně začátek prvního slova hráčského vstupu), jednak funkcí, která se má v objektu definujícím akci spustit, pokud herní ovladač na vstupu rozpoznal jeden z udané množiny řetězců. Například zmíněné dveře definují akci, kterou je možno vyvolat jedním ze slov otevři, otevřu, otevri, otevru, otevírám a oteviram, a která spouští v objektu dveří funkci open_command().

Když hráč zadá libovolný příkaz, pak se herní ovladač začne postupně dotazovat všech objektů, které se v blízkosti hráče vyskytují (tedy jednak těch, které má hráč ve svém inventáři, jednak těch, které jsou s hráčem v téže místnosti, jednak místnosti, v níž se hráč právě nachází, a jednak objektu hráče samotného), zda mají k zadanému příkazu přiřazenu nějakou funkci.

Pokud nyní hráč zadal v blízkosti našich dveří příkaz začínající jedním ze slov, která jsou v objektu dveří přiřazena funkci open_command(), a ovladač se ve svém dotazování obrátí na dveře, tato funkce se spustí. Nemůže však hned provést otevření dveří (tedy vydat hlášky o otevírání dveří a kdesi v hloubi objektu dveří změnit vlastnost otevřenosti z 0 na 1), nýbrž musí nejdříve prověřit celou řadu podmínek:

  • Míní hráč skutečně tento objekt? Co když hráč zadal otevři truhlu (nebo zadal otevři dřevěné dveře, a tyto dveře nejsou dřevěné, nebo zadal otevři 2. dveře, a tyto dveře jsou v inventáři místnosti první, nebo zadal pouhé otevři, či dokonce otevři qwertzuiop) — pak se přece jeho příkaz vůbec netýká tohoto objektu.
  • Míní hráč skutečně akci, kterou tento objekt může provést? Co když má hráč v ruce otvírák, který dokáže otvírat konzervy a podobné nádoby, a napíše otevři dveře otvírákem? Pak sice míní tento objekt, ale chce s ním provést něco jiného, než jsou dveře schopny jakožto dveře nabídnout.
  • Dá se akce, kterou hráč míní, skutečně provést? Co když hráč zadal otevři dveře, ale dveře jsou už otevřené? Nebo co když jsou dveře zamčené, takže bez odemknutí není možno je otevřít? Nebo co když má hráč plné obě ruce, takže nemá jak otevřít dveře?

Jenom v případě, že jsou tyto podmínky splněny, se dveře skutečně otevřou. Víme už, že v útrobách počítače při tom nedojde k žádnému fyzickému pohybu objektu, nýbrž že v rámci objektu se prostě přenastaví vlastnost otevřenosti (konkrétně se hodnota 0 změní na 1). O provedené změně jsou zároveň informovány okolní objekty (například hráč Všudybud, který dveře otevřel, dostane hlášku Otevíráš dveře., ostatní hráči v místnosti dostanou hlášku Všudybud otevírá dveře., ale zpráva se pošle také této místnosti i místnosti na druhé straně dveří. Některé akce kromě změny vlastností objektu, s nímž hráč zachází, mohou měnit vlastnosti jiných objektů (když hráč sekne mečem po kolemjdoucím skřetovi, pak ve většině případů kolemjdoucí skřet ztratí nějaké ty životní body) nebo spouštět další procesy (když hráč sekne mečem po skřetovi, zahájí tím boj, tedy s určitým zpožděním se spustí nějaké funkce v objektu skřeta — například protiútok — nebo v objektu hráče samotného — například příští rána, která zase se zpožděním spustí tu přespříští atd.).

Pokud některá z výše rozepsaných podmínek není splněna, objekt dveří příkaz odmítne (na úrovni programu se to odehraje tak, že zavolaná funkce open_command() vrátí hodnotu 0) a ovladač pokračuje ve svém vyptávání u dalších objektů. Pokud příkaz odmítnou všechny objekty v blízkosti hráče (i objekt hráče samotného), pak se neprovede akce žádná a hráč je o tom v nejjednodušším případě zpraven univerzální hláškou Prosím?. Často může být smysluplné, aby objekt odmítl příkaz, ale hráči nějak přesněji sdělil, proč ho odmítl. V našem příkladu s dveřmi by bylo vhodné, aby v prvním případě hráč místo obecného Prosím? obdržel třeba hlášku Co chceš otevřít?, ve druhém případě třeba Otvírákem? a ve třetím případě třeba Dveře už jsou otevřené.. Hláška se však smí vydat jen v případě, že příkaz byl odmítnut skutečně všemi objekty. To se na úrovni programu zařídí tím, že objekt, který odmítá příkaz, zároveň vestavěnou funkcí notify_fail() sdělí ovladači, jakou hlášku by rád poslal hráči v případě, že příkaz odmítnou i ostatní objekty, a ovladač pak z těchto hlášek vybere tu, která byla nastavena s nejvyšší prioritou, resp. jako poslední.[1]

Posloupnost objektů v blízkosti hráče[editovat]

Protože poté, co jsme se naučili měnit vlastnosti předmětů, chceme nyní měnit i příkazy, jimiž je možno s objekty zacházet, musíme si velmi dobře uvědomit, jaké příkazy jsou definovány v jakém objektu a v jaké posloupnosti se jich herní ovladač dotazuje, zda chtějí zadaný příkaz zpracovat. První dotázaný objekt, který příkaz přijme, tedy vrátí hernímu ovladači 1 po zavolání příkazové funkce, totiž sebere všem ještě nedotázaným objektům možnost příkaz vykonat a jejich případnou funkci zastoupí svou vlastní funkcí.

Prakticky se s otázkou posloupnosti dotazovaných objektů v různých podobách setkávají již herní nováčci: Hráčka Alena například odloží svůj batoh, aby si něco přerovnala, hráč Bobeš nacházející se ve stejné místnosti odloží následně svůj batoh také, hráčka Alena zašněruje batoh (ovšem netušíc zašněruje batoh Bobšův, protože ten je ovladačem dotázán dříve), hráč Bobeš dá svoje věci do batohu (ovšem netuše je vloží do batohu Alenina, protože jeho vlastní je již zašněrován), vezme si batoh a odejde, aby teprve mnohem později zjistil, že své věci v batohu nemá.

Zatímco v případě běžných herních situací ovšem oslovení jiných než zamýšlených objektů nenastává tak často a vede povětšinou nanejvýš ke ztrátě určitého objektu, jakmile se staneme tovaryši v Bratrstvu změny, můžeme podobnými záměnami velmi výrazně zasahovat do hry, a to někdy i smrtelně pro její další účastníky — představme si například, že námi do hry vložený objekt na sebe vztáhne všechny příkazy tas, které v jeho okolí někdo zadá, takže přítomní hráči se nebudou moci zákeřnému útoku bránit jinak než holýma rukama. Jak uvidíme, vložit do hry takový předmět není vůbec těžké.

Herní ovladač nabízí příkaz k vykonání postupně samotnému objektu, který příkaz zadal, okolí tohoto objektu, objektům nacházejícím se v okolí objektu a objektům nacházejícím se v inventáři objektu, a to v pořadí určeném interním seznamem příkazů, které jsou objektu hráče (nebo nehráčské postavy) k dispozici. Tento seznam se vytváří postupně, jak se hráč setkává s různými objekty ve hře, přičemž příkazy definované nejnověji potkaným objektem se zařadí na začátek seznamu.

První objekt, se kterým se objekt hráče setkává, je tento objekt sám. Hned po svém vytvoření v sobě objekt hráče definuje základní příkazy, které mají být hráči k dispozici všude ve hře bez ohledu na to, jaké vybavení s sebou nese nebo jaké předměty se kolem něho nacházejí. Jsou to jednak příkazy k zacházení se hrou (jako třeba pomoc), jednak příkazy smyslového zkoumání a zacházení s okolím (jako prohlédni si nebo vezmi), jednak příkazy pohybové (jako sever).

Následně objekt hráče přijímá definice příkazů od dalších objektů v těchto případech:[2]

  • Když se objekt hráče pohne, tedy přesune do jiné místnosti (což poprvé nastane hned po vytvoření objektu a právě popsané definici základních příkazů), pak přijme definice příkazů ode všech objektů v nové místnosti se nacházejících v pořadí, v němž byly do místnosti přesunuty (tedy v opačném pořadí, než je vidíme při prohlédnutí místnosti), a nakonec od objektu místnosti samotné.
  • Když se do místnosti, v níž se hráč nachází, přesune další objekt, objekt hráče od něho přijme definice příkazů.
  • Když se do hráčova inventáře přesune další objekt, objekt hráče od něho přijme definice příkazů.

Prvním často využívaným důsledkem tohoto principu přijímání definic příkazů je, že základní příkazy definované v objektu hráče se provedou jen tehdy, pokud žádný z okolních objektů nedefinuje stejnojmenný příkaz, který by se v dané situaci mohl úspěšně provést. Objekty tedy mohou podle herní potřeby tyto základní příkazy předefinovat. Typicky se toho využívá u příkazu pomoc, který v základní definici nahlíží do databáze nápovědních textů, a když text k danému heslu nenalezne, napíše: K tomu bohužel žádná nápověda nejestvuje. Pokud chce nějaký objekt poskytnout hráči nápovědu, stačí když definuje příkaz pomoc, který skončí s návratovou hodnotou 1 při oslovení objektu a s návratovou hodnotou 0 v jiných případech. Tak například tržiště definuje příkaz pomoc, který v případě zadání hesla tržiště nebo trh vypíše instrukce k používání tržiště a skončí s hodnotou 1 (tedy příkaz se tím považuje za vyřízený), v případě zadání jiného hesla však skončí s hodnotou 0, což znamená, že ovladač má hledat další objekty definující stejnojmenný příkaz a nakonec se zeptat hráčova objektu samotného, tedy nechat provést onen základní příkaz pomoc.

Druhým často využívaným důsledkem popsaného principu je, že předmět, který se nově přesune do místnosti nebo do inventáře hráče, svými definicemi příkazů překryje definice příkazů všech objektů, které hráč dosud měl u sebe nebo které se dosud nacházely kolem něho. Když se stane, že příkazy nějakého objektu jsou nežádoucím způsobem pro hráče překryty jiným objektem, se kterým se setkal později, pak zkušený hráč například položí objekt, jehož příkaz je právě nežádoucně překryt, a znovu jej uchopí, čímž se příkazy definované tímto objektem dostanou opět do popředí.

Uvědomění si základních principů, podle nichž herní ovladač řadí definice příkazů, je potřebné pro úspěšnou práci s dovednostmi měničského tovaryše. Samozřejmě není nutno se výše uvedený a složitostí vztahů poněkud nepřehledný výklad učit nazpaměť. Daleko spíše pomůže zkušenost, nebo i cílené experimentování s tím, jak různé objekty mohou navzájem pro hráče překrývat své příkazy.

Definice a redefinice akcí[editovat]

Jakmile jsme nasbírali dost zkušeností s měničským příkazem změň, můžeme se u mistra Bratrstva nechat povýšit na tovaryše. Máte-li dojem, že samotné měnění vás už omrzelo, navštivte mistra Ezechiela a řekněte mu, že se chcete stát tovaryšem. Ezechiel vám buď odpoví, že jste ještě nenasbírali dost měničské zkušenosti (takže je potřeba i s tím omrzelým příkazem změň ještě nějakou dobu laborovat), nebo vás povýší na tovaryše. Když pak následně navštívíte Matici, vaše měničská mušle začne místo dosavadní bronzové světélkovat stříbrně — to je znakem toho, že se obnovila a že nyní můžete používat tovaryšské dovednosti.

Nejvýrazněji se postup dovedností projeví v tom, že k příkazu změň vám nyní přibude možnost užívat příkazu přeonač. Jeho užití je sice o něco složitější než užití příkazu změň, několika příklady však snadno pochopíme, jak se do toho pustit, a zbytek se naučíme při vlastních pokusech a omylech. K dispozici máme samozřejmě též základní nápovědu pomoc přeonač.

Nejjednodušší použití příkazu přeonač si můžeme ilustrovat na příkladu vytvoření místnosti, v níž je možno rozjímat:

> rozjímej
Prosím?
> přeonač okolí
Soustředíš se na měnění...

Zadej příkazy, pomocí nichž má být možné tvoji metodu zavolat.
Seznam příkazů: rozjímej,rozjimej

Zadej efekty, jež by měla tvoje metoda vyvolat.
Efekt (a jeho parametr): self:Noříš se do hlubokého rozjímání. Dělá ti to opravdu dobře!

Celková náročnost přeonačení je nyní 9 ŽB a 17 DB.
Po posledním efektu zadej "." pro provedení přeonačení.
Chceš-li celé přeonačení ukončit, použij "~q".

Zadej další efekty, jež by měla tvoje metoda vyvolat.
Efekt (a jeho parametr): .
Svět se ti krátce zavlnil před očima.
Přeonačil jsi své okolí na docela dlouho.
> rozjímej
Noříš se do hlubokého rozjímání. Dělá ti to opravdu dobře!

Definice příkazu přeonač je zde skutečně minimální. Vybrali jsme si jeden objekt (v tomto případě okolí, tedy objekt místnosti, v níž se právě nacházíme) a přiřadili jsme k němu definici nového příkazu rozjímej (s variantou rozjimej, aby příkaz fungoval i bez diakritiky[3]), který spočívá v provedení jediného efektu, a to vyslání hlášky hráči, který příkaz zadal. Těchto efektů by mohlo být definováno více, a mohly by být různých druhů. Podrobněji se jim budeme věnovat v příštím kroku, pilný student si o nich může přečíst s předstihem v nápovědě pomoc přeonač.[4]

Protože příkazy definované v objektu místnosti jsou přístupné všem hráčům, kteří do místnosti vstoupí, a protože žádný jiný objekt v okolí nedefinuje příkaz rozjímej, nemusíme se starat o to, v jakém pořadí nabízí herní ovladač jednotlivým objektům příkaz k vykonání — okolní místnost nikdy nevynechá a žádný jiný objekt ji svým příkazem nepřekryje. Jiné je to, když použijeme příkazu přeonač k definici příkazu, který již existuje:

> přeonač kleště
Soustředíš se na měnění...

Zadej příkazy, pomocí nichž má být možné tvoji metodu zavolat.
Seznam příkazů: vem,vezmi,vezmu,beru

Zadej efekty, jež by měla tvoje metoda vyvolat.
Efekt (a jeho parametr): self:Ne! Věci prosím zůstanou ležet na svém místě!

Celková náročnost přeonačení je nyní 13 ŽB a 21 DB.
Po posledním efektu zadej "." pro provedení přeonačení.
Chceš-li celé přeonačení ukončit, použij "~q".

Zadej další efekty, jež by měla tvoje metoda vyvolat.
Efekt (a jeho parametr): .
Přeonačil jsi kleště na docela dlouho.
> polož kleště
Pokládáš kleště.
> vem kleště
Ne! Věci prosím zůstanou ležet na svém místě!

V tomto případě jsme nenadefinovali nový příkaz, ale předefinovali jsme příkaz vem, či přesněji vyrobili jsme definici příkazu, která — díky tomu, že jsme kleště položili do místnosti, kde jsou přístupné všem hráčům — bude konkurovat základnímu příkazu vem, a protože herní ovladač nabízí vykonání příkazu jiným objektům (včetně příkazem opatřených kleští) dříve než objektu hráče, v němž je tento základní příkaz definován, překryje jej. Z výše uvedeného výkladu ovšem víme, že bychom nyní mohli přiřadit nějaký další příkaz vem nějakému jinému objektu a ten pak položit ke kleštím — protože by se tím ocitl na seznamu před kleštěmi, vykonala by se při zadání příkazu vem jeho funkce.

Na tomto příkladu si rovněž všimněme, že jsme zadali více různých podob příkazu — to abychom překryli pokud možno všechna používaná synonyma, tedy aby náš příkaz fungoval co nejpodobněji příkazům, s nimiž se jinak hráči ve hře setkávají.[5]

Herní využití nově definovaných akcí[editovat]

Podobně jako v minulém kroku pro příkaz změň, uvádíme v tomto kroku několik nápadů pro herní využití příkazu přeonač:

  • Některé místnosti mají programově nastaveno, že se v nich nesmí například bojovat, kopat, krást apod. Nyní si takto umíme nastavit tyto vlastosti místností sami — redefinicí příslušných hráčských příkazů.
  • Poměrně zajímavé konfuze mezi přítomnými hráči nastanou, když běžné hráčské příkazy najednou úplně zmizí — tedy například když hráč zadá rozhlédni se a obdrží odpověď Prosím?. Jako tovaryši v Bratrstvu změny to nyní umíme zařídit.
  • Šípek, který jste onehdy změnili na Gondorský zlaťák, nezdržel vašeho pronásledovatele na dost dlouho? Lehce váš trik prohlédl, když zkusil zadat vem zlaťák a dostalo se mu odpovědi Zlaťák? Kde?? Co k této změně přidat ještě přeonačení příkazu vem (např. opět na objektu šípku) s efektem self:Bereš si zlaťák.?
  • Potřebujete-li definovat příkaz, který je bez dalších přípravných úkonů k dispozici všude, kam přijdete, můžete přeonačit sebe samotné.

Úkoly[editovat]

Povinné[editovat]

  • Nasbírejte dostatek měničské zkušenosti, aby vás mistr Ezechiel povýšil na tovaryše. Minimální potřebná hodnota odpovídá hlášce Chtělo by to změnu... ale jak na to? ve zkušenost řemeslo (zku r).
  • Po povýšení si v Matici obnovte mushli tak, aby její záře přešla z bronzové ve stříbrnou.
  • Vyzkoušejte si příkaz přeonač.

Dobrovolné[editovat]

  • Nalezněte alespoň dva příkazy, které v některé místnosti na Calenhadu fungují a v jiné ne. Pokuste se určit, který z objektů v dané místnosti tento příkaz nabízí.
  • Zkuste zjistit, zda se po povýšení na tovaryše změnily nějak vaše šance na úspěšnou a dlouhou proměnu pomocí změň a jak velká změna to asi je.
  • Převezte někoho ze svých spoluhráčů nečekaným použitím příkazu přeonač.

Pomocné stránky[editovat]

Poznámky[editovat]

  1. Přesně si užívání funkce notify_fail() a tento mechanismus osvětlíme později.
  2. Ve všech následně popsaných případech se definice příkazů předávají objektu hráče tím, že se ve druhém objektu — po přesunu automaticky — zavolá funkce init(), která způsobí předání definic příkazů všem objektům nacházejícím se v téže místnosti s objektem, všem objektům nacházejícím se v inventáři objektu a objektu místnosti samotné. Předání definic příkazů je tedy možno vynutit explicitním zavoláním funkce init(), čehož se využívá právě při programátorské realizaci měničského příkazu přeonač, který je popsán níže.
  3. Na rozdíl od hledání objektu podle zbytku vstupního řetězce, při němž se automaticky zkouší doplňovat a odstraňovat diakritika, pokud se objekt nenalezne přesně podle zadaného pojmenování, v případě samotného příkazu se diakritika nikdy nedoplňuje ani neodstraňuje, takže rozjímej a rozjimej by teoreticky mohly být různé příkazy. Je to proto, aby při zadávání s diakritikou nemohlo docházet k záměnám jasně odlišených příkazů (jako třeba žádej a zadej). V praxi proto programátor při definicích příkazů musí dbát na to, aby zadal též všechny přípustné formy s chybějící diakritikou (což může znamenat i forem více, jako čumím, čumim a cumim).
  4. Na tomto místě jen upozorníme, že zadávání efektů je nekonečná smyčka, ze které musí hráč cíleně vystoupit buď zadáním . jako ve výše uvedeném příkladu (pak se dosud zadané efekty uloží), nebo zadáním ~q (pak se celé zadávání efektů zruší).
  5. Příkaz vem má ve skutečnosti ještě několik dalších synonym, která však na tomto místě nejsou podstatná. Pilný student tohoto kurzu si je ve volných chvílích jistě dokáže zjistit (zatímco líný student si zaslouží, aby jím vyrobené překrytí příkazu bylo možno obejít nečekaným synonymem).