diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 877cfee68..fe39491c0 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -3713,6 +3713,33 @@ bool Creature::CanGeneratePickPocketLoot() const return (lootPickPocketRestoreTime == 0 || lootPickPocketRestoreTime < GameTime::GetGameTime().count()); } +void Creature::SetTextRepeatId(uint8 textGroup, uint8 id) +{ + CreatureTextRepeatIds& repeats = m_textRepeat[textGroup]; + if (std::find(repeats.begin(), repeats.end(), id) == repeats.end()) + repeats.push_back(id); + else + LOG_ERROR("sql.sql", "CreatureTextMgr: TextGroup {} for Creature({}) {}, id {} already added", uint32(textGroup), GetName(), GetGUID().ToString(), uint32(id)); +} + +CreatureTextRepeatIds const& Creature::GetTextRepeatGroup(uint8 textGroup) +{ + static CreatureTextRepeatIds const emptyIds; + + CreatureTextRepeatGroup::const_iterator groupItr = m_textRepeat.find(textGroup); + if (groupItr != m_textRepeat.end()) + return groupItr->second; + + return emptyIds; +} + +void Creature::ClearTextRepeatGroup(uint8 textGroup) +{ + CreatureTextRepeatGroup::iterator groupItr = m_textRepeat.find(textGroup); + if (groupItr != m_textRepeat.end()) + groupItr->second.clear(); +} + void Creature::SetRespawnTime(uint32 respawn) { m_respawnTime = respawn ? GameTime::GetGameTime().count() + respawn : 0; diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index e5ebcd45a..950bc5367 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -39,6 +39,10 @@ class CreatureGroup; #define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY +//used for handling non-repeatable random texts +typedef std::vector CreatureTextRepeatIds; +typedef std::unordered_map CreatureTextRepeatGroup; + class Creature : public Unit, public GridObject, public MovableMapObject, public UpdatableMapObject { public: @@ -388,6 +392,10 @@ public: void UpdateLeashExtensionTime(); uint8 GetLeashTimer() const; + CreatureTextRepeatIds const& GetTextRepeatGroup(uint8 textGroup); + void SetTextRepeatId(uint8 textGroup, uint8 id); + void ClearTextRepeatGroup(uint8 textGroup); + bool IsFreeToMove(); static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000; static constexpr uint32 MOVE_BACKWARDS_CHECK_INTERVAL = 2000; @@ -519,6 +527,8 @@ private: Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing + CreatureTextRepeatGroup m_textRepeat; + bool _isMissingSwimmingFlagOutOfCombat; uint32 m_assistanceTimer; diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index c471c7815..0a69981cd 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -83,7 +83,7 @@ void CreatureTextMgr::LoadCreatureTexts() uint32 oldMSTime = getMSTime(); mTextMap.clear(); // for reload case - mTextRepeatMap.clear(); //reset all currently used temp texts + //all currently used temp texts are NOT reset WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEXT); PreparedQueryResult result = WorldDatabase.Query(stmt); @@ -218,7 +218,7 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject } CreatureTextGroup const& textGroupContainer = itr->second; //has all texts in the group - CreatureTextRepeatIds repeatGroup = GetRepeatGroup(source, textGroup);//has all textIDs from the group that were already said + CreatureTextRepeatIds repeatGroup = source->GetTextRepeatGroup(textGroup);//has all textIDs from the group that were already said CreatureTextGroup tempGroup;//will use this to talk after sorting repeatGroup for (CreatureTextGroup::const_iterator giter = textGroupContainer.begin(); giter != textGroupContainer.end(); ++giter) @@ -227,52 +227,14 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject if (tempGroup.empty()) { - CreatureTextRepeatMap::iterator mapItr = mTextRepeatMap.find(source->GetGUID()); - if (mapItr != mTextRepeatMap.end()) - { - CreatureTextRepeatGroup::iterator groupItr = mapItr->second.find(textGroup); - groupItr->second.clear(); - } - + source->ClearTextRepeatGroup(textGroup); tempGroup = textGroupContainer; } - uint8 count = 0; - float lastChance = -1; - bool isEqualChanced = true; - - float totalChance = 0; - - for (CreatureTextGroup::const_iterator iter = tempGroup.begin(); iter != tempGroup.end(); ++iter) + auto iter = Acore::Containers::SelectRandomWeightedContainerElement(tempGroup, [](CreatureTextEntry const& t) -> double { - if (lastChance >= 0 && lastChance != iter->probability) - isEqualChanced = false; - - lastChance = iter->probability; - totalChance += iter->probability; - ++count; - } - - int32 offset = -1; - if (!isEqualChanced) - { - for (CreatureTextGroup::const_iterator iter = tempGroup.begin(); iter != tempGroup.end(); ++iter) - { - uint32 chance = uint32(iter->probability); - uint32 r = urand(0, 100); - ++offset; - if (r <= chance) - break; - } - } - - uint32 pos = 0; - if (isEqualChanced || offset < 0) - pos = urand(0, count - 1); - else if (offset >= 0) - pos = offset; - - CreatureTextGroup::const_iterator iter = tempGroup.begin() + pos; + return t.probability; + }); ChatMsg finalType = (msgType == CHAT_MSG_ADDON) ? iter->type : msgType; Language finalLang = (language == LANG_ADDON) ? iter->lang : language; @@ -301,9 +263,8 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject CreatureTextBuilder builder(finalSource, finalSource->getGender(), finalType, iter->group, iter->id, finalLang, target); SendChatPacket(finalSource, builder, finalType, target, range, teamId, gmOnly); } - if (isEqualChanced || (!isEqualChanced && totalChance == 100.0f)) - SetRepeatId(source, textGroup, iter->id); + source->SetTextRepeatId(textGroup, iter->id); return iter->duration; } @@ -410,34 +371,6 @@ void CreatureTextMgr::SendEmote(Unit* source, uint32 emote) source->HandleEmoteCommand(emote); } -void CreatureTextMgr::SetRepeatId(Creature* source, uint8 textGroup, uint8 id) -{ - if (!source) - return; - - CreatureTextRepeatIds& repeats = mTextRepeatMap[source->GetGUID()][textGroup]; - if (std::find(repeats.begin(), repeats.end(), id) == repeats.end()) - repeats.push_back(id); - else - LOG_ERROR("sql.sql", "CreatureTextMgr: TextGroup {} for Creature {} ({}), id {} already added", - uint32(textGroup), source->GetName(), source->GetGUID().ToString(), uint32(id)); -} - -CreatureTextRepeatIds CreatureTextMgr::GetRepeatGroup(Creature* source, uint8 textGroup) -{ - ASSERT(source);//should never happen - CreatureTextRepeatIds ids; - - CreatureTextRepeatMap::const_iterator mapItr = mTextRepeatMap.find(source->GetGUID()); - if (mapItr != mTextRepeatMap.end()) - { - CreatureTextRepeatGroup::const_iterator groupItr = (*mapItr).second.find(textGroup); - if (groupItr != mapItr->second.end()) - ids = groupItr->second; - } - return ids; -} - bool CreatureTextMgr::TextExist(uint32 sourceEntry, uint8 textGroup) { if (!sourceEntry) diff --git a/src/server/game/Texts/CreatureTextMgr.h b/src/server/game/Texts/CreatureTextMgr.h index d84d91c8d..569de9586 100644 --- a/src/server/game/Texts/CreatureTextMgr.h +++ b/src/server/game/Texts/CreatureTextMgr.h @@ -77,11 +77,6 @@ typedef std::unordered_map CreatureTextMap; // a typedef std::map LocaleCreatureTextMap; -//used for handling non-repeatable random texts -typedef std::vector CreatureTextRepeatIds; -typedef std::unordered_map CreatureTextRepeatGroup; -typedef std::unordered_map CreatureTextRepeatMap;//guid based - class CreatureTextMgr { CreatureTextMgr() { } @@ -105,14 +100,10 @@ public: template void SendChatPacket(WorldObject* source, Builder const& builder, ChatMsg msgType, WorldObject const* target = nullptr, CreatureTextRange range = TEXT_RANGE_NORMAL, TeamId teamId = TEAM_NEUTRAL, bool gmOnly = false) const; private: - CreatureTextRepeatIds GetRepeatGroup(Creature* source, uint8 textGroup); - void SetRepeatId(Creature* source, uint8 textGroup, uint8 id); - void SendNonChatPacket(WorldObject* source, WorldPacket const* data, ChatMsg msgType, WorldObject const* target, CreatureTextRange range, TeamId teamId, bool gmOnly) const; float GetRangeForChatType(ChatMsg msgType) const; CreatureTextMap mTextMap; - CreatureTextRepeatMap mTextRepeatMap; LocaleCreatureTextMap mLocaleTextMap; };