Zdravím všechny
Rozhodl jsem se do zdejší sbírky návodů přidat jeden další. Je to návod k práci s gossipy v TC2 na úrovni emulátoru. Ano, v databázi se taky dají vytvářet, ale s velmi omezenými možnostmi. Vzhledem k tomu, že v jádře si můžete lecos dopsat sami, tak jste omezeni pouze svými schopnostmi a představivostí. To není tak hrozné, pokud umíte alespoň základy C++...
Pro začátek bych uvedl reference na pár návodů, abych úplné základy nemusel vysvětlovat.
Kompilace: http://www.trinitycore.info/How-to:Win http://www.trinitycore.info/How-to:Linux
Přidání scriptu do zdrojových kódů: http://www.trinitycore.info/How-to:CustomScript
Jako příklad jsem zvolil teleportera – přijde mi jednoduchý a názorný
Takže přejděme k samotnému scriptu:
Začneme tím, že připojíme hlavičku ->
#include "ScriptPCH.h"
Tímto jsme připojili soubory, ve kterých jsou deklarované třídy a jejich metody, které zde budeme používat.
Nyní si vytvoříme vlastní třídu, která bude dědit CreatureScript:
class teleporter : public CreatureScript
{
public:
teleporter() : CreatureScript("teleporter_npc") {}
Toto je začátek naší třídy. Vytvořili jsme si zatím jen konstruktor. Řetězec “teleporter_npc“ , který předáváme konstruktoru CreatureScript, je jméno scriptu, které přiřadíme npc v databázi, aby emulátor věděl, že má náš script použít.
Dále si vytvoříme metody, které se budou volat při událostech(eventech), při kterých budeme chtít, aby se něco dělo. Tedy když hráč začne mluvit s gossipem, a nebo když si vybere jednu z možností v gossip menu.
bool OnGossipHello(Player * player, Creature * npc);
bool OnGossipSelect(Player * player , Creature* npc, uint32 sender, uint32 action);
};
Metodě OnGossipHello se předává hráč, který kliknul na gossipa a gossip.
Metodě OnGossipSelec se předává hráč, který klinul na gossipa, gossip, a dvě 32bitové celočíselné proměnné, podle kterých určíme, na kterou položku menu hráč klikl.
Tím máme navrženou třídu. Ovšem takhle zatím gossip nic nedělá. Potřebujeme tedy napsat, co má dělat. Začneme metodou OnGossipHello -> co se má udělat, když hráč klikne na gossipa(pozdraví ho)
if(player->isInCombat()) //zjistíme, zda je hráč v combatu
{
npc->MonsterWhisper("Jsi v combatu!!!", player->GetGUID());
return false;
}
switch(player->getTeam()) //zjistíme si frakci hráče
{
case HORDE:
player->ADD_GOSSIP_ITEM(2, "Teleport to Orgrimmar", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); //přidáme položku do menu, podrobněji vysvětlím níže
player->ADD_GOSSIP_ITEM(2, "Teleport to Thunder Bluff", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
player->ADD_GOSSIP_ITEM(2, "Teleport to Silvermoon City", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
player->ADD_GOSSIP_ITEM(2, "Teleport to Undercity", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
break;
case ALLIANCE:
player->ADD_GOSSIP_ITEM(2, "Stormwind City", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5);
player->ADD_GOSSIP_ITEM(2, "Ironforge", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6);
player->ADD_GOSSIP_ITEM(2, "The Exodar", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7);
player->ADD_GOSSIP_ITEM(2, "Darnassus", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8);
break;
default:
break;
}
if(player->getLevel() >= 58) //podle levelu hráče se rozhodneme, zda mu zobrazíme další města
player->ADD_GOSSIP_ITEM(2, "Shattrath City", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9);
if(player->getLevel() >= 68)
player->ADD_GOSSIP_ITEM(2, "Dalaran", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10);
player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, npc->GetGUID()); //odešleme menu
return true;
}
Nyní si podrobněji rozebereme makro player->ADD_GOSSIP_ITEM(a, b, c, d);
(je to vlastně metoda player->PlayerTalkClass->GetGossipMenu().AddMenuItem(-1, a, b, c, d, "", 0); )
a... id ikonky, která bude u možnosti v menu. (celá čísla v rozmezí 1-10 včetně)
b... text, který bude popisovat možnost v menu
c... sender – většinou se používá/používám hodnota GOSSIP_SENDER_MAIN, ovšem tato proměnná by se dala využít třeba i pro rozeznávání úrovní menu, ze kterých byla položka odeslána.... netrapme se s tím.
d... action – celočíselný klíč, podle kterého poznáte, na kterou položku hráč klikl
Budeme pokračovat metodou OnGosipSelect(Player *, Creature *, uint32, uint32)
Jak jsem již říkal, v jednodušších případech není třeba používat proměnnou sender, stačí nám action, takže pro našeho teleportera bude vypadat takto:
bool teleporter::OnGossipSelect(Player * player , Creature* npc, uint32 sender, uint32 action)
{
player->PlayerTalkClass->ClearMenus(); //pročistíme menu – smažeme položky
//Zde bychom ještě mohli/měli prověřovat sender pomocí if(sender == GOSSIP_SENDER_MAIN) , ovšem zde to není nutné.
switch(action) //podle hodnoty action zjistíme, na kterou položku hráč klikl(viz. výše)
{
case GOSSIP_ACTION_INFO_DEF + 1: //Orgrimmar
player->CLOSE_GOSSIP_MENU();
//metoda pro teleport hráče – vysvětlím níže
player->TeleportTo(1, 1483.25f, -4416.525f, 25.003f, 0);
break;
case GOSSIP_ACTION_INFO_DEF + 2: //Thunder Bluff
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(1, -1197.3f, 30 , 177, 1.589f);
break;
case GOSSIP_ACTION_INFO_DEF + 3: //Silvermoon City
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(530, 9530.775f, -7300.459f, 15.24f, 3.139f);
break;
case GOSSIP_ACTION_INFO_DEF + 4: //Undercity
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(0, 1560.7f, 240.45f, -43.1045f, 0.01f);
break;
case GOSSIP_ACTION_INFO_DEF + 5: //Stormwind City
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(0, -8800.41f, 622.355f, 96.8f, 2.255f);
break;
case GOSSIP_ACTION_INFO_DEF + 6: //Ironforge
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(0, -4918.880f, -940.406f, 501.57f, 5.42f);
break;
case GOSSIP_ACTION_INFO_DEF + 7: //The Exodar
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(530 , -4016.944f, -11675.455f, -134.932f , 0);
break;
case GOSSIP_ACTION_INFO_DEF + 8: //Darnassus
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(1, 9951.804f, 2280.401f, 1341.394f, 1.425f);
break;
case GOSSIP_ACTION_INFO_DEF + 9: //Shattrath City
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(530, -1837.538f, 5378.270f, -12.427f, 1.941f);
break;
case GOSSIP_ACTION_INFO_DEF + 10: //Dalaran
player->CLOSE_GOSSIP_MENU();
player->TeleportTo(571, 5848.875f, 602.287f, 651.142f, 2.448f);
break;
}
return true;
}
Myslím, že většina kódu je jasná, ovšem vrátím se k metodě TeleportTo(map, x, y, z, o).
Tato metoda teleportuje hráči na vámi zvolené místo. Map je mapa, na kterou chcete teleportovat, x y z o jsou souřadnice.
Možná jste si všimli, že za každým desetinným číslem mám f. Je to proto, že Visual Studio, které používám, volí implicitně datový typ double pro všechna desetinná čísla, která mu napíšu konstantně do kódu. Jenže fukce TeleportTo() má bere souřadnice ve float, pto dávám symbolem f najevo, že toto číslo má být ve float (ono by to vlastně nevadilo, jenže při kompilaci si na to visualko postěžuje... takže aby to tam nepřekáželo...)
Tím máme hotovou tu nejtěžší část scriptu, tím ale práce nekončí. Ještě musíme na konec souboru připojit jednu funkci, kterou budeme dále volat ve Scriptloader.cpp (tam se zapisují všechny scripty)
Vypadá takto:
void AddSCTeleporter()
{
new teleporter();
}
Nyní funkci AddScTeleporter() zapíšeme do ScriptLoader.cpp
Je potřeba ji zapsat na dvě různá místa dvěma různými způsoby: nejdříve ji deklarovat, poté zavolat.
Deklarace:
#include "ScriptLoader.h"
//custom
void AddSCTeleporter();
//examples
void AddSC_example_creature();
void AddSC_example_escort();
void AddSC_example_gossip_codebox();
void AddSC_example_misc();
void AddSC_example_commandscript();
(jen si pomocí ctrl+f najděte jednu z funkcí, která je okolo naší funkce – schválně jsem napsal i další...)
Zavolání funkce:
void AddCustomScripts()
{
#ifdef SCRIPTS
/* This is where custom scripts should be added. */
AddSCTeleporter();
#endif
}
Stejě jako u deklarace zkopírováno i pár dalších funkcí okolo pro zorientování.
Úplně posledním krokem bude přiřadit script nějakému npc – změníme hodnotu sloupce‘ ScriptName‘ na “teleporter_npc“ a zajistíme, aby ‘npcflag‘ bylo nastaveno na gossip – tedy 1
Celý script zde:
Tím je to hotové. Doufám, že návod byl srozumitelný, a že se bude někomu hodit.
EDIT: děkuji wolfovi za připomínky, snad už je to v pořádku (i to entry/GUID )...