aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2019-08-07 01:45:24 +0200
committerTreeston <treeston.mmoc@gmail.com>2019-08-07 01:45:24 +0200
commit57b36dfdc6b077cc4eba29406e3ded4dbf9f8ce6 (patch)
tree9bb55c238a8e7832d4f027084b072ceb973fcce6
parent4320a021e93423122745684e2689aa1a7028f8b4 (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.sql30
-rw-r--r--src/server/game/Miscellaneous/Language.h12
-rw-r--r--src/server/scripts/Commands/cs_go.cpp159
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()