Scripts/Commands: Add .go boss, and do a usability pass over .go instance to match it.

This commit is contained in:
Treeston
2019-08-07 01:45:24 +02:00
parent 4320a021e9
commit 57b36dfdc6
3 changed files with 171 additions and 30 deletions

View File

@@ -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).');

View File

@@ -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,

View File

@@ -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()