Core/Quests: implement Quest Greeting (DB table quest_greeting)

* Core/Quests: implement Quest Greetings. Partial port 22e230ecec
This commit is contained in:
ForesterDev
2017-10-29 13:15:22 +04:00
committed by Aokromes
parent bbd339370e
commit a64d1ec51e
9 changed files with 260 additions and 16 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,15 @@
DELETE FROM `rbac_permissions` WHERE `id` = 843; -- this id does not exist in TDB 335.63
INSERT INTO `rbac_permissions` (`id`,`name`) VALUES
(843, 'Command: reload quest_greeting');
DELETE FROM `rbac_linked_permissions` WHERE `linkedId` = 843;
INSERT INTO `rbac_linked_permissions` (`id`,`linkedId`) VALUES
(196, 843);
DELETE FROM `rbac_permissions` WHERE `id` = 867;
INSERT INTO `rbac_permissions` (`id`,`name`) VALUES
(867, 'Command: reload quest_greeting_locale');
DELETE FROM `rbac_linked_permissions` WHERE `id` = 867;
INSERT INTO `rbac_linked_permissions` (`id`,`linkedId`) VALUES
(196, 867);

View File

@@ -0,0 +1,28 @@
DELETE FROM `command` WHERE `name`='reload quest_greeting';
INSERT INTO `command` (`name`, `permission`, `help`) VALUES
('reload quest_greeting', 843, 'Syntax: .reload quest_greeting\nReload quest_greeting table.');
DELETE FROM `command` WHERE `name`='reload quest_greeting_locale';
INSERT INTO `command` (`name`, `permission`, `help`) VALUES
('reload quest_greeting_locale', 867, 'Syntax: .reload quest_greeting_locale\nReload quest_greeting_locale table.');
DROP TABLE IF EXISTS `quest_greeting`;
CREATE TABLE `quest_greeting` (
`ID` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0',
`Type` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
`GreetEmoteType` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0',
`GreetEmoteDelay` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`Greeting` TEXT,
`VerifiedBuild` SMALLINT(5) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`Type`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `quest_greeting_locale`;
CREATE TABLE `quest_greeting_locale` (
`ID` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0',
`Type` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
`locale` VARCHAR(4) NOT NULL,
`Greeting` TEXT,
`VerifiedBuild` SMALLINT(5) DEFAULT '0',
PRIMARY KEY (`ID`,`Type`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8;

View File

@@ -748,7 +748,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_SERVER_RESTART_FORCE = 840,
RBAC_PERM_COMMAND_NEARGRAVEYARD = 841,
RBAC_PERM_COMMAND_RELOAD_CHARACTER_TEMPLATE = 842, // not on 3.3.5a
RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING = 843, // not on 3.3.5a
RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING = 843,
RBAC_PERM_COMMAND_SCENE = 844, // not on 3.3.5a
RBAC_PERM_COMMAND_SCENE_DEBUG = 845, // not on 3.3.5a
RBAC_PERM_COMMAND_SCENE_PLAY = 846, // not on 3.3.5a
@@ -772,6 +772,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_GROUP_MAINASSIST = 864,
RBAC_PERM_COMMAND_NPC_SHOWLOOT = 865,
RBAC_PERM_COMMAND_LIST_SPAWNPOINTS = 866,
RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING_LOCALE = 867,
// custom permissions 1000+
RBAC_PERM_MAX

View File

@@ -323,16 +323,33 @@ void QuestMenu::ClearMenu()
_questMenuItems.clear();
}
void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string& Title, ObjectGuid npcGUID)
void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string& Title, ObjectGuid guid)
{
WorldPacket data(SMSG_QUESTGIVER_QUEST_LIST, 100); // guess size
data << uint64(npcGUID);
data << Title;
data << uint32(eEmote._Delay); // player emote
data << uint32(eEmote._Emote); // NPC emote
data << uint64(guid);
if (QuestGreeting const* questGreeting = sObjectMgr->GetQuestGreeting(guid))
{
std::string strGreeting = questGreeting->greeting;
LocaleConstant localeConstant = _session->GetSessionDbLocaleIndex();
if (localeConstant != LOCALE_enUS)
if (QuestGreetingLocale const* questGreetingLocale = sObjectMgr->GetQuestGreetingLocale(MAKE_PAIR32(guid.GetEntry(), guid.GetTypeId())))
ObjectMgr::GetLocaleString(questGreetingLocale->greeting, localeConstant, strGreeting);
data << strGreeting;
data << uint32(questGreeting->greetEmoteDelay);
data << uint32(questGreeting->greetEmoteType);
}
else
{
data << Title;
data << uint32(eEmote._Delay); // player emote
data << uint32(eEmote._Emote); // NPC emote
}
size_t count_pos = data.wpos();
data << uint8 (0);
data << uint8(0);
uint32 count = 0;
// Store this instead of checking the Singleton every loop iteration
@@ -340,9 +357,9 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string
for (uint32 i = 0; i < _questMenu.GetMenuItemCount(); ++i)
{
QuestMenuItem const& qmi = _questMenu.GetItem(i);
QuestMenuItem const& questMenuItem = _questMenu.GetItem(i);
uint32 questID = qmi.QuestId;
uint32 questID = questMenuItem.QuestId;
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questID))
{
@@ -351,14 +368,14 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string
LocaleConstant localeConstant = _session->GetSessionDbLocaleIndex();
if (localeConstant != LOCALE_enUS)
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID))
ObjectMgr::GetLocaleString(localeData->Title, localeConstant, title);
if (QuestLocale const* questTemplateLocaleData = sObjectMgr->GetQuestLocale(questID))
ObjectMgr::GetLocaleString(questTemplateLocaleData->Title, localeConstant, title);
if (questLevelInTitle)
Quest::AddQuestLevelToTitle(title, quest->GetQuestLevel());
data << uint32(questID);
data << uint32(qmi.QuestIcon);
data << uint32(questMenuItem.QuestIcon);
data << int32(quest->GetQuestLevel());
data << uint32(quest->GetFlags()); // 3.3.3 quest flags
data << uint8(0); // 3.3.3 changes icon: blue question or yellow exclamation
@@ -368,7 +385,8 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string
data.put<uint8>(count_pos, count);
_session->SendPacket(&data);
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_QUEST_LIST NPC=%s", npcGUID.ToString().c_str());
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_QUEST_LIST (QuestGiver: %s)", guid.ToString().c_str());
}
void PlayerMenu::SendQuestGiverStatus(uint8 questStatus, ObjectGuid npcGUID) const

