diff --git a/sql/mangos.sql b/sql/mangos.sql index 83c1d7d13..d6b9f24ba 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -24,7 +24,7 @@ CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, `cache_id` int(10) default '0', - `required_11117_01_mangos_world_template` bit(1) default NULL + `required_11169_02_mangos_command` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -641,6 +641,7 @@ INSERT INTO `command` VALUES ('lookup player account',2,'Syntax: .lookup player account $accountpart [#limit] \r\n\r\n Searchs players, which account username including $accountpart with optional parametr #limit of results. If #limit not provided expected 100.'), ('lookup player email',2,'Syntax: .lookup player email $emailpart [#limit] \r\n\r\n Searchs players, which account email including $emailpart with optional parametr #limit of results. If #limit not provided expected 100.'), ('lookup player ip',2,'Syntax: .lookup player ip $ippart [#limit] \r\n\r\n Searchs players, which account last used ip inluding $ippart (textual) with optional parametr #limit of results. If #limit not provided expected 100.'), +('lookup pool',2,'Syntax: .lookup pool $pooldescpart\r\n\r\nList of pools (anywhere) with substring in description.'), ('lookup quest',3,'Syntax: .lookup quest $namepart\r\n\r\nLooks up a quest by $namepart, and returns all matches with their quest ID\'s.'), ('lookup skill',3,'Syntax: .lookup skill $$namepart\r\n\r\nLooks up a skill by $namepart, and returns all matches with their skill ID\'s.'), ('lookup spell',3,'Syntax: .lookup spell $namepart\r\n\r\nLooks up a spell by $namepart, and returns all matches with their spell ID\'s.'), @@ -707,6 +708,9 @@ INSERT INTO `command` VALUES ('pdump write',3,'Syntax: .pdump write $filename $playerNameOrGUID\r\nWrite character dump with name/guid $playerNameOrGUID to file $filename.'), ('pdump load',3,'Syntax: .pdump load $filename $account [$newname] [$newguid]\r\nLoad character dump from dump file into character list of $account with saved or $newname, with saved (or first free) or $newguid guid.'), ('pinfo',2,'Syntax: .pinfo [$player_name]\r\n\r\nOutput account information for selected player or player find by $player_name.'), +('pool',2,'Syntax: .pool #pool_id\r\n\r\nPool information and full list creatures/gameobjects included in pool.'), +('pool list',2,'Syntax: .pool list\r\n\r\nList of pools with spawn in current map (only work in instances. Non-instanceable maps share pool system state os useless attempt get all pols at all continents.'), +('pool spawns',2,'Syntax: .pool spawns #pool_id\r\n\r\nList current creatures/objects listed in pools (or in specific #pool_id) and spawned (added to grid data, not meaning show in world.'), ('quest add',3,'Syntax: .quest add #quest_id\r\n\r\nAdd to character quest log quest #quest_id. Quest started from item can\'t be added by this command but correct .additem call provided in command output.'), ('quest complete',3,'Syntax: .quest complete #questid\r\nMark all quest objectives as completed for target character active quest. After this target character can go and get quest reward.'), ('quest remove',3,'Syntax: .quest remove #quest_id\r\n\r\nSet quest #quest_id state to not completed and not active (and remove from active quest list) for selected player.'), @@ -3384,6 +3388,27 @@ INSERT INTO `mangos_string` VALUES (373,'Response:\n%s ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (374,'Tickets count: %i\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (375,'Player %s not have tickets.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(376,'%u - |cffffffff|Hpool:%u|h[%s]|h|r AutoSpawn: %u MaxLimit: %u Creatures: %u GameObjecs: %u Pools %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(377,"No pools found for map '%s' (Id:%u)",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(378,"You can't use this command at non-instanceable map '%s' (Id:%u). Use .lookup pool command instead.",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(379,"You can't use this command without args at non-instanceable map '%s' (Id:%u).",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(380,'%d%s - |cffffffff|Hcreature:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r Chance:%f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(381,'%d%s - [%s] X:%f Y:%f Z:%f MapId:%d Chance:%f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(382,'%d%s - |cffffffff|Hcreature:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(383,'%d%s - [%s] X:%f Y:%f Z:%f MapId:%d %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(384,'%d%s - |cffffffff|Hgameobject:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r Chance:%f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(385,'%d%s - [%s] X:%f Y:%f Z:%f MapId:%d Chance:%f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(386,'%d%s - |cffffffff|Hgameobject:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(387,'%d%s - [%s] X:%f Y:%f Z:%f MapId:%d %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(388,'Creatures with explicitly chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(389,'Creatures with equal chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(390,'Gameobjects with explicitly chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(391,'Gameobjects with equal chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(392,'Pool %u - Mother pool: %u |cffffffff|Hpool:%u|h[%s]|h|r AutoSpawn: %u MaxLimit: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(393,'Pool %u - Mother pool: %u [%s] AutoSpawn: %u MaxLimit: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(394,'Pool %u - Mother pool: none AutoSpawn: %u MaxLimit: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(395,'No pools found',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(396,'%u - [%s] AutoSpawn: %u MaxLimit: %u Creatures: %u GameObjecs: %u Pools %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (400,'|cffff0000[System Message]:|rScripts reloaded',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (401,'You change security level of account %s to %i.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (402,'%s changed your security level to %i.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), diff --git a/sql/updates/11169_01_mangos_mangos_string.sql b/sql/updates/11169_01_mangos_mangos_string.sql new file mode 100644 index 000000000..fba16dc74 --- /dev/null +++ b/sql/updates/11169_01_mangos_mangos_string.sql @@ -0,0 +1,32 @@ +ALTER TABLE db_version CHANGE COLUMN required_11117_01_mangos_world_template required_11169_01_mangos_mangos_string bit; + +DELETE FROM mangos_string WHERE entry IN (376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,1500,15001,1502); + +INSERT INTO mangos_string VALUES +(376,'%u - |cffffffff|Hpool:%u|h[%s]|h|r AutoSpawn: %u MaxLimit: %u Creatures: %u GameObjecs: %u Pools %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(377,"No pools found for map '%s' (Id:%u)",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(378,"You can't use this command at non-instanceable map '%s' (Id:%u). Use .lookup pool command instead.",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(379,"You can't use this command without args at non-instanceable map '%s' (Id:%u).",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(380,'%d%s - |cffffffff|Hcreature:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r Chance:%f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(381,'%d%s - [%s] X:%f Y:%f Z:%f MapId:%d Chance:%f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(382,'%d%s - |cffffffff|Hcreature:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(383,'%d%s - [%s] X:%f Y:%f Z:%f MapId:%d %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(384,'%d%s - |cffffffff|Hgameobject:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r Chance:%f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(385,'%d%s - [%s] X:%f Y:%f Z:%f MapId:%d Chance:%f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(386,'%d%s - |cffffffff|Hgameobject:%d|h[%s X:%f Y:%f Z:%f MapId:%d]|h|r %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(387,'%d%s - [%s] X:%f Y:%f Z:%f MapId:%d %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(388,'Creatures with explicitly chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(389,'Creatures with equal chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(390,'Gameobjects with explicitly chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(391,'Gameobjects with equal chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(392,'Pool %u - Mother pool: %u |cffffffff|Hpool:%u|h[%s]|h|r AutoSpawn: %u MaxLimit: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(393,'Pool %u - Mother pool: %u [%s] AutoSpawn: %u MaxLimit: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(394,'Pool %u - Mother pool: none AutoSpawn: %u MaxLimit: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(395,'No pools found',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(396,'%u - [%s] AutoSpawn: %u MaxLimit: %u Creatures: %u GameObjecs: %u Pools %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(397,'Pools with explicitly chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(398,'Pools with equal chance:',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(399,'%u - |cffffffff|Hpool:%u|h[%s]|h|r AutoSpawn: %u MaxLimit: %u Creatures: %u GameObjecs: %u Pools %u Chance: %f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(1500,'%u - [%s] AutoSpawn: %u MaxLimit: %u Creatures: %u GameObjecs: %u Pools %u Chance: %f %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(1501,'%u - |cffffffff|Hpool:%u|h[%s]|h|r AutoSpawn: %u MaxLimit: %u Creatures: %u GameObjecs: %u Pools %u %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(1502,'%u - [%s] AutoSpawn: %u MaxLimit: %u Creatures: %u GameObjecs: %u Pools %u %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); diff --git a/sql/updates/11169_02_mangos_command.sql b/sql/updates/11169_02_mangos_command.sql new file mode 100644 index 000000000..e9e483131 --- /dev/null +++ b/sql/updates/11169_02_mangos_command.sql @@ -0,0 +1,9 @@ +ALTER TABLE db_version CHANGE COLUMN required_11169_01_mangos_mangos_string required_11169_02_mangos_command bit; + +DELETE FROM command WHERE name IN ('lookup pool','pool list','pool spawns','pool'); + +INSERT INTO command (name, security, help) VALUES +('lookup pool',2,'Syntax: .lookup pool $pooldescpart\r\n\r\nList of pools (anywhere) with substring in description.'), +('pool list',2,'Syntax: .pool list\r\n\r\nList of pools with spawn in current map (only work in instances. Non-instanceable maps share pool system state os useless attempt get all pols at all continents.'), +('pool spawns',2,'Syntax: .pool spawns #pool_id\r\n\r\nList current creatures/objects listed in pools (or in specific #pool_id) and spawned (added to grid data, not meaning show in world.'), +('pool',2,'Syntax: .pool #pool_id\r\n\r\nPool information and full list creatures/gameobjects included in pool.'); diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 30e760143..145e5799c 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -53,6 +53,7 @@ // - client, item icon shift click // |color|Hitemset:itemset_id|h[name]|h|r // |color|Hplayer:name|h[name]|h|r - client, in some messages, at click copy only name instead link, so no way generate it in client string send to server +// |color|Hpool:pool_id|h[name]|h|r // |color|Hquest:quest_id:quest_level|h[name]|h|r - client, quest list name shift-click // |color|Hskill:skill_id|h[name]|h|r // |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click @@ -346,6 +347,7 @@ ChatCommand * ChatHandler::getCommandTable() { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupObjectCommand, "", NULL }, { "quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupQuestCommand, "", NULL }, { "player", SEC_GAMEMASTER, true, NULL, "", lookupPlayerCommandTable }, + { "pool", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPoolCommand, "", NULL }, { "skill", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSkillCommand, "", NULL }, { "spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSpellCommand, "", NULL }, { "taxinode", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupTaxiNodeCommand, "", NULL }, @@ -427,6 +429,14 @@ ChatCommand * ChatHandler::getCommandTable() { NULL, 0, false, NULL, "", NULL } }; + static ChatCommand poolCommandTable[] = + { + { "list", SEC_GAMEMASTER, false, &ChatHandler::HandlePoolListCommand, "", NULL }, + { "spawns", SEC_GAMEMASTER, false, &ChatHandler::HandlePoolSpawnsCommand, "", NULL }, + { "", SEC_GAMEMASTER, true, &ChatHandler::HandlePoolInfoCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand questCommandTable[] = { { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestAddCommand, "", NULL }, @@ -688,6 +698,7 @@ ChatCommand * ChatHandler::getCommandTable() { "lookup", SEC_MODERATOR, true, NULL, "", lookupCommandTable }, { "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable }, { "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable }, + { "pool", SEC_GAMEMASTER, true, NULL, "", poolCommandTable }, { "pdump", SEC_ADMINISTRATOR, true, NULL, "", pdumpCommandTable }, { "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable }, { "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable }, diff --git a/src/game/Chat.h b/src/game/Chat.h index 4ed9ff6f8..c86c8776a 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -287,6 +287,7 @@ class ChatHandler bool HandleLookupPlayerIpCommand(char* args); bool HandleLookupPlayerAccountCommand(char* args); bool HandleLookupPlayerEmailCommand(char* args); + bool HandleLookupPoolCommand(char* args); bool HandleLookupQuestCommand(char* args); bool HandleLookupSkillCommand(char* args); bool HandleLookupSpellCommand(char* args); @@ -352,6 +353,10 @@ class ChatHandler bool HandlePDumpLoadCommand(char* args); bool HandlePDumpWriteCommand(char* args); + bool HandlePoolListCommand(char* args); + bool HandlePoolSpawnsCommand(char* args); + bool HandlePoolInfoCommand(char* args); + bool HandleQuestAddCommand(char* args); bool HandleQuestRemoveCommand(char* args); bool HandleQuestCompleteCommand(char* args); @@ -626,6 +631,7 @@ class ChatHandler void ShowQuestListHelper(uint32 questId, int32 loc_idx, Player* target = NULL); bool ShowPlayerListHelper(QueryResult* result, uint32* limit = NULL, bool title = true, bool error = true); void ShowSpellListHelper(Player* target, SpellEntry const* spellInfo, LocaleConstant loc); + void ShowPoolListHelper(uint16 pool_id); void ShowTicket(GMTicket const* ticket); void ShowTriggerListHelper(AreaTriggerEntry const * atEntry); void ShowTriggerTargetListHelper(uint32 id, AreaTrigger const* at, bool subpart = false); diff --git a/src/game/Language.h b/src/game/Language.h index 6656561a9..4a0404d2d 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -366,7 +366,31 @@ enum MangosStrings LANG_COMMAND_TICKETRESPONSE = 373, LANG_COMMAND_TICKETCOUNT_CONSOLE = 374, LANG_COMMAND_TICKETNOTEXIST_NAME = 375, - // Room for more level 2 376-399 not used + LANG_POOL_ENTRY_LIST_CHAT = 376, + LANG_NO_POOL_FOR_MAP = 377, + LANG_POOL_LIST_NON_INSTANCE = 378, + LANG_POOL_SPAWNS_NON_INSTANCE = 379, + LANG_POOL_CHANCE_CREATURE_LIST_CHAT = 380, + LANG_POOL_CHANCE_CREATURE_LIST_CONSOLE = 381, + LANG_POOL_CREATURE_LIST_CHAT = 382, + LANG_POOL_CREATURE_LIST_CONSOLE = 383, + LANG_POOL_CHANCE_GO_LIST_CHAT = 384, + LANG_POOL_CHANCE_GO_LIST_CONSOLE = 385, + LANG_POOL_GO_LIST_CHAT = 386, + LANG_POOL_GO_LIST_CONSOLE = 387, + LANG_POOL_CHANCE_CREATURE_LIST_HEADER = 388, + LANG_POOL_CREATURE_LIST_HEADER = 389, + LANG_POOL_CHANCE_GO_LIST_HEADER = 390, + LANG_POOL_GO_LIST_HEADER = 391, + LANG_POOL_INFO_HEADER_CHAT = 392, + LANG_POOL_INFO_HEADER_CONSOLE = 393, + LANG_POOL_INFO_HEADER = 394, + LANG_NO_POOL = 395, + LANG_POOL_ENTRY_LIST_CONSOLE = 396, + LANG_POOL_CHANCE_POOL_LIST_HEADER = 397, + LANG_POOL_POOL_LIST_HEADER = 398, + LANG_POOL_CHANCE_POOL_LIST_CHAT = 399, + // End Level 2 list, continued at 1500 // level 3 chat LANG_SCRIPTS_RELOADED_ANNOUNCE = 400, @@ -902,7 +926,13 @@ enum MangosStrings // Room for old clients 2.x 1300-1399 not used // Room for old clients 1.x 1400-1499 not used - // FREE IDS 1500-9999 + // Level 2 (continue) + LANG_POOL_CHANCE_POOL_LIST_CONSOLE = 1500, + LANG_POOL_POOL_LIST_CHAT = 1501, + LANG_POOL_POOL_LIST_CONSOLE = 1502, + // Room for more Level 2 1503-1599 not used + + // FREE IDS 1600-9999 // Use for not-in-offcial-sources patches // 10000-10999 diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 173a53ea5..526fc4a3b 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -4668,6 +4668,288 @@ bool ChatHandler::LookupPlayerSearchCommand(QueryResult* result, uint32* limit) return true; } +void ChatHandler::ShowPoolListHelper(uint16 pool_id) +{ + PoolTemplateData const& pool_template = sPoolMgr.GetPoolTemplate(pool_id); + if (m_session) + PSendSysMessage(LANG_POOL_ENTRY_LIST_CHAT, + pool_id, pool_id, pool_template.description.c_str(), pool_template.AutoSpawn ? 1 : 0, pool_template.MaxLimit, + sPoolMgr.GetPoolCreatures(pool_id).size(), sPoolMgr.GetPoolGameObjects(pool_id).size(), sPoolMgr.GetPoolPools(pool_id).size()); + else + PSendSysMessage(LANG_POOL_ENTRY_LIST_CONSOLE, + pool_id, pool_template.description.c_str(), pool_template.AutoSpawn ? 1 : 0, pool_template.MaxLimit, + sPoolMgr.GetPoolCreatures(pool_id).size(), sPoolMgr.GetPoolGameObjects(pool_id).size(), sPoolMgr.GetPoolPools(pool_id).size()); +} + +bool ChatHandler::HandleLookupPoolCommand(char * args) +{ + if (!*args) + return false; + + std::string namepart = args; + + Player* player = m_session ? m_session->GetPlayer() : NULL; + MapPersistentState* mapState = player ? player->GetMap()->GetPersistentState() : NULL; + + strToLower(namepart); + + uint32 counter = 0; + + // spawn pools for expected map or for not initialized shared pools state for non-instanceable maps + for(uint16 pool_id = 0; pool_id < sPoolMgr.GetMaxPoolId(); ++pool_id) + { + PoolTemplateData const& pool_template = sPoolMgr.GetPoolTemplate(pool_id); + if (pool_template.description.find(namepart) == std::wstring::npos) + continue; + + ShowPoolListHelper(pool_id); + ++counter; + } + + if (counter==0) + SendSysMessage(LANG_NO_POOL); + + return true; +} + +bool ChatHandler::HandlePoolListCommand(char* args) +{ + Player* player = m_session->GetPlayer(); + + MapPersistentState* mapState = player->GetMap()->GetPersistentState(); + + if (!mapState->GetMapEntry()->Instanceable()) + { + PSendSysMessage(LANG_POOL_LIST_NON_INSTANCE, mapState->GetMapEntry()->name[GetSessionDbcLocale()], mapState->GetMapId()); + SetSentErrorMessage(false); + return false; + } + + uint32 counter = 0; + + // spawn pools for expected map or for not initialized shared pools state for non-instanceable maps + for(uint16 pool_id = 0; pool_id < sPoolMgr.GetMaxPoolId(); ++pool_id) + { + PoolTemplateData const& pool_template = sPoolMgr.GetPoolTemplate(pool_id); + if (sPoolMgr.GetPoolTemplate(pool_id).CanBeSpawnedAtMap(mapState->GetMapEntry())) + { + ShowPoolListHelper(pool_id); + ++counter; + } + } + + if (counter==0) + PSendSysMessage(LANG_NO_POOL_FOR_MAP, mapState->GetMapEntry()->name[GetSessionDbcLocale()], mapState->GetMapId()); + + return true; +} + +bool ChatHandler::HandlePoolSpawnsCommand(char* args) +{ + Player* player = m_session->GetPlayer(); + + MapPersistentState* mapState = player->GetMap()->GetPersistentState(); + + // shared continent pools data expected too big for show + uint32 pool_id = 0; + if (!ExtractUint32KeyFromLink(&args, "Hpool", pool_id) && !mapState->GetMapEntry()->Instanceable()) + { + PSendSysMessage(LANG_POOL_SPAWNS_NON_INSTANCE, mapState->GetMapEntry()->name[GetSessionDbcLocale()], mapState->GetMapId()); + SetSentErrorMessage(false); + return false; + } + + SpawnedPoolData const& spawns = mapState->GetSpawnedPoolData(); + + SpawnedPoolObjects const& crSpawns = spawns.GetSpawnedCreatures(); + for(SpawnedPoolObjects::const_iterator itr = crSpawns.begin(); itr != crSpawns.end(); ++itr) + if (!pool_id || pool_id == sPoolMgr.IsPartOfAPool(*itr)) + if (CreatureData const* data = sObjectMgr.GetCreatureData(*itr)) + if (CreatureInfo const* info = ObjectMgr::GetCreatureTemplate(data->id)) + PSendSysMessage(LANG_CREATURE_LIST_CHAT, *itr, PrepareStringNpcOrGoSpawnInformation(*itr).c_str(), + *itr, info->Name, data->posX, data->posY, data->posZ, data->mapid); + + SpawnedPoolObjects const& goSpawns = spawns.GetSpawnedGameobjects(); + for(SpawnedPoolObjects::const_iterator itr = goSpawns.begin(); itr != goSpawns.end(); ++itr) + if (!pool_id || pool_id == sPoolMgr.IsPartOfAPool(*itr)) + if (GameObjectData const* data = sObjectMgr.GetGOData(*itr)) + if (GameObjectInfo const* info = ObjectMgr::GetGameObjectInfo(data->id)) + PSendSysMessage(LANG_GO_LIST_CHAT, *itr, PrepareStringNpcOrGoSpawnInformation(*itr).c_str(), + *itr, info->name, data->posX, data->posY, data->posZ, data->mapid); + + return true; +} + +bool ChatHandler::HandlePoolInfoCommand(char* args) +{ + // id or [name] Shift-click form |color|Hpool:id|h[name]|h|r + uint32 pool_id; + if (!ExtractUint32KeyFromLink(&args, "Hpool", pool_id)) + return false; + + Player* player = m_session ? m_session->GetPlayer() : NULL; + + MapPersistentState* mapState = player ? player->GetMap()->GetPersistentState() : NULL; + SpawnedPoolData const* spawns = mapState ? &mapState->GetSpawnedPoolData() : NULL; + + std::string active_str = GetMangosString(LANG_ACTIVE); + + PoolTemplateData const& pool_template = sPoolMgr.GetPoolTemplate(pool_id); + uint32 mother_pool_id = sPoolMgr.IsPartOfAPool(pool_id); + if (!mother_pool_id) + PSendSysMessage(LANG_POOL_INFO_HEADER, pool_id, pool_template.AutoSpawn, pool_template.MaxLimit); + else + { + PoolTemplateData const& mother_template = sPoolMgr.GetPoolTemplate(mother_pool_id); + if (m_session) + PSendSysMessage(LANG_POOL_INFO_HEADER_CHAT, pool_id, mother_pool_id, mother_pool_id, mother_template.description.c_str(), + pool_template.AutoSpawn, pool_template.MaxLimit); + else + PSendSysMessage(LANG_POOL_INFO_HEADER_CONSOLE, pool_id, mother_pool_id, mother_template.description.c_str(), + pool_template.AutoSpawn, pool_template.MaxLimit); + } + + PoolGroup const& poolCreatures = sPoolMgr.GetPoolCreatures(pool_id); + SpawnedPoolObjects const* crSpawns = spawns ? &spawns->GetSpawnedCreatures() : NULL; + + PoolObjectList const& poolCreaturesEx = poolCreatures.GetExplicitlyChanced(); + if (!poolCreaturesEx.empty()) + { + SendSysMessage(LANG_POOL_CHANCE_CREATURE_LIST_HEADER); + for (PoolObjectList::const_iterator itr = poolCreaturesEx.begin(); itr != poolCreaturesEx.end(); ++itr) + { + if (CreatureData const* data = sObjectMgr.GetCreatureData(itr->guid)) + { + if (CreatureInfo const* info = ObjectMgr::GetCreatureTemplate(data->id)) + { + char const* active = crSpawns && crSpawns->find(itr->guid) != crSpawns->end() ? active_str.c_str() : ""; + if (m_session) + PSendSysMessage(LANG_POOL_CHANCE_CREATURE_LIST_CHAT, itr->guid, PrepareStringNpcOrGoSpawnInformation(itr->guid).c_str(), + itr->guid, info->Name, data->posX, data->posY, data->posZ, data->mapid, itr->chance, active); + else + PSendSysMessage(LANG_POOL_CHANCE_CREATURE_LIST_CONSOLE, itr->guid, PrepareStringNpcOrGoSpawnInformation(itr->guid).c_str(), + info->Name, data->posX, data->posY, data->posZ, data->mapid, itr->chance, active); + } + } + } + } + + PoolObjectList const& poolCreaturesEq = poolCreatures.GetEqualChanced(); + if (!poolCreaturesEq.empty()) + { + SendSysMessage(LANG_POOL_CREATURE_LIST_HEADER); + for (PoolObjectList::const_iterator itr = poolCreaturesEq.begin(); itr != poolCreaturesEq.end(); ++itr) + { + if (CreatureData const* data = sObjectMgr.GetCreatureData(itr->guid)) + { + if (CreatureInfo const* info = ObjectMgr::GetCreatureTemplate(data->id)) + { + char const* active = crSpawns && crSpawns->find(itr->guid) != crSpawns->end() ? active_str.c_str() : ""; + if (m_session) + PSendSysMessage(LANG_POOL_CREATURE_LIST_CHAT, itr->guid, PrepareStringNpcOrGoSpawnInformation(itr->guid).c_str(), + itr->guid, info->Name, data->posX, data->posY, data->posZ, data->mapid, active); + else + PSendSysMessage(LANG_POOL_CREATURE_LIST_CONSOLE, itr->guid, PrepareStringNpcOrGoSpawnInformation(itr->guid).c_str(), + info->Name, data->posX, data->posY, data->posZ, data->mapid, active); + } + } + } + } + + PoolGroup const& poolGameObjects = sPoolMgr.GetPoolGameObjects(pool_id); + SpawnedPoolObjects const* goSpawns = spawns ? &spawns->GetSpawnedGameobjects() : NULL; + + PoolObjectList const& poolGameObjectsEx = poolGameObjects.GetExplicitlyChanced(); + if (!poolGameObjectsEx.empty()) + { + SendSysMessage(LANG_POOL_CHANCE_GO_LIST_HEADER); + for (PoolObjectList::const_iterator itr = poolGameObjectsEx.begin(); itr != poolGameObjectsEx.end(); ++itr) + { + if (GameObjectData const* data = sObjectMgr.GetGOData(itr->guid)) + { + if (GameObjectInfo const* info = ObjectMgr::GetGameObjectInfo(data->id)) + { + char const* active = goSpawns && goSpawns->find(itr->guid) != goSpawns->end() ? active_str.c_str() : ""; + if (m_session) + PSendSysMessage(LANG_POOL_CHANCE_GO_LIST_CHAT, itr->guid, PrepareStringNpcOrGoSpawnInformation(itr->guid).c_str(), + itr->guid, info->name, data->posX, data->posY, data->posZ, data->mapid, itr->chance, active); + else + PSendSysMessage(LANG_POOL_CHANCE_GO_LIST_CONSOLE, itr->guid, PrepareStringNpcOrGoSpawnInformation(itr->guid).c_str(), + info->name, data->posX, data->posY, data->posZ, data->mapid, itr->chance, active); + } + } + } + } + + PoolObjectList const& poolGameObjectsEq = poolGameObjects.GetEqualChanced(); + if (!poolGameObjectsEq.empty()) + { + SendSysMessage(LANG_POOL_GO_LIST_HEADER); + for (PoolObjectList::const_iterator itr = poolGameObjectsEq.begin(); itr != poolGameObjectsEq.end(); ++itr) + { + if (GameObjectData const* data = sObjectMgr.GetGOData(itr->guid)) + { + if (GameObjectInfo const* info = ObjectMgr::GetGameObjectInfo(data->id)) + { + char const* active = goSpawns && goSpawns->find(itr->guid) != goSpawns->end() ? active_str.c_str() : ""; + if (m_session) + PSendSysMessage(LANG_POOL_GO_LIST_CHAT, itr->guid, PrepareStringNpcOrGoSpawnInformation(itr->guid).c_str(), + itr->guid, info->name, data->posX, data->posY, data->posZ, data->mapid, active); + else + PSendSysMessage(LANG_POOL_GO_LIST_CONSOLE, itr->guid, PrepareStringNpcOrGoSpawnInformation(itr->guid).c_str(), + info->name, data->posX, data->posY, data->posZ, data->mapid, active); + } + } + } + } + + PoolGroup const& poolPools = sPoolMgr.GetPoolPools(pool_id); + SpawnedPoolPools const* poolSpawns = spawns ? &spawns->GetSpawnedPools() : NULL; + + PoolObjectList const& poolPoolsEx = poolPools.GetExplicitlyChanced(); + if (!poolPoolsEx.empty()) + { + SendSysMessage(LANG_POOL_CHANCE_POOL_LIST_HEADER); + for (PoolObjectList::const_iterator itr = poolPoolsEx.begin(); itr != poolPoolsEx.end(); ++itr) + { + PoolTemplateData const& itr_template = sPoolMgr.GetPoolTemplate(itr->guid); + char const* active = poolSpawns && poolSpawns->find(itr->guid) != poolSpawns->end() ? active_str.c_str() : ""; + if (m_session) + PSendSysMessage(LANG_POOL_CHANCE_POOL_LIST_CHAT, itr->guid, + itr->guid, itr_template.description.c_str(), itr_template.AutoSpawn ? 1 : 0, itr_template.MaxLimit, + sPoolMgr.GetPoolCreatures(itr->guid).size(), sPoolMgr.GetPoolGameObjects(itr->guid).size(), sPoolMgr.GetPoolPools(itr->guid).size(), + itr->chance, active); + else + PSendSysMessage(LANG_POOL_CHANCE_POOL_LIST_CONSOLE, itr->guid, + itr_template.description.c_str(), itr_template.AutoSpawn ? 1 : 0, itr_template.MaxLimit, + sPoolMgr.GetPoolCreatures(itr->guid).size(), sPoolMgr.GetPoolGameObjects(itr->guid).size(), sPoolMgr.GetPoolPools(itr->guid).size(), + itr->chance, active); + } + } + + PoolObjectList const& poolPoolsEq = poolPools.GetEqualChanced(); + if (!poolPoolsEq.empty()) + { + SendSysMessage(LANG_POOL_POOL_LIST_HEADER); + for (PoolObjectList::const_iterator itr = poolPoolsEq.begin(); itr != poolPoolsEq.end(); ++itr) + { + PoolTemplateData const& itr_template = sPoolMgr.GetPoolTemplate(itr->guid); + char const* active = poolSpawns && poolSpawns->find(itr->guid) != poolSpawns->end() ? active_str.c_str() : ""; + if (m_session) + PSendSysMessage(LANG_POOL_POOL_LIST_CHAT, itr->guid, + itr->guid, itr_template.description.c_str(), itr_template.AutoSpawn ? 1 : 0, itr_template.MaxLimit, + sPoolMgr.GetPoolCreatures(itr->guid).size(), sPoolMgr.GetPoolGameObjects(itr->guid).size(), sPoolMgr.GetPoolPools(itr->guid).size(), + active); + else + PSendSysMessage(LANG_POOL_POOL_LIST_CONSOLE, itr->guid, + itr_template.description.c_str(), itr_template.AutoSpawn ? 1 : 0, itr_template.MaxLimit, + sPoolMgr.GetPoolCreatures(itr->guid).size(), sPoolMgr.GetPoolGameObjects(itr->guid).size(), sPoolMgr.GetPoolPools(itr->guid).size(), + active); + } + } + return true; +} + /// Triggering corpses expire check in world bool ChatHandler::HandleServerCorpsesCommand(char* /*args*/) { diff --git a/src/game/PoolManager.cpp b/src/game/PoolManager.cpp index de4206b4d..8eef4b023 100644 --- a/src/game/PoolManager.cpp +++ b/src/game/PoolManager.cpp @@ -584,7 +584,7 @@ void PoolManager::LoadFromDB() mPoolTemplate.resize(max_pool_id + 1); - result = WorldDatabase.Query("SELECT entry,max_limit FROM pool_template"); + result = WorldDatabase.Query("SELECT entry, max_limit, description FROM pool_template"); if (!result) { mPoolTemplate.clear(); @@ -606,7 +606,8 @@ void PoolManager::LoadFromDB() uint16 pool_id = fields[0].GetUInt16(); PoolTemplateData& pPoolTemplate = mPoolTemplate[pool_id]; - pPoolTemplate.MaxLimit = fields[1].GetUInt32(); + pPoolTemplate.MaxLimit = fields[1].GetUInt32(); + pPoolTemplate.description = fields[2].GetCppString(); pPoolTemplate.AutoSpawn = true; // will update and later data loading } while (result->NextRow()); diff --git a/src/game/PoolManager.h b/src/game/PoolManager.h index 24b34ab5c..2042f0b80 100644 --- a/src/game/PoolManager.h +++ b/src/game/PoolManager.h @@ -37,6 +37,7 @@ struct PoolTemplateData // NULL is no spawns by some reason uint32 MaxLimit; bool AutoSpawn; // spawn at pool system start (not part of another pool and not part of event spawn) + std::string description; // helpers bool CanBeSpawnedAtMap(MapEntry const* entry) const @@ -82,6 +83,10 @@ class SpawnedPoolData bool IsInitialized() const { return m_isInitialized; } void SetInitialized() { m_isInitialized = true; } + + SpawnedPoolObjects const& GetSpawnedCreatures() const { return mSpawnedCreatures; } + SpawnedPoolObjects const& GetSpawnedGameobjects() const { return mSpawnedGameobjects; } + SpawnedPoolPools const& GetSpawnedPools() const { return mSpawnedPools; } private: SpawnedPoolObjects mSpawnedCreatures; SpawnedPoolObjects mSpawnedGameobjects; @@ -89,10 +94,11 @@ class SpawnedPoolData bool m_isInitialized; }; +typedef std::vector PoolObjectList; + template class PoolGroup { - typedef std::vector PoolObjectList; public: explicit PoolGroup() : poolId(0) { } void SetPoolId(uint32 pool_id) { poolId = pool_id; } @@ -110,6 +116,11 @@ class PoolGroup void Spawn1Object(MapPersistentState& mapState, PoolObject* obj, bool instantly); void ReSpawn1Object(MapPersistentState& mapState, PoolObject* obj); void RemoveOneRelation(uint16 child_pool_id); + + PoolObjectList const& GetExplicitlyChanced() const { return ExplicitlyChanced; } + PoolObjectList const& GetEqualChanced() const { return EqualChanced; } + + size_t size() const { return ExplicitlyChanced.size() + EqualChanced.size(); } private: uint32 poolId; PoolObjectList ExplicitlyChanced; @@ -170,6 +181,10 @@ class PoolManager void RemoveAutoSpawnForPool(uint16 pool_id) { mPoolTemplate[pool_id].AutoSpawn = false; } typedef std::vector PoolTemplateDataMap; + PoolTemplateData const& GetPoolTemplate(uint16 pool_id) const { return mPoolTemplate[pool_id]; } + PoolGroup const& GetPoolCreatures(uint16 pool_id) const { return mPoolCreatureGroups[pool_id]; } + PoolGroup const& GetPoolGameObjects(uint16 pool_id) const { return mPoolGameobjectGroups[pool_id]; } + PoolGroup const& GetPoolPools(uint16 pool_id) const { return mPoolPoolGroups[pool_id]; } protected: template void SpawnPoolGroup(MapPersistentState& mapState, uint16 pool_id, uint32 db_guid_or_pool_id, bool instantly); diff --git a/src/shared/Util.h b/src/shared/Util.h index 69e8c5426..389184e60 100644 --- a/src/shared/Util.h +++ b/src/shared/Util.h @@ -258,6 +258,16 @@ inline bool isEastAsianString(std::wstring wstr, bool numericOrSpace) return true; } +inline void strToUpper(std::string& str) +{ + std::transform( str.begin(), str.end(), str.begin(), toupper ); +} + +inline void strToLower(std::string& str) +{ + std::transform( str.begin(), str.end(), str.begin(), tolower ); +} + inline wchar_t wcharToUpper(wchar_t wchar) { if(wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b45007f95..e628cadfd 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11168" + #define REVISION_NR "11169" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index a708867dc..847223830 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ #define REVISION_DB_CHARACTERS "required_11117_02_characters_world" - #define REVISION_DB_MANGOS "required_11117_01_mangos_world_template" + #define REVISION_DB_MANGOS "required_11169_02_mangos_command" #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" #endif // __REVISION_SQL_H__