Teleportační NPC (ScriptDev2): Porovnání verzí

Z WoWResource Wiki
Přejít na: navigace, hledání
(Popis tabulky)
m (UNORDERED_MAP)
Řádek 76: Řádek 76:
 
   } substruct;
 
   } substruct;
 
                                 //id, detaily
 
                                 //id, detaily
   typedef HM_NAMESPACE::hash_map<uint32, substruct> subvector;
+
   typedef UNORDERED_MAP<uint32, substruct> subvector;
 
                                 // mid, id kolekce
 
                                 // mid, id kolekce
   typedef HM_NAMESPACE::hash_map<uint32, subvector> subentry;
+
   typedef UNORDERED_MAP<uint32, subvector> subentry;
 
                                 // entry, mid kolekce
 
                                 // entry, mid kolekce
   typedef HM_NAMESPACE::hash_map<uint32, subentry> portmap;
+
   typedef UNORDERED_MAP<uint32, subentry> portmap;
 
    
 
    
 
   portmap TeleportMap;
 
   portmap TeleportMap;

Verze z 26. 1. 2009, 13:37

Teleportační NPC slouží k portování hráčů na administrátorem zvolená místa, tento skript pracuje s nastavením v databázi a je ho možné použít pro několik různých teleportačních NPC.

Popis tabulky

  • entry - Entry NPC ke kterému záznam přísluší
  • icon - id ikony, která se zobrazí na začátku řádku ve výpisu voleb
  • text - popisek položky
  • mid (sender) - slouží k identifikaci menu, po zavolání GossipHello se standardně otevře menu s MID = 1. Ostatní MID v rozsahu 2 - 998 lze otevřít přes jinou položku.
  • id (action) - slouží jako identifikátor čísla portu, pokud je id >= 1000 tak při kliknutí na tuto položku se provede portnutí na dané souřadnice, pokud je nižší otevře se další menu, které má MID hodnotu aktuálního id. Je nutné udržovat entry - mid - id unikátní!
  • map,x,y,z,o - cílové souřadnice
  • orderbyme - podle této položky se řadí výpis položek (nižší číslo je výše)
  • reqmoney - počet peněz (v bronzácích) potřebných k portnutí (tuto volbu nelze nastavit u otevření submenu (id < 999))
  • reqlevel - potřebný level pro portnutí (tuto volbu nelze nastavit u otevření submenu (id < 999))
  • reqguild - id guildy pro který je daný port určen, pokud není pro guildy ponechat hodnotu -1. Lze tímto skrýt celé submenu.
  • reqteam - položka je dostupná jen pro určitou frakci, -1 - pro všechny, 0 - aliance, 1 - horda

Akce s ID 999 je rezervovaná pro reload tabulky (volba se zobrazuje gamemasterům v gm režimu)

Příklad se submenu

e,  text       mid  id   pos                      orderbyme
    
// hlavní menu (mid/1)
10, Port A,    1, 1000,  0, 0, 0, 500, 0,         0
10, Submenu A, 1,    2,  0, 0, 0, 0, 0,           1

// menu mid/2
10, SA Port B, 2, 1001,  1, 500, 500, 1500, 0,    0
10, SA Port A, 2, 1000,  1, 0, 0, 1500, 0,        1
10, Return..., 2,    1,  0, 0, 0, 0, 0,         999

Po promluvení s npc se zobrazí položky Port A a Submenu A. Položka Submenu A způsobí vyvolání dalšího menu, kde mid = 2


SQL tabulka

Tabulku je nutné vytvořit v databázi ScriptDev2!

CREATE TABLE `teleport` (                                                                            
             `entry` int(10) unsigned default NULL,                                                               
             `icon` int(10) unsigned default NULL,                                                                
             `text` tinytext collate utf8_bin,                                                                    
             `mid` int(10) unsigned default '1',                                                                  
             `id` int(10) unsigned default '1000',                                                                
             `map` int(10) unsigned default NULL,                                                                 
             `x` float default NULL,                                                                              
             `y` float default NULL,                                                                              
             `z` float default NULL,                                                                              
             `o` float default NULL,                                                                              
             `orderbyme` int(10) unsigned default NULL,
             `reqmoney` int(10) unsigned default NULL,
             `reqlevel` int(10) unsigned default NULL,
             `reqguild` int(10) default '-1',
             `reqteam` int(10) default '-1',
             PRIMARY KEY (`entry`,`mid`,`id`)                                                                               
           ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC  

Zdrojový kód skriptu

 #include "precompiled.h"            // pch
 #include "Database/DatabaseEnv.h" // db
 extern DatabaseType SD2Database;  // db
 
 // action < DBTELEPORT_SENDER_SUBMENU - otevri submenu s MID = action
 #define DBTELEPORT_SENDER_SUBMENU 999
 // pri GossipHello je zobrazen vypis s mid = DBTELEPORT_SENDER_MAIN
 #define DBTELEPORT_SENDER_MAIN 1
 
 typedef struct _substruct
 {
     uint32 id;
     uint8 icon;
     std::string text;
     uint32 map;
     float x,y,z,o;
     uint32 ordererbyme;
 
     uint32 reqmoney, reqlevel;
     int32 reqguild, reqteam;
 } substruct;
                               //id, detaily
 typedef UNORDERED_MAP<uint32, substruct> subvector;
                               // mid, id kolekce
 typedef UNORDERED_MAP<uint32, subvector> subentry;
                               // entry, mid kolekce
 typedef UNORDERED_MAP<uint32, subentry> portmap;
 
 portmap TeleportMap;
 
 typedef std::vector<substruct*> sortvector;
 
 // stuktura pro sorting
 struct sorter
 {
     bool operator() (substruct* a, substruct* b)
     {
         return a->ordererbyme < b->ordererbyme;
     }
 };
 
 // vypsani seznamu dle entry, mid
 void doGossipTeleport(uint32 entry, uint32 mid, Player* player)
 {
     portmap::iterator ita = TeleportMap.find(entry);
     if (ita == TeleportMap.end())
         return;
 
     subentry::iterator itb = ita->second.find(mid);
     if (itb == ita->second.end())
         return;
 
     sortvector sorted;
     for(subvector::iterator itc = itb->second.begin(); itc != itb->second.end(); itc++)
     {
         sorted.push_back(&(itc->second));
     }
 
     std::sort(sorted.begin(), sorted.end(), sorter());
 
     for(sortvector::iterator itd = sorted.begin(); itd != sorted.end(); itd++)
     {
         if ((*itd)->reqguild != -1 && (*itd)->reqguild != player->GetGuildId())
             continue; // guildovni porty jsou neviditelne ostatnim hracum
         
         if ((*itd)->reqteam != -1 && (
                 ((*itd)->reqteam == 0 && player->GetTeam() != ALLIANCE) ||
                 ((*itd)->reqteam == 1 && player->GetTeam() != HORDE)
             ))
             continue;

         // icon, text, mid, id
         player->ADD_GOSSIP_ITEM(
             (*itd)->icon,
             (*itd)->text.c_str(),
             mid,
             (*itd)->id
         );
     }

     if (player->isGameMaster())
     {
         player->ADD_GOSSIP_ITEM(
             0,
             "[Reload Table]",
             1,
             DBTELEPORT_SENDER_SUBMENU
         );
     }
 }
 
 bool GossipHello_npc_dbteleport(Player *player, Creature *_Creature)
 {   
     // prazdna hashmapa v pameti, pokus se nacist data z db
     if (TeleportMap.empty())
     {
         QueryResult* result = SD2Database.Query("SELECT entry, mid, id, icon, text, map, x, y, z, o, orderbyme, reqmoney, reqlevel, reqguild, reqteam FROM teleport");
         if (!result)
         {
             _Creature->Yell("Huh! Data chybi...", 0, player->GetGUID());
             return false;
         }
         
         do {
             Field* f = result->Fetch();
 
             substruct s;
             s.id = f[2].GetUInt32();
             s.icon = f[3].GetUInt8();
             s.text = f[4].GetCppString();
             s.map = f[5].GetUInt32();
             s.x = f[6].GetFloat();
             s.y = f[7].GetFloat();
             s.z = f[8].GetFloat();
             s.o = f[9].GetFloat();
             s.ordererbyme = f[10].GetUInt32();
 
             s.reqmoney = f[11].GetUInt32();
             s.reqlevel = f[12].GetUInt32();
             s.reqguild = f[13].GetInt32();
             s.reqteam = f[14].GetInt32();
 
             TeleportMap[ f[0].GetUInt32() ][ f[1].GetUInt32() ][ f[2].GetUInt32() ] = s;
         } while(result->NextRow());
 
         delete result;
     }
 
     // generuj hlavni menu
     uint32 e = _Creature->GetCreatureInfo()->Entry;
     doGossipTeleport(e, DBTELEPORT_SENDER_MAIN, player);
 
     player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID());
     return true;
 }
 
 
 bool GossipSelect_npc_dbteleport(Player *player, Creature *_Creature, uint32 sender, uint32 action )
 {
     uint32 e = _Creature->GetCreatureInfo()->Entry;
     // pokud action je mensi nez DBTELEPORT_SENDER_SUBMENU vypis submenu
     if (action < DBTELEPORT_SENDER_SUBMENU)
     {
         doGossipTeleport(e, action, player);
 
         player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID());
         return true;
     }
     else
     {
         if (action == DBTELEPORT_SENDER_SUBMENU && player->isGameMaster())
         {
             TeleportMap.clear();
             player->CLOSE_GOSSIP_MENU();
             return true;
         }

         // test combat rezimu
         if (player->isInCombat())
         {
             _Creature->Yell("Nesmis bojovat!", 0, player->GetGUID());
             player->CLOSE_GOSSIP_MENU();
             return true;
         }
 
         portmap::iterator ita = TeleportMap.find(e);
         if (ita == TeleportMap.end())
             return true;
 
         subentry::iterator itb = ita->second.find(sender);
         if (itb == ita->second.end())
             return true;
 
         subvector::iterator itc = itb->second.find(action);
         if (itc == itb->second.end())
             return true;

         // test teamu
         if (itc->second.reqteam != -1)
         {
             if (
                 (itc->second.reqteam == 0 && player->GetTeam() != ALLIANCE) ||
                 (itc->second.reqteam == 1 && player->GetTeam() != HORDE)
                 )
             {
                 player->CLOSE_GOSSIP_MENU();
                 return true;
             }
         }

         // test guildy
         if (itc->second.reqguild != -1)
         {
             if (player->GetGuildId() != itc->second.reqguild)
             {
                 player->CLOSE_GOSSIP_MENU();
                 return true;
             }
         }  

         // test levelu
         if (itc->second.reqlevel)
         {
             if (player->getLevel() < itc->second.reqlevel)
             {
                 std::stringstream st;
                 st << "Nemas potrebny level (";
                 st << itc->second.reqlevel << ")";
                 _Creature->Whisper(st.str().c_str(), player->GetGUID());
                 player->CLOSE_GOSSIP_MENU();
                 return true;
             }
         }
  
         // test penez
         if (itc->second.reqmoney)
         {
             if (player->GetMoney() < itc->second.reqmoney)
             {
                 uint32 g = itc->second.reqmoney/10000,
                        s = itc->second.reqmoney/100%100,
                        b = itc->second.reqmoney%100;
                 std::stringstream st;
                 st << "Nemas dost penez, je potreba ";
                 st << g << "g ";
                 st << s << "s ";
                 st << b << "b";
                 _Creature->Whisper(st.str().c_str(), player->GetGUID());
                 player->CLOSE_GOSSIP_MENU();
                 return true;
             }
             player->ModifyMoney(-(int32)(itc->second.reqmoney));
         }
 
         player->CLOSE_GOSSIP_MENU();
         // teleportni
         player->TeleportTo(
             itc->second.map,
             itc->second.x,
             itc->second.y,
             itc->second.z,
             itc->second.o
             );
     }
     return true;
 }
 
 void AddSC_npc_dbteleport()
 {
     Script *newscript;
 
     newscript = new Script;
     newscript->Name = "npc_dbteleport";
     newscript->pGossipHello = &GossipHello_npc_dbteleport;
     newscript->pGossipSelect = &GossipSelect_npc_dbteleport;
     m_scripts[nrscripts++] = newscript;
 }