View File

@@ -5982,6 +5982,134 @@ void ObjectMgr::LoadQuestAreaTriggers()
TC_LOG_INFO("server.loading", ">> Loaded %u quest trigger points in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
QuestGreeting const* ObjectMgr::GetQuestGreeting(ObjectGuid guid) const
{
auto itr = _questGreetingStore.find(guid.GetTypeId());
if (itr == _questGreetingStore.end())
return nullptr;
auto questItr = itr->second.find(guid.GetEntry());
if (questItr == itr->second.end())
return nullptr;
return questItr->second;
}
void ObjectMgr::LoadQuestGreetings()
{
uint32 oldMSTime = getMSTime();
_questGreetingStore.clear(); // need for reload case
// 0 1 2 3 4
QueryResult result = WorldDatabase.Query("SELECT ID, Type, GreetEmoteType, GreetEmoteDelay, Greeting FROM quest_greeting");
if (!result)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 quest greetings. DB table `quest_greeting` is empty.");
return;
}
_questGreetingStore.rehash(result->GetRowCount());
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 id = fields[0].GetUInt32();
uint8 type = fields[1].GetUInt8();
// overwrite
switch (type)
{
case 0: // Creature
type = TYPEID_UNIT;
if (!sObjectMgr->GetCreatureTemplate(id))
{
TC_LOG_ERROR("sql.sql", "Table `quest_greeting`: creature template (entry: %u) does not exist.", id);
continue;
}
break;
case 1: // GameObject
type = TYPEID_GAMEOBJECT;
if (!sObjectMgr->GetGameObjectTemplate(id))
{
TC_LOG_ERROR("sql.sql", "Table `quest_greeting`: gameobject template (entry: %u) does not exist.", id);
continue;
}
break;
default:
TC_LOG_ERROR("sql.sql", "Table `quest_greeting`: unknown type = %u for entry = %u. Skipped.", type, id);
continue;
}
uint16 greetEmoteType = fields[2].GetUInt16();
if (greetEmoteType > 0 && !sEmotesStore.LookupEntry(greetEmoteType))
{
TC_LOG_DEBUG("sql.sql", "Table `quest_greeting`: entry %u has greetEmoteType = %u but emote does not exist. Set to 0.", id, greetEmoteType);
greetEmoteType = 0;
}
uint32 greetEmoteDelay = fields[3].GetUInt32();
std::string greeting = fields[4].GetString();
_questGreetingStore[type][id] = new QuestGreeting(greetEmoteType, greetEmoteDelay, greeting);
++count;
}
while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u quest_greeting in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadQuestGreetingsLocales()
{
uint32 oldMSTime = getMSTime();
_questGreetingLocaleStore.clear(); // need for reload case
// 0 1 2 3
QueryResult result = WorldDatabase.Query("SELECT ID, Type, Locale, Greeting FROM quest_greeting_locale");
if (!result)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 quest_greeting locales. DB table `quest_greeting_locale` is empty.");
return;
}
do
{
Field* fields = result->Fetch();
uint32 id = fields[0].GetUInt32();
uint8 type = fields[1].GetUInt8();
// overwrite
switch (type)
{
case 0: // Creature
type = TYPEID_UNIT;
break;
case 1: // GameObject
type = TYPEID_GAMEOBJECT;
break;
default:
break;
}
std::string localeName = fields[2].GetString();
std::string greeting = fields[3].GetString();
QuestGreetingLocale& data = _questGreetingLocaleStore[MAKE_PAIR32(id, type)];
LocaleConstant locale = GetLocaleByName(localeName);
if (locale == LOCALE_enUS)
continue;
AddLocaleString(greeting, locale, data.greeting);
} while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u quest greeting locale strings in %u ms", uint32(_questGreetingLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadTavernAreaTriggers()
{
uint32 oldMSTime = getMSTime();

View File

@@ -532,6 +532,11 @@ struct TrinityString
std::vector<std::string> Content;
};
struct QuestGreetingLocale
{
std::vector<std::string> greeting;
};
typedef std::map<ObjectGuid, ObjectGuid> LinkedRespawnContainer;
typedef std::unordered_map<uint32, CreatureTemplate> CreatureTemplateContainer;
typedef std::unordered_map<uint32, CreatureAddon> CreatureTemplateAddonContainer;
@@ -574,6 +579,7 @@ struct PointOfInterestLocale
};
typedef std::unordered_map<uint32, PointOfInterestLocale> PointOfInterestLocaleContainer;
typedef std::unordered_map<uint32, QuestGreetingLocale> QuestGreetingLocaleContainer;
typedef std::unordered_map<uint32, TrinityString> TrinityStringContainer;
@@ -794,6 +800,19 @@ struct QuestPOIWrapper
typedef std::unordered_map<uint32, QuestPOIWrapper> QuestPOIContainer;
struct QuestGreeting
{
uint16 greetEmoteType;
uint32 greetEmoteDelay;
std::string greeting;
QuestGreeting() : greetEmoteType(0), greetEmoteDelay(0) { }
QuestGreeting(uint16 _greetEmoteType, uint32 _greetEmoteDelay, std::string _greeting)
: greetEmoteType(_greetEmoteType), greetEmoteDelay(_greetEmoteDelay), greeting(_greeting) { }
};
typedef std::unordered_map<uint8, std::unordered_map<uint32, QuestGreeting const*>> QuestGreetingContainer;
struct GraveyardData
{
uint32 safeLocId;
@@ -998,6 +1017,7 @@ class TC_GAME_API ObjectMgr
}
GossipText const* GetGossipText(uint32 Text_ID) const;
QuestGreeting const* GetQuestGreeting(ObjectGuid guid) const;
WorldSafeLocsEntry const* GetDefaultGraveyard(uint32 team) const;
WorldSafeLocsEntry const* GetClosestGraveyard(float x, float y, float z, uint32 MapId, uint32 team) const;
@@ -1155,6 +1175,7 @@ class TC_GAME_API ObjectMgr
void LoadPageTextLocales();
void LoadGossipMenuItemsLocales();
void LoadPointOfInterestLocales();
void LoadQuestGreetingsLocales();
void LoadInstanceTemplate();
void LoadInstanceEncounters();
void LoadMailLevelRewards();
@@ -1166,6 +1187,7 @@ class TC_GAME_API ObjectMgr
void LoadAreaTriggerTeleports();
void LoadAccessRequirements();
void LoadQuestAreaTriggers();
void LoadQuestGreetings();
void LoadAreaTriggerScripts();
void LoadTavernAreaTriggers();
void LoadGameObjectForQuests();
@@ -1374,6 +1396,12 @@ class TC_GAME_API ObjectMgr
if (itr == _pointOfInterestLocaleStore.end()) return nullptr;
return &itr->second;
}
QuestGreetingLocale const* GetQuestGreetingLocale(uint32 id) const
{
QuestGreetingLocaleContainer::const_iterator itr = _questGreetingLocaleStore.find(id);
if (itr == _questGreetingLocaleStore.end()) return nullptr;
return &itr->second;
}
TrinityString const* GetTrinityString(uint32 entry) const
{
@@ -1527,6 +1555,7 @@ class TC_GAME_API ObjectMgr
TavernAreaTriggerContainer _tavernAreaTriggerStore;
GameObjectForQuestContainer _gameObjectForQuestStore;
GossipTextContainer _gossipTextStore;
QuestGreetingContainer _questGreetingStore;
AreaTriggerContainer _areaTriggerStore;
AreaTriggerScriptContainer _areaTriggerScriptStore;
AccessRequirementContainer _accessRequirementStore;
@@ -1637,6 +1666,7 @@ class TC_GAME_API ObjectMgr
PageTextLocaleContainer _pageTextLocaleStore;
GossipMenuItemsLocaleContainer _gossipMenuItemsLocaleStore;
PointOfInterestLocaleContainer _pointOfInterestLocaleStore;
QuestGreetingLocaleContainer _questGreetingLocaleStore;
TrinityStringContainer _trinityStringStore;

View File

@@ -1611,6 +1611,7 @@ void World::SetInitialWorldSettings()
sObjectMgr->LoadPageTextLocales();
sObjectMgr->LoadGossipMenuItemsLocales();
sObjectMgr->LoadPointOfInterestLocales();
sObjectMgr->LoadQuestGreetingsLocales();
sObjectMgr->SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts)
TC_LOG_INFO("server.loading", ">> Localization strings loaded in %u ms", GetMSTimeDiffToNow(oldMSTime));
@@ -1762,6 +1763,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Quests Starters and Enders...");
sObjectMgr->LoadQuestStartersAndEnders(); // must be after quest load
TC_LOG_INFO("server.loading", "Loading Quests Greetings...");
sObjectMgr->LoadQuestGreetings(); // must be loaded after creature_template, gameobject_template tables
TC_LOG_INFO("server.loading", "Loading Objects Pooling Data...");
sPoolMgr->LoadFromDB();

View File

@@ -129,6 +129,8 @@ public:
{ "pickpocketing_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_PICKPOCKETING_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesPickpocketingCommand, "" },
{ "points_of_interest", rbac::RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST, true, &HandleReloadPointsOfInterestCommand, "" },
{ "prospecting_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_PROSPECTING_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesProspectingCommand, "" },
{ "quest_greeting", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING, true, &HandleReloadQuestGreetingCommand, "" },
{ "quest_greeting_locale", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING_LOCALE, true, &HandleReloadLocalesQuestGreetingCommand, "" },
{ "quest_poi", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_POI, true, &HandleReloadQuestPOICommand, "" },
{ "quest_template", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE, true, &HandleReloadQuestTemplateCommand, "" },
{ "rbac", rbac::RBAC_PERM_COMMAND_RELOAD_RBAC, true, &HandleReloadRBACCommand, "" },
@@ -243,6 +245,7 @@ public:
static bool HandleReloadAllQuestCommand(ChatHandler* handler, char const* /*args*/)
{
HandleReloadQuestGreetingCommand(handler, "");
HandleReloadQuestAreaTriggersCommand(handler, "a");
HandleReloadQuestPOICommand(handler, "a");
HandleReloadQuestTemplateCommand(handler, "a");
@@ -317,6 +320,7 @@ public:
HandleReloadLocalesPageTextCommand(handler, "a");
HandleReloadLocalesPointsOfInterestCommand(handler, "a");
HandleReloadLocalesQuestCommand(handler, "a");
HandleReloadLocalesQuestGreetingCommand(handler, "");
return true;
}
@@ -523,6 +527,22 @@ public:
return true;
}
static bool HandleReloadQuestGreetingCommand(ChatHandler* handler, char const* /*args*/)
{
TC_LOG_INFO("misc", "Re-Loading Quest Greeting ...");
sObjectMgr->LoadQuestGreetings();
handler->SendGlobalGMSysMessage("DB table `quest_greeting` reloaded.");
return true;
}
static bool HandleReloadLocalesQuestGreetingCommand(ChatHandler* handler, char const* /*args*/)
{
TC_LOG_INFO("misc", "Re-Loading Quest Greeting locales...");
sObjectMgr->LoadQuestGreetingsLocales();
handler->SendGlobalGMSysMessage("DB table `quest_greeting_locale` reloaded.");
return true;
}
static bool HandleReloadQuestTemplateCommand(ChatHandler* handler, char const* /*args*/)
{
TC_LOG_INFO("misc", "Re-Loading Quest Templates...");