diff options
author | Treeston <treeston.mmoc@gmail.com> | 2019-08-07 01:45:24 +0200 |
---|---|---|
committer | Treeston <treeston.mmoc@gmail.com> | 2019-08-07 01:45:24 +0200 |
commit | 57b36dfdc6b077cc4eba29406e3ded4dbf9f8ce6 (patch) | |
tree | 9bb55c238a8e7832d4f027084b072ceb973fcce6 | |
parent | 4320a021e93423122745684e2689aa1a7028f8b4 (diff) |
Scripts/Commands: Add .go boss, and do a usability pass over .go instance to match it.
-rw-r--r-- | sql/updates/world/3.3.5/2019_08_06_05_world.sql | 30 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/Language.h | 12 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_go.cpp | 159 |
3 files changed, 171 insertions, 30 deletions
diff --git a/sql/updates/world/3.3.5/2019_08_06_05_world.sql b/sql/updates/world/3.3.5/2019_08_06_05_world.sql new file mode 100644 index 00000000000..591d7564c3e --- /dev/null +++ b/sql/updates/world/3.3.5/2019_08_06_05_world.sql @@ -0,0 +1,30 @@ +-- +DELETE FROM `trinity_string` WHERE `entry` BETWEEN 1205 AND 1211; +INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES +(1205, 'No bosses were found matching your input.'), +(1206, 'Multiple bosses match your input - please be more specific:'), +(1207, '|- #%05u \'%s\' (%s)'), +(1208, 'Multiple spawn points exist for boss \'%s\' (creature #%05u) - go to one using .go creature:'), +(1209, '|- %06u (map #%03u \'%s\' at %s)'), +(1210, 'Failed to teleport you to spawn point %u for boss \'%s\' (creature #%05u) - are you missing an attunement for map \'%s\'?'), +(1211, 'Teleported you to spawn point for boss \'%s\' (creature #%05u, spawnid %u)'); + +DELETE FROM `trinity_string` WHERE `entry` BETWEEN 1189 AND 1198; +INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES +(1189, 'No instances were found matching your input.'), +(1190, 'Multiple instances match your input - please be more specific:'), +(1191,'|- \'%s\' (map #%03u, %s)'), +-- 1192 is newly unused +(1193,'Could not find entrance portal for map \'%s\' (map #%03u)'), +(1194,'Could not find exit portal for map \'%s\' (map #%03u)'), +(1195,'Teleported you to the entrance of \'%s\' (map #%03u)'), +(1196,'Teleported you to the start of \'%s\' (map #%03u)'), +(1197,'Failed to teleport you to the entrance of \'%s\' (map #%03u) - are you missing an attunement for map \'%s\' (#%03u)?'), +(1198,'Failed to teleport you to the start of \'%s\' (map #%03u) - are you missing an attunement for the instance?'); + +DELETE FROM `command` WHERE `name` IN ('go boss','go instance'); +INSERT INTO `command` (`name`,`permission`,`help`) VALUES +('go instance', 377, 'Syntax: .go instance <part(s) of name> +Teleport yourself to the instance whose name and/or script name best matches the specified search string(s).'), +('go boss', 377, 'Syntax: .go boss <part(s) of name> +Teleport yourself to the dungeon boss whose name and/or script name best matches the specified search string(s).'); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 133deee6347..e7e15b88b61 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -915,7 +915,7 @@ enum TrinityStrings LANG_COMMAND_NO_INSTANCES_MATCH = 1189, LANG_COMMAND_MULTIPLE_INSTANCES_MATCH = 1190, LANG_COMMAND_MULTIPLE_INSTANCES_ENTRY = 1191, - LANG_COMMAND_MAP_NOT_INSTANCE = 1192, + // 1192 unused LANG_COMMAND_INSTANCE_NO_ENTRANCE = 1193, LANG_COMMAND_INSTANCE_NO_EXIT = 1194, LANG_COMMAND_WENT_TO_INSTANCE_GATE = 1195, @@ -931,7 +931,15 @@ enum TrinityStrings LANG_DEBUG_AREATRIGGER_OFF = 1203, LANG_DEBUG_AREATRIGGER_REACHED = 1204, - // 1205-1998 - free + LANG_COMMAND_NO_BOSSES_MATCH = 1205, + LANG_COMMAND_MULTIPLE_BOSSES_MATCH = 1206, + LANG_COMMAND_MULTIPLE_BOSSES_ENTRY = 1207, + LANG_COMMAND_BOSS_MULTIPLE_SPAWNS = 1208, + LANG_COMMAND_BOSS_MULTIPLE_SPAWN_ETY = 1209, + LANG_COMMAND_GO_BOSS_FAILED = 1210, + LANG_COMMAND_WENT_TO_BOSS = 1211, + + // 1212-1998 - free LANG_DO_NOT_USE_6X_DEBUG_AREATRIGGER_LEFT = 1999, // Ticket Strings 2000-2030 LANG_COMMAND_TICKETNEW = 2000, diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index d22f6776c04..fe34f212dea 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -67,7 +67,8 @@ public: { "xyz", rbac::RBAC_PERM_COMMAND_GO, false, &HandleGoXYZCommand, "" }, { "ticket", rbac::RBAC_PERM_COMMAND_GO, false, &HandleGoTicketCommand, "" }, { "offset", rbac::RBAC_PERM_COMMAND_GO, false, &HandleGoOffsetCommand, "" }, - { "instance", rbac::RBAC_PERM_COMMAND_GO, false, &HandleGoInstanceCommand, "" } + { "instance", rbac::RBAC_PERM_COMMAND_GO, false, &HandleGoInstanceCommand, "" }, + { "boss", rbac::RBAC_PERM_COMMAND_GO, false, &HandleGoBossCommand, "" } }; static std::vector<ChatCommand> commandTable = @@ -389,19 +390,22 @@ public: static bool HandleGoInstanceCommand(ChatHandler* handler, std::vector<std::string> const& labels) { - uint32 mapid = 0; + if (labels.empty()) + return false; - std::multimap<uint32, std::pair<uint16, std::string>> matches; + // #matched labels -> (mapid, scriptname) + std::multimap<uint32, std::tuple<uint16, char const*, char const*>> matches; for (auto const& pair : sObjectMgr->GetInstanceTemplates()) { uint32 count = 0; std::string const& scriptName = sObjectMgr->GetScriptName(pair.second.ScriptId); + char const* mapName = ASSERT_NOTNULL(sMapStore.LookupEntry(pair.first))->name[handler->GetSessionDbcLocale()]; for (auto const& label : labels) if (StringContainsStringI(scriptName, label)) ++count; if (count) - matches.emplace(count, decltype(matches)::mapped_type({ pair.first, scriptName })); + matches.emplace(count, decltype(matches)::mapped_type({ pair.first, mapName, scriptName.c_str() })); } if (matches.empty()) { @@ -409,30 +413,23 @@ public: handler->SetSentErrorMessage(true); return false; } - auto it = matches.rbegin(); - uint32 maxCount = it->first; - mapid = it->second.first; - if (++it != matches.rend() && it->first == maxCount) + + auto it = matches.crbegin(), end = matches.crend(); + uint32 const maxCount = it->first; + if ((++it) != end && it->first == maxCount) { handler->SendSysMessage(LANG_COMMAND_MULTIPLE_INSTANCES_MATCH); --it; do - handler->PSendSysMessage(LANG_COMMAND_MULTIPLE_INSTANCES_ENTRY, it->second.first, it->second.second); - while (++it != matches.rend() && it->first == maxCount); + handler->PSendSysMessage(LANG_COMMAND_MULTIPLE_INSTANCES_ENTRY, std::get<1>(it->second), std::get<0>(it->second), std::get<2>(it->second)); + while (((++it) != end) && (it->first == maxCount)); handler->SetSentErrorMessage(true); return false; } - ASSERT(mapid); - - InstanceTemplate const* temp = sObjectMgr->GetInstanceTemplate(mapid); - if (!temp) - { - handler->PSendSysMessage(LANG_COMMAND_MAP_NOT_INSTANCE, mapid); - handler->SetSentErrorMessage(true); - return false; - } - std::string const& scriptname = sObjectMgr->GetScriptName(temp->ScriptId); + it = matches.crbegin(); + uint32 const mapId = std::get<0>(it->second); + char const* const mapName = std::get<1>(it->second); Player* player = handler->GetSession()->GetPlayer(); if (player->IsInFlight()) @@ -441,36 +438,142 @@ public: player->SaveRecallPosition(); // try going to entrance - if (AreaTrigger const* exit = sObjectMgr->GetGoBackTrigger(mapid)) + if (AreaTrigger const* exit = sObjectMgr->GetGoBackTrigger(mapId)) { if (player->TeleportTo(exit->target_mapId, exit->target_X, exit->target_Y, exit->target_Z, exit->target_Orientation + M_PI)) { - handler->PSendSysMessage(LANG_COMMAND_WENT_TO_INSTANCE_GATE, mapid, scriptname); + handler->PSendSysMessage(LANG_COMMAND_WENT_TO_INSTANCE_GATE, mapName, mapId); return true; } else - handler->PSendSysMessage(LANG_COMMAND_GO_INSTANCE_GATE_FAILED, mapid, scriptname, exit->target_mapId); + { + uint32 const parentMapId = exit->target_mapId; + char const* const parentMapName = ASSERT_NOTNULL(sMapStore.LookupEntry(parentMapId))->name[handler->GetSessionDbcLocale()]; + handler->PSendSysMessage(LANG_COMMAND_GO_INSTANCE_GATE_FAILED, mapName, mapId, parentMapName, parentMapId); + } } else - handler->PSendSysMessage(LANG_COMMAND_INSTANCE_NO_EXIT, mapid, scriptname); + handler->PSendSysMessage(LANG_COMMAND_INSTANCE_NO_EXIT, mapName, mapId); // try going to start - if (AreaTrigger const* entrance = sObjectMgr->GetMapEntranceTrigger(mapid)) + if (AreaTrigger const* entrance = sObjectMgr->GetMapEntranceTrigger(mapId)) { if (player->TeleportTo(entrance->target_mapId, entrance->target_X, entrance->target_Y, entrance->target_Z, entrance->target_Orientation)) { - handler->PSendSysMessage(LANG_COMMAND_WENT_TO_INSTANCE_START, mapid, scriptname); + handler->PSendSysMessage(LANG_COMMAND_WENT_TO_INSTANCE_START, mapName, mapId); return true; } else - handler->PSendSysMessage(LANG_COMMAND_GO_INSTANCE_START_FAILED, mapid, scriptname); + handler->PSendSysMessage(LANG_COMMAND_GO_INSTANCE_START_FAILED, mapName, mapId); } else - handler->PSendSysMessage(LANG_COMMAND_INSTANCE_NO_ENTRANCE, mapid, scriptname); + handler->PSendSysMessage(LANG_COMMAND_INSTANCE_NO_ENTRANCE, mapName, mapId); handler->SetSentErrorMessage(true); return false; } + + static bool HandleGoBossCommand(ChatHandler* handler, std::vector<std::string> const& needles) + { + if (needles.empty()) + return false; + + std::multimap<uint32, CreatureTemplate const*> matches; + std::unordered_map<uint32, std::vector<CreatureData const*>> spawnLookup; + + // find all boss flagged mobs that match our needles + for (auto const& pair : sObjectMgr->GetCreatureTemplates()) + { + CreatureTemplate const& data = pair.second; + if (!(data.flags_extra & CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) + continue; + + uint32 count = 0; + std::string const& scriptName = sObjectMgr->GetScriptName(data.ScriptID); + for (auto const& label : needles) + if (StringContainsStringI(scriptName, label) || StringContainsStringI(data.Name, label)) + ++count; + + if (count) + { + matches.emplace(count, &data); + (void)spawnLookup[data.Entry]; // inserts default-constructed vector + } + } + + if (!matches.empty()) + { + // find the spawn points of any matches + for (auto const& pair : sObjectMgr->GetAllCreatureData()) + { + CreatureData const& data = pair.second; + auto it = spawnLookup.find(data.id); + if (it != spawnLookup.end()) + it->second.push_back(&data); + } + + // remove any matches without spawns + Trinity::Containers::EraseIf(matches, [&spawnLookup](decltype(matches)::value_type const& pair) { return spawnLookup[pair.second->Entry].empty(); }); + } + + // check if we even have any matches left + if (matches.empty()) + { + handler->SendSysMessage(LANG_COMMAND_NO_BOSSES_MATCH); + handler->SetSentErrorMessage(true); + return false; + } + + // see if we have multiple equal matches left + auto it = matches.crbegin(), end = matches.crend(); + uint32 const maxCount = it->first; + if ((++it) != end && it->first == maxCount) + { + handler->SendSysMessage(LANG_COMMAND_MULTIPLE_BOSSES_MATCH); + --it; + do + handler->PSendSysMessage(LANG_COMMAND_MULTIPLE_BOSSES_ENTRY, it->second->Entry, it->second->Name.c_str(), sObjectMgr->GetScriptName(it->second->ScriptID).c_str()); + while (((++it) != end) && (it->first == maxCount)); + handler->SetSentErrorMessage(true); + return false; + } + + CreatureTemplate const* const boss = matches.crbegin()->second; + std::vector<CreatureData const*> const& spawns = spawnLookup[boss->Entry]; + ASSERT(!spawns.empty()); + + if (spawns.size() > 1) + { + handler->PSendSysMessage(LANG_COMMAND_BOSS_MULTIPLE_SPAWNS, boss->Name.c_str(), boss->Entry); + for (CreatureData const* spawn : spawns) + { + uint32 const mapId = spawn->spawnPoint.GetMapId(); + MapEntry const* const map = ASSERT_NOTNULL(sMapStore.LookupEntry(mapId)); + handler->PSendSysMessage(LANG_COMMAND_BOSS_MULTIPLE_SPAWN_ETY, spawn->spawnId, mapId, map->name[handler->GetSessionDbcLocale()], spawn->spawnPoint.GetPosition().ToString().c_str()); + } + handler->SetSentErrorMessage(true); + return false; + } + + Player* player = handler->GetSession()->GetPlayer(); + if (player->IsInFlight()) + player->FinishTaxiFlight(); + else + player->SaveRecallPosition(); + + CreatureData const* const spawn = spawns.front(); + uint32 const mapId = spawn->spawnPoint.GetMapId(); + if (!player->TeleportTo(spawn->spawnPoint)) + { + char const* const mapName = ASSERT_NOTNULL(sMapStore.LookupEntry(mapId))->name[handler->GetSessionDbcLocale()]; + handler->PSendSysMessage(LANG_COMMAND_GO_BOSS_FAILED, spawn->spawnId, boss->Name.c_str(), boss->Entry, mapName); + handler->SetSentErrorMessage(true); + return false; + } + + handler->PSendSysMessage(LANG_COMMAND_WENT_TO_BOSS, boss->Name.c_str(), boss->Entry, spawn->spawnId); + return true; + } }; void AddSC_go_commandscript() |