Třetí kapitola scriptování v NWN
3.1 Seznámení s funkcemi a cykly
Aby jste mohli používat funkce, musíte udělat následující :
- Poskytněte definici funkce
- Poskytněte prototyp funkce
- Vyvolejte funkci
První dva body jsou již hotové a pokud nepotřebujete vytvářet vlastní
funkce, nemusíte se o ně starat. Spousta funkcí je již v toolsetu
hotová a v každém datadisku je několik nových. Pro naši potřebu
bude dostačující, když se dozvíme něco o funkcích již předdefinovaných.
Na několika příkladech si ukážeme základní práci s funkcemi.
3.2 Příklad – Testovací modul
V tomto příkladu si vytvoříme modul, ve kterém snadno dosáhneme
level 20.
V toolsetu umístíme jedno přátelské NPC (např. „Boy“), jakýkoliv
placeable objekt (např. Barrel) a trigger. Na všechny tyto tři věci
umístíme variaci našeho scriptu. V prvním případě se script spustí
při rozhovoru, ve druhém při otevření Barrelu a ve třetím při vstupu
do triggeru.
a) V properities našeho NPC dáme Edit konverzace, přidáme jakoukoliv
větu a v záložce Action Taken spustíme Script Wizarda. Zaškrtneme
„Give Reward“ a na dalším okně určíme sumu XP. Pojmenujeme script
jménem „xp_01“. Nyní když na záložce Action Taken (script by se
nám měl ukazovat v okně) klikneme na Edit, spustí se script wizard
a ukáže nám naše veledílo.
void main()
{
// Give the speaker some XP
GiveXPToCreature(GetPCSpeaker(), 10000); }
Jak už jsme si řekli dříve, každý script musí obsahovat funkci
main. Ta nám posléze (ve hře) zajistí spuštění funkce GiveXPToCreature.
Parametry (pokud zadáte jméno této funkce ve Filtru, zobrazí se
vám v okně zpráv) této funkce jsou
void GiveXPToCreature(object oCreature, int nXpAmount).
void – znamená, že tato funkce nemá návratovou hodnotu
object oCreature – je objekt, který bude obohacen o sumu XP
int nXpAmount – je ona suma XP
Pokud si necháte zobrazit také funkci GetPCSpeaker(), zjistíte,
že tato funkce nám navrátí hráče, který je zapojen v konverzaci.
b) Pro druhý případ, kde chceme tento script umístit (placeable),
nám stačí tento script jednoduše upravit. Nejprve ale pro jistotu
nastavte svoje placeable jako použitelné (zaškrtněte „Useable“)
a zároveň mu dejte i inventář (Has inventory). V properities jakéhokoliv
placeable, na záložce „Scripts“, se můžeme podívat jak náš script
spustíme. Vybereme OnOpen kliknutím na „Edit“ a otevře se nám script
editor. Opíšeme předchozí script s jednou malou úpravou.
void main()
{
GiveXPToCreature(GetLastOpenedBy(), 10000);
}
Jelikož jsme zvolili OnOpen event, funkce na zjištění jestli hráč
s placeable mluví je nám na nic, místo toho si zjistíme kdo naposledy
naše placeable otevřel.
c) Takto můžeme postupovat i u triggeru. Opět trochu script pozměníme
a podíváme se, kdo vstoupil do triggeru.
GiveXPToCreature(GetEnteringObject(), 10000);
3.3 Cykly for, while a do while
Často potřebujeme, aby script prováděl opakovatelné úlohy, jako
například sečtení prvků pole. Nebo aby opakoval jeden příkaz po
dobu platnosti podmínky. Ukážeme si nejprve jednoduchý příklad a
na něm si probereme jak to funguje.
int i;
for(i=0, i<5; i++)
{tělo cyklu}
i=0 - cyklus začíná nastavením proměnné i na nulu. To je inicializační
část cyklu.
i<5 – testovací cyklus testuje, zda je i menší než 5. Je-li tomu
tak, program provede následující příkaz, který se nazývá tělo cyklu.
i++ - potom cyklus použije změnovou část cyklu. V našem případě
navýší hodnotu proměnné i o jednu (o to se postará výraz ++, pro
lepší pochopení by se tento výraz mohl napsat jako i=i+1).
Po této inkrementaci proměnné proběhne cyklus znovu a to přesně
pětkrát - dokud bude platit podmínka i<5. Pokud cyklus změní
i na 5, testovací podmínka selže a provede se příkaz za cyklem.
Ani jeden ze tří výrazů není povinný, povinné jsou pouze dva středníky,
ale cyklus for ( ; ; ) nikdy neskončí.
Cyklus while je cyklus for zbavený inicializační a změnové části.
Má pouze testovací podmínku a tělo.
while(testovací podmínka)
tělo
To znamená, že musíme testovat již deklarovanou proměnnou a musíme
také tuto proměnnou změnit v těle cyklu (aby ovlivnil testovací
podmínku), pokud chceme aby se cyklus konečně ukončil. Jinak se
nám script zacykluje. Jestliže se testovací podmínka na začátku
vyhodnotí jako FALSE, cyklus se nikdy neprovede, stejně jako u cyklu
for. Příkazy for a while jsou téměř ekvivalentní a je na vás, který
použijete. Existuje však jemný rozdíl, pokud tělo obsahuje příkaz
continue, ale o tom snad až někdy jindy (stačí vám vědět, že continue
přeskočí zbytek těla cyklu a začíná novým průběhem cyklu).
Třetím cyklem je cyklus do while, který se od ostatních liší tím,
že se nejprve provede tělo cyklu a až potom je vyhodnotí testovací
výraz, aby scritp viděl, zda má cyklus znovu opakovat. Takovýto
cyklus se na rozdíl od předchozích provede vždy alespoň jednou.
do
tělo
while (testovací výraz)
Závěr – identifikujte podmínku, která ukončuje cyklus
- inicializujte podmínku před testem
- změňte podmínku při každém průběhu cyklu předtím, než ji znovu
otestujete
3.4 Operátor if a if else
Když si Script editor musí vybrat, zda udělá určitou činnost, můžeme
použít operátor if. Vyskytuje se ve dvou podobách : if a if else.
Příkaz if směruje script k provedení příkazu nebo bloku příkazů
(blok příkazů je několik příkazů ohraničených složenými závorkami
{}), je-li testovací podmínka TRUE a tyto příkazy přeskočí, je-li
FALSE. Pokud nepoužijeme složené závorky, provede se pouze první
příkaz po podmínce if. U příkazu if nekončí řádek středníkem a je
to jeden z mála případů kdy tomu tak je.
if (testovací podmínka)
příkaz
Zkusíme tuto podmínku použít v našem případě a budeme testovat,
zda objekt, který má dostat vstoupil do triggeru je hráč. Nechceme
přece rozdávat expy každému NPC, které do triggeru vstoupí.
void main()
{
if (GetIsPC(GetEnteringObject())==TRUE) /* fce GetIsPC vraci TRUE
pokud objekt vstupujici do triggeru je hrac */
GiveXPToCreature(GetEnteringObject (), 10000);
}
Možná jste si všimnuli použití dvou rovnítek. V tomto případě to
je zcela v pořádku, protože pokud použiji dvě, tak porovnávám, pokud
jedno, tak přiřazuji (například i=0 přiřadí proměnné i hodnotu nula).
Takto napsaná funkce ale může mít své mouchy a proto ji uděláme
o něco lépe. Nadeklarujeme proměnnou, kterou potom budeme testovat
a použijeme ji ve fci GiveXPToCreature.
void main()
{
object oPC = GetEnteringObject(); // definice objektu
if (GetIsPC(oPC))
/* podmínka, není nutne psat ==TRUE, pokud je navratovou hodnotou funkce TRUE nebo FALSE.
Příklad ze života, taky neřikáte 'Pokud je pravda že prší tak..' ale řeknete 'Pokud prši tak...'
Pokud si nechate v okne nformaci vypsat informace o funkci GetIsPC, zjistite že u této funkce tomu tak je */
GiveXPToCreature(oPC, 10000); // odmena pripadne objektu oPC pokud je splnena podmínka.
}
Uvnitř podmínky if by se neměla deklarovat žádná proměnná. Proto
jsme objekt oPC deklarovali předem. Obecně tedy příkaz if způsobí,
že se script rozhodne, zda provede určitý příkaz nebo blok. Příkaz
if else způsobí, že se program rozhodne, který ze dvou příkazů provede.
if (testovací podmínka)
příkaz1
else
příkaz2
Je-li testovací podmínka TRUE nebo nenulová, script provede příkaz1
a přeskočí příkaz2. Jestliže je ovšem testovací podmínka FALSE nebo
nula, script příkaz1 přeskočí a místo něho provede příkaz2. Příkaz
if else se dá použít několikrát za sebou.
if (testovací podmínka)
příkaz1
else
if (testovací podmínka)
příkaz2
else
příkaz3
Operátor ?: je schopný nahradit podmínku if else.
výraz1 ? výraz2 : výraz3
Je-li výraz1 pravdivý, potom je hodnota celého podmíněného výrazu
hodnotou výraz2. Jinak je hodnota celého výrazu hodnotou výraz3.
int i;
i = 5 > 3 ? 65 : 7;
Je-li 5 větší než 3, vyhodnotí se i jako 65. Kdyby náhodou 5 bylo
menší než 3, bude výraz 7. Ale když už se vám v této podmínce podaří,
aby i bylo 7, děláte asi něco špatně.
3.5 Příkaz switch
Pokud testujete více dostupných alternativ, můžete rozšířit sekvenci
if else, ale příkaz switch pracuje v tomto případě daleko lépe.
switch (celočíselný výraz)
{
case návěstí1 : příkaz
case návěstí1 : příkaz
…
default : příkaz
}
Příkaz switch funguje jako směrové zařízení, které scriptu říká,
jaký řádek programováho kódu se má provést. Při průběhu příkazu
switch přeskočí script na řádek programu, který má návěstí odpovídající
hodnotě testovaného celočíselného výrazu (tzn pouze int). Například,
má-li celočíselný výraz hodnotu 4, script jde na řádek, který má
návěstí case 4:. Jestliže celočíselný výraz neodpovídá žádnému návěstí,
přeskočí script na řádek označený default (default není povinný,
příkaz ho nemusí vůbec obsahovat, jestliže ho vynecháte, script
přeskočí na další příkaz, který následuje za switch).
Pokud vše proběhne podle plánu a provede se příkaz, script by nám
proveld jednu nemilou věc (která se ovšem může někdy hodit). Pokračoval
by hned na dalším řádku, nikoliv na řádku, který následuje za switch.
Příkaz break umožňuje scriptu přeskočit část programového kódu.
Tento příkaz můžete použít v příkazu switch, nebo v libovolném cyklu.
int i;
int y
i = d4(); // prikaz na nahodna cisla
switch (i)
{
case 1 : y=4; break;
case 2 : y=3; break;
case 3 : y=2; break;
case 4 : y=1; break;
}
Hodnota návěstí case musí být konstanta. Pokud vaše alternativy
zahrnují testy ve float, string apod, použijte příkaz if else. Nebo
převeďte převod pomocí fcí FloatToInt, StringToInt.
Mole
|