diff options
Diffstat (limited to 'src/server/game')
149 files changed, 10601 insertions, 7111 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index e808f91db55..b6d15a9632c 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -181,7 +181,7 @@ void PetAI::UpdateAI(uint32 diff) } } - if (spellInfo->HasEffect(SPELL_EFFECT_JUMP_DEST)) + if (spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_JUMP_DEST)) { if (!spellUsed) delete spell; diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 33772c2c165..a9d428a0489 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -62,16 +62,16 @@ void UnitAI::DoMeleeAttackIfReady() } } -bool UnitAI::DoSpellAttackIfReady(uint32 spell) +bool UnitAI::DoSpellAttackIfReady(uint32 spellId) { if (me->HasUnitState(UNIT_STATE_CASTING) || !me->isAttackReady()) return true; - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) { if (me->IsWithinCombatRange(me->GetVictim(), spellInfo->GetMaxRange(false))) { - me->CastSpell(me->GetVictim(), spell, false); + me->CastSpell(me->GetVictim(), spellInfo, TRIGGERED_NONE); me->resetAttackTimer(); return true; } @@ -90,40 +90,6 @@ void UnitAI::SelectTargetList(std::list<Unit*>& targetList, uint32 num, SelectAg SelectTargetList(targetList, DefaultTargetSelector(me, dist, playerOnly, aura), num, targetType); } -float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool positive) -{ - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - return spellInfo ? spellInfo->GetMaxRange(positive) : 0; -} - -void UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid) -{ - if (me->IsInCombat()) - { - ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList(); - for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) - { - if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) - if (unit->GetTypeId() == TYPEID_PLAYER) - me->AddAura(spellid, unit); - } - } -} - -void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered) -{ - if (me->IsInCombat()) - { - ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList(); - for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) - { - if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) - if (unit->GetTypeId() == TYPEID_PLAYER) - me->CastSpell(unit, spellid, triggered); - } - } -} - void UnitAI::DoCast(uint32 spellId) { Unit* target = NULL; @@ -227,9 +193,12 @@ void UnitAI::FillAISpellInfo() UPDATE_TARGET(AITARGET_SELF) else { - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - uint32 targetType = spellInfo->Effects[j].TargetA.GetTarget(); + if (!effect) + continue; + + uint32 targetType = effect->TargetA.GetTarget(); if (targetType == TARGET_UNIT_TARGET_ENEMY || targetType == TARGET_DEST_TARGET_ENEMY) @@ -237,7 +206,7 @@ void UnitAI::FillAISpellInfo() else if (targetType == TARGET_UNIT_DEST_AREA_ENEMY) UPDATE_TARGET(AITARGET_ENEMY) - if (spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA) + if (effect->Effect == SPELL_EFFECT_APPLY_AURA) { if (targetType == TARGET_UNIT_TARGET_ENEMY) UPDATE_TARGET(AITARGET_DEBUFF) @@ -282,7 +251,7 @@ void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) } SpellTargetSelector::SpellTargetSelector(Unit* caster, uint32 spellId) : - _caster(caster), _spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(sSpellMgr->GetSpellInfo(spellId), caster)) + _caster(caster), _spellInfo(sSpellMgr->GetSpellInfo(spellId)) { ASSERT(_spellInfo); } diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 5d67c9546aa..79ba8cbdbbc 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -238,17 +238,13 @@ class UnitAI void AttackStartCaster(Unit* victim, float dist); - void DoAddAuraToAllHostilePlayers(uint32 spellid); void DoCast(uint32 spellId); void DoCast(Unit* victim, uint32 spellId, bool triggered = false); - void DoCastToAllHostilePlayers(uint32 spellid, bool triggered = false); void DoCastVictim(uint32 spellId, bool triggered = false); void DoCastAOE(uint32 spellId, bool triggered = false); - float DoGetSpellMaxRange(uint32 spellId, bool positive = false); - void DoMeleeAttackIfReady(); - bool DoSpellAttackIfReady(uint32 spell); + bool DoSpellAttackIfReady(uint32 spellId); static AISpellInfoType* AISpellInfo; static void FillAISpellInfo(); diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 5bf3c41df41..6d8e5d67ebb 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -282,9 +282,9 @@ struct ScriptedAI : public CreatureAI { switch (_difficulty) { - case DUNGEON_DIFFICULTY_NORMAL: + case DIFFICULTY_NORMAL: return normal5; - case DUNGEON_DIFFICULTY_HEROIC: + case DIFFICULTY_HEROIC: return heroic10; default: break; @@ -298,9 +298,9 @@ struct ScriptedAI : public CreatureAI { switch (_difficulty) { - case RAID_DIFFICULTY_10MAN_NORMAL: + case DIFFICULTY_10_N: return normal10; - case RAID_DIFFICULTY_25MAN_NORMAL: + case DIFFICULTY_25_N: return normal25; default: break; @@ -314,13 +314,13 @@ struct ScriptedAI : public CreatureAI { switch (_difficulty) { - case RAID_DIFFICULTY_10MAN_NORMAL: + case DIFFICULTY_10_N: return normal10; - case RAID_DIFFICULTY_25MAN_NORMAL: + case DIFFICULTY_25_N: return normal25; - case RAID_DIFFICULTY_10MAN_HEROIC: + case DIFFICULTY_10_HC: return heroic10; - case RAID_DIFFICULTY_25MAN_HEROIC: + case DIFFICULTY_25_HC: return heroic25; default: break; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index cc7864f1f4e..d1a590e24b1 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -823,13 +823,13 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) return false; SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellInfo->Effects[j].IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellInfo->Effects[j].IsEffect(SPELL_EFFECT_KILL_CREDIT2)) + if (effect && (effect->IsEffect(SPELL_EFFECT_KILL_CREDIT) || effect->IsEffect(SPELL_EFFECT_KILL_CREDIT2))) { - if (spellInfo->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER) + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER) TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: %u targetA: %u - targetB: %u) has invalid target for this Action", - e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.cast.spell, spellInfo->Effects[j].TargetA.GetTarget(), spellInfo->Effects[j].TargetB.GetTarget()); + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.cast.spell, effect->TargetA.GetTarget(), effect->TargetB.GetTarget()); } } break; @@ -1277,19 +1277,22 @@ void SmartAIMgr::LoadHelperStores() if (!spellInfo) continue; - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellInfo->Effects[j].IsEffect(SPELL_EFFECT_SUMMON)) - SummonCreatureSpellStore.insert(std::make_pair(uint32(spellInfo->Effects[j].MiscValue), std::make_pair(i, SpellEffIndex(j)))); + if (!effect) + continue; + + if (effect->IsEffect(SPELL_EFFECT_SUMMON)) + SummonCreatureSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(i, SpellEffIndex(effect->EffectIndex)))); - else if (spellInfo->Effects[j].IsEffect(SPELL_EFFECT_SUMMON_OBJECT_WILD)) - SummonGameObjectSpellStore.insert(std::make_pair(uint32(spellInfo->Effects[j].MiscValue), std::make_pair(i, SpellEffIndex(j)))); + else if (effect->IsEffect(SPELL_EFFECT_SUMMON_OBJECT_WILD)) + SummonGameObjectSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(i, SpellEffIndex(effect->EffectIndex)))); - else if (spellInfo->Effects[j].IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellInfo->Effects[j].IsEffect(SPELL_EFFECT_KILL_CREDIT2)) - KillCreditSpellStore.insert(std::make_pair(uint32(spellInfo->Effects[j].MiscValue), std::make_pair(i, SpellEffIndex(j)))); + else if (effect->IsEffect(SPELL_EFFECT_KILL_CREDIT) || effect->IsEffect(SPELL_EFFECT_KILL_CREDIT2)) + KillCreditSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(i, SpellEffIndex(effect->EffectIndex)))); - else if (spellInfo->Effects[j].IsEffect(SPELL_EFFECT_CREATE_ITEM)) - CreateItemSpellStore.insert(std::make_pair(uint32(spellInfo->Effects[j].ItemType), std::make_pair(i, SpellEffIndex(j)))); + else if (effect->IsEffect(SPELL_EFFECT_CREATE_ITEM)) + CreateItemSpellStore.insert(std::make_pair(uint32(effect->ItemType), std::make_pair(i, SpellEffIndex(effect->EffectIndex)))); } } diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 55f19d1612e..8b2365079c7 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -456,7 +456,7 @@ void AccountMgr::LoadRBAC() while (result->NextRow()); TC_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading default permissions"); - result = LoginDatabase.Query("SELECT secId, permissionId FROM rbac_default_permissions ORDER BY secId ASC"); + result = LoginDatabase.PQuery("SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = %u OR realmId = -1) ORDER BY secId ASC", realmHandle.Index); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty."); diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 650bd998028..bb347113e60 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -595,7 +595,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_SMART_SCRIPTS = 689, RBAC_PERM_COMMAND_RELOAD_SPELL_REQUIRED = 690, RBAC_PERM_COMMAND_RELOAD_SPELL_AREA = 691, - RBAC_PERM_COMMAND_RELOAD_SPELL_BONUS_DATA = 692, + // REUSE RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP = 693, RBAC_PERM_COMMAND_RELOAD_SPELL_LEARN_SPELL = 694, RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695, diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 8fe96be26fb..35fb5ec4d76 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -138,13 +138,14 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id); return false; } - if (aura.effect_idx >= 3) + SpellEffectInfo const* effect = spellEntry->GetEffect(DIFFICULTY_NONE, aura.effect_idx); + if (!effect) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell effect index in value2 (%u), ignored.", criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx); return false; } - if (!spellEntry->Effects[aura.effect_idx].ApplyAuraName) + if (!effect->ApplyAuraName) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has non-aura spell effect (ID: %u Effect: %u), ignores.", criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx); @@ -2533,7 +2534,7 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac if (!achievIdForDungeon[j][2]) break; // for } - else if (referencePlayer->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL) + else if (referencePlayer->GetDungeonDifficulty() == DIFFICULTY_NORMAL) { // dungeon in normal mode accepted if (!achievIdForDungeon[j][1]) @@ -2882,6 +2883,7 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 41 if (!unit || unit->GetZoneId() != reqValue) return false; + break; case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW: // 46 if (!unit || unit->GetHealthPct() >= reqValue) return false; @@ -3227,7 +3229,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() uint32 dataType = fields[1].GetUInt8(); std::string scriptName = fields[4].GetString(); uint32 scriptId = 0; - if (scriptName.length()) // not empty + if (!scriptName.empty()) { if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has ScriptName set for non-scripted data type (Entry: %u, type %u), useless data.", criteria_id, dataType); diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 7f9359053a1..49bd25e6252 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -70,7 +70,9 @@ namespace Trinity private: void do_helper(WorldPacket& data, char const* text) { - ChatHandler::BuildChatPacket(data, _msgtype, LANG_UNIVERSAL, _source, _source, text); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, _msgtype, LANG_UNIVERSAL, _source, _source, text); + data = *packet.Write(); } ChatMsg _msgtype; @@ -94,7 +96,9 @@ namespace Trinity char str[2048]; snprintf(str, 2048, text, arg1str, arg2str); - ChatHandler::BuildChatPacket(data, _msgtype, LANG_UNIVERSAL, _source, _source, str); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, _msgtype, LANG_UNIVERSAL, _source, _source, str); + data = *packet.Write(); } private: @@ -507,7 +511,7 @@ inline void Battleground::_ProcessJoin(uint32 diff) StartingEventOpenDoors(); - SendWarningToAll(StartMessageIds[BG_STARTING_EVENT_FOURTH]); + SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_RAID_BOSS_EMOTE); SetStatus(STATUS_IN_PROGRESS); SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FOURTH]); @@ -1688,32 +1692,6 @@ void Battleground::PSendMessageToAll(uint32 entry, ChatMsg type, Player const* s va_end(ap); } -void Battleground::SendWarningToAll(uint32 entry, ...) -{ - if (!entry) - return; - - std::map<uint32, WorldPacket> localizedPackets; - for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) - if (Player* player = _GetPlayer(itr, "SendWarningToAll")) - { - if (localizedPackets.find(player->GetSession()->GetSessionDbLocaleIndex()) == localizedPackets.end()) - { - char const* format = sObjectMgr->GetTrinityString(entry, player->GetSession()->GetSessionDbLocaleIndex()); - - char str[1024]; - va_list ap; - va_start(ap, entry); - vsnprintf(str, 1024, format, ap); - va_end(ap); - - ChatHandler::BuildChatPacket(localizedPackets[player->GetSession()->GetSessionDbLocaleIndex()], CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, NULL, NULL, str); - } - - player->SendDirectMessage(&localizedPackets[player->GetSession()->GetSessionDbLocaleIndex()]); - } -} - void Battleground::SendMessage2ToAll(uint32 entry, ChatMsg type, Player const* source, uint32 arg1, uint32 arg2) { Trinity::Battleground2ChatBuilder bg_builder(type, entry, source, arg1, arg2); diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 5bd18977c3d..05873f5f2fc 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -365,7 +365,6 @@ class Battleground virtual void EndBattleground(uint32 winner); void BlockMovement(Player* player); - void SendWarningToAll(uint32 entry, ...); void SendMessageToAll(uint32 entry, ChatMsg type, Player const* source = NULL); void PSendMessageToAll(uint32 entry, ChatMsg type, Player const* source, ...); diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index ced77d06514..ee5b14a7f1c 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -894,7 +894,7 @@ void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid data->WriteBit(guid[3]); data->WriteBit(0); // unk data->WriteBit(guid[5]); - data->WriteBit(0); // unk + data->WriteBit(1); // hide battleground list window data->FlushBits(); diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 65f07b625e1..a316c8630dc 100644 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -31,18 +31,16 @@ Channel::Channel(std::string const& name, uint32 channelId, uint32 team): _IsSaved(false), _flags(0), _channelId(channelId), - _Team(team), - _ownerGUID(), - _name(name), - _password("") + _team(team), + _name(name) { // set special flags if built-in channel if (ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(channelId)) // check whether it's a built-in channel { - _announce = false; // no join/leave announces - _ownership = false; // no ownership handout + _announce = false; // no join/leave announces + _ownership = false; // no ownership handout - _flags |= CHANNEL_FLAG_GENERAL; // for all built-in channels + _flags |= CHANNEL_FLAG_GENERAL; // for all built-in channels if (ch->Flags & CHANNEL_DBC_FLAG_TRADE) // for trade channel _flags |= CHANNEL_FLAG_TRADE; @@ -62,31 +60,31 @@ Channel::Channel(std::string const& name, uint32 channelId, uint32 team): // If storing custom channels in the db is enabled either load or save the channel if (sWorld->getBoolConfig(CONFIG_PRESERVE_CUSTOM_CHANNELS)) { - PreparedStatement *stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHANNEL); - stmt->setString(0, name); - stmt->setUInt32(1, _Team); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHANNEL); + stmt->setString(0, _name); + stmt->setUInt32(1, _team); PreparedQueryResult result = CharacterDatabase.Query(stmt); - if (result) //load + if (result) // load { Field* fields = result->Fetch(); _announce = fields[0].GetBool(); _ownership = fields[1].GetBool(); _password = fields[2].GetString(); - const char* db_BannedList = fields[3].GetCString(); + std::string bannedList = fields[3].GetString(); - if (db_BannedList) + if (!bannedList.empty()) { - Tokenizer tokens(db_BannedList, ' '); + Tokenizer tokens(bannedList, ' '); for (Tokenizer::const_iterator i = tokens.begin(); i != tokens.end(); ++i) { std::string bannedGuidStr(*i); - ObjectGuid banned_guid; - banned_guid.SetRawValue(uint64(strtoull(bannedGuidStr.substr(0, 16).c_str(), NULL, 16)), uint64(strtoull(bannedGuidStr.substr(16).c_str(), NULL, 16))); - if (!banned_guid.IsEmpty()) + ObjectGuid bannedGuid; + bannedGuid.SetRawValue(uint64(strtoull(bannedGuidStr.substr(0, 16).c_str(), nullptr, 16)), uint64(strtoull(bannedGuidStr.substr(16).c_str(), nullptr, 16))); + if (!bannedGuid.IsEmpty()) { - TC_LOG_DEBUG("chat.system", "Channel(%s) loaded bannedStore %s", name.c_str(), banned_guid.ToString().c_str()); - bannedStore.insert(banned_guid); + TC_LOG_DEBUG("chat.system", "Channel (%s) loaded bannedStore %s", _name.c_str(), bannedGuid.ToString().c_str()); + _bannedStore.insert(bannedGuid); } } } @@ -94,10 +92,10 @@ Channel::Channel(std::string const& name, uint32 channelId, uint32 team): else // save { stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHANNEL); - stmt->setString(0, name); - stmt->setUInt32(1, _Team); + stmt->setString(0, _name); + stmt->setUInt32(1, _team); CharacterDatabase.Execute(stmt); - TC_LOG_DEBUG("chat.system", "Channel(%s) saved in database", name.c_str()); + TC_LOG_DEBUG("chat.system", "Channel (%s) saved in database", _name.c_str()); } _IsSaved = true; @@ -110,22 +108,19 @@ void Channel::UpdateChannelInDB() const if (_IsSaved) { std::ostringstream banlist; - BannedContainer::const_iterator iter; - for (iter = bannedStore.begin(); iter != bannedStore.end(); ++iter) - banlist << *iter << ' '; - - std::string banListStr = banlist.str(); + for (ObjectGuid const& guid : _bannedStore) + banlist << guid << ' '; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL); stmt->setBool(0, _announce); stmt->setBool(1, _ownership); stmt->setString(2, _password); - stmt->setString(3, banListStr); + stmt->setString(3, banlist.str()); stmt->setString(4, _name); - stmt->setUInt32(5, _Team); + stmt->setUInt32(5, _team); CharacterDatabase.Execute(stmt); - TC_LOG_DEBUG("chat.system", "Channel(%s) updated in database", _name.c_str()); + TC_LOG_DEBUG("chat.system", "Channel (%s) updated in database", _name.c_str()); } } @@ -133,7 +128,7 @@ void Channel::UpdateChannelUseageInDB() const { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_USAGE); stmt->setString(0, _name); - stmt->setUInt32(1, _Team); + stmt->setUInt32(1, _team); CharacterDatabase.Execute(stmt); } @@ -151,32 +146,32 @@ void Channel::CleanOldChannelsInDB() void Channel::JoinChannel(Player* player, std::string const& pass) { - ObjectGuid guid = player->GetGUID(); + ObjectGuid const& guid = player->GetGUID(); if (IsOn(guid)) { // Do not send error message for built-in channels if (!IsConstant()) { - WorldPacket data; - MakePlayerAlreadyMember(&data, guid); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerAlreadyMember(notify, guid); + player->SendDirectMessage(notify.Write()); } return; } if (IsBanned(guid)) { - WorldPacket data; - MakeBanned(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeBanned(notify); + player->SendDirectMessage(notify.Write()); return; } if (!_password.empty() && pass != _password) { - WorldPacket data; - MakeWrongPassword(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeWrongPassword(notify); + player->SendDirectMessage(notify.Write()); return; } @@ -185,9 +180,9 @@ void Channel::JoinChannel(Player* player, std::string const& pass) AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) && //FIXME: Move to RBAC player->GetGroup()) { - WorldPacket data; - MakeNotInLfg(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotInLfg(notify); + player->SendDirectMessage(notify.Write()); return; } @@ -195,73 +190,90 @@ void Channel::JoinChannel(Player* player, std::string const& pass) if (_announce && !player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL)) { - WorldPacket data; - MakeJoined(&data, guid); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify notify; + MakeJoined(notify, guid); + SendToAll(notify.Write()); } - PlayerInfo pinfo; - pinfo.player = guid; - pinfo.flags = MEMBER_FLAG_NONE; - playersStore[guid] = pinfo; + PlayerInfo playerInfo; + playerInfo.PlayerGuid = guid; + _playersStore[guid] = playerInfo; - WorldPacket data; - MakeYouJoined(&data); - SendToOne(&data, guid); + /* + WorldPackets::Channel::ChannelNotify notify; + MakeYouJoined(notify); + player->SendDirectMessage(notify.Write()); + */ - JoinNotify(guid); + WorldPackets::Channel::ChannelNotifyJoined notify; + //notify.ChannelWelcomeMsg = ""; + notify.ChatChannelID = _channelId; + //notify.InstanceID = 0; + notify._ChannelFlags = _flags; + notify._Channel = _name; + player->SendDirectMessage(notify.Write()); + + JoinNotify(player); // Custom channel handling if (!IsConstant()) { // Update last_used timestamp in db - if (!playersStore.empty()) + if (!_playersStore.empty()) UpdateChannelUseageInDB(); // If the channel has no owner yet and ownership is allowed, set the new owner. - if (!_ownerGUID && _ownership) + if (_ownerGUID.IsEmpty() && _ownership) { - SetOwner(guid, playersStore.size() > 1); - playersStore[guid].SetModerator(true); + SetOwner(guid, _playersStore.size() > 1); + _playersStore[guid].SetModerator(true); } } } void Channel::LeaveChannel(Player* player, bool send) { - ObjectGuid guid = player->GetGUID(); + ObjectGuid const& guid = player->GetGUID(); if (!IsOn(guid)) { if (send) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); } return; } + player->LeftChannel(this); + if (send) { - WorldPacket data; - MakeYouLeft(&data); - SendToOne(&data, guid); - player->LeftChannel(this); - data.clear(); + /* + WorldPackets::Channel::ChannelNotify notify; + MakeYouLeft(notify); + player->SendDirectMessage(notify.Write()); + */ + + WorldPackets::Channel::ChannelNotifyLeft notify; + notify.Channel = _name; + notify.ChatChannelID = 0; + //notify.Suspended = false; + player->SendDirectMessage(notify.Write()); } - bool changeowner = playersStore[guid].IsOwner(); + bool changeowner = _playersStore[guid].IsOwner(); - playersStore.erase(guid); + _playersStore.erase(guid); if (_announce && !player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL)) { - WorldPacket data; - MakeLeft(&data, guid); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify notify; + MakeLeft(notify, guid); + SendToAll(notify.Write()); } - LeaveNotify(guid); + LeaveNotify(player); if (!IsConstant()) { @@ -269,10 +281,10 @@ void Channel::LeaveChannel(Player* player, bool send) UpdateChannelUseageInDB(); // If the channel owner left and there are still playersStore inside, pick a new owner - if (changeowner && _ownership && !playersStore.empty()) + if (changeowner && _ownership && !_playersStore.empty()) { - ObjectGuid newowner = playersStore.begin()->second.player; - playersStore[newowner].SetModerator(true); + ObjectGuid const& newowner = _playersStore.begin()->second.PlayerGuid; + _playersStore[newowner].SetModerator(true); SetOwner(newowner); } } @@ -280,21 +292,21 @@ void Channel::LeaveChannel(Player* player, bool send) void Channel::KickOrBan(Player const* player, std::string const& badname, bool ban) { - ObjectGuid good = player->GetGUID(); + ObjectGuid const& good = player->GetGUID(); if (!IsOn(good)) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, good); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); return; } - if (!playersStore[good].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) + if (!_playersStore[good].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, good); + WorldPackets::Channel::ChannelNotify notify; + MakeNotModerator(notify); + player->SendDirectMessage(notify.Write()); return; } @@ -302,9 +314,9 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b ObjectGuid victim = bad ? bad->GetGUID() : ObjectGuid::Empty; if (!victim || !IsOn(victim)) { - WorldPacket data; - MakePlayerNotFound(&data, badname); - SendToOne(&data, good); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerNotFound(notify, badname); + player->SendDirectMessage(notify.Write()); return; } @@ -312,154 +324,152 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && changeowner && good != _ownerGUID) { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, good); + WorldPackets::Channel::ChannelNotify notify; + MakeNotOwner(notify); + player->SendDirectMessage(notify.Write()); return; } if (ban && !IsBanned(victim)) { - bannedStore.insert(victim); + _bannedStore.insert(victim); UpdateChannelInDB(); if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL)) { - WorldPacket data; - MakePlayerBanned(&data, victim, good); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerBanned(notify, victim, good); + SendToAll(notify.Write()); } } else if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL)) { - WorldPacket data; - MakePlayerKicked(&data, victim, good); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerKicked(notify, victim, good); + SendToAll(notify.Write()); } - playersStore.erase(victim); + _playersStore.erase(victim); bad->LeftChannel(this); - if (changeowner && _ownership && !playersStore.empty()) + if (changeowner && _ownership && !_playersStore.empty()) { - ObjectGuid newowner = good; - playersStore[newowner].SetModerator(true); - SetOwner(newowner); + _playersStore[good].SetModerator(true); + SetOwner(good); } } void Channel::UnBan(Player const* player, std::string const& badname) { - ObjectGuid good = player->GetGUID(); + ObjectGuid const& good = player->GetGUID(); if (!IsOn(good)) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, good); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); return; } - if (!playersStore[good].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) + if (!_playersStore[good].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, good); + WorldPackets::Channel::ChannelNotify notify; + MakeNotModerator(notify); + player->SendDirectMessage(notify.Write()); return; } Player* bad = ObjectAccessor::FindConnectedPlayerByName(badname); ObjectGuid victim = bad ? bad->GetGUID() : ObjectGuid::Empty; - if (!victim || !IsBanned(victim)) + if (victim.IsEmpty() || !IsBanned(victim)) { - WorldPacket data; - MakePlayerNotFound(&data, badname); - SendToOne(&data, good); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerNotFound(notify, badname); + player->SendDirectMessage(notify.Write()); return; } - bannedStore.erase(victim); + _bannedStore.erase(victim); - WorldPacket data; - MakePlayerUnbanned(&data, victim, good); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerUnbanned(notify, victim, good); + SendToAll(notify.Write()); UpdateChannelInDB(); } void Channel::Password(Player const* player, std::string const& pass) { - ObjectGuid guid = player->GetGUID(); + ObjectGuid const& guid = player->GetGUID(); - ChatHandler chat(player->GetSession()); if (!IsOn(guid)) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); return; } - if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) + if (!_playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotModerator(notify); + player->SendDirectMessage(notify.Write()); return; } _password = pass; - WorldPacket data; - MakePasswordChanged(&data, guid); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify notify; + MakePasswordChanged(notify, guid); + SendToAll(notify.Write()); UpdateChannelInDB(); } void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bool set) { - ObjectGuid guid = player->GetGUID(); + ObjectGuid const& guid = player->GetGUID(); if (!IsOn(guid)) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); return; } - if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) + if (!_playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotModerator(notify); + player->SendDirectMessage(notify.Write()); return; } - if (guid == _ownerGUID && std::string(p2n) == player->GetName() && mod) + if (guid == _ownerGUID && p2n == player->GetName() && mod) return; Player* newp = ObjectAccessor::FindConnectedPlayerByName(p2n); ObjectGuid victim = newp ? newp->GetGUID() : ObjectGuid::Empty; - if (!victim || !IsOn(victim) || + if (victim.IsEmpty() || !IsOn(victim) || (player->GetTeam() != newp->GetTeam() && (!player->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) || !newp->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL)))) { - WorldPacket data; - MakePlayerNotFound(&data, p2n); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerNotFound(notify, p2n); + player->SendDirectMessage(notify.Write()); return; } if (_ownerGUID == victim && _ownerGUID != guid) { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotOwner(notify); + player->SendDirectMessage(notify.Write()); return; } @@ -471,21 +481,21 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo void Channel::SetOwner(Player const* player, std::string const& newname) { - ObjectGuid guid = player->GetGUID(); + ObjectGuid const& guid = player->GetGUID(); if (!IsOn(guid)) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); return; } if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && guid != _ownerGUID) { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotOwner(notify); + player->SendDirectMessage(notify.Write()); return; } @@ -497,55 +507,50 @@ void Channel::SetOwner(Player const* player, std::string const& newname) (!player->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) || !newp->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL)))) { - WorldPacket data; - MakePlayerNotFound(&data, newname); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerNotFound(notify, newname); + player->SendDirectMessage(notify.Write()); return; } - playersStore[victim].SetModerator(true); + _playersStore[victim].SetModerator(true); SetOwner(victim); } -void Channel::SendWhoOwner(ObjectGuid guid) +void Channel::SendWhoOwner(Player const* player) { - WorldPacket data; - if (IsOn(guid)) - MakeChannelOwner(&data); + WorldPackets::Channel::ChannelNotify notify; + if (IsOn(player->GetGUID())) + MakeChannelOwner(notify); else - MakeNotMember(&data); - SendToOne(&data, guid); + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); } void Channel::List(Player const* player) { - ObjectGuid guid = player->GetGUID(); - - if (!IsOn(guid)) + if (!IsOn(player->GetGUID())) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); return; } TC_LOG_DEBUG("chat.system", "SMSG_CHANNEL_LIST %s Channel: %s", player->GetSession()->GetPlayerInfo().c_str(), GetName().c_str()); - WorldPacket data(SMSG_CHANNEL_LIST, 1+(GetName().size()+1)+1+4+playersStore.size()*(8+1)); - data << uint8(1); // channel type? - data << GetName(); // channel name - data << uint8(GetFlags()); // channel flags? - - size_t pos = data.wpos(); - data << uint32(0); // size of list, placeholder + WorldPackets::Channel::ChannelListResponse list; + list._Display = true; /// always true? + list._Channel = GetName(); + list._ChannelFlags = GetFlags(); uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); - uint32 count = 0; - for (PlayerContainer::const_iterator i = playersStore.begin(); i != playersStore.end(); ++i) + list._Members.reserve(_playersStore.size()); + for (PlayerContainer::value_type const& i : _playersStore) { - Player* member = ObjectAccessor::FindConnectedPlayer(i->first); + Player* member = ObjectAccessor::FindConnectedPlayer(i.first); // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters // MODERATOR, GAME MASTER, ADMINISTRATOR can see all @@ -554,50 +559,46 @@ void Channel::List(Player const* player) member->GetSession()->GetSecurity() <= AccountTypes(gmLevelInWhoList)) && member->IsVisibleGloballyFor(player)) { - data << i->first; - data << uint8(i->second.flags); // flags seems to be changed... - ++count; + list._Members.emplace_back(i.second.PlayerGuid, GetVirtualRealmAddress(), i.second.GetFlags()); } } - data.put<uint32>(pos, count); - - SendToOne(&data, guid); + player->SendDirectMessage(list.Write()); } void Channel::Announce(Player const* player) { - ObjectGuid guid = player->GetGUID(); + ObjectGuid const& guid = player->GetGUID(); if (!IsOn(guid)) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); return; } - if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) + if (!_playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotModerator(notify); + player->SendDirectMessage(notify.Write()); return; } _announce = !_announce; - WorldPacket data; + WorldPackets::Channel::ChannelNotify notify; if (_announce) - MakeAnnouncementsOn(&data, guid); + MakeAnnouncementsOn(notify, guid); else - MakeAnnouncementsOff(&data, guid); - SendToAll(&data); + MakeAnnouncementsOff(notify, guid); + SendToAll(notify.Write()); UpdateChannelInDB(); } -void Channel::Say(ObjectGuid guid, std::string const& what, uint32 lang) +void Channel::Say(ObjectGuid const& guid, std::string const& what, uint32 lang) { if (what.empty()) return; @@ -608,55 +609,59 @@ void Channel::Say(ObjectGuid guid, std::string const& what, uint32 lang) if (!IsOn(guid)) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + SendToOne(notify.Write(), guid); return; } - if (playersStore[guid].IsMuted()) + if (_playersStore[guid].IsMuted()) { - WorldPacket data; - MakeMuted(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeMuted(notify); + SendToOne(notify.Write(), guid); return; } - WorldPacket data; + WorldPackets::Chat::Chat packet; if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) - ChatHandler::BuildChatPacket(data, CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, _name); + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, _name); else - ChatHandler::BuildChatPacket(data, CHAT_MSG_CHANNEL, Language(lang), guid, guid, what, 0, "", "", 0, false, _name); + { + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_CHANNEL, Language(lang), NULL, NULL, what, 0, _name); + packet.SenderGUID = guid; + packet.TargetGUID = guid; + } - SendToAll(&data, !playersStore[guid].IsModerator() ? guid : ObjectGuid::Empty); + SendToAll(packet.Write(), !_playersStore[guid].IsModerator() ? guid : ObjectGuid::Empty); } void Channel::Invite(Player const* player, std::string const& newname) { - ObjectGuid guid = player->GetGUID(); + ObjectGuid const& guid = player->GetGUID(); if (!IsOn(guid)) { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeNotMember(notify); + player->SendDirectMessage(notify.Write()); return; } Player* newp = ObjectAccessor::FindConnectedPlayerByName(newname); if (!newp || !newp->isGMVisible()) { - WorldPacket data; - MakePlayerNotFound(&data, newname); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerNotFound(notify, newname); + player->SendDirectMessage(notify.Write()); return; } if (IsBanned(newp->GetGUID())) { - WorldPacket data; - MakePlayerInviteBanned(&data, newname); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerInviteBanned(notify, newname); + player->SendDirectMessage(notify.Write()); return; } @@ -664,169 +669,167 @@ void Channel::Invite(Player const* player, std::string const& newname) (!player->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) || !newp->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL))) { - WorldPacket data; - MakeInviteWrongFaction(&data); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakeInviteWrongFaction(notify); + player->SendDirectMessage(notify.Write()); return; } if (IsOn(newp->GetGUID())) { - WorldPacket data; - MakePlayerAlreadyMember(&data, newp->GetGUID()); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerAlreadyMember(notify, newp->GetGUID()); + player->SendDirectMessage(notify.Write()); return; } if (!newp->GetSocial()->HasIgnore(guid)) { - WorldPacket data; - MakeInvite(&data, guid); - SendToOne(&data, newp->GetGUID()); - data.clear(); + WorldPackets::Channel::ChannelNotify notify; + MakeInvite(notify, guid); + newp->SendDirectMessage(notify.Write()); } - WorldPacket data; - MakePlayerInvited(&data, newp->GetName()); - SendToOne(&data, guid); + WorldPackets::Channel::ChannelNotify notify; + MakePlayerInvited(notify, newp->GetName()); + player->SendDirectMessage(notify.Write()); } -void Channel::SetOwner(ObjectGuid guid, bool exclaim) +void Channel::SetOwner(ObjectGuid const& guid, bool exclaim) { if (!_ownerGUID.IsEmpty()) { // [] will re-add player after it possible removed - PlayerContainer::iterator p_itr = playersStore.find(_ownerGUID); - if (p_itr != playersStore.end()) - p_itr->second.SetOwner(false); + PlayerContainer::iterator itr = _playersStore.find(_ownerGUID); + if (itr != _playersStore.end()) + itr->second.SetOwner(false); } _ownerGUID = guid; if (!_ownerGUID.IsEmpty()) { - uint8 oldFlag = GetPlayerFlags(_ownerGUID); - playersStore[_ownerGUID].SetModerator(true); - playersStore[_ownerGUID].SetOwner(true); + uint8 oldFlag = _playersStore[_ownerGUID].GetFlags(); + _playersStore[_ownerGUID].SetModerator(true); + _playersStore[_ownerGUID].SetOwner(true); - WorldPacket data; - MakeModeChange(&data, _ownerGUID, oldFlag); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify notify; + MakeModeChange(notify, _ownerGUID, oldFlag, _playersStore[_ownerGUID].GetFlags()); + SendToAll(notify.Write()); if (exclaim) { - MakeOwnerChanged(&data, _ownerGUID); - SendToAll(&data); + MakeOwnerChanged(notify, _ownerGUID); + SendToAll(notify.Write()); } UpdateChannelInDB(); } } -void Channel::SendToAll(WorldPacket* data, ObjectGuid guid) +void Channel::SendToAll(WorldPacket const* data, ObjectGuid const& guid) { - for (PlayerContainer::const_iterator i = playersStore.begin(); i != playersStore.end(); ++i) - if (Player* player = ObjectAccessor::FindConnectedPlayer(i->first)) - if (!guid || !player->GetSocial()->HasIgnore(guid)) - player->GetSession()->SendPacket(data); + for (PlayerContainer::value_type const& i : _playersStore) + if (Player* player = ObjectAccessor::FindConnectedPlayer(i.first)) + if (guid.IsEmpty() || !player->GetSocial()->HasIgnore(guid)) + player->SendDirectMessage(data); } -void Channel::SendToAllButOne(WorldPacket* data, ObjectGuid who) +void Channel::SendToAllButOne(WorldPacket const* data, ObjectGuid const& who) { - for (PlayerContainer::const_iterator i = playersStore.begin(); i != playersStore.end(); ++i) - if (i->first != who) - if (Player* player = ObjectAccessor::FindConnectedPlayer(i->first)) - player->GetSession()->SendPacket(data); + for (PlayerContainer::value_type const& i : _playersStore) + if (i.first != who) + if (Player* player = ObjectAccessor::FindConnectedPlayer(i.first)) + player->SendDirectMessage(data); } -void Channel::SendToOne(WorldPacket* data, ObjectGuid who) +void Channel::SendToOne(WorldPacket const* data, ObjectGuid const& who) { if (Player* player = ObjectAccessor::FindConnectedPlayer(who)) - player->GetSession()->SendPacket(data); + player->SendDirectMessage(data); } -void Channel::Voice(ObjectGuid /*guid1*/, ObjectGuid /*guid2*/) +void Channel::Voice(ObjectGuid const& /*guid1*/, ObjectGuid const& /*guid2*/) { } -void Channel::DeVoice(ObjectGuid /*guid1*/, ObjectGuid /*guid2*/) +void Channel::DeVoice(ObjectGuid const& /*guid1*/, ObjectGuid const& /*guid2*/) { } -void Channel::MakeNotifyPacket(WorldPacket* data, uint8 notify_type) +void Channel::MakeNotifyPacket(WorldPackets::Channel::ChannelNotify& data, uint8 notifyType) { - data->Initialize(SMSG_CHANNEL_NOTIFY, 1 + _name.size()); - *data << uint8(notify_type); - *data << _name; + data.Type = notifyType; + data._Channel = _name; } -void Channel::MakeJoined(WorldPacket* data, ObjectGuid guid) +void Channel::MakeJoined(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_JOINED_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakeLeft(WorldPacket* data, ObjectGuid guid) +void Channel::MakeLeft(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_LEFT_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakeYouJoined(WorldPacket* data) +void Channel::MakeYouJoined(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_YOU_JOINED_NOTICE); - *data << uint8(GetFlags()); - *data << uint32(GetChannelId()); - *data << uint32(0); + //*data << uint8(GetFlags()); + data.ChatChannelID = GetChannelId(); + //*data << uint32(0); } -void Channel::MakeYouLeft(WorldPacket* data) +void Channel::MakeYouLeft(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_YOU_LEFT_NOTICE); - *data << uint32(GetChannelId()); - *data << uint8(IsConstant()); + data.ChatChannelID = GetChannelId(); + //*data << uint8(IsConstant()); } -void Channel::MakeWrongPassword(WorldPacket* data) +void Channel::MakeWrongPassword(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_WRONG_PASSWORD_NOTICE); } -void Channel::MakeNotMember(WorldPacket* data) +void Channel::MakeNotMember(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_NOT_MEMBER_NOTICE); } -void Channel::MakeNotModerator(WorldPacket* data) +void Channel::MakeNotModerator(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_NOT_MODERATOR_NOTICE); } -void Channel::MakePasswordChanged(WorldPacket* data, ObjectGuid guid) +void Channel::MakePasswordChanged(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_PASSWORD_CHANGED_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakeOwnerChanged(WorldPacket* data, ObjectGuid guid) +void Channel::MakeOwnerChanged(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_OWNER_CHANGED_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakePlayerNotFound(WorldPacket* data, std::string const& name) +void Channel::MakePlayerNotFound(WorldPackets::Channel::ChannelNotify& data, std::string const& name) { MakeNotifyPacket(data, CHAT_PLAYER_NOT_FOUND_NOTICE); - *data << name; + data.Sender = name; } -void Channel::MakeNotOwner(WorldPacket* data) +void Channel::MakeNotOwner(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_NOT_OWNER_NOTICE); } -void Channel::MakeChannelOwner(WorldPacket* data) +void Channel::MakeChannelOwner(WorldPackets::Channel::ChannelNotify& data) { std::string name; @@ -834,139 +837,140 @@ void Channel::MakeChannelOwner(WorldPacket* data) name = "PLAYER_NOT_FOUND"; MakeNotifyPacket(data, CHAT_CHANNEL_OWNER_NOTICE); - *data << ((IsConstant() || !_ownerGUID) ? "Nobody" : name); + data.Sender = ((IsConstant() || !_ownerGUID) ? "Nobody" : name); } -void Channel::MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags) +void Channel::MakeModeChange(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid, uint8 oldFlags, uint8 newFlags) { MakeNotifyPacket(data, CHAT_MODE_CHANGE_NOTICE); - *data << guid; - *data << uint8(oldflags); - *data << uint8(GetPlayerFlags(guid)); + data.SenderGuid = guid; + data.OldFlags = oldFlags; + data.NewFlags = newFlags; } -void Channel::MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid) +void Channel::MakeAnnouncementsOn(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_ON_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid) +void Channel::MakeAnnouncementsOff(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_OFF_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakeMuted(WorldPacket* data) +void Channel::MakeMuted(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_MUTED_NOTICE); } -void Channel::MakePlayerKicked(WorldPacket* data, ObjectGuid bad, ObjectGuid good) +void Channel::MakePlayerKicked(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& bad, ObjectGuid const& good) { MakeNotifyPacket(data, CHAT_PLAYER_KICKED_NOTICE); - *data << bad; - *data << good; + data.SenderGuid = good; + data.TargetGuid = bad; } -void Channel::MakeBanned(WorldPacket* data) +void Channel::MakeBanned(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_BANNED_NOTICE); } -void Channel::MakePlayerBanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good) +void Channel::MakePlayerBanned(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& bad, ObjectGuid const& good) { MakeNotifyPacket(data, CHAT_PLAYER_BANNED_NOTICE); - *data << bad; - *data << good; + data.SenderGuid = good; + data.TargetGuid = bad; } -void Channel::MakePlayerUnbanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good) +void Channel::MakePlayerUnbanned(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& bad, ObjectGuid const& good) { MakeNotifyPacket(data, CHAT_PLAYER_UNBANNED_NOTICE); - *data << bad; - *data << good; + data.SenderGuid = good; + data.TargetGuid = bad; } -void Channel::MakePlayerNotBanned(WorldPacket* data, const std::string &name) +void Channel::MakePlayerNotBanned(WorldPackets::Channel::ChannelNotify& data, std::string const& name) { MakeNotifyPacket(data, CHAT_PLAYER_NOT_BANNED_NOTICE); - *data << name; + data.Sender = name; } -void Channel::MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid) +void Channel::MakePlayerAlreadyMember(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_PLAYER_ALREADY_MEMBER_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakeInvite(WorldPacket* data, ObjectGuid guid) +void Channel::MakeInvite(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_INVITE_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakeInviteWrongFaction(WorldPacket* data) +void Channel::MakeInviteWrongFaction(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_INVITE_WRONG_FACTION_NOTICE); } -void Channel::MakeWrongFaction(WorldPacket* data) +void Channel::MakeWrongFaction(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_WRONG_FACTION_NOTICE); } -void Channel::MakeInvalidName(WorldPacket* data) +void Channel::MakeInvalidName(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_INVALID_NAME_NOTICE); } -void Channel::MakeNotModerated(WorldPacket* data) +void Channel::MakeNotModerated(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_NOT_MODERATED_NOTICE); } -void Channel::MakePlayerInvited(WorldPacket* data, const std::string& name) +void Channel::MakePlayerInvited(WorldPackets::Channel::ChannelNotify& data, std::string const& name) { MakeNotifyPacket(data, CHAT_PLAYER_INVITED_NOTICE); - *data << name; + data.Sender = name; } -void Channel::MakePlayerInviteBanned(WorldPacket* data, const std::string& name) +void Channel::MakePlayerInviteBanned(WorldPackets::Channel::ChannelNotify& data, std::string const& name) { MakeNotifyPacket(data, CHAT_PLAYER_INVITE_BANNED_NOTICE); - *data << name; + data.Sender = name; } -void Channel::MakeThrottled(WorldPacket* data) +void Channel::MakeThrottled(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_THROTTLED_NOTICE); } -void Channel::MakeNotInArea(WorldPacket* data) +void Channel::MakeNotInArea(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_NOT_IN_AREA_NOTICE); } -void Channel::MakeNotInLfg(WorldPacket* data) +void Channel::MakeNotInLfg(WorldPackets::Channel::ChannelNotify& data) { MakeNotifyPacket(data, CHAT_NOT_IN_LFG_NOTICE); } -void Channel::MakeVoiceOn(WorldPacket* data, ObjectGuid guid) +void Channel::MakeVoiceOn(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_VOICE_ON_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::MakeVoiceOff(WorldPacket* data, ObjectGuid guid) +void Channel::MakeVoiceOff(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid) { MakeNotifyPacket(data, CHAT_VOICE_OFF_NOTICE); - *data << guid; + data.SenderGuid = guid; } -void Channel::JoinNotify(ObjectGuid guid) +void Channel::JoinNotify(Player const* player) { + ObjectGuid const& guid = player->GetGUID(); WorldPacket data(IsConstant() ? SMSG_USERLIST_ADD : SMSG_USERLIST_UPDATE, 8 + 1 + 1 + 4 + GetName().size()); data << guid; data << uint8(GetPlayerFlags(guid)); @@ -980,8 +984,9 @@ void Channel::JoinNotify(ObjectGuid guid) SendToAll(&data); } -void Channel::LeaveNotify(ObjectGuid guid) +void Channel::LeaveNotify(Player const* player) { + ObjectGuid const& guid = player->GetGUID(); WorldPacket data(SMSG_USERLIST_REMOVE, 8 + 1 + 4 + GetName().size()); data << guid; data << uint8(GetFlags()); diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h index 6489c8b47ad..4ee83b8fbb2 100644 --- a/src/server/game/Chat/Channels/Channel.h +++ b/src/server/game/Chat/Channels/Channel.h @@ -19,14 +19,11 @@ #ifndef _CHANNEL_H #define _CHANNEL_H -#include <list> -#include <map> -#include <string> - #include "Common.h" #include "WorldSession.h" -#include "WorldPacket.h" + +#include "Packets/ChannelPackets.h" class Player; @@ -122,33 +119,47 @@ class Channel { struct PlayerInfo { - ObjectGuid player; - uint8 flags; + ObjectGuid PlayerGuid; + + uint8 GetFlags() const { return _flags; } + inline bool HasFlag(uint8 flag) const { return (_flags & flag) != 0; } + inline void SetFlag(uint8 flag) { _flags |= flag; } + inline void RemoveFlag(uint8 flag) { _flags &= ~flag; } - bool HasFlag(uint8 flag) const { return (flags & flag) != 0; } - void SetFlag(uint8 flag) { flags |= flag; } - bool IsOwner() const { return (flags & MEMBER_FLAG_OWNER) != 0; } + bool IsOwner() const { return HasFlag(MEMBER_FLAG_OWNER); } void SetOwner(bool state) { - if (state) flags |= MEMBER_FLAG_OWNER; - else flags &= ~MEMBER_FLAG_OWNER; + if (state) + SetFlag(MEMBER_FLAG_OWNER); + else + RemoveFlag(MEMBER_FLAG_OWNER); } - bool IsModerator() const { return (flags & MEMBER_FLAG_MODERATOR) != 0; } + + bool IsModerator() const { return HasFlag(MEMBER_FLAG_MODERATOR); } void SetModerator(bool state) { - if (state) flags |= MEMBER_FLAG_MODERATOR; - else flags &= ~MEMBER_FLAG_MODERATOR; + if (state) + SetFlag(MEMBER_FLAG_MODERATOR); + else + RemoveFlag(MEMBER_FLAG_MODERATOR); } - bool IsMuted() const { return (flags & MEMBER_FLAG_MUTED) != 0; } + + bool IsMuted() const { return HasFlag(MEMBER_FLAG_MUTED); } void SetMuted(bool state) { - if (state) flags |= MEMBER_FLAG_MUTED; - else flags &= ~MEMBER_FLAG_MUTED; + if (state) + SetFlag(MEMBER_FLAG_MUTED); + else + RemoveFlag(MEMBER_FLAG_MUTED); } + + private: + uint8 _flags = MEMBER_FLAG_NONE; }; public: Channel(std::string const& name, uint32 channel_id, uint32 Team = 0); + std::string const& GetName() const { return _name; } uint32 GetChannelId() const { return _channelId; } bool IsConstant() const { return _channelId != 0; } @@ -157,7 +168,7 @@ class Channel std::string const& GetPassword() const { return _password; } void SetPassword(std::string const& npassword) { _password = npassword; } void SetAnnounce(bool nannounce) { _announce = nannounce; } - uint32 GetNumPlayers() const { return playersStore.size(); } + uint32 GetNumPlayers() const { return _playersStore.size(); } uint8 GetFlags() const { return _flags; } bool HasFlag(uint8 flag) const { return (_flags & flag) != 0; } @@ -169,102 +180,102 @@ class Channel void UnBan(Player const* player, std::string const& badname); void Password(Player const* player, std::string const& pass); void SetMode(Player const* player, std::string const& p2n, bool mod, bool set); - void SetOwner(ObjectGuid guid, bool exclaim = true); + void SetOwner(ObjectGuid const& guid, bool exclaim = true); void SetOwner(Player const* player, std::string const& name); - void SendWhoOwner(ObjectGuid guid); + void SendWhoOwner(Player const* player); void SetModerator(Player const* player, std::string const& newname) { SetMode(player, newname, true, true); } void UnsetModerator(Player const* player, std::string const& newname) { SetMode(player, newname, true, false); } void SetMute(Player const* player, std::string const& newname) { SetMode(player, newname, false, true); } void UnsetMute(Player const* player, std::string const& newname) { SetMode(player, newname, false, false); } void List(Player const* player); void Announce(Player const* player); - void Say(ObjectGuid guid, std::string const& what, uint32 lang); + void Say(ObjectGuid const& guid, std::string const& what, uint32 lang); void Invite(Player const* player, std::string const& newp); - void Voice(ObjectGuid guid1, ObjectGuid guid2); - void DeVoice(ObjectGuid guid1, ObjectGuid guid2); - void JoinNotify(ObjectGuid guid); // invisible notify - void LeaveNotify(ObjectGuid guid); // invisible notify + void Voice(ObjectGuid const& guid1, ObjectGuid const& guid2); + void DeVoice(ObjectGuid const& guid1, ObjectGuid const& guid2); + void JoinNotify(Player const* player); + void LeaveNotify(Player const* player); void SetOwnership(bool ownership) { _ownership = ownership; }; static void CleanOldChannelsInDB(); private: // initial packet data (notify type and channel name) - void MakeNotifyPacket(WorldPacket* data, uint8 notify_type); + void MakeNotifyPacket(WorldPackets::Channel::ChannelNotify& data, uint8 notifyType); // type specific packet data - void MakeJoined(WorldPacket* data, ObjectGuid guid); //+ 0x00 - void MakeLeft(WorldPacket* data, ObjectGuid guid); //+ 0x01 - void MakeYouJoined(WorldPacket* data); //+ 0x02 - void MakeYouLeft(WorldPacket* data); //+ 0x03 - void MakeWrongPassword(WorldPacket* data); //? 0x04 - void MakeNotMember(WorldPacket* data); //? 0x05 - void MakeNotModerator(WorldPacket* data); //? 0x06 - void MakePasswordChanged(WorldPacket* data, ObjectGuid guid); //+ 0x07 - void MakeOwnerChanged(WorldPacket* data, ObjectGuid guid); //? 0x08 - void MakePlayerNotFound(WorldPacket* data, std::string const& name); //+ 0x09 - void MakeNotOwner(WorldPacket* data); //? 0x0A - void MakeChannelOwner(WorldPacket* data); //? 0x0B - void MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags);//+ 0x0C - void MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid); //+ 0x0D - void MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid); //+ 0x0E - void MakeMuted(WorldPacket* data); //? 0x11 - void MakePlayerKicked(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x12 - void MakeBanned(WorldPacket* data); //? 0x13 - void MakePlayerBanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x14 - void MakePlayerUnbanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x15 - void MakePlayerNotBanned(WorldPacket* data, std::string const& name); //? 0x16 - void MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid); //+ 0x17 - void MakeInvite(WorldPacket* data, ObjectGuid guid); //? 0x18 - void MakeInviteWrongFaction(WorldPacket* data); //? 0x19 - void MakeWrongFaction(WorldPacket* data); //? 0x1A - void MakeInvalidName(WorldPacket* data); //? 0x1B - void MakeNotModerated(WorldPacket* data); //? 0x1C - void MakePlayerInvited(WorldPacket* data, std::string const& name); //+ 0x1D - void MakePlayerInviteBanned(WorldPacket* data, std::string const& name);//? 0x1E - void MakeThrottled(WorldPacket* data); //? 0x1F - void MakeNotInArea(WorldPacket* data); //? 0x20 - void MakeNotInLfg(WorldPacket* data); //? 0x21 - void MakeVoiceOn(WorldPacket* data, ObjectGuid guid); //+ 0x22 - void MakeVoiceOff(WorldPacket* data, ObjectGuid guid); //+ 0x23 + void MakeJoined(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //+ 0x00 + void MakeLeft(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //+ 0x01 + void MakeYouJoined(WorldPackets::Channel::ChannelNotify& data); //+ 0x02 + void MakeYouLeft(WorldPackets::Channel::ChannelNotify& data); //+ 0x03 + void MakeWrongPassword(WorldPackets::Channel::ChannelNotify& data); //? 0x04 + void MakeNotMember(WorldPackets::Channel::ChannelNotify& data); //? 0x05 + void MakeNotModerator(WorldPackets::Channel::ChannelNotify& data); //? 0x06 + void MakePasswordChanged(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //+ 0x07 + void MakeOwnerChanged(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //? 0x08 + void MakePlayerNotFound(WorldPackets::Channel::ChannelNotify& data, std::string const& name); //+ 0x09 + void MakeNotOwner(WorldPackets::Channel::ChannelNotify& data); //? 0x0A + void MakeChannelOwner(WorldPackets::Channel::ChannelNotify& data); //? 0x0B + void MakeModeChange(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid, uint8 oldFlags, uint8 newFlags); //+ 0x0C + void MakeAnnouncementsOn(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //+ 0x0D + void MakeAnnouncementsOff(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //+ 0x0E + void MakeMuted(WorldPackets::Channel::ChannelNotify& data); //? 0x11 + void MakePlayerKicked(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& bad, ObjectGuid const& good); //? 0x12 + void MakeBanned(WorldPackets::Channel::ChannelNotify& data); //? 0x13 + void MakePlayerBanned(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& bad, ObjectGuid const& good); //? 0x14 + void MakePlayerUnbanned(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& bad, ObjectGuid const& good); //? 0x15 + void MakePlayerNotBanned(WorldPackets::Channel::ChannelNotify& data, std::string const& name); //? 0x16 + void MakePlayerAlreadyMember(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //+ 0x17 + void MakeInvite(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //? 0x18 + void MakeInviteWrongFaction(WorldPackets::Channel::ChannelNotify& data); //? 0x19 + void MakeWrongFaction(WorldPackets::Channel::ChannelNotify& data); //? 0x1A + void MakeInvalidName(WorldPackets::Channel::ChannelNotify& data); //? 0x1B + void MakeNotModerated(WorldPackets::Channel::ChannelNotify& data); //? 0x1C + void MakePlayerInvited(WorldPackets::Channel::ChannelNotify& data, std::string const& name); //+ 0x1D + void MakePlayerInviteBanned(WorldPackets::Channel::ChannelNotify& data, std::string const& name); //? 0x1E + void MakeThrottled(WorldPackets::Channel::ChannelNotify& data); //? 0x1F + void MakeNotInArea(WorldPackets::Channel::ChannelNotify& data); //? 0x20 + void MakeNotInLfg(WorldPackets::Channel::ChannelNotify& data); //? 0x21 + void MakeVoiceOn(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //+ 0x22 + void MakeVoiceOff(WorldPackets::Channel::ChannelNotify& data, ObjectGuid const& guid); //+ 0x23 - void SendToAll(WorldPacket* data, ObjectGuid guid = ObjectGuid::Empty); - void SendToAllButOne(WorldPacket* data, ObjectGuid who); - void SendToOne(WorldPacket* data, ObjectGuid who); + void SendToAll(WorldPacket const* data, ObjectGuid const& guid = ObjectGuid::Empty); + void SendToAllButOne(WorldPacket const* data, ObjectGuid const& who); + void SendToOne(WorldPacket const* data, ObjectGuid const& who); - bool IsOn(ObjectGuid who) const { return playersStore.find(who) != playersStore.end(); } - bool IsBanned(ObjectGuid guid) const { return bannedStore.find(guid) != bannedStore.end(); } + bool IsOn(ObjectGuid const& who) const { return _playersStore.find(who) != _playersStore.end(); } + bool IsBanned(ObjectGuid const& guid) const { return _bannedStore.find(guid) != _bannedStore.end(); } void UpdateChannelInDB() const; void UpdateChannelUseageInDB() const; - uint8 GetPlayerFlags(ObjectGuid guid) const + uint8 GetPlayerFlags(ObjectGuid const& guid) const { - PlayerContainer::const_iterator itr = playersStore.find(guid); - return itr != playersStore.end() ? itr->second.flags : 0; + PlayerContainer::const_iterator itr = _playersStore.find(guid); + return itr != _playersStore.end() ? itr->second.GetFlags() : 0; } - void SetModerator(ObjectGuid guid, bool set) + void SetModerator(ObjectGuid const& guid, bool set) { - if (playersStore[guid].IsModerator() != set) + if (_playersStore[guid].IsModerator() != set) { - uint8 oldFlag = GetPlayerFlags(guid); - playersStore[guid].SetModerator(set); + uint8 oldFlag = _playersStore[guid].GetFlags(); + _playersStore[guid].SetModerator(set); - WorldPacket data; - MakeModeChange(&data, guid, oldFlag); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify data; + MakeModeChange(data, guid, oldFlag, _playersStore[guid].GetFlags()); + SendToAll(data.Write()); } } - void SetMute(ObjectGuid guid, bool set) + void SetMute(ObjectGuid const& guid, bool set) { - if (playersStore[guid].IsMuted() != set) + if (_playersStore[guid].IsMuted() != set) { - uint8 oldFlag = GetPlayerFlags(guid); - playersStore[guid].SetMuted(set); + uint8 oldFlag = _playersStore[guid].GetFlags(); + _playersStore[guid].SetMuted(set); - WorldPacket data; - MakeModeChange(&data, guid, oldFlag); - SendToAll(&data); + WorldPackets::Channel::ChannelNotify data; + MakeModeChange(data, guid, oldFlag, _playersStore[guid].GetFlags()); + SendToAll(data.Write()); } } @@ -276,12 +287,12 @@ class Channel bool _IsSaved; uint8 _flags; uint32 _channelId; - uint32 _Team; + uint32 _team; ObjectGuid _ownerGUID; std::string _name; std::string _password; - PlayerContainer playersStore; - BannedContainer bannedStore; + PlayerContainer _playersStore; + BannedContainer _bannedStore; }; -#endif +#endif diff --git a/src/server/game/Chat/Channels/ChannelMgr.cpp b/src/server/game/Chat/Channels/ChannelMgr.cpp index a3a4ef69e63..097eea5bb09 100644 --- a/src/server/game/Chat/Channels/ChannelMgr.cpp +++ b/src/server/game/Chat/Channels/ChannelMgr.cpp @@ -23,11 +23,11 @@ ChannelMgr::~ChannelMgr() { - for (ChannelMap::iterator itr = channels.begin(); itr != channels.end(); ++itr) + for (ChannelMap::iterator itr = _channels.begin(); itr != _channels.end(); ++itr) delete itr->second; } -ChannelMgr* ChannelMgr::forTeam(uint32 team) +ChannelMgr* ChannelMgr::ForTeam(uint32 team) { static ChannelMgr allianceChannelMgr; static ChannelMgr hordeChannelMgr; @@ -40,49 +40,43 @@ ChannelMgr* ChannelMgr::forTeam(uint32 team) if (team == HORDE) return &hordeChannelMgr; - return NULL; + return nullptr; } Channel* ChannelMgr::GetJoinChannel(std::string const& name, uint32 channelId) { std::wstring wname; if (!Utf8toWStr(name, wname)) - return NULL; + return nullptr; wstrToLower(wname); - ChannelMap::const_iterator i = channels.find(wname); - - if (i == channels.end()) + ChannelMap::const_iterator i = _channels.find(wname); + if (i == _channels.end()) { - Channel* nchan = new Channel(name, channelId, team); - channels[wname] = nchan; + Channel* nchan = new Channel(name, channelId, _team); + _channels[wname] = nchan; return nchan; } return i->second; } -Channel* ChannelMgr::GetChannel(std::string const& name, Player* player, bool pkt) +Channel* ChannelMgr::GetChannel(std::string const& name, Player* player, bool notify /*= true*/) { std::wstring wname; if (!Utf8toWStr(name, wname)) - return NULL; + return nullptr; wstrToLower(wname); - ChannelMap::const_iterator i = channels.find(wname); - - if (i == channels.end()) + ChannelMap::const_iterator i = _channels.find(wname); + if (i == _channels.end()) { - if (pkt) - { - WorldPacket data; - MakeNotOnPacket(&data, name); - player->GetSession()->SendPacket(&data); - } - - return NULL; + if (notify) + SendNotOnChannelNotify(player, name); + + return nullptr; } return i->second; @@ -96,22 +90,23 @@ void ChannelMgr::LeftChannel(std::string const& name) wstrToLower(wname); - ChannelMap::const_iterator i = channels.find(wname); - - if (i == channels.end()) + ChannelMap::const_iterator i = _channels.find(wname); + if (i == _channels.end()) return; Channel* channel = i->second; if (!channel->GetNumPlayers() && !channel->IsConstant()) { - channels.erase(wname); + _channels.erase(i); delete channel; } } -void ChannelMgr::MakeNotOnPacket(WorldPacket* data, std::string const& name) +void ChannelMgr::SendNotOnChannelNotify(Player const* player, std::string const& name) { - data->Initialize(SMSG_CHANNEL_NOTIFY, 1 + name.size()); - (*data) << uint8(5) << name; + WorldPackets::Channel::ChannelNotify notify; + notify.Type = CHAT_NOT_MEMBER_NOTICE; + notify._Channel = name; + player->SendDirectMessage(notify.Write()); } diff --git a/src/server/game/Chat/Channels/ChannelMgr.h b/src/server/game/Chat/Channels/ChannelMgr.h index eee45ba5b97..9a8fdb10767 100644 --- a/src/server/game/Chat/Channels/ChannelMgr.h +++ b/src/server/game/Chat/Channels/ChannelMgr.h @@ -21,11 +21,6 @@ #include "Common.h" #include "Channel.h" -#include <map> -#include <string> - -#include "World.h" - #define MAX_CHANNEL_PASS_STR 31 class ChannelMgr @@ -33,22 +28,22 @@ class ChannelMgr typedef std::map<std::wstring, Channel*> ChannelMap; protected: - ChannelMgr() : team(0) { } + ChannelMgr() : _team(0) { } ~ChannelMgr(); public: - static ChannelMgr* forTeam(uint32 team); - void setTeam(uint32 newTeam) { team = newTeam; } + static ChannelMgr* ForTeam(uint32 team); + void SetTeam(uint32 newTeam) { _team = newTeam; } - Channel* GetJoinChannel(std::string const& name, uint32 channel_id); - Channel* GetChannel(std::string const& name, Player* p, bool pkt = true); + Channel* GetJoinChannel(std::string const& name, uint32 channelId); + Channel* GetChannel(std::string const& name, Player* player, bool notify = true); void LeftChannel(std::string const& name); private: - ChannelMap channels; - uint32 team; + ChannelMap _channels; + uint32 _team; - void MakeNotOnPacket(WorldPacket* data, std::string const& name); + static void SendNotOnChannelNotify(Player const* player, std::string const& name); }; #endif diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index ec3bc458066..cbb0e4683aa 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -35,6 +35,8 @@ #include "SpellMgr.h" #include "ScriptMgr.h" #include "ChatLink.h" +#include "Guild.h" +#include "Group.h" bool ChatHandler::load_command_table = true; @@ -202,7 +204,7 @@ bool ChatHandler::hasStringAbbr(const char* name, const char* part) void ChatHandler::SendSysMessage(const char *str) { - WorldPacket data; + WorldPackets::Chat::Chat packet; // need copy to prevent corruption by strtok call in LineFromMessage original string char* buf = strdup(str); @@ -210,8 +212,8 @@ void ChatHandler::SendSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); - m_session->SendPacket(&data); + BuildChatPacket(&packet, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); + m_session->SendPacket(packet.Write()); } free(buf); @@ -220,7 +222,7 @@ void ChatHandler::SendSysMessage(const char *str) void ChatHandler::SendGlobalSysMessage(const char *str) { // Chat output - WorldPacket data; + WorldPackets::Chat::Chat packet; // need copy to prevent corruption by strtok call in LineFromMessage original string char* buf = strdup(str); @@ -228,8 +230,8 @@ void ChatHandler::SendGlobalSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); - sWorld->SendGlobalMessage(&data); + BuildChatPacket(&packet, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); + sWorld->SendGlobalMessage(packet.Write()); } free(buf); @@ -238,7 +240,7 @@ void ChatHandler::SendGlobalSysMessage(const char *str) void ChatHandler::SendGlobalGMSysMessage(const char *str) { // Chat output - WorldPacket data; + WorldPackets::Chat::Chat packet; // need copy to prevent corruption by strtok call in LineFromMessage original string char* buf = strdup(str); @@ -246,8 +248,8 @@ void ChatHandler::SendGlobalGMSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); - sWorld->SendGlobalGMMessage(&data); + BuildChatPacket(&packet, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); + sWorld->SendGlobalGMMessage(packet.Write()); } free(buf); @@ -628,132 +630,56 @@ bool ChatHandler::ShowHelpForCommand(ChatCommand* table, const char* cmd) return ShowHelpForSubCommands(table, "", cmd); } -size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string const& message, uint8 chatTag, - std::string const& senderName /*= ""*/, std::string const& receiverName /*= ""*/, - uint32 achievementId /*= 0*/, bool gmMessage /*= false*/, std::string const& channelName /*= ""*/, - std::string const& addonPrefix /*= ""*/) +void ChatHandler::BuildChatPacket(WorldPackets::Chat::Chat* packet, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, + uint32 achievementId /*= 0*/, std::string const& channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/, std::string const& addonPrefix /*= ""*/) { - size_t receiverGUIDPos = 0; - data.Initialize(!gmMessage ? SMSG_MESSAGECHAT : SMSG_GM_MESSAGECHAT); - data << uint8(chatType); - data << int32(language); - data << senderGUID; - data << uint32(0); // some flags - switch (chatType) - { - case CHAT_MSG_MONSTER_SAY: - case CHAT_MSG_MONSTER_PARTY: - case CHAT_MSG_MONSTER_YELL: - case CHAT_MSG_MONSTER_WHISPER: - case CHAT_MSG_MONSTER_EMOTE: - case CHAT_MSG_RAID_BOSS_EMOTE: - case CHAT_MSG_RAID_BOSS_WHISPER: - case CHAT_MSG_BATTLENET: - data << uint32(senderName.length() + 1); - data << senderName; - receiverGUIDPos = data.wpos(); - data << receiverGUID; - if (!receiverGUID.IsEmpty() && !receiverGUID.IsPlayer() && !receiverGUID.IsPet()) - { - data << uint32(receiverName.length() + 1); - data << receiverName; - } - - if (language == LANG_ADDON) - data << addonPrefix; - break; - case CHAT_MSG_WHISPER_FOREIGN: - data << uint32(senderName.length() + 1); - data << senderName; - receiverGUIDPos = data.wpos(); - data << receiverGUID; - if (language == LANG_ADDON) - data << addonPrefix; - break; - case CHAT_MSG_BG_SYSTEM_NEUTRAL: - case CHAT_MSG_BG_SYSTEM_ALLIANCE: - case CHAT_MSG_BG_SYSTEM_HORDE: - receiverGUIDPos = data.wpos(); - data << receiverGUID; - if (!receiverGUID.IsEmpty() && !receiverGUID.IsPlayer()) - { - data << uint32(receiverName.length() + 1); - data << receiverName; - } - - if (language == LANG_ADDON) - data << addonPrefix; - break; - case CHAT_MSG_ACHIEVEMENT: - case CHAT_MSG_GUILD_ACHIEVEMENT: - receiverGUIDPos = data.wpos(); - data << receiverGUID; - if (language == LANG_ADDON) - data << addonPrefix; - break; - default: - if (gmMessage) - { - data << uint32(senderName.length() + 1); - data << senderName; - } - - if (chatType == CHAT_MSG_CHANNEL) - { - ASSERT(channelName.length() > 0); - data << channelName; - } + // Clear everything because same packet can be used multiple times + packet->Reset(); + packet->SenderGUID.Clear(); + packet->SenderAccountGUID.Clear(); + packet->SenderGuildGUID.Clear(); + packet->PartyGUID.Clear(); + packet->TargetGUID.Clear(); + packet->SenderName.clear(); + packet->TargetName.clear(); + packet->ChatFlags = CHAT_FLAG_NONE; + + packet->SlashCmd = chatType; + packet->Language = language; - receiverGUIDPos = data.wpos(); - data << receiverGUID; - - if (language == LANG_ADDON) - data << addonPrefix; - break; - } - - data << uint32(message.length() + 1); - data << message; - data << uint8(chatTag); - - if (chatType == CHAT_MSG_ACHIEVEMENT || chatType == CHAT_MSG_GUILD_ACHIEVEMENT) - data << uint32(achievementId); - else if (chatType == CHAT_MSG_RAID_BOSS_WHISPER || chatType == CHAT_MSG_RAID_BOSS_EMOTE) + if (sender) { - data << float(0.0f); // Display time in middle of the screen (in seconds), defaults to 10 if not set (cannot be below 1) - data << uint8(0); // Hide in chat frame (only shows in middle of the screen) - } + packet->SenderGUID = sender->GetGUID(); - return receiverGUIDPos; -} + if (Creature const* creatureSender = sender->ToCreature()) + packet->SenderName = creatureSender->GetNameForLocaleIdx(locale); -size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, - uint32 achievementId /*= 0*/, std::string const& channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/, std::string const& addonPrefix /*= ""*/) -{ - ObjectGuid senderGUID; - std::string senderName = ""; - uint8 chatTag = 0; - bool gmMessage = false; - ObjectGuid receiverGUID; - std::string receiverName = ""; - if (sender) - { - senderGUID = sender->GetGUID(); - senderName = sender->GetNameForLocaleIdx(locale); if (Player const* playerSender = sender->ToPlayer()) { - chatTag = playerSender->GetChatTag(); - gmMessage = playerSender->GetSession()->HasPermission(rbac::RBAC_PERM_COMMAND_GM_CHAT); + packet->SenderAccountGUID = playerSender->GetSession()->GetAccountGUID(); + packet->ChatFlags = playerSender->GetChatFlags(); + + if (Guild const* guild = playerSender->GetGuild()) + packet->SenderGuildGUID = guild->GetGUID(); + + if (Group const* group = playerSender->GetGroup()) + packet->PartyGUID = group->GetGUID(); } } if (receiver) { - receiverGUID = receiver->GetGUID(); - receiverName = receiver->GetNameForLocaleIdx(locale); + packet->TargetGUID = receiver->GetGUID(); + if (Creature const* creatureReceiver = receiver->ToCreature()) + packet->TargetName = creatureReceiver->GetNameForLocaleIdx(locale); } - return BuildChatPacket(data, chatType, language, senderGUID, receiverGUID, message, chatTag, senderName, receiverName, achievementId, gmMessage, channelName, addonPrefix); + packet->SenderVirtualAddress = GetVirtualRealmAddress(); + packet->TargetVirtualAddress = GetVirtualRealmAddress(); + packet->AchievementID = achievementId; + packet->Channel = channelName; + packet->Prefix = addonPrefix; + packet->ChatText = message; } Player* ChatHandler::getSelectedPlayer() @@ -1000,7 +926,7 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text) if (!idS) return 0; - uint32 id = (uint32)atol(idS); + uint32 id = atoul(idS); switch (type) { @@ -1020,7 +946,7 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text) return id; case SPELL_LINK_GLYPH: { - uint32 glyph_prop_id = param1_str ? (uint32)atol(param1_str) : 0; + uint32 glyph_prop_id = param1_str ? atoul(param1_str) : 0; GlyphPropertiesEntry const* glyphPropEntry = sGlyphPropertiesStore.LookupEntry(glyph_prop_id); if (!glyphPropEntry) diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 98c3bc3efbb..5db48db0fbe 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -22,6 +22,7 @@ #include "SharedDefines.h" #include "WorldSession.h" #include "RBAC.h" +#include "Packets/ChatPackets.h" #include <vector> @@ -53,14 +54,7 @@ class ChatHandler explicit ChatHandler(WorldSession* session) : m_session(session), sentErrorMessage(false) { } virtual ~ChatHandler() { } - // Builds chat packet and returns receiver guid position in the packet to substitute in whisper builders - static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string const& message, uint8 chatTag, - std::string const& senderName = "", std::string const& receiverName = "", - uint32 achievementId = 0, bool gmMessage = false, std::string const& channelName = "", - std::string const& addonPrefix = ""); - - // Builds chat packet and returns receiver guid position in the packet to substitute in whisper builders - static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, uint32 achievementId = 0, std::string const& channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string const& addonPrefix = ""); + static void BuildChatPacket(WorldPackets::Chat::Chat* packet, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, uint32 achievementId = 0, std::string const& channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string const& addonPrefix = ""); static char* LineFromMessage(char*& pos) { char* start = strtok(pos, "\n"); pos = NULL; return start; } diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 85510ab0545..cd1e3d5be95 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -41,8 +41,8 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float threat *= threatEntry->pctMod; // Energize is not affected by Mods - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) - if (threatSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE || threatSpell->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_ENERGIZE) + for (SpellEffectInfo const* effect : threatSpell->GetEffectsForDifficulty(hatedUnit->GetMap()->GetDifficulty())) + if (effect && (effect->Effect == SPELL_EFFECT_ENERGIZE || effect->ApplyAuraName == SPELL_AURA_PERIODIC_ENERGIZE)) return threat; if (Player* modOwner = hatedUnit->GetSpellModOwner()) diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 6e4878ce4c5..654451af949 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -29,6 +29,79 @@ #include "SpellMgr.h" #include "Spell.h" +char const* ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX] = +{ + "None", + "Creature Loot", + "Disenchant Loot", + "Fishing Loot", + "GameObject Loot", + "Item Loot", + "Mail Loot", + "Milling Loot", + "Pickpocketing Loot", + "Prospecting Loot", + "Reference Loot", + "Skinning Loot", + "Spell Loot", + "Spell Impl. Target", + "Gossip Menu", + "Gossip Menu Option", + "Creature Vehicle", + "Spell Expl. Target", + "Spell Click Event", + "Quest Accept", + "Quest Show Mark", + "Vehicle Spell", + "SmartScript", + "Npc Vendor", + "Spell Proc", + "Phase Def" +}; + +ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[CONDITION_MAX] = +{ + { "None", false, false, false }, + { "Aura", true, true, true }, + { "Item Stored", true, true, true }, + { "Item Equipped", true, false, false }, + { "Zone", true, false, false }, + { "Reputation", true, true, false }, + { "Team", true, false, false }, + { "Skill", true, true, false }, + { "Quest Rewarded", true, false, false }, + { "Quest Taken", true, false, false }, + { "Drunken", true, false, false }, + { "WorldState", true, true, false }, + { "Active Event", true, false, false }, + { "Instance Info", true, true, true }, + { "Quest None", true, false, false }, + { "Class", true, false, false }, + { "Race", true, false, false }, + { "Achievement", true, false, false }, + { "Title", true, false, false }, + { "SpawnMask", true, false, false }, + { "Gender", true, false, false }, + { "Unit State", true, false, false }, + { "Map", true, false, false }, + { "Area", true, false, false }, + { "CreatureType", true, false, false }, + { "Spell Known", true, false, false }, + { "Phase", true, false, false }, + { "Level", true, true, false }, + { "Quest Completed", true, false, false }, + { "Near Creature", true, true, false }, + { "Near GameObject", true, true, false }, + { "Object Entry or Guid", true, true, true }, + { "Object TypeMask", true, false, false }, + { "Relation", true, true, false }, + { "Reaction", true, true, false }, + { "Distance", true, true, true }, + { "Alive", false, false, false }, + { "Health Value", true, true, false }, + { "Health Pct", true, true, false } +}; + // Checks if object meets the condition // Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: SmartAI) bool Condition::Meets(ConditionSourceInfo& sourceInfo) @@ -38,7 +111,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) // object not present, return false if (!object) { - TC_LOG_DEBUG("condition", "Condition object not found for condition (Entry: %u Type: %u Group: %u)", SourceEntry, SourceType, SourceGroup); + TC_LOG_DEBUG("condition", "Condition object not found for %s", ToString().c_str()); return false; } bool condMeets = false; @@ -540,6 +613,34 @@ uint32 Condition::GetMaxAvailableConditionTargets() } } +std::string Condition::ToString(bool ext /*= false*/) const +{ + std::ostringstream ss; + ss << "[Condition "; + ss << "SourceType: " << SourceType; + if (SourceType < CONDITION_SOURCE_TYPE_MAX) + ss << " (" << ConditionMgr::StaticSourceTypeData[SourceType] << ")"; + else + ss << " (Unknown)"; + if (ConditionMgr::CanHaveSourceGroupSet(SourceType)) + ss << ", SourceGroup: " << SourceGroup; + ss << ", SourceEntry: " << SourceEntry; + if (ConditionMgr::CanHaveSourceIdSet(SourceType)) + ss << ", SourceId: " << SourceId; + + if (ext) + { + ss << ", ConditionType: " << ConditionType; + if (ConditionType < CONDITION_MAX) + ss << " (" << ConditionMgr::StaticConditionTypeData[ConditionType].Name << ")"; + else + ss << " (Unknown)"; + } + + ss << "]"; + return ss.str(); +} + ConditionMgr::ConditionMgr() { } ConditionMgr::~ConditionMgr() @@ -602,7 +703,7 @@ bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, std::map<uint32, bool> ElseGroupStore; for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i) { - TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList condType: %u val1: %u", (*i)->ConditionType, (*i)->ConditionValue1); + TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList %s val1: %u", (*i)->ToString().c_str(), (*i)->ConditionValue1); if ((*i)->isLoaded()) { //! Find ElseGroup in ElseGroupStore @@ -623,8 +724,8 @@ bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, } else { - TC_LOG_DEBUG("condition", "IsPlayerMeetToConditionList: Reference template -%u not found", - (*i)->ReferenceId);//checked at loading, should never happen + TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList %s Reference template -%u not found", + (*i)->ToString().c_str(), (*i)->ReferenceId); // checked at loading, should never happen } } @@ -663,7 +764,7 @@ bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, Con return IsObjectMeetToConditionList(sourceInfo, conditions); } -bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const +bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) { return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || @@ -687,7 +788,7 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR); } -bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const +bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) { return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT); } @@ -721,7 +822,7 @@ ConditionList ConditionMgr::GetConditionsForSpellClickEvent(uint32 creatureId, u if (i != (*itr).second.end()) { cond = (*i).second; - TC_LOG_DEBUG("condition", "GetConditionsForSpellClickEvent: found conditions for Vehicle entry %u spell %u", creatureId, spellId); + TC_LOG_DEBUG("condition", "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry %u spell %u", creatureId, spellId); } } return cond; @@ -753,7 +854,7 @@ ConditionList ConditionMgr::GetConditionsForSmartEvent(int64 entryOrGuid, uint32 if (i != (*itr).second.end()) { cond = (*i).second; - TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid " SI64FMTD " event_id %u", entryOrGuid, eventId); + TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid " SI64FMTD " eventId %u", entryOrGuid, eventId); } } return cond; @@ -917,26 +1018,26 @@ void ConditionMgr::LoadConditions(bool isReload) //Grouping is only allowed for some types (loot templates, gossip menus, gossip items) if (cond->SourceGroup && !CanHaveSourceGroupSet(cond->SourceType)) { - TC_LOG_ERROR("sql.sql", "Condition type %u has not allowed value of SourceGroup = %u!", uint32(cond->SourceType), cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s has not allowed value of SourceGroup = %u!", cond->ToString().c_str(), cond->SourceGroup); delete cond; continue; } if (cond->SourceId && !CanHaveSourceIdSet(cond->SourceType)) { - TC_LOG_ERROR("sql.sql", "Condition type %u has not allowed value of SourceId = %u!", uint32(cond->SourceType), cond->SourceId); + TC_LOG_ERROR("sql.sql", "%s has not allowed value of SourceId = %u!", cond->ToString().c_str(), cond->SourceId); delete cond; continue; } if (cond->ErrorType && cond->SourceType != CONDITION_SOURCE_TYPE_SPELL) { - TC_LOG_ERROR("sql.sql", "Condition type %u entry %i can't have ErrorType (%u), set to 0!", uint32(cond->SourceType), cond->SourceEntry, cond->ErrorType); + TC_LOG_ERROR("sql.sql", "%s can't have ErrorType (%u), set to 0!", cond->ToString().c_str(), cond->ErrorType); cond->ErrorType = 0; } if (cond->ErrorTextId && !cond->ErrorType) { - TC_LOG_ERROR("sql.sql", "Condition type %u entry %i has any ErrorType, ErrorTextId (%u) is set, set to 0!", uint32(cond->SourceType), cond->SourceEntry, cond->ErrorTextId); + TC_LOG_ERROR("sql.sql", "%s has any ErrorType, ErrorTextId (%u) is set, set to 0!", cond->ToString().c_str(), cond->ErrorTextId); cond->ErrorTextId = 0; } @@ -1034,7 +1135,7 @@ void ConditionMgr::LoadConditions(bool isReload) if (!valid) { - TC_LOG_ERROR("sql.sql", "Not handled grouped condition, SourceGroup %u", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s Not handled grouped condition.", cond->ToString().c_str()); delete cond; } else @@ -1067,21 +1168,20 @@ void ConditionMgr::LoadConditions(bool isReload) while (result->NextRow()); TC_LOG_INFO("server.loading", ">> Loaded %u conditions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - } bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot) { if (!loot) { - TC_LOG_ERROR("sql.sql", "ConditionMgr: LootTemplate %u not found", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s LootTemplate %u not found.", cond->ToString().c_str(), cond->SourceGroup); return false; } if (loot->addConditionItem(cond)) return true; - TC_LOG_ERROR("sql.sql", "ConditionMgr: Item %u not found in LootTemplate %u", cond->SourceEntry, cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s Item %u not found in LootTemplate %u.", cond->ToString().c_str(), cond->SourceEntry, cond->SourceGroup); return false; } @@ -1101,7 +1201,7 @@ bool ConditionMgr::addToGossipMenus(Condition* cond) } } - TC_LOG_ERROR("sql.sql", "addToGossipMenus: GossipMenu %u not found", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s GossipMenu %u not found.", cond->ToString().c_str(), cond->SourceGroup); return false; } @@ -1120,7 +1220,7 @@ bool ConditionMgr::addToGossipMenuItems(Condition* cond) } } - TC_LOG_ERROR("sql.sql", "addToGossipMenuItems: GossipMenuId %u Item %u not found", cond->SourceGroup, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s GossipMenuId %u Item %u not found.", cond->ToString().c_str(), cond->SourceGroup, cond->SourceEntry); return false; } @@ -1131,6 +1231,9 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) std::list<uint32> sharedMasks; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { + SpellEffectInfo const* effect = spellInfo->GetEffect(DIFFICULTY_NONE, i); + if (!effect) + continue; // check if effect is already a part of some shared mask bool found = false; for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) @@ -1146,10 +1249,13 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) // build new shared mask with found effect uint32 sharedMask = (1<<i); - ConditionList* cmp = spellInfo->Effects[i].ImplicitTargetConditions; + ConditionList* cmp = effect->ImplicitTargetConditions; for (uint8 effIndex = i+1; effIndex < MAX_SPELL_EFFECTS; ++effIndex) { - if (spellInfo->Effects[effIndex].ImplicitTargetConditions == cmp) + SpellEffectInfo const* inner = spellInfo->GetEffect(DIFFICULTY_NONE, effIndex); + if (!inner) + continue; + if (inner->ImplicitTargetConditions == cmp) sharedMask |= 1<<effIndex; } sharedMasks.push_back(sharedMask); @@ -1168,8 +1274,12 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) if (firstEffIndex >= MAX_SPELL_EFFECTS) return false; + SpellEffectInfo const* effect = spellInfo->GetEffect(DIFFICULTY_NONE, firstEffIndex); + if (!effect) + continue; + // get shared data - ConditionList* sharedList = spellInfo->Effects[firstEffIndex].ImplicitTargetConditions; + ConditionList* sharedList = effect->ImplicitTargetConditions; // there's already data entry for that sharedMask if (sharedList) @@ -1177,8 +1287,8 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) // we have overlapping masks in db if (conditionEffMask != *itr) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set - " - "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring.", cond->SourceEntry, cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s in `condition` table, has incorrect SourceGroup %u (spell effectMask) set - " + "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring.", cond->ToString().c_str(), cond->SourceGroup); return false; } } @@ -1190,9 +1300,13 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) bool assigned = false; for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i) { + SpellEffectInfo const* eff = spellInfo->GetEffect(DIFFICULTY_NONE, firstEffIndex); + if (!eff) + continue; + if ((1<<i) & commonMask) { - spellInfo->Effects[i].ImplicitTargetConditions = sharedList; + const_cast<SpellEffectInfo*>(eff)->ImplicitTargetConditions = sharedList; assigned = true; } } @@ -1211,7 +1325,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (cond->SourceType == CONDITION_SOURCE_TYPE_NONE || cond->SourceType >= CONDITION_SOURCE_TYPE_MAX) { - TC_LOG_ERROR("sql.sql", "Invalid ConditionSourceType %u in `condition` table, ignoring.", uint32(cond->SourceType)); + TC_LOG_ERROR("sql.sql", "%s Invalid ConditionSourceType in `condition` table, ignoring.", cond->ToString().c_str()); return false; } @@ -1221,7 +1335,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Creature.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1229,7 +1343,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1238,7 +1352,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Disenchant.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1246,7 +1360,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1255,7 +1369,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Fishing.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1263,7 +1377,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1272,7 +1386,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Gameobject.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1280,7 +1394,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1289,7 +1403,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Item.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1297,7 +1411,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1306,7 +1420,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Mail.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1314,7 +1428,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1323,7 +1437,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Milling.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1331,7 +1445,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1340,7 +1454,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Pickpocketing.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1348,7 +1462,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1357,7 +1471,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Prospecting.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1365,7 +1479,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1374,7 +1488,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Reference.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1382,7 +1496,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1391,7 +1505,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Skinning.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1399,7 +1513,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1408,7 +1522,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!LootTemplates_Spell.HaveLootFor(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceGroup in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->ToString().c_str()); return false; } @@ -1416,7 +1530,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!pItemProto && !loot->isReference(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceType, SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1426,13 +1540,13 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s in `condition` table, SourceEntry does not exist in `spell.dbc`, ignoring.", cond->ToString().c_str()); return false; } if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set, ignoring.", cond->SourceEntry, cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s in `condition` table, has incorrect SourceGroup (spell effectMask) set, ignoring.", cond->ToString().c_str()); return false; } @@ -1440,10 +1554,14 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (!((1<<i) & cond->SourceGroup)) + if (!((1 << i) & cond->SourceGroup)) + continue; + + SpellEffectInfo const* effect = spellInfo->GetEffect(DIFFICULTY_NONE, i); + if (!effect) continue; - switch (spellInfo->Effects[i].TargetA.GetSelectionCategory()) + switch (effect->TargetA.GetSelectionCategory()) { case TARGET_SELECT_CATEGORY_NEARBY: case TARGET_SELECT_CATEGORY_CONE: @@ -1453,7 +1571,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) break; } - switch (spellInfo->Effects[i].TargetB.GetSelectionCategory()) + switch (effect->TargetB.GetSelectionCategory()) { case TARGET_SELECT_CATEGORY_NEARBY: case TARGET_SELECT_CATEGORY_CONE: @@ -1464,7 +1582,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) } TC_LOG_ERROR("sql.sql", "SourceEntry %u SourceGroup %u in `condition` table - spell %u does not have implicit targets of types: _AREA_, _CONE_, _NEARBY_ for effect %u, SourceGroup needs correction, ignoring.", cond->SourceEntry, origGroup, cond->SourceEntry, uint32(i)); - cond->SourceGroup &= ~(1<<i); + cond->SourceGroup &= ~(1 << i); } // all effects were removed, no need to add the condition at all if (!cond->SourceGroup) @@ -1475,7 +1593,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1486,48 +1604,42 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry); if (!spellProto) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->ToString().c_str()); return false; } break; } case CONDITION_SOURCE_TYPE_QUEST_ACCEPT: - if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry)) - { - TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_QUEST_ACCEPT specifies non-existing quest (%u), skipped", cond->SourceEntry); - return false; - } - break; case CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK: if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK specifies non-existing quest (%u), skipped", cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceEntry specifies non-existing quest, skipped.", cond->ToString().c_str()); return false; } break; case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString().c_str()); return false; } if (!sSpellMgr->GetSpellInfo(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->ToString().c_str()); return false; } break; case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString().c_str()); return false; } if (!sSpellMgr->GetSpellInfo(cond->SourceEntry)) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1542,13 +1654,13 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString().c_str()); return false; } ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(cond->SourceEntry); if (!itemTemplate) { - TC_LOG_ERROR("sql.sql", "SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `item_template`, ignoring.", cond->ToString().c_str()); return false; } break; @@ -1568,13 +1680,13 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (cond->ConditionType == CONDITION_NONE || cond->ConditionType >= CONDITION_MAX) { - TC_LOG_ERROR("sql.sql", "Invalid ConditionType %u at SourceEntry %u in `condition` table, ignoring.", uint32(cond->ConditionType), cond->SourceEntry); + TC_LOG_ERROR("sql.sql", "%s Invalid ConditionType in `condition` table, ignoring.", cond->ToString().c_str()); return false; } if (cond->ConditionTarget >= cond->GetMaxAvailableConditionTargets()) { - TC_LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u, SourceGroup %u in `condition` table, has incorrect ConditionTarget set, ignoring.", cond->SourceType, cond->SourceEntry, cond->SourceGroup); + TC_LOG_ERROR("sql.sql", "%s in `condition` table, has incorrect ConditionTarget set, ignoring.", cond->ToString(true).c_str()); return false; } @@ -1584,17 +1696,15 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1)) { - TC_LOG_ERROR("sql.sql", "Aura condition has non existing spell (Id: %d), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing spell (Id: %d), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (cond->ConditionValue2 > EFFECT_2) { - TC_LOG_ERROR("sql.sql", "Aura condition has non existing effect index (%u) (must be 0..2), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has non existing effect index (%u) (must be 0..2), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Aura condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ITEM: @@ -1602,13 +1712,13 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1); if (!proto) { - TC_LOG_ERROR("sql.sql", "Item condition has non existing item (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s Item (%u) does not exist, skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (!cond->ConditionValue2) { - TC_LOG_ERROR("sql.sql", "Item condition has 0 set for item count in value2 (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s Zero item count in ConditionValue2, skipped.", cond->ToString(true).c_str()); return false; } break; @@ -1618,14 +1728,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1); if (!proto) { - TC_LOG_ERROR("sql.sql", "ItemEquipped condition has non existing item (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s Item (%u) does not exist, skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "ItemEquipped condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "ItemEquipped condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ZONEID: @@ -1633,20 +1738,15 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->ConditionValue1); if (!areaEntry) { - TC_LOG_ERROR("sql.sql", "ZoneID condition has non existing area (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s Area (%u) does not exist, skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (areaEntry->ParentAreaID != 0) { - TC_LOG_ERROR("sql.sql", "ZoneID condition requires to be in area (%u) which is a subzone but zone expected, skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s requires to be in area (%u) which is a subzone but zone expected, skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "ZoneID condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "ZoneID condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_REPUTATION_RANK: @@ -1654,25 +1754,18 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->ConditionValue1); if (!factionEntry) { - TC_LOG_ERROR("sql.sql", "Reputation condition has non existing faction (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing faction (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Reputation condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_TEAM: { if (cond->ConditionValue1 != ALLIANCE && cond->ConditionValue1 != HORDE) { - TC_LOG_ERROR("sql.sql", "Team condition specifies unknown team (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s specifies unknown team (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Team condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Team condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_SKILL: @@ -1680,17 +1773,15 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(cond->ConditionValue1); if (!pSkill) { - TC_LOG_ERROR("sql.sql", "Skill condition specifies non-existing skill (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s specifies non-existing skill (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (cond->ConditionValue2 < 1 || cond->ConditionValue2 > sWorld->GetConfigMaxSkillValue()) { - TC_LOG_ERROR("sql.sql", "Skill condition specifies skill (%u) with invalid value (%u), skipped", cond->ConditionValue1, cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s specifies skill (%u) with invalid value (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1, cond->ConditionValue2); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Skill condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_QUESTREWARDED: @@ -1700,30 +1791,19 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (!sObjectMgr->GetQuestTemplate(cond->ConditionValue1)) { - TC_LOG_ERROR("sql.sql", "Quest condition (Type: %u) points to non-existing quest (%u) for Source Entry %u. SourceGroup: %u, SourceTypeOrReferenceId: %u", - cond->ConditionType, cond->ConditionValue1, cond->SourceEntry, cond->SourceGroup, cond->SourceType); + TC_LOG_ERROR("sql.sql", "%s points to non-existing quest (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2 > 1) - TC_LOG_ERROR("sql.sql", "Quest condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Quest condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ACTIVE_EVENT: { GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); - if (cond->ConditionValue1 >=events.size() || !events[cond->ConditionValue1].isValid()) + if (cond->ConditionValue1 >= events.size() || !events[cond->ConditionValue1].isValid()) { - TC_LOG_ERROR("sql.sql", "ActiveEvent condition has non existing event id (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing event id (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "ActiveEvent condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "ActiveEvent condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_ACHIEVEMENT: @@ -1731,56 +1811,36 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) AchievementEntry const* achievement = sAchievementMgr->GetAchievement(cond->ConditionValue1); if (!achievement) { - TC_LOG_ERROR("sql.sql", "Achivement condition has non existing achivement id (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing achivement id (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Achivement condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Achivement condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_CLASS: { if (!(cond->ConditionValue1 & CLASSMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Class condition has non existing classmask (%u), skipped", cond->ConditionValue1 & ~CLASSMASK_ALL_PLAYABLE); + TC_LOG_ERROR("sql.sql", "%s has non existing classmask (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1 & ~CLASSMASK_ALL_PLAYABLE); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Class condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Class condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_RACE: { if (!(cond->ConditionValue1 & RACEMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Race condition has non existing racemask (%u), skipped", cond->ConditionValue1 & ~RACEMASK_ALL_PLAYABLE); + TC_LOG_ERROR("sql.sql", "%s has non existing racemask (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1 & ~RACEMASK_ALL_PLAYABLE); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Race condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Race condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_GENDER: { if (!Player::IsValidGender(uint8(cond->ConditionValue1))) { - TC_LOG_ERROR("sql.sql", "Gender condition has invalid gender (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has invalid gender (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Gender condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Gender condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_MAPID: @@ -1788,77 +1848,54 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) MapEntry const* me = sMapStore.LookupEntry(cond->ConditionValue1); if (!me) { - TC_LOG_ERROR("sql.sql", "Map condition has non existing map (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing map (%u), skipped", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Map condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Map condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_SPELL: { if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1)) { - TC_LOG_ERROR("sql.sql", "Spell condition has non existing spell (Id: %d), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing spell (Id: %d), skipped", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Spell condition has useless data (spell Id: %d) in value2 (%u)!", cond->ConditionValue1, cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Spell condition has useless data (spell Id: %d) in value3 (%u)!", cond->ConditionValue1, cond->ConditionValue3); break; } case CONDITION_LEVEL: { if (cond->ConditionValue2 >= COMP_TYPE_MAX) { - TC_LOG_ERROR("sql.sql", "Level condition has invalid ComparisionType (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has invalid ComparisionType (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Level condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_DRUNKENSTATE: { if (cond->ConditionValue1 > DRUNKEN_SMASHED) { - TC_LOG_ERROR("sql.sql", "DrunkState condition has invalid state (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has invalid state (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - if (cond->ConditionValue2) - { - TC_LOG_ERROR("sql.sql", "DrunkState condition has useless data in value2 (%u)!", cond->ConditionValue2); - return false; - } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "DrunkState condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_NEAR_CREATURE: { if (!sObjectMgr->GetCreatureTemplate(cond->ConditionValue1)) { - TC_LOG_ERROR("sql.sql", "NearCreature condition has non existing creature template entry (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing creature template entry (%u), skipped", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "NearCreature condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_NEAR_GAMEOBJECT: { if (!sObjectMgr->GetGameObjectTemplate(cond->ConditionValue1)) { - TC_LOG_ERROR("sql.sql", "NearGameObject condition has non existing gameobject template entry (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing gameobject template entry (%u), skipped.", cond->ToString().c_str(), cond->ConditionValue1); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "NearGameObject condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_OBJECT_ENTRY_GUID: @@ -1868,7 +1905,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) case TYPEID_UNIT: if (cond->ConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->ConditionValue2)) { - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has non existing creature template entry (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has non existing creature template entry (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } if (cond->ConditionValue3) @@ -1877,13 +1914,13 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (cond->ConditionValue2 && creatureData->id != cond->ConditionValue2) { - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has guid %u set but does not match creature entry (%u), skipped", cond->ConditionValue3, cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has guid %u set but does not match creature entry (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue3, cond->ConditionValue2); return false; } } else { - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has non existing creature guid (%u), skipped", cond->ConditionValue3); + TC_LOG_ERROR("sql.sql", "%s has non existing creature guid (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue3); return false; } } @@ -1891,7 +1928,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) case TYPEID_GAMEOBJECT: if (cond->ConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->ConditionValue2)) { - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has non existing gameobject template entry (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has non existing gameobject template entry (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } if (cond->ConditionValue3) @@ -1900,13 +1937,13 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (cond->ConditionValue2 && goData->id != cond->ConditionValue2) { - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has guid %u set but does not match gameobject entry (%u), skipped", cond->ConditionValue3, cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has guid %u set but does not match gameobject entry (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue3, cond->ConditionValue2); return false; } } else { - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has non existing gameobject guid (%u), skipped", cond->ConditionValue3); + TC_LOG_ERROR("sql.sql", "%s has non existing gameobject guid (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue3); return false; } } @@ -1914,12 +1951,12 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) case TYPEID_PLAYER: case TYPEID_CORPSE: if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has useless data in value2 (%u)!", cond->ConditionValue2); + LogUselessConditionValue(cond, 2, cond->ConditionValue2); if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has useless data in value3 (%u)!", cond->ConditionValue3); + LogUselessConditionValue(cond, 3, cond->ConditionValue3); break; default: - TC_LOG_ERROR("sql.sql", "ObjectEntryGuid condition has wrong typeid set (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has wrong typeid set (%u), skipped", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } break; @@ -1928,51 +1965,45 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (!cond->ConditionValue1 || (cond->ConditionValue1 & ~(TYPEMASK_UNIT | TYPEMASK_PLAYER | TYPEMASK_GAMEOBJECT | TYPEMASK_CORPSE))) { - TC_LOG_ERROR("sql.sql", "TypeMask condition has invalid typemask set (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has invalid typemask set (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "TypeMask condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "TypeMask condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_RELATION_TO: { if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) { - TC_LOG_ERROR("sql.sql", "RelationTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has invalid ConditionValue1(ConditionTarget selection) (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (cond->ConditionValue1 == cond->ConditionTarget) { - TC_LOG_ERROR("sql.sql", "RelationTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has ConditionValue1(ConditionTarget selection) set to self (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (cond->ConditionValue2 >= RELATION_MAX) { - TC_LOG_ERROR("sql.sql", "RelationTo condition has invalid ConditionValue2(RelationType) (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has invalid ConditionValue2(RelationType) (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "RelationTo condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_REACTION_TO: { if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) { - TC_LOG_ERROR("sql.sql", "ReactionTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has invalid ConditionValue1(ConditionTarget selection) (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (cond->ConditionValue1 == cond->ConditionTarget) { - TC_LOG_ERROR("sql.sql", "ReactionTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has ConditionValue1(ConditionTarget selection) set to self (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (!cond->ConditionValue2) { - TC_LOG_ERROR("sql.sql", "mConditionValue2 condition has invalid ConditionValue2(rankMask) (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has invalid ConditionValue2(rankMask) (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } break; @@ -1981,83 +2012,60 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (cond->ConditionValue1 >= cond->GetMaxAvailableConditionTargets()) { - TC_LOG_ERROR("sql.sql", "DistanceTo condition has invalid ConditionValue1(ConditionTarget selection) (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has invalid ConditionValue1(ConditionTarget selection) (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (cond->ConditionValue1 == cond->ConditionTarget) { - TC_LOG_ERROR("sql.sql", "DistanceTo condition has ConditionValue1(ConditionTarget selection) set to self (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has ConditionValue1(ConditionTarget selection) set to self (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (cond->ConditionValue3 >= COMP_TYPE_MAX) { - TC_LOG_ERROR("sql.sql", "DistanceTo condition has invalid ComparisionType (%u), skipped", cond->ConditionValue3); + TC_LOG_ERROR("sql.sql", "%s has invalid ComparisionType (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue3); return false; } break; } - case CONDITION_ALIVE: - { - if (cond->ConditionValue1) - TC_LOG_ERROR("sql.sql", "Alive condition has useless data in value1 (%u)!", cond->ConditionValue1); - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Alive condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Alive condition has useless data in value3 (%u)!", cond->ConditionValue3); - break; - } case CONDITION_HP_VAL: { if (cond->ConditionValue2 >= COMP_TYPE_MAX) { - TC_LOG_ERROR("sql.sql", "HpVal condition has invalid ComparisionType (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has invalid ComparisionType (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "HpVal condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_HP_PCT: { if (cond->ConditionValue1 > 100) { - TC_LOG_ERROR("sql.sql", "HpPct condition has too big percent value (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has too big percent value (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } if (cond->ConditionValue2 >= COMP_TYPE_MAX) { - TC_LOG_ERROR("sql.sql", "HpPct condition has invalid ComparisionType (%u), skipped", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "%s has invalid ComparisionType (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue2); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "HpPct condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_AREAID: - case CONDITION_INSTANCE_INFO: - break; case CONDITION_WORLD_STATE: { if (!sWorld->getWorldState(cond->ConditionValue1)) { - TC_LOG_ERROR("sql.sql", "World state condition has non existing world state in value1 (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing world state in value1 (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "World state condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_PHASEID: { if (!sPhaseStore.LookupEntry(cond->ConditionValue1)) { - TC_LOG_ERROR("sql.sql", "Phase condition has nonexistent phaseid in value1 (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has nonexistent phaseid in value1 (%u), skipped", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Phase condition has useless data in value2 (%u)!", cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Phase condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_TITLE: @@ -2065,7 +2073,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(cond->ConditionValue1); if (!titleEntry) { - TC_LOG_ERROR("sql.sql", "Title condition has non existing title in value1 (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing title in value1 (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } break; @@ -2074,7 +2082,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (cond->ConditionValue1 > SPAWNMASK_RAID_ALL) { - TC_LOG_ERROR("sql.sql", "SpawnMask condition has non existing SpawnMask in value1 (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing SpawnMask in value1 (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } break; @@ -2083,7 +2091,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (!(cond->ConditionValue1 & UNIT_STATE_ALL_STATE_SUPPORTED)) { - TC_LOG_ERROR("sql.sql", "UnitState condition has non existing UnitState in value1 (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing UnitState in value1 (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } break; @@ -2092,17 +2100,34 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (!cond->ConditionValue1 || cond->ConditionValue1 > CREATURE_TYPE_GAS_CLOUD) { - TC_LOG_ERROR("sql.sql", "CreatureType condition has non existing CreatureType in value1 (%u), skipped", cond->ConditionValue1); + TC_LOG_ERROR("sql.sql", "%s has non existing CreatureType in value1 (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; } break; } + case CONDITION_INSTANCE_INFO: + case CONDITION_AREAID: + case CONDITION_ALIVE: + break; default: break; } + + if (cond->ConditionValue1 && !StaticConditionTypeData[cond->ConditionType].HasConditionValue1) + LogUselessConditionValue(cond, 1, cond->ConditionValue1); + if (cond->ConditionValue2 && !StaticConditionTypeData[cond->ConditionType].HasConditionValue2) + LogUselessConditionValue(cond, 2, cond->ConditionValue2); + if (cond->ConditionValue3 && !StaticConditionTypeData[cond->ConditionType].HasConditionValue3) + LogUselessConditionValue(cond, 3, cond->ConditionValue3); + return true; } +void ConditionMgr::LogUselessConditionValue(Condition* cond, uint8 index, uint32 value) +{ + TC_LOG_ERROR("sql.sql", "%s has useless data in ConditionValue%u (%u)!", cond->ToString(true).c_str(), index, value); +} + void ConditionMgr::Clean() { for (ConditionReferenceContainer::iterator itr = ConditionReferenceStore.begin(); itr != ConditionReferenceStore.end(); ++itr) diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index e7f5b64716b..98bc1775e0d 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -23,6 +23,7 @@ #include "Errors.h" #include <list> #include <map> +#include <string> class Player; class Unit; @@ -210,6 +211,8 @@ struct Condition uint32 GetSearcherTypeMaskForCondition(); bool isLoaded() const { return ConditionType > CONDITION_NONE || ReferenceId; } uint32 GetMaxAvailableConditionTargets(); + + std::string ToString(bool ext = false) const; /// For logging purpose }; typedef std::list<Condition*> ConditionList; @@ -229,7 +232,6 @@ class ConditionMgr ~ConditionMgr(); public: - static ConditionMgr* instance() { static ConditionMgr instance; @@ -244,8 +246,8 @@ class ConditionMgr bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions); bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions); bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions); - bool CanHaveSourceGroupSet(ConditionSourceType sourceType) const; - bool CanHaveSourceIdSet(ConditionSourceType sourceType) const; + static bool CanHaveSourceGroupSet(ConditionSourceType sourceType); + static bool CanHaveSourceIdSet(ConditionSourceType sourceType); ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry); ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId); ConditionList GetConditionsForSmartEvent(int64 entryOrGuid, uint32 eventId, uint32 sourceType); @@ -253,6 +255,16 @@ class ConditionMgr ConditionList const* GetConditionsForPhaseDefinition(uint32 zone, uint32 entry); ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId); + struct ConditionTypeInfo + { + char const* Name; + bool HasConditionValue1; + bool HasConditionValue2; + bool HasConditionValue3; + }; + static char const* StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX]; + static ConditionTypeInfo const StaticConditionTypeData[CONDITION_MAX]; + private: bool isSourceTypeValid(Condition* cond); bool addToLootTemplate(Condition* cond, LootTemplate* loot); @@ -261,6 +273,8 @@ class ConditionMgr bool addToSpellImplicitTargetConditions(Condition* cond); bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions); + static void LogUselessConditionValue(Condition* cond, uint8 index, uint32 value); + void Clean(); // free up resources std::list<Condition*> AllocatedMemoryStore; // some garbage collection :) diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index a7cf8478704..65c5ec6873a 100644 --- a/src/server/game/Conditions/DisableMgr.cpp +++ b/src/server/game/Conditions/DisableMgr.cpp @@ -134,11 +134,11 @@ void LoadDisables() break; case MAP_INSTANCE: case MAP_RAID: - if (flags & DUNGEON_STATUSFLAG_HEROIC && !GetMapDifficultyData(entry, DUNGEON_DIFFICULTY_HEROIC)) + if (flags & DUNGEON_STATUSFLAG_HEROIC && !GetMapDifficultyData(entry, DIFFICULTY_HEROIC)) flags -= DUNGEON_STATUSFLAG_HEROIC; - if (flags & RAID_STATUSFLAG_10MAN_HEROIC && !GetMapDifficultyData(entry, RAID_DIFFICULTY_10MAN_HEROIC)) + if (flags & RAID_STATUSFLAG_10MAN_HEROIC && !GetMapDifficultyData(entry, DIFFICULTY_10_HC)) flags -= RAID_STATUSFLAG_10MAN_HEROIC; - if (flags & RAID_STATUSFLAG_25MAN_HEROIC && !GetMapDifficultyData(entry, RAID_DIFFICULTY_25MAN_HEROIC)) + if (flags & RAID_STATUSFLAG_25MAN_HEROIC && !GetMapDifficultyData(entry, DIFFICULTY_25_HC)) flags -= RAID_STATUSFLAG_25MAN_HEROIC; if (!flags) isFlagInvalid = true; @@ -354,13 +354,13 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags GetDownscaledMapDifficultyData(entry, targetDifficulty); switch (targetDifficulty) { - case DUNGEON_DIFFICULTY_NORMAL: + case DIFFICULTY_NORMAL: return (disabledModes & DUNGEON_STATUSFLAG_NORMAL) != 0; - case DUNGEON_DIFFICULTY_HEROIC: + case DIFFICULTY_HEROIC: return (disabledModes & DUNGEON_STATUSFLAG_HEROIC) != 0; - case RAID_DIFFICULTY_10MAN_HEROIC: + case DIFFICULTY_10_HC: return (disabledModes & RAID_STATUSFLAG_10MAN_HEROIC) != 0; - case RAID_DIFFICULTY_25MAN_HEROIC: + case DIFFICULTY_25_HC: return (disabledModes & RAID_STATUSFLAG_25MAN_HEROIC) != 0; } } diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 7a29f7f5894..ae488a5f449 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -39,6 +39,7 @@ DB2Storage<SpellCastingRequirementsEntry> sSpellCastingRequirementsStore(Spell DB2Storage<SpellClassOptionsEntry> sSpellClassOptionsStore(SpellClassOptionsEntryfmt); DB2Storage<SpellMiscEntry> sSpellMiscStore(SpellMiscEntryfmt); DB2Storage<SpellPowerEntry> sSpellPowerStore(SpellPowerEntryfmt); +SpellPowerBySpellIDMap sSpellPowerBySpellIDStore; DB2Storage<SpellReagentsEntry> sSpellReagentsStore(SpellReagentsEntryfmt); DB2Storage<SpellRuneCostEntry> sSpellRuneCostStore(SpellRuneCostEntryfmt); DB2Storage<SpellTotemsEntry> sSpellTotemsStore(SpellTotemsEntryfmt); @@ -52,6 +53,7 @@ TaxiMask sAllianceTaxiNodesMask; TaxiMask sDeathKnightTaxiNodesMask; TaxiPathSetBySource sTaxiPathSetBySource; TaxiPathNodesByPath sTaxiPathNodesByPath; +PhaseGroupContainer sPhasesByGroup; typedef std::list<std::string> DB2StoreProblemList; @@ -142,10 +144,19 @@ void LoadDB2Stores(std::string const& dataPath) LoadDB2(availableDb2Locales, bad_db2_files, sTaxiNodesStore, db2Path, "TaxiNodes.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sTaxiPathStore, db2Path, "TaxiPath.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sTaxiPathNodeStore, db2Path, "TaxiPathNode.db2"); + + for (uint32 i = 0; i < sSpellPowerStore.GetNumRows(); ++i) + if (SpellPowerEntry const* power = sSpellPowerStore.LookupEntry(i)) + sSpellPowerBySpellIDStore[power->SpellID] = power; + + for (uint32 i = 0; i < sPhaseGroupStore.GetNumRows(); ++i) + if (PhaseGroupEntry const* group = sPhaseGroupStore.LookupEntry(i)) + if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseID)) + sPhasesByGroup[group->PhaseGroupID].insert(phase->ID); for (uint32 i = 0; i < sItemAppearanceStore.GetNumRows(); ++i) if (ItemAppearanceEntry const* entry = sItemAppearanceStore.LookupEntry(i)) - sItemDisplayIDMap[entry->AppearanceID] = entry->DisplayID; + sItemDisplayIDMap[entry->FileDataID] = entry->DisplayID; for (uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i) if (TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(i)) @@ -277,3 +288,8 @@ uint32 GetItemDisplayID(uint32 appearanceID) return itr->second; return 0; } + +std::set<uint32> const& GetPhasesForGroup(uint32 group) +{ + return sPhasesByGroup[group]; +} diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 29fe93ce2b1..6521ea930a8 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -39,6 +39,7 @@ extern DB2Storage<SpellCastingRequirementsEntry> sSpellCastingRequirementsStore; extern DB2Storage<SpellClassOptionsEntry> sSpellClassOptionsStore; extern DB2Storage<SpellMiscEntry> sSpellMiscStore; extern DB2Storage<SpellPowerEntry> sSpellPowerStore; +extern SpellPowerBySpellIDMap sSpellPowerBySpellIDStore; extern DB2Storage<SpellReagentsEntry> sSpellReagentsStore; extern DB2Storage<SpellRuneCostEntry> sSpellRuneCostStore; extern DB2Storage<SpellTotemsEntry> sSpellTotemsStore; @@ -59,4 +60,6 @@ DB2StorageBase const* GetDB2Storage(uint32 type); uint32 GetItemDisplayID(uint32 appearanceID); +std::set<uint32> const& GetPhasesForGroup(uint32 group); + #endif diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index de5436860a6..8e91ec8396f 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -21,6 +21,7 @@ #include "Common.h" #include "DBCEnums.h" #include "ItemPrototype.h" +#include "Path.h" // GCC has alternative #pragma pack(N) syntax and old gcc version does not support pack(push, N), also any gcc version does not support it at some platform #if defined(__GNUC__) @@ -60,15 +61,15 @@ struct ItemEntry int32 Material; // 4 uint32 InventoryType; // 5 uint32 Sheath; // 6 - uint32 AppearanceID; // 7 (ItemAppearance.db2) - //uint32 Unk; // 8 + uint32 FileDataID; // 7 + uint32 GroupSoundsID; // 8 }; struct ItemAppearanceEntry { uint32 ID; // 0 (reference to ItemModifiedAppearance.db2?) uint32 DisplayID; // 1 - uint32 AppearanceID; // 2 + uint32 FileDataID; // 2 }; struct ItemCurrencyCostEntry @@ -94,7 +95,7 @@ struct ItemSparseEntry { uint32 ID; // 0 uint32 Quality; // 1 - uint32 Flags[3]; // 2-4 + uint32 Flags[MAX_ITEM_PROTO_FLAGS]; // 2-4 float Unk1; // 5 float Unk2; // 6 uint32 BuyCount; // 7 @@ -153,77 +154,7 @@ struct ItemSparseEntry float StatScalingFactor; // 98 uint32 CurrencySubstitutionID; // 99 uint32 CurrencySubstitutionCount; // 100 - //uint32 Unk3; // 101 - - /*uint32 ID; // 0 - uint32 Quality; // 1 - uint32 Flags; // 2 - uint32 Flags2; // 3 - float Unk430_1; - float Unk430_2; - uint32 BuyCount; - uint32 BuyPrice; // 4 - uint32 SellPrice; // 5 - uint32 InventoryType; // 6 - int32 AllowableClass; // 7 - int32 AllowableRace; // 8 - uint32 ItemLevel; // 9 - int32 RequiredLevel; // 10 - uint32 RequiredSkill; // 11 - uint32 RequiredSkillRank; // 12 - uint32 RequiredSpell; // 13 - uint32 RequiredHonorRank; // 14 - uint32 RequiredCityRank; // 15 - uint32 RequiredReputationFaction; // 16 - uint32 RequiredReputationRank; // 17 - uint32 MaxCount; // 18 - uint32 Stackable; // 19 - uint32 ContainerSlots; // 20 - int32 ItemStatType[MAX_ITEM_PROTO_STATS]; // 21 - 30 - uint32 ItemStatValue[MAX_ITEM_PROTO_STATS]; // 31 - 40 - int32 ItemStatUnk1[MAX_ITEM_PROTO_STATS]; // 41 - 50 - int32 ItemStatUnk2[MAX_ITEM_PROTO_STATS]; // 51 - 60 - uint32 ScalingStatDistribution; // 61 - uint32 DamageType; // 62 - uint32 Delay; // 63 - float RangedModRange; // 64 - int32 SpellId[MAX_ITEM_PROTO_SPELLS]; // 65 - 69 - int32 SpellTrigger[MAX_ITEM_PROTO_SPELLS]; // 70 - 74 - int32 SpellCharges[MAX_ITEM_PROTO_SPELLS]; // 75 - 79 - int32 SpellCooldown[MAX_ITEM_PROTO_SPELLS]; // 80 - 84 - int32 SpellCategory[MAX_ITEM_PROTO_SPELLS]; // 85 - 89 - int32 SpellCategoryCooldown[MAX_ITEM_PROTO_SPELLS]; // 90 - 94 - uint32 Bonding; // 95 - LocalizedString* Name; // 96 - LocalizedString* Name2; // 97 - LocalizedString* Name3; // 98 - LocalizedString* Name4; // 99 - LocalizedString* Description; // 100 - uint32 PageText; // 101 - uint32 LanguageID; // 102 - uint32 PageMaterial; // 103 - uint32 StartQuest; // 104 - uint32 LockID; // 105 - int32 Material; // 106 - uint32 Sheath; // 107 - uint32 RandomProperty; // 108 - uint32 RandomSuffix; // 109 - uint32 ItemSet; // 110 - uint32 Area; // 112 - uint32 Map; // 113 - uint32 BagFamily; // 114 - uint32 TotemCategory; // 115 - uint32 Color[MAX_ITEM_PROTO_SOCKETS]; // 116 - 118 - uint32 Content[MAX_ITEM_PROTO_SOCKETS]; // 119 - 121 - int32 SocketBonus; // 122 - uint32 GemProperties; // 123 - float ArmorDamageModifier; // 124 - uint32 Duration; // 125 - uint32 ItemLimitCategory; // 126 - uint32 HolidayId; // 127 - float StatScalingFactor; // 128 - int32 CurrencySubstitutionId; // 129 - int32 CurrencySubstitutionCount; // 130*/ + uint32 ItemNameDescriptionID; // 101 }; #define MAX_ITEM_EXT_COST_ITEMS 5 @@ -232,13 +163,13 @@ struct ItemSparseEntry struct ItemExtendedCostEntry { uint32 ID; // 0 extended-cost entry id - //uint32 reqhonorpoints; // 1 required honor points - //uint32 reqarenapoints; // 2 required arena points + uint32 RequiredHonorPoints; // 1 required honor points + uint32 RequiredArenaPoints; // 2 required arena points uint32 RequiredArenaSlot; // 3 arena slot restrictions (min slot value) uint32 RequiredItem[MAX_ITEM_EXT_COST_ITEMS]; // 4-8 required item id uint32 RequiredItemCount[MAX_ITEM_EXT_COST_ITEMS]; // 9-13 required count of 1st item uint32 RequiredPersonalArenaRating; // 14 required personal arena rating - //uint32 ItemPurchaseGroup; // 15 + uint32 ItemPurchaseGroup; // 15 uint32 RequiredCurrency[MAX_ITEM_EXT_COST_CURRENCIES];// 16-20 required curency id uint32 RequiredCurrencyCount[MAX_ITEM_EXT_COST_CURRENCIES];// 21-25 required curency count uint32 RequiredFactionId; @@ -423,6 +354,8 @@ struct TaxiPathNodeEntry typedef std::map<uint32, uint32> ItemDisplayIDMap; +typedef std::map<uint32, SpellPowerEntry const*> SpellPowerBySpellIDMap; + struct TaxiPathBySourceAndDestination { TaxiPathBySourceAndDestination() : ID(0), price(0) { } @@ -448,4 +381,5 @@ typedef std::vector<TaxiPathNodeList> TaxiPathNodesByPath; #define TaxiMaskSize 114 typedef uint8 TaxiMask[TaxiMaskSize]; -#endif
\ No newline at end of file +typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer; +#endif diff --git a/src/server/game/DataStores/DB2Utility.cpp b/src/server/game/DataStores/DB2Utility.cpp index 37b7fb949db..a835547b640 100644 --- a/src/server/game/DataStores/DB2Utility.cpp +++ b/src/server/game/DataStores/DB2Utility.cpp @@ -42,15 +42,15 @@ void DB2Utilities::WriteItemDbReply(DB2Storage<ItemEntry> const& /*store*/, uint buffer << uint32(proto->Class); buffer << uint32(proto->SubClass); buffer << int32(proto->SoundOverrideSubclass); - buffer << uint32(proto->Material); - buffer << uint32(proto->DisplayInfoID); + buffer << int32(proto->Material); buffer << uint32(proto->InventoryType); buffer << uint32(proto->Sheath); + buffer << uint32(proto->FileDataID); + buffer << uint32(proto->GroupSoundsID); } void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*store*/, uint32 id, uint32 locale, ByteBuffer& buffer) { - /* TODO: 6.x update ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id); ASSERT(proto); @@ -58,10 +58,12 @@ void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*s buffer << uint32(proto->ItemId); buffer << uint32(proto->Quality); - buffer << uint32(proto->Flags); - buffer << uint32(proto->Flags2); - buffer << float(proto->Unk430_1); - buffer << float(proto->Unk430_2); + + for (uint32 i = 0; i < MAX_ITEM_PROTO_FLAGS; ++i) + buffer << uint32(proto->Flags[i]); + + buffer << float(proto->Unk1); + buffer << float(proto->Unk2); buffer << uint32(proto->BuyCount); buffer << int32(proto->BuyPrice); buffer << uint32(proto->SellPrice); @@ -97,25 +99,6 @@ void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*s buffer << uint32(proto->DamageType); buffer << uint32(proto->Delay); buffer << float(proto->RangedModRange); - - for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) - buffer << int32(proto->Spells[x].SpellId); - - for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) - buffer << uint32(proto->Spells[x].SpellTrigger); - - for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) - buffer << int32(proto->Spells[x].SpellCharges); - - for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) - buffer << int32(proto->Spells[x].SpellCooldown); - - for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) - buffer << uint32(proto->Spells[x].SpellCategory); - - for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) - buffer << int32(proto->Spells[x].SpellCategoryCooldown); - buffer << uint32(proto->Bonding); // item name @@ -145,8 +128,8 @@ void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*s buffer << uint32(proto->LockID); buffer << int32(proto->Material); buffer << uint32(proto->Sheath); - buffer << int32(proto->RandomProperty); - buffer << int32(proto->RandomSuffix); + buffer << uint32(proto->RandomProperty); + buffer << uint32(proto->RandomSuffix); buffer << uint32(proto->ItemSet); buffer << uint32(proto->Area); @@ -157,9 +140,6 @@ void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*s for (uint32 x = 0; x < MAX_ITEM_PROTO_SOCKETS; ++x) buffer << uint32(proto->Socket[x].Color); - for (uint32 x = 0; x < MAX_ITEM_PROTO_SOCKETS; ++x) - buffer << uint32(proto->Socket[x].Content); - buffer << uint32(proto->socketBonus); buffer << uint32(proto->GemProperties); buffer << float(proto->ArmorDamageModifier); @@ -169,5 +149,5 @@ void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*s buffer << float(proto->StatScalingFactor); // StatScalingFactor buffer << uint32(proto->CurrencySubstitutionId); buffer << uint32(proto->CurrencySubstitutionCount); - */ + buffer << uint32(proto->ItemNameDescriptionID); } diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h index 5d2f374f2a7..f47efa43f89 100644 --- a/src/server/game/DataStores/DB2fmt.h +++ b/src/server/game/DataStores/DB2fmt.h @@ -19,11 +19,11 @@ #define TRINITY_DB2SFRM_H char const HolidaysEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix"; -char const Itemfmt[]="niiiiiiix"; +char const Itemfmt[]="niiiiiiii"; char const ItemAppearanceEntryfmt[]="nii"; char const ItemCurrencyCostfmt[]="xn"; -char const ItemSparsefmt[]="niiiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifisssssiiiiiiiiiiiiiiiiiiifiiifiix"; -char const ItemExtendedCostEntryfmt[]="nxxiiiiiiiiiiiixiiiiiiiiiiiiii"; +char const ItemSparsefmt[]="niiiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifisssssiiiiiiiiiiiiiiiiiiifiiifiii"; +char const ItemExtendedCostEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; char const ItemEffectEntryfmt[]="niiiiiiii"; char const KeyChainfmt[]="nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; char const OverrideSpellDataEntryfmt[] = "niiiiiiiiiixx"; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index d4831127183..fa1ca29f4ef 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -51,11 +51,11 @@ enum LevelLimit enum BattlegroundBracketId // bracketId for level ranges { BG_BRACKET_ID_FIRST = 0, - BG_BRACKET_ID_LAST = 15 -}; + BG_BRACKET_ID_LAST = 10, -// must be max value in PvPDificulty slot+1 -#define MAX_BATTLEGROUND_BRACKETS 16 + // must be max value in PvPDificulty slot + 1 + MAX_BATTLEGROUND_BRACKETS +}; enum AreaTeams { @@ -337,16 +337,26 @@ enum AreaFlags enum Difficulty { - REGULAR_DIFFICULTY = 0, - - DUNGEON_DIFFICULTY_NORMAL = 0, - DUNGEON_DIFFICULTY_HEROIC = 1, - DUNGEON_DIFFICULTY_EPIC = 2, - - RAID_DIFFICULTY_10MAN_NORMAL = 0, - RAID_DIFFICULTY_25MAN_NORMAL = 1, - RAID_DIFFICULTY_10MAN_HEROIC = 2, - RAID_DIFFICULTY_25MAN_HEROIC = 3 + DIFFICULTY_NONE = 0, + DIFFICULTY_NORMAL = 1, + DIFFICULTY_HEROIC = 2, + DIFFICULTY_10_N = 3, + DIFFICULTY_25_N = 4, + DIFFICULTY_10_HC = 5, + DIFFICULTY_25_HC = 6, + DIFFICULTY_LFR = 7, + DIFFICULTY_CHALLENGE = 8, + DIFFICULTY_40 = 9, + DIFFICULTY_HC_SCENARIO = 11, + DIFFICULTY_N_SCENARIO = 12, + DIFFICULTY_NORMAL2 = 14, + DIFFICULTY_HEROIC2 = 15, + DIFFICULTY_MYTHIC = 16, + DIFFICULTY_LFR2 = 17, + DIFFICULTY_EVENT = 18, + DIFFICULTY_EVENT2 = 19, + DIFFICULTY_EVENT_SCENARIO = 20, + DIFFICULTY_MAX = 21, }; #define RAID_DIFFICULTY_MASK_25MAN 1 // since 25man difficulties are 1 and 3, we can check them like that @@ -357,18 +367,18 @@ enum Difficulty enum SpawnMask { - SPAWNMASK_CONTINENT = (1 << REGULAR_DIFFICULTY), // any maps without spawn modes + SPAWNMASK_CONTINENT = (1 << DIFFICULTY_NONE), // any maps without spawn modes - SPAWNMASK_DUNGEON_NORMAL = (1 << DUNGEON_DIFFICULTY_NORMAL), - SPAWNMASK_DUNGEON_HEROIC = (1 << DUNGEON_DIFFICULTY_HEROIC), + SPAWNMASK_DUNGEON_NORMAL = (1 << DIFFICULTY_NORMAL), + SPAWNMASK_DUNGEON_HEROIC = (1 << DIFFICULTY_HEROIC), SPAWNMASK_DUNGEON_ALL = (SPAWNMASK_DUNGEON_NORMAL | SPAWNMASK_DUNGEON_HEROIC), - SPAWNMASK_RAID_10MAN_NORMAL = (1 << RAID_DIFFICULTY_10MAN_NORMAL), - SPAWNMASK_RAID_25MAN_NORMAL = (1 << RAID_DIFFICULTY_25MAN_NORMAL), + SPAWNMASK_RAID_10MAN_NORMAL = (1 << DIFFICULTY_10_N), + SPAWNMASK_RAID_25MAN_NORMAL = (1 << DIFFICULTY_25_N), SPAWNMASK_RAID_NORMAL_ALL = (SPAWNMASK_RAID_10MAN_NORMAL | SPAWNMASK_RAID_25MAN_NORMAL), - SPAWNMASK_RAID_10MAN_HEROIC = (1 << RAID_DIFFICULTY_10MAN_HEROIC), - SPAWNMASK_RAID_25MAN_HEROIC = (1 << RAID_DIFFICULTY_25MAN_HEROIC), + SPAWNMASK_RAID_10MAN_HEROIC = (1 << DIFFICULTY_10_HC), + SPAWNMASK_RAID_25MAN_HEROIC = (1 << DIFFICULTY_25_HC), SPAWNMASK_RAID_HEROIC_ALL = (SPAWNMASK_RAID_10MAN_HEROIC | SPAWNMASK_RAID_25MAN_HEROIC), SPAWNMASK_RAID_ALL = (SPAWNMASK_RAID_NORMAL_ALL | SPAWNMASK_RAID_HEROIC_ALL) diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 5defb7e527c..2af63e0b6bf 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -20,6 +20,7 @@ #include "Containers.h" #include "Log.h" #include "SharedDefines.h" +#include "SpellInfo.h" #include "SpellMgr.h" #include "TransportMgr.h" #include "DBCfmt.h" @@ -101,25 +102,25 @@ DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt); DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt); DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt); +DBCStorage <GameTablesEntry> sGameTablesStore(GameTablesFmt); DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt); DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore(GlyphPropertiesfmt); DBCStorage <GlyphSlotEntry> sGlyphSlotStore(GlyphSlotfmt); -DBCStorage <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore(GtBarberShopCostBasefmt); -DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore(GtCombatRatingsfmt); -DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore(GtChanceToMeleeCritBasefmt); -DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore(GtChanceToMeleeCritfmt); -DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore(GtChanceToSpellCritBasefmt); -DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore(GtChanceToSpellCritfmt); -DBCStorage <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore(GtNPCManaCostScalerfmt); -DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore(GtOCTClassCombatRatingScalarfmt); -DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt); -//DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore(GtOCTRegenMPfmt); -- not used currently -DBCStorage <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore(GtOCTHpPerStaminafmt); -DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt); -DBCStorage <GtSpellScalingEntry> sGtSpellScalingStore(GtSpellScalingfmt); -DBCStorage <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore(GtOCTBaseHPByClassfmt); -DBCStorage <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore(GtOCTBaseMPByClassfmt); +GameTable <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore(GtBarberShopCostBasefmt); +GameTable <GtCombatRatingsEntry> sGtCombatRatingsStore(GtCombatRatingsfmt); +GameTable <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore(GtChanceToMeleeCritBasefmt); +GameTable <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore(GtChanceToMeleeCritfmt); +GameTable <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore(GtChanceToSpellCritBasefmt); +GameTable <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore(GtChanceToSpellCritfmt); +GameTable <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore(GtNPCManaCostScalerfmt); +GameTable <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore(GtOCTClassCombatRatingScalarfmt); +GameTable <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt); +GameTable <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore(GtOCTHpPerStaminafmt); +GameTable <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt); +GameTable <GtSpellScalingEntry> sGtSpellScalingStore(GtSpellScalingfmt); +GameTable <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore(GtOCTBaseHPByClassfmt); +GameTable <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore(GtOCTBaseMPByClassfmt); DBCStorage <GuildPerkSpellsEntry> sGuildPerkSpellsStore(GuildPerkSpellsfmt); DBCStorage <ImportPriceArmorEntry> sImportPriceArmorStore(ImportPriceArmorfmt); @@ -191,8 +192,13 @@ DBCStorage <SpecializationSpellsEntry> sSpecializationSpellsStore(Specialization DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt); DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt); DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt); +DBCStorage <SpellEffectScalingEntry> sSpellEffectScalingStore(SpellEffectScalingfmt); + SpellCategoryStore sSpellsByCategoryStore; PetFamilySpellsStore sPetFamilySpellsStore; +SpellsPerClassStore sSpellsPerClassStore; +ClassBySkillIdStore sClassBySkillIdStore; +SpellEffectScallingByEffectId sSpellEffectScallingByEffectId; DBCStorage <SpellScalingEntry> sSpellScalingStore(SpellScalingEntryfmt); @@ -216,6 +222,8 @@ DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt); DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt); DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt); TalentBySpellIDMap sTalentBySpellIDMap; +SpecializationSpellsMap sSpecializationSpellsMap; +SpecializationOverrideSpellsMap sSpecializationOverrideSpellMap; DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt); DBCStorage <TransportAnimationEntry> sTransportAnimationStore(TransportAnimationfmt); @@ -229,8 +237,6 @@ DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt) DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt); DBCStorage <PhaseEntry> sPhaseStore(PhaseEntryfmt); -PhaseGroupContainer sPhasesByGroup; - typedef std::list<std::string> StoreProblemList; uint32 DBCFileCount = 0; @@ -289,6 +295,51 @@ inline void LoadDBC(uint32& availableDbcLocales, StoreProblemList& errors, DBCSt delete sql; } +template<class T> +inline void LoadGameTable(StoreProblemList& errors, std::string const& tableName, GameTable<T>& storage, std::string const& dbcPath, std::string const& filename) +{ + // compatibility format and C++ structure sizes + ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename)); + + ++DBCFileCount; + std::string dbcFilename = dbcPath + filename; + + if (storage.Load(dbcFilename.c_str())) + { + bool found = false; + // Find table definition in GameTables.dbc + for (uint32 i = 0; i < sGameTablesStore.GetNumRows(); ++i) + { + GameTablesEntry const* gt = sGameTablesStore.LookupEntry(i); + if (!gt) + continue; + + if (tableName == gt->Name) + { + found = true; + storage.SetGameTableEntry(gt); + break; + } + } + + ASSERT(found, "Game table %s definition not found in GameTables.dbc", tableName.c_str()); + } + else + { + // sort problematic dbc to (1) non compatible and (2) non-existed + if (FILE* f = fopen(dbcFilename.c_str(), "rb")) + { + std::ostringstream stream; + stream << dbcFilename << " exists, and has " << storage.GetFieldCount() << " field(s) (expected " << strlen(storage.GetFormat()) << "). Extracted file might be from wrong client version or a database-update has been forgotten."; + std::string buf = stream.str(); + errors.push_back(buf); + fclose(f); + } + else + errors.push_back(dbcFilename); + } +} + void LoadDBCStores(const std::string& dataPath) { uint32 oldMSTime = getMSTime(); @@ -398,24 +449,10 @@ void LoadDBCStores(const std::string& dataPath) } } + LoadDBC(availableDbcLocales, bad_dbc_files, sGameTablesStore, dbcPath, "GameTables.dbc");//19243 LoadDBC(availableDbcLocales, bad_dbc_files, sGemPropertiesStore, dbcPath, "GemProperties.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sGlyphPropertiesStore, dbcPath, "GlyphProperties.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sGlyphSlotStore, dbcPath, "GlyphSlot.dbc");//19116 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtBarberShopCostBaseStore, dbcPath, "gtBarberShopCostBase.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtCombatRatingsStore, dbcPath, "gtCombatRatings.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToMeleeCritBaseStore, dbcPath, "gtChanceToMeleeCritBase.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToMeleeCritStore, dbcPath, "gtChanceToMeleeCrit.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToSpellCritBaseStore, dbcPath, "gtChanceToSpellCritBase.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToSpellCritStore, dbcPath, "gtChanceToSpellCrit.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtNPCManaCostScalerStore, dbcPath, "gtNPCManaCostScaler.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTClassCombatRatingScalarStore, dbcPath, "gtOCTClassCombatRatingScalar.dbc");//15595 - //LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTRegenHPStore, dbcPath, "gtOCTRegenHP.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTHpPerStaminaStore, dbcPath, "gtOCTHpPerStamina.dbc");//15595 - //LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sGtOCTRegenMPStore, dbcPath, "gtOCTRegenMP.dbc"); -- not used currently - LoadDBC(availableDbcLocales, bad_dbc_files, sGtRegenMPPerSptStore, dbcPath, "gtRegenMPPerSpt.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtSpellScalingStore, dbcPath, "gtSpellScaling.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTBaseHPByClassStore, dbcPath, "gtOCTBaseHPByClass.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTBaseMPByClassStore, dbcPath, "gtOCTBaseMPByClass.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sGuildPerkSpellsStore, dbcPath, "GuildPerkSpells.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sImportPriceArmorStore, dbcPath, "ImportPriceArmor.dbc"); // 19116 @@ -478,11 +515,6 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sPhaseStore, dbcPath, "Phase.dbc"); // 19116 - for (uint32 i = 0; i < sPhaseGroupStore.GetNumRows(); ++i) - if (PhaseGroupEntry const* group = sPhaseGroupStore.LookupEntry(i)) - if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseID)) - sPhasesByGroup[group->PhaseGroupID].insert(phase->ID); - LoadDBC(availableDbcLocales, bad_dbc_files, sPowerDisplayStore, dbcPath, "PowerDisplay.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sPvPDifficultyStore, dbcPath, "PvpDifficulty.dbc");//19116 @@ -517,7 +549,10 @@ void LoadDBCStores(const std::string& dataPath) SpecializationSpellsEntry const* specSpells = sSpecializationSpellsStore.LookupEntry(i); if (!specSpells) continue; - sSpecializationSpellsBySpecStore[specSpells->SpecID].insert(specSpells); + sSpecializationSpellsBySpecStore[specSpells->SpecID].push_back(specSpells); + + if (specSpells->OverridesSpellID) + sSpecializationOverrideSpellMap[specSpells->SpecID][specSpells->OverridesSpellID] = specSpells->SpellID; } LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc"/*, &CustomSpellEntryfmt, &CustomSpellEntryIndex*/); LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoriesStore, dbcPath, "SpellCategories.dbc");//15595 @@ -543,6 +578,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCastTimesStore, dbcPath, "SpellCastTimes.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellDurationStore, dbcPath, "SpellDuration.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellFocusObjectStore, dbcPath, "SpellFocusObject.dbc");//19116 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellEffectScalingStore, dbcPath, "SpellEffectScaling.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellItemEnchantmentStore, dbcPath, "SpellItemEnchantment.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellItemEnchantmentConditionStore, dbcPath, "SpellItemEnchantmentCondition.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellRadiusStore, dbcPath, "SpellRadius.dbc");//19116 @@ -552,41 +588,67 @@ void LoadDBCStores(const std::string& dataPath) //LoadDBC(availableDbcLocales, bad_dbc_files, sStableSlotPricesStore, dbcPath, "StableSlotPrices.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sSummonPropertiesStore, dbcPath, "SummonProperties.dbc");//15595 - // Must be done when sSkillLineAbilityStore, sSpellStore, sSpellLevelsStore and sCreatureFamilyStore are all loaded - /* TODO: Requires spells attributes from SpellMisc.db2 is loaded after dbc + for (uint32 j = 0; j < sSpellEffectScalingStore.GetNumRows(); j++) + { + SpellEffectScalingEntry const* spellEffectScaling = sSpellEffectScalingStore.LookupEntry(j); + if (!spellEffectScaling) + continue; + + sSpellEffectScallingByEffectId.insert(std::make_pair(spellEffectScaling->SpellEffectID, j)); + } + std::map<std::string, uint32> classIdByName; + for (uint32 j = 0; j < sChrClassesStore.GetNumRows(); j++) + { + ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(j); + if (!classEntry) + continue; + + classIdByName.insert(std::make_pair(std::string(classEntry->Name_lang), j)); + } + + for (uint32 j = 0; j < sSkillLineStore.GetNumRows(); j++) + { + SkillLineEntry const* skillEntry = sSkillLineStore.LookupEntry(j); + if (!skillEntry) + continue; + + if (skillEntry->CategoryID!= SKILL_CATEGORY_CLASS) + continue; + + std::map<std::string, uint32> ::const_iterator iter = classIdByName.find(std::string(skillEntry->DisplayName_lang)); + if (iter == classIdByName.end()) + continue; + + sClassBySkillIdStore.insert(std::make_pair(j, iter->second)); + } + for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) { - SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j); - if (!skillLine) + SkillLineAbilityEntry const* skillAbility = sSkillLineAbilityStore.LookupEntry(j); + if (!skillAbility) continue; - SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->SpellID); + if (skillAbility->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillAbility->SpellID); if (!spellInfo) continue; - SpellLevelsEntry const* levels = sSpellLevelsStore.LookupEntry(spellInfo->SpellLevelsID); - if (spellInfo->SpellLevelsID && (!levels || levels->spellLevel)) + SpellLevelsEntry const* spellLevels = sSpellLevelsStore.LookupEntry(spellInfo->LevelsID); + if (!spellLevels || !spellLevels->SpellLevel) continue; - if (spellInfo && spellInfo->Attributes & SPELL_ATTR0_PASSIVE) - { - for (uint32 i = 1; i < sCreatureFamilyStore.GetNumRows(); ++i) - { - CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(i); - if (!cFamily) - continue; + uint32 classId = GetClassBySkillId(skillAbility->SkillLine); - if (skillLine->SkillLine != cFamily->SkillLine[0] && skillLine->SkillLine != cFamily->SkillLine[1]) - continue; + if (!classId) + continue; - if (skillLine->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) - continue; + if (sSpellsPerClassStore.find(classId) == sSpellsPerClassStore.end()) + sSpellsPerClassStore.insert(make_pair(classId, std::list<SkillLineAbilityEntry const*>())); - sPetFamilySpellsStore[i].insert(spellInfo->ID); - } - } + sSpellsPerClassStore[classId].push_back(skillAbility); } - */ LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//15595 @@ -664,6 +726,20 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sWorldMapOverlayStore, dbcPath, "WorldMapOverlay.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sWorldSafeLocsStore, dbcPath, "WorldSafeLocs.dbc"); // 19116 + LoadGameTable(bad_dbc_files, "BarberShopCostBase", sGtBarberShopCostBaseStore, dbcPath, "gtBarberShopCostBase.dbc");//15595 + LoadGameTable(bad_dbc_files, "CombatRatings", sGtCombatRatingsStore, dbcPath, "gtCombatRatings.dbc");//15595 + LoadGameTable(bad_dbc_files, "ChanceToMeleeCritBase", sGtChanceToMeleeCritBaseStore, dbcPath, "gtChanceToMeleeCritBase.dbc");//15595 + LoadGameTable(bad_dbc_files, "ChanceToMeleeCrit", sGtChanceToMeleeCritStore, dbcPath, "gtChanceToMeleeCrit.dbc");//15595 + LoadGameTable(bad_dbc_files, "ChanceToSpellCritBase", sGtChanceToSpellCritBaseStore, dbcPath, "gtChanceToSpellCritBase.dbc");//15595 + LoadGameTable(bad_dbc_files, "ChanceToSpellCrit", sGtChanceToSpellCritStore, dbcPath, "gtChanceToSpellCrit.dbc");//15595 + LoadGameTable(bad_dbc_files, "NPCManaCostScaler", sGtNPCManaCostScalerStore, dbcPath, "gtNPCManaCostScaler.dbc"); + LoadGameTable(bad_dbc_files, "OCTClassCombatRatingScalar", sGtOCTClassCombatRatingScalarStore, dbcPath, "gtOCTClassCombatRatingScalar.dbc");//15595 + LoadGameTable(bad_dbc_files, "OCTHPPerStamina", sGtOCTHpPerStaminaStore, dbcPath, "gtOCTHpPerStamina.dbc");//15595 + LoadGameTable(bad_dbc_files, "RegenMPPerSpt", sGtRegenMPPerSptStore, dbcPath, "gtRegenMPPerSpt.dbc");//15595 + LoadGameTable(bad_dbc_files, "SpellScaling", sGtSpellScalingStore, dbcPath, "gtSpellScaling.dbc");//15595 + LoadGameTable(bad_dbc_files, "OCTBaseHPByClass", sGtOCTBaseHPByClassStore, dbcPath, "gtOCTBaseHPByClass.dbc");//15595 + LoadGameTable(bad_dbc_files, "OCTBaseMPByClass", sGtOCTBaseMPByClassStore, dbcPath, "gtOCTBaseMPByClass.dbc");//15595 + // error checks if (bad_dbc_files.size() >= DBCFileCount) { @@ -896,7 +972,7 @@ MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &di MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); if (!mapDiff) { - if (tmpDiff > RAID_DIFFICULTY_25MAN_NORMAL) // heroic, downscale to normal + if (tmpDiff > DIFFICULTY_25_N) // heroic, downscale to normal tmpDiff -= 2; else tmpDiff -= 1; // any non-normal mode for raids like tbc (only one mode) @@ -1178,7 +1254,81 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u return NULL; } -std::set<uint32> const& GetPhasesForGroup(uint32 group) +uint32 GetClassBySkillId(uint32 skillId) +{ + ClassBySkillIdStore::const_iterator iter = sClassBySkillIdStore.find(skillId); + if (iter != sClassBySkillIdStore.end()) + return iter->second; + return 0; +} + +uint32 GetSkillIdByClass(uint32 classId) +{ + for (ClassBySkillIdStore::const_iterator iter = sClassBySkillIdStore.begin(); iter != sClassBySkillIdStore.end(); iter++) + if (iter->second == classId) + return iter->first; + return 0; +} + +std::list<uint32> GetSpellsForLevels(uint32 classId, uint32 raceMask, uint32 specializationId, uint32 minLevel, uint32 maxLevel) +{ + std::list<uint32> spellList; + + if (classId != 0) + { + SpellsPerClassStore::const_iterator classIter = sSpellsPerClassStore.find(classId); + if (classIter != sSpellsPerClassStore.end()) + { + const std::list<SkillLineAbilityEntry const*>& learnSpellList = classIter->second; + for (std::list<SkillLineAbilityEntry const*>::const_iterator iter = learnSpellList.begin(); iter != learnSpellList.end(); iter++) + { + SkillLineAbilityEntry const* skillLine = *iter; + if (!skillLine) + continue; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillLine->SpellID); + if (!spellInfo) + continue; + + if (skillLine->RaceMask && !(skillLine->RaceMask & raceMask)) + continue; + + if (spellInfo->SpellLevel <= minLevel || spellInfo->SpellLevel > maxLevel) + continue; + + spellList.push_back(spellInfo->Id); + } + } + } + + if (!specializationId) + return spellList; + + SpecializationSpellsBySpecStore::const_iterator specIter = sSpecializationSpellsBySpecStore.find(specializationId); + if (specIter != sSpecializationSpellsBySpecStore.end()) + { + SpecializationSpellsBySpecEntry learnSpellList = specIter->second; + for (int i = 0; i < learnSpellList.size(); i++) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learnSpellList[i]->SpellID); + if (!spellInfo) + { + TC_LOG_ERROR("spells", "GetSpellsForLevels: spell %u not found in spellstore", learnSpellList[i]->SpellID); + continue; + } + if (spellInfo->SpellLevel <= minLevel || spellInfo->SpellLevel > maxLevel) + continue; + + spellList.push_back(spellInfo->Id); + } + } + return spellList; +} + +uint32 GetTalentSpellCost(uint32 spellId) { - return sPhasesByGroup[group]; + TalentBySpellIDMap::const_iterator itr = sTalentBySpellIDMap.find(spellId); + if (itr == sTalentBySpellIDMap.end()) + return 0; + return 1; } diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index e9a9b3c692f..20e8e1fc423 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -26,11 +26,14 @@ #include <list> +typedef std::map<uint32, uint32> SpecializationOverrideSpellsList; +typedef std::map<uint32, SpecializationOverrideSpellsList> SpecializationOverrideSpellsMap; + typedef std::list<uint32> SimpleFactionsList; SimpleFactionsList const* GetFactionTeamList(uint32 faction); char const* GetPetName(uint32 petfamily, uint32 dbclang); - +uint32 GetTalentSpellCost(uint32 spellId); TalentEntry const* GetTalentBySpellID(uint32 spellID); int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found @@ -66,6 +69,9 @@ bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredT void Zone2MapCoordinates(float &x, float &y, uint32 zone); void Map2ZoneCoordinates(float &x, float &y, uint32 zone); +uint32 GetClassBySkillId(uint32 skillId); +uint32 GetSkillIdByClass(uint32 classId); +std::list<uint32> GetSpellsForLevels(uint32 classId, uint32 raceMask, uint32 specializationId, uint32 minLevel, uint32 maxLevel); typedef std::map<uint32/*pair32(map, diff)*/, MapDifficulty> MapDifficultyMap; MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); @@ -83,17 +89,47 @@ LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty); uint32 GetDefaultMapLight(uint32 mapId); -std::set<uint32> const& GetPhasesForGroup(uint32 group); - typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoMap; typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds; SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); -typedef std::set<SpecializationSpellsEntry const*> SpecializationSpellsBySpecEntry; +typedef std::vector<SpecializationSpellsEntry const*> SpecializationSpellsBySpecEntry; typedef std::unordered_map<uint32, SpecializationSpellsBySpecEntry> SpecializationSpellsBySpecStore; typedef ChrSpecializationEntry const* ChrSpecializationByIndexArray[MAX_CLASSES][MAX_SPECIALIZATIONS]; typedef std::unordered_map<uint32, TalentEntry const*> TalentBySpellIDMap; +typedef std::map<uint32, std::vector<uint32> > SpecializationSpellsMap; +extern SpecializationSpellsMap sSpecializationSpellsMap; +extern SpecializationOverrideSpellsMap sSpecializationOverrideSpellMap; + +template<class T> +class GameTable +{ +public: + GameTable(char const* format) : _storage(format), _gtEntry(nullptr) { } + + void SetGameTableEntry(GameTablesEntry const* gtEntry) { _gtEntry = gtEntry; } + + T const* EvaluateTable(uint32 row, uint32 column) const + { + ASSERT(row < _gtEntry->NumRows); + ASSERT(column < _gtEntry->NumColumns); + + return _storage.LookupEntry(_gtEntry->NumRows * column + row); + } + + char const* GetFormat() const { return _storage.GetFormat(); } + uint32 GetFieldCount() const { return _storage.GetFieldCount(); } + bool Load(char const* fileName) { return _storage.Load(fileName, nullptr); } + + uint32 GetTableRowCount() const { return _gtEntry->NumRows; } + uint32 GetTableColumnCount() const { return _gtEntry->NumColumns; } + +private: + DBCStorage<T> _storage; + GameTablesEntry const* _gtEntry; +}; + extern DBCStorage <AchievementEntry> sAchievementStore; extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore; extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions @@ -134,20 +170,19 @@ extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore; extern DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore; extern DBCStorage <GlyphSlotEntry> sGlyphSlotStore; -extern DBCStorage <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore; -extern DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore; -extern DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore; -extern DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore; -extern DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore; -extern DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore; -extern DBCStorage <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore; -extern DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore; -//extern DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore; -- not used currently -extern DBCStorage <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore; -extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore; -extern DBCStorage <GtSpellScalingEntry> sGtSpellScalingStore; -extern DBCStorage <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore; -extern DBCStorage <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore; +extern GameTable <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore; +extern GameTable <GtCombatRatingsEntry> sGtCombatRatingsStore; +extern GameTable <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore; +extern GameTable <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore; +extern GameTable <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore; +extern GameTable <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore; +extern GameTable <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore; +extern GameTable <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore; +extern GameTable <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore; +extern GameTable <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore; +extern GameTable <GtSpellScalingEntry> sGtSpellScalingStore; +extern GameTable <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore; +extern GameTable <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore; extern DBCStorage <GuildPerkSpellsEntry> sGuildPerkSpellsStore; extern DBCStorage <ImportPriceArmorEntry> sImportPriceArmorStore; extern DBCStorage <ImportPriceQualityEntry> sImportPriceQualityStore; @@ -200,6 +235,7 @@ extern DBCStorage <SkillLineEntry> sSkillLineStore; extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore; extern DBCStorage <SkillTiersEntry> sSkillTiersStore; extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore; +extern SpellEffectScallingByEffectId sSpellEffectScallingByEffectId; extern DBCStorage <SpecializationSpellsEntry> sSpecializationSpellsStore; extern SpecializationSpellsBySpecStore sSpecializationSpellsBySpecStore; extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore; @@ -215,6 +251,7 @@ extern DBCStorage <SpellRangeEntry> sSpellRangeStore; extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore; extern DBCStorage <SpellShapeshiftFormEntry> sSpellShapeshiftFormStore; extern DBCStorage <SpellEntry> sSpellStore; +extern DBCStorage <SpellEffectScalingEntry> sSpellEffectScalingStore; extern DBCStorage <SpellAuraOptionsEntry> sSpellAuraOptionsStore; extern DBCStorage <SpellCategoriesEntry> sSpellCategoriesStore; extern DBCStorage <SpellCooldownsEntry> sSpellCooldownsStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 3bf632001b0..2f16ce9a0e5 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -647,7 +647,7 @@ struct BarberShopStyleEntry struct BattlemasterListEntry { uint32 ID; // 0 - uint32 MapID[16]; // 1-16 mapid + int32 MapID[16]; // 1-16 mapid uint32 InstanceType; // 17 map type (3 - BG, 4 - arena) //uint32 GroupsAllowed; // 18 (0 or 1) char* Name_lang; // 19 @@ -812,7 +812,7 @@ struct CreatureDisplayInfoEntry //uint32 ObjectEffectPackageID; // 16 //uint32 AnimReplacementSetID; // 17 //uint32 Flags; // 18 - //uint32 Gender; // 19 + int32 Gender; // 19 //uint32 StateSpellVisualKitID; // 20 }; @@ -1102,6 +1102,14 @@ struct GameObjectDisplayInfoEntry //float OverrideNameScale; // 20 }; +struct GameTablesEntry +{ + //uint32 Index; // 0 - not a real field, not counted for columns + char const* Name; // 1 + uint32 NumRows; // 2 + uint32 NumColumns; // 3 +}; + struct GemPropertiesEntry { uint32 ID; // 0 @@ -1128,11 +1136,6 @@ struct GlyphSlotEntry //uint32 Tooltip; // 2 }; -// All Gt* DBC store data for 100 levels, some by 100 per class/race -#define GT_MAX_LEVEL 100 -// gtOCTClassCombatRatingScalar.dbc stores data for 32 ratings, look at MAX_COMBAT_RATING for real used amount -#define GT_MAX_RATING 32 - struct GtBarberShopCostBaseEntry { //uint32 level; @@ -1364,7 +1367,7 @@ struct ItemRandomPropertiesEntry { uint32 ID; // 0 //char* Name; // 1 - uint32 Enchantment[MAX_ITEM_RANDOM_PROPERTIES]; // 2-6 + uint32 Enchantment[MAX_ITEM_RANDOM_PROPERTIES]; // 2-6 char* Name_lang; // 7 }; @@ -1800,8 +1803,18 @@ struct SpellEffectEntry float BonusCoefficientFromAP; // 30 }; -#define MAX_SPELL_EFFECTS 3 -#define MAX_EFFECT_MASK 7 +#define MAX_SPELL_EFFECTS 32 +#define MAX_EFFECT_MASK 0xFFFFFFFF + +// SpellEffectScaling.dbc +struct SpellEffectScalingEntry +{ + uint32 ID; // 0 + float Coefficient; // 1 + float Variance; // 2 + float ResourceCoefficient; // 3 + uint32 SpellEffectID; // 4 +}; // SpellAuraOptions.dbc struct SpellAuraOptionsEntry @@ -1865,6 +1878,9 @@ typedef std::set<uint32> SpellCategorySet; typedef std::map<uint32, SpellCategorySet > SpellCategoryStore; typedef std::set<uint32> PetFamilySpellsSet; typedef std::map<uint32, PetFamilySpellsSet > PetFamilySpellsStore; +typedef std::unordered_map<uint32, std::list<SkillLineAbilityEntry const*> > SpellsPerClassStore; +typedef std::unordered_map<uint32, uint32> ClassBySkillIdStore; +typedef std::unordered_map<uint32, uint32> SpellEffectScallingByEffectId; struct SpellCastTimesEntry { @@ -2371,6 +2387,4 @@ struct MapDifficulty }; typedef std::map<uint32, uint32> TalentSpellPosMap; - -typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer; #endif diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 867e64ef92e..c92d3babb25 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -43,7 +43,7 @@ char const ChrRacesEntryfmt[] = "niixiixxxxxxiisxxxxxxxxxxxxxxxxxxxxxxxxx"; char const ChrClassesXPowerTypesfmt[] = "nii"; char const ChrSpecializationEntryfmt[] = "nxiiiiiiiiixxxii"; char const CinematicSequencesEntryfmt[] = "nxxxxxxxxx"; -char const CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxxxxxxx"; +char const CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxxxxxix"; char const CreatureDisplayInfoExtrafmt[] = "dixxxxxxxxxxxxxxxxxxxx"; char const CreatureFamilyfmt[] = "nfifiiiiixsx"; char const CreatureModelDatafmt[] = "nixxxxxxxxxxxxxffxxxxxxxxxxxxxxxxx"; @@ -59,6 +59,7 @@ char const EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx"; char const FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixsxixx"; char const FactionTemplateEntryfmt[] = "niiiiiiiiiiiii"; char const GameObjectDisplayInfofmt[] = "nixxxxxxxxxxffffffxxx"; +char const GameTablesFmt[] = "dsii"; char const GemPropertiesEntryfmt[] = "nixxii"; char const GlyphPropertiesfmt[] = "niiix"; char const GlyphSlotfmt[] = "nix"; @@ -129,12 +130,13 @@ char const SpellCastTimefmt[] = "nixx"; char const SpellCategoriesEntryfmt[] = "diiiiiiiix"; char const SpellCategoryfmt[] = "nixxxx"; char const SpellDurationfmt[] = "niii"; -char const SpellEffectEntryfmt[] = "niifiiiffiiiiiifiifiiiiifiiiiif"; +char const SpellEffectEntryfmt[] = "iiifiiiffiiiiiifiifiiiiifiiiiif"; const std::string CustomSpellEffectEntryfmt = "ppppppppppppppappppppppppp"; const std::string CustomSpellEffectEntryIndex = "Id"; char const SpellEntryfmt[] = "nsxxxiiiiiiiiiiiiiiiiiii"; const std::string CustomSpellEntryfmt = "ppppppppppppppapaaaaaaaaapaaaaaapapppaapppaaapa"; const std::string CustomSpellEntryIndex = "Id"; +char const SpellEffectScalingfmt[] = "nfffi"; char const SpellFocusObjectfmt[] = "nx"; char const SpellItemEnchantmentfmt[] = "niiiiiiiiiixiiiiiiiiiiifff"; char const SpellItemEnchantmentConditionfmt[] = "nbbbbbiiiiibbbbbbbbbbiiiiibbbbb"; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 863324f278c..7099d38d428 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -1406,7 +1406,7 @@ void LFGMgr::FinishDungeon(ObjectGuid gguid, const uint32 dungeonId) } // Update achievements - if (dungeon->difficulty == DUNGEON_DIFFICULTY_HEROIC) + if (dungeon->difficulty == DIFFICULTY_HEROIC) player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS, 1); LfgReward const* reward = GetRandomDungeonReward(rDungeonId, player->getLevel()); @@ -1594,7 +1594,7 @@ LfgLockMap const LFGMgr::GetLockedDungeons(ObjectGuid guid) lockStatus = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player)) lockStatus = LFG_LOCKSTATUS_RAID_LOCKED; - else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty))) + else if (dungeon->difficulty > DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty))) lockStatus = LFG_LOCKSTATUS_RAID_LOCKED; else if (dungeon->minlevel > level) lockStatus = LFG_LOCKSTATUS_TOO_LOW_LEVEL; diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index dea8d996c53..4fbd60202c3 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -268,7 +268,7 @@ struct LfgPlayerBoot struct LFGDungeonData { LFGDungeonData(): id(0), name(""), map(0), type(0), expansion(0), group(0), minlevel(0), - maxlevel(0), difficulty(REGULAR_DIFFICULTY), seasonal(false), x(0.0f), y(0.0f), z(0.0f), o(0.0f), + maxlevel(0), difficulty(DIFFICULTY_NONE), seasonal(false), x(0.0f), y(0.0f), z(0.0f), o(0.0f), requiredItemLevel(0) { } LFGDungeonData(LFGDungeonEntry const* dbc): id(dbc->ID), name(dbc->Name_lang), map(dbc->MapID), diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 7fb3822c888..7dbb87bcbf3 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -51,6 +51,7 @@ #include "WaypointMovementGenerator.h" #include "World.h" #include "WorldPacket.h" +#include "CombatPackets.h" #include "Transport.h" @@ -283,7 +284,7 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) } // for instances heroic to normal, other cases attempt to retrieve previous difficulty - if (diff >= RAID_DIFFICULTY_10MAN_HEROIC && GetMap()->IsRaid()) + if (diff >= DIFFICULTY_10_HC && GetMap()->IsRaid()) diff -= 2; // to normal raid difficulty cases else --diff; @@ -297,10 +298,10 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) m_creatureInfo = cinfo; // map mode related always // equal to player Race field, but creature does not have race - SetByteValue(UNIT_FIELD_BYTES_0, 0, 0); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE, 0); // known valid are: CLASS_WARRIOR, CLASS_PALADIN, CLASS_ROGUE, CLASS_MAGE - SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class)); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, uint8(cinfo->unit_class)); // Cancel load if no model defined if (!(cinfo->GetFirstValidModelId())) @@ -319,7 +320,7 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) SetDisplayId(displayID); SetNativeDisplayId(displayID); - SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); // Load creature equipment if (!data || data->equipmentId == 0) @@ -804,7 +805,7 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 /*phaseMask* { SetDisplayId(displayID); SetNativeDisplayId(displayID); - SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); } LastUsedScriptID = GetCreatureTemplate()->ScriptID; @@ -1559,7 +1560,7 @@ void Creature::Respawn(bool force) { SetDisplayId(displayID); SetNativeDisplayId(displayID); - SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); } GetMotionMaster()->InitDefault(); @@ -1619,11 +1620,11 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo) const // This check must be done instead of 'if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))' for not break // the check of mechanic immunity on DB (tested) because GetCreatureTemplate()->MechanicImmuneMask and m_spellImmune[IMMUNITY_MECHANIC] don't have same data. bool immunedToAllEffects = true; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - if (!spellInfo->Effects[i].IsEffect()) + if (!effect || !effect->IsEffect()) continue; - if (!IsImmunedToSpellEffect(spellInfo, i)) + if (!IsImmunedToSpellEffect(spellInfo, effect->EffectIndex)) { immunedToAllEffects = false; break; @@ -1637,10 +1638,13 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo) const bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const { - if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (spellInfo->Effects[index].Mechanic - 1))) + SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficulty()); + if (!effect) + return true; + if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (effect->Mechanic - 1))) return true; - if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && spellInfo->Effects[index].Effect == SPELL_EFFECT_HEAL) + if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && effect->Effect == SPELL_EFFECT_HEAL) return true; return Unit::IsImmunedToSpellEffect(spellInfo, index); @@ -1680,13 +1684,13 @@ SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) } bool bcontinue = true; - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; j++) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - if ((spellInfo->Effects[j].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) || - (spellInfo->Effects[j].Effect == SPELL_EFFECT_INSTAKILL) || - (spellInfo->Effects[j].Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) || - (spellInfo->Effects[j].Effect == SPELL_EFFECT_HEALTH_LEECH) - ) + if (effect && ((effect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE) || + (effect->Effect == SPELL_EFFECT_INSTAKILL) || + (effect->Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) || + (effect->Effect == SPELL_EFFECT_HEALTH_LEECH) + )) { bcontinue = false; break; @@ -1728,9 +1732,9 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim) } bool bcontinue = true; - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; j++) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - if ((spellInfo->Effects[j].Effect == SPELL_EFFECT_HEAL)) + if (effect && (effect->Effect == SPELL_EFFECT_HEAL)) { bcontinue = false; break; @@ -1826,12 +1830,12 @@ Player* Creature::SelectNearestPlayer(float distance) const void Creature::SendAIReaction(AiReaction reactionType) { - WorldPacket data(SMSG_AI_REACTION, 12); + WorldPackets::Combat::AIReaction packet; - data << GetGUID(); - data << uint32(reactionType); + packet.UnitGUID = GetGUID(); + packet.Reaction = reactionType; - ((WorldObject*)this)->SendMessageToSet(&data, true); + SendMessageToSet(packet.Write(), true); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_AI_REACTION, type %u.", reactionType); } @@ -2212,12 +2216,7 @@ void Creature::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs continue; uint32 unSpellId = m_spells[i]; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(unSpellId); - if (!spellInfo) - { - ASSERT(spellInfo); - continue; - } + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId); // Not send cooldown for this spells if (spellInfo->IsCooldownStartedOnEvent()) @@ -2573,7 +2572,7 @@ void Creature::SetDisplayId(uint32 modelId) } } -void Creature::SetTarget(ObjectGuid guid) +void Creature::SetTarget(ObjectGuid const& guid) { if (!_focusSpell) SetGuidValue(UNIT_FIELD_TARGET, guid); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 9acde98a7a8..e9212b50933 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -88,9 +88,9 @@ struct CreatureTemplate std::string SubName; std::string IconName; uint32 GossipMenuId; - uint8 minlevel; - uint8 maxlevel; - uint32 expansion; + int16 minlevel; + int16 maxlevel; + int32 expansion; uint32 expansionUnknown; // either 0 or 3, sent to the client / wdb uint32 faction; uint32 npcflag; @@ -287,8 +287,8 @@ struct CreatureModelInfo { float bounding_radius; float combat_reach; - uint8 gender; - uint32 modelid_other_gender; + int8 gender; + uint32 displayId_other_gender; }; // Benchmarked: Faster than std::map (insert/find) @@ -392,11 +392,13 @@ struct VendorItemCount typedef std::list<VendorItemCount> VendorItemCounts; +#define MAX_TRAINERSPELL_ABILITY_REQS 3 + struct TrainerSpell { TrainerSpell() : SpellID(0), MoneyCost(0), ReqSkillLine(0), ReqSkillRank(0), ReqLevel(0) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint8 i = 0; i < MAX_TRAINERSPELL_ABILITY_REQS; ++i) ReqAbility[i] = 0; } @@ -405,7 +407,7 @@ struct TrainerSpell uint32 ReqSkillLine; uint32 ReqSkillRank; uint32 ReqLevel; - uint32 ReqAbility[3]; + uint32 ReqAbility[MAX_TRAINERSPELL_ABILITY_REQS]; // helpers bool IsCastable() const { return ReqAbility[0] != SpellID; } @@ -674,7 +676,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject bool m_isTempWorldObject; //true when possessed // Handling caster facing during spellcast - void SetTarget(ObjectGuid guid) override; + void SetTarget(ObjectGuid const& guid) override; void FocusTarget(Spell const* focusSpell, WorldObject const* target); void ReleaseFocus(Spell const* focusSpell); diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 4d14ede70fe..2b07683d335 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -23,6 +23,8 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "Formulas.h" +#include "QuestPackets.h" +#include "NPCPackets.h" GossipMenu::GossipMenu() { @@ -192,44 +194,45 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, ObjectGuid objectGUID) { _gossipMenu.SetSenderGUID(objectGUID); - WorldPacket data(SMSG_GOSSIP_MESSAGE, 100); // guess size - data << objectGUID; - data << uint32(_gossipMenu.GetMenuId()); // new 2.4.0 - data << uint32(titleTextId); - data << uint32(_gossipMenu.GetMenuItemCount()); // max count 0x10 + WorldPackets::NPC::GossipMessage packet; + packet.GossipGUID = objectGUID; + packet.TextID = titleTextId; + packet.GossipOptions.resize(_gossipMenu.GetMenuItems().size()); + uint32 count = 0; for (GossipMenuItemContainer::const_iterator itr = _gossipMenu.GetMenuItems().begin(); itr != _gossipMenu.GetMenuItems().end(); ++itr) { + WorldPackets::NPC::ClientGossipOptions& opt = packet.GossipOptions[count]; GossipMenuItem const& item = itr->second; - data << uint32(itr->first); - data << uint8(item.MenuItemIcon); - data << uint8(item.IsCoded); // makes pop up box password - data << uint32(item.BoxMoney); // money required to open menu, 2.0.3 - data << item.Message; // text for gossip item - data << item.BoxMessage; // accept text (related to money) pop up box, 2.0.3 + opt.ClientOption = itr->first; + opt.OptionNPC = item.MenuItemIcon; + opt.OptionFlags = item.IsCoded; // makes pop up box password + opt.OptionCost = item.BoxMoney; // money required to open menu, 2.0.3 + opt.Text = item.Message; // text for gossip item + opt.Confirm = item.BoxMessage; // accept text (related to money) pop up box, 2.0.3 + ++count; } - size_t count_pos = data.wpos(); - data << uint32(0); // max count 0x20 - uint32 count = 0; - // Store this instead of checking the Singleton every loop iteration bool questLevelInTitle = sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS); + packet.GossipText.resize(_questMenu.GetMenuItemCount()); + count = 0; for (uint8 i = 0; i < _questMenu.GetMenuItemCount(); ++i) { QuestMenuItem const& item = _questMenu.GetItem(i); uint32 questID = item.QuestId; if (Quest const* quest = sObjectMgr->GetQuestTemplate(questID)) { - ++count; - data << uint32(questID); - data << uint32(item.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 - std::string title = quest->GetTitle(); + WorldPackets::NPC::ClientGossipText& text = packet.GossipText[count]; + text.QuestID = questID; + text.QuestType = item.QuestIcon; + text.QuestLevel = quest->GetQuestLevel(); + text.QuestFlags[0] = quest->GetFlags(); + text.QuestFlags[1] = 0; + text.Repeatable = quest->IsRepeatable(); + std::string title = quest->GetTitle(); int32 locale = _session->GetSessionDbLocaleIndex(); if (locale >= 0) if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID)) @@ -238,12 +241,15 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, ObjectGuid objectGUID) if (questLevelInTitle) AddQuestLevelToTitle(title, quest->GetQuestLevel()); - data << title; // max 0x200 + text.QuestTitle = title; + ++count; } } - data.put<uint8>(count_pos, count); - _session->SendPacket(&data); + // Shrink to the real size + packet.GossipText.resize(count); + + _session->SendPacket(packet.Write()); } void PlayerMenu::SendCloseGossip() @@ -373,11 +379,11 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string void PlayerMenu::SendQuestGiverStatus(uint32 questStatus, ObjectGuid npcGUID) const { - WorldPacket data(SMSG_QUESTGIVER_STATUS, 8 + 4); - data << npcGUID; - data << uint32(questStatus); + WorldPackets::Quest::QuestGiverStatus packet; + packet.QuestGiver.Guid = npcGUID; + packet.QuestGiver.Status = questStatus; - _session->SendPacket(&data); + _session->SendPacket(packet.Write()); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_STATUS NPC=%s, status=%u", npcGUID.ToString().c_str(), questStatus); } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 2b13c859255..382bf45052b 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1809,9 +1809,9 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /*= true return; bool self = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - if (spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_CASTER) + if (effect && effect->TargetA.GetTarget() == TARGET_UNIT_CASTER) { self = true; break; @@ -2150,7 +2150,7 @@ void GameObject::SetTransportState(GOState state, uint32 stopFrame /*= 0*/) } else { - ASSERT(state < GO_STATE_TRANSPORT_STOPPED + MAX_GO_STATE_TRANSPORT_STOP_FRAMES); + ASSERT(state < GOState(GO_STATE_TRANSPORT_STOPPED + MAX_GO_STATE_TRANSPORT_STOP_FRAMES)); ASSERT(stopFrame < m_goValue.Transport.StopFrames->size()); m_goValue.Transport.PathProgress = getMSTime() + m_goValue.Transport.StopFrames->at(stopFrame); SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + stopFrame)); diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp index f5813ae0781..ea9e24dff94 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp @@ -127,36 +127,42 @@ uint32 GenerateEnchSuffixFactor(uint32 item_id) if (!itemProto->RandomSuffix) return 0; - RandomPropertiesPointsEntry const* randomProperty = sRandomPropertiesPointsStore.LookupEntry(itemProto->ItemLevel); - if (!randomProperty) - return 0; + return GetRandomPropertyPoints(itemProto->ItemLevel, itemProto->Quality, itemProto->InventoryType, itemProto->SubClass); +} + +uint32 GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint32 inventoryType, uint32 subClass) +{ + uint32 propIndex; - uint32 suffixFactor; - switch (itemProto->InventoryType) + switch (inventoryType) { - // Items of that type don`t have points - case INVTYPE_NON_EQUIP: - case INVTYPE_BAG: - case INVTYPE_TABARD: - case INVTYPE_AMMO: - case INVTYPE_QUIVER: - case INVTYPE_RELIC: - return 0; - // Select point coefficient case INVTYPE_HEAD: case INVTYPE_BODY: case INVTYPE_CHEST: case INVTYPE_LEGS: + case INVTYPE_RANGED: case INVTYPE_2HWEAPON: case INVTYPE_ROBE: - suffixFactor = 0; + case INVTYPE_THROWN: + propIndex = 0; + break; + case INVTYPE_RANGEDRIGHT: + if (subClass == ITEM_SUBCLASS_WEAPON_WAND) + propIndex = 3; + else + propIndex = 0; + break; + case INVTYPE_WEAPON: + case INVTYPE_WEAPONMAINHAND: + case INVTYPE_WEAPONOFFHAND: + propIndex = 3; break; case INVTYPE_SHOULDERS: case INVTYPE_WAIST: case INVTYPE_FEET: case INVTYPE_HANDS: case INVTYPE_TRINKET: - suffixFactor = 1; + propIndex = 1; break; case INVTYPE_NECK: case INVTYPE_WRISTS: @@ -164,36 +170,29 @@ uint32 GenerateEnchSuffixFactor(uint32 item_id) case INVTYPE_SHIELD: case INVTYPE_CLOAK: case INVTYPE_HOLDABLE: - suffixFactor = 2; - break; - case INVTYPE_WEAPON: - case INVTYPE_WEAPONMAINHAND: - case INVTYPE_WEAPONOFFHAND: - suffixFactor = 3; - break; - case INVTYPE_RANGED: - case INVTYPE_THROWN: - case INVTYPE_RANGEDRIGHT: - suffixFactor = 4; + propIndex = 2; break; + case INVTYPE_RELIC: + propIndex = 4; default: return 0; } - // Select rare/epic modifier - switch (itemProto->Quality) + + RandomPropertiesPointsEntry const* randPropPointsEntry = sRandomPropertiesPointsStore.LookupEntry(itemLevel); + if (!randPropPointsEntry) + return 0; + + switch (quality) { case ITEM_QUALITY_UNCOMMON: - return randomProperty->UncommonPropertiesPoints[suffixFactor]; + return randPropPointsEntry->UncommonPropertiesPoints[propIndex]; case ITEM_QUALITY_RARE: - return randomProperty->RarePropertiesPoints[suffixFactor]; + case ITEM_QUALITY_HEIRLOOM: + return randPropPointsEntry->RarePropertiesPoints[propIndex]; case ITEM_QUALITY_EPIC: - return randomProperty->EpicPropertiesPoints[suffixFactor]; case ITEM_QUALITY_LEGENDARY: - case ITEM_QUALITY_ARTIFACT: - return 0; // not have random properties - default: - break; + return randPropPointsEntry->EpicPropertiesPoints[propIndex]; } + return 0; } - diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.h b/src/server/game/Entities/Item/ItemEnchantmentMgr.h index a263ec0dae4..73d3d97bb0b 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.h +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.h @@ -24,5 +24,6 @@ void LoadRandomEnchantmentsTable(); uint32 GetItemEnchantMod(int32 entry); uint32 GenerateEnchSuffixFactor(uint32 item_id); +uint32 GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint32 inventoryType, uint32 subclass); #endif diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h index e28e8a21678..3846f7dd642 100644 --- a/src/server/game/Entities/Item/ItemPrototype.h +++ b/src/server/game/Entities/Item/ItemPrototype.h @@ -598,7 +598,7 @@ struct ItemEffect { uint32 SpellID; uint32 Trigger; - uint32 Charges; + int32 Charges; int32 Cooldown; uint32 Category; int32 CategoryCooldown; @@ -611,6 +611,7 @@ struct ItemEffect #pragma pack(pop) #endif +#define MAX_ITEM_PROTO_FLAGS 3 #define MAX_ITEM_PROTO_DAMAGES 2 // changed in 3.1.0 #define MAX_ITEM_PROTO_SOCKETS 3 #define MAX_ITEM_PROTO_STATS 10 @@ -623,8 +624,10 @@ struct ItemTemplate int32 SoundOverrideSubclass; // < 0: id from ItemSubClass.dbc, used to override weapon sound from actual SubClass std::string Name1; uint32 DisplayInfoID; // id from ItemDisplayInfo.dbc + uint32 FileDataID; + uint32 GroupSoundsID; uint32 Quality; - uint32 Flags[3]; + uint32 Flags[MAX_ITEM_PROTO_FLAGS]; float Unk1; float Unk2; uint32 BuyCount; @@ -678,6 +681,7 @@ struct ItemTemplate float StatScalingFactor; uint32 CurrencySubstitutionId; // May be used instead of a currency uint32 CurrencySubstitutionCount; + uint32 ItemNameDescriptionID; // extra fields, not part of db2 files float DamageMin; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index e482e0a449d..40a8ed046fb 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -943,7 +943,14 @@ uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const case TYPEID_AREATRIGGER: flags = AreaTriggerUpdateFieldFlags; break; + case TYPEID_SCENEOBJECT: + flags = SceneObjectUpdateFieldFlags; + break; + case TYPEID_CONVERSATION: + flags = ConversationUpdateFieldFlags; + break; case TYPEID_OBJECT: + ASSERT(false); break; } @@ -981,6 +988,9 @@ uint32 Object::GetDynamicUpdateFieldData(Player const* target, uint32*& flags) c visibleFlag |= UF_FLAG_PARTY_MEMBER; break; } + case TYPEID_CONVERSATION: + flags = ConversationDynamicUpdateFieldFlags; + break; default: flags = nullptr; break; @@ -1001,7 +1011,7 @@ void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uin for (uint32 index = 0; index < count; ++index) { - m_uint32Values[startOffset + index] = atol(tokens[index]); + m_uint32Values[startOffset + index] = atoul(tokens[index]); _changesMask.SetBit(startOffset + index); } } @@ -2359,19 +2369,19 @@ void Object::ForceValuesUpdateAtIndex(uint32 i) } } -void WorldObject::SendMessageToSet(WorldPacket* data, bool self) +void WorldObject::SendMessageToSet(WorldPacket const* data, bool self) { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), self); } -void WorldObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*self*/) +void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/) { Trinity::MessageDistDeliverer notifier(this, data, dist); VisitNearbyWorldObject(dist, notifier); } -void WorldObject::SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) +void WorldObject::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) { Trinity::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr); VisitNearbyWorldObject(GetVisibilityRange(), notifier); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index bae3a8b07c1..d2dd0108d20 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -661,9 +661,9 @@ class WorldObject : public Object, public WorldLocation virtual void CleanupsBeforeDelete(bool finalCleanup = true); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units - virtual void SendMessageToSet(WorldPacket* data, bool self); - virtual void SendMessageToSetInRange(WorldPacket* data, float dist, bool self); - virtual void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr); + virtual void SendMessageToSet(WorldPacket const* data, bool self); + virtual void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self); + virtual void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr); virtual uint8 getLevelForTarget(WorldObject const* /*target*/) const { return 1; } diff --git a/src/server/game/Entities/Object/ObjectGuid.cpp b/src/server/game/Entities/Object/ObjectGuid.cpp index f59c82d44f5..327b83ba6d4 100644 --- a/src/server/game/Entities/Object/ObjectGuid.cpp +++ b/src/server/game/Entities/Object/ObjectGuid.cpp @@ -231,13 +231,13 @@ ObjectGuid const ObjectGuid::Empty = ObjectGuid(); ObjectGuid const ObjectGuid::TradeItem = ObjectGuid::Create<HighGuid::Uniq>(uint64(10)); template<HighGuid type> -ObjectGuid ObjectGuid::Create(LowType counter) +ObjectGuid ObjectGuid::Create(LowType /*counter*/) { static_assert(type == HighGuid::Count, "This guid type cannot be constructed using Create(LowType counter)."); } template<HighGuid type> -ObjectGuid ObjectGuid::Create(uint16 mapId, uint32 entry, LowType counter) +ObjectGuid ObjectGuid::Create(uint16 /*mapId*/, uint32 /*entry*/, LowType /*counter*/) { static_assert(type == HighGuid::Count, "This guid type cannot be constructed using Create(uint16 mapId, uint32 entry, LowType counter)."); } diff --git a/src/server/game/Entities/Object/Updates/UpdateData.cpp b/src/server/game/Entities/Object/Updates/UpdateData.cpp index 74f6b62e398..c6a9a0b1132 100644 --- a/src/server/game/Entities/Object/Updates/UpdateData.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateData.cpp @@ -45,7 +45,7 @@ void UpdateData::AddUpdateBlock(const ByteBuffer &block) bool UpdateData::BuildPacket(WorldPacket* packet) { ASSERT(packet->empty()); // shouldn't happen - packet->Initialize(SMSG_UPDATE_OBJECT, 2 + 4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos(), CONNECTION_TYPE_INSTANCE); + packet->Initialize(SMSG_UPDATE_OBJECT, 2 + 4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos()); *packet << uint32(m_blockCount); *packet << uint16(m_map); diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 52045f46472..bc08e8b1baf 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -214,18 +214,15 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c { case SUMMON_PET: petlevel = owner->getLevel(); - - SetUInt32Value(UNIT_FIELD_BYTES_0, 0x800); // class = mage - SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); - // this enables popup window (pet dismiss, cancel) + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, CLASS_MAGE); + SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet dismiss, cancel) break; case HUNTER_PET: - SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); // class = warrior, gender = none, power = focus + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, CLASS_WARRIOR); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, GENDER_NONE); SetSheath(SHEATH_STATE_MELEE); SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED); - - SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); - // this enables popup window (pet abandon, cancel) + SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet abandon, cancel) setPowerType(POWER_FOCUS); break; default: @@ -782,7 +779,9 @@ bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phas if (cinfo->type == CREATURE_TYPE_BEAST) { - SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, CLASS_WARRIOR); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, GENDER_NONE); + SetUInt32Value(UNIT_FIELD_DISPLAY_POWER, POWER_FOCUS); SetSheath(SHEATH_STATE_MELEE); SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED); } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ae8f0191137..a3a6c0d21a1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -28,7 +28,6 @@ #include "BattlegroundMgr.h" #include "BattlegroundScore.h" #include "CellImpl.h" -#include "Channel.h" #include "ChannelMgr.h" #include "CharacterDatabaseCleaner.h" #include "CharacterPackets.h" @@ -40,6 +39,7 @@ #include "DatabaseEnv.h" #include "DB2Stores.h" #include "DisableMgr.h" +#include "EquipmentSetPackets.h" #include "Formulas.h" #include "GameEventMgr.h" #include "GameObjectAI.h" @@ -87,6 +87,9 @@ #include "WorldSession.h" #include "WorldStatePackets.h" #include "MiscPackets.h" +#include "ChatPackets.h" +#include "MovementPackets.h" +#include "ItemPackets.h" #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) @@ -169,7 +172,7 @@ void PlayerTaxi::LoadTaxiMask(std::string const &data) for (Tokenizer::const_iterator iter = tokens.begin(); index < TaxiMaskSize && iter != tokens.end(); ++iter, ++index) { // load and set bits only for existing taxi nodes - m_taximask[index] = sTaxiNodesMask[index] & uint32(atol(*iter)); + m_taximask[index] = sTaxiNodesMask[index] & atoul(*iter); } } @@ -196,7 +199,7 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint3 for (Tokenizer::const_iterator iter = Tokenizer.begin(); iter != Tokenizer.end(); ++iter) { - uint32 node = uint32(atol(*iter)); + uint32 node = atoul(*iter); AddTaxiDestination(node); } @@ -785,9 +788,9 @@ Player::Player(WorldSession* session): Unit(true) m_HomebindTimer = 0; m_InstanceValid = true; - m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; - m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; - m_raidMapDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; + m_dungeonDifficulty = DIFFICULTY_NORMAL; + m_raidDifficulty = DIFFICULTY_10_N; + m_raidMapDifficulty = DIFFICULTY_10_N; m_lastPotionId = 0; _talentMgr = new PlayerTalentInfo(); @@ -982,9 +985,10 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac return false; } - uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Sex << 16); - - SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24))); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE, createInfo->Race); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, createInfo->Class); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, createInfo->Sex); + SetUInt32Value(UNIT_FIELD_DISPLAY_POWER, powertype); InitDisplayIds(); if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP) { @@ -1930,18 +1934,18 @@ void Player::ToggleDND() ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); } -uint8 Player::GetChatTag() const +uint8 Player::GetChatFlags() const { - uint8 tag = CHAT_TAG_NONE; + uint8 tag = CHAT_FLAG_NONE; if (isGMChat()) - tag |= CHAT_TAG_GM; + tag |= CHAT_FLAG_GM; if (isDND()) - tag |= CHAT_TAG_DND; + tag |= CHAT_FLAG_DND; if (isAFK()) - tag |= CHAT_TAG_AFK; + tag |= CHAT_FLAG_AFK; if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DEVELOPER)) - tag |= CHAT_TAG_DEV; + tag |= CHAT_FLAG_DEV; return tag; } @@ -2133,18 +2137,16 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!GetSession()->PlayerLogout()) { // send transfer packets - WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4); - data.WriteBit(0); // unknown + WorldPackets::Movement::TransferPending transferPending; + transferPending.MapID = mapid; if (Transport* transport = GetTransport()) { - data.WriteBit(1); // has transport - data << GetMapId() << transport->GetEntry(); + transferPending.Ship.HasValue = true; + transferPending.Ship.Value.ID = transport->GetEntry(); + transferPending.Ship.Value.OriginMapID = GetMapId(); } - else - data.WriteBit(0); // has transport - data << uint32(mapid); - GetSession()->SendPacket(&data); + GetSession()->SendPacket(transferPending.Write()); } // remove from old map now @@ -2158,14 +2160,12 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!GetSession()->PlayerLogout()) { - WorldPacket data(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4); - data << float(m_teleport_dest.GetPositionX()); - data << float(m_teleport_dest.GetOrientation()); - data << float(m_teleport_dest.GetPositionZ()); - data << uint32(mapid); - data << float(m_teleport_dest.GetPositionY()); + WorldPackets::Movement::NewWorld packet; + packet.MapID = mapid; + packet.Pos = m_teleport_dest; + packet.Reason = NEW_WORLD_NORMAL; - GetSession()->SendPacket(&data); + SendDirectMessage(packet.Write()); SendSavedInstances(); } @@ -2985,11 +2985,39 @@ void Player::GiveLevel(uint8 level) SetByteFlag(PLAYER_FIELD_BYTES, 1, 0x01); } + std::list<uint32> learnList = GetSpellsForLevels(getClass(), getRaceMask(), GetTalentSpec(GetActiveTalentGroup()), oldLevel, level); + for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++) + { + if (!HasSpell(*iter)) + LearnSpell(*iter, true); + } + sScriptMgr->OnPlayerLevelChanged(this, oldLevel); } void Player::InitTalentForLevel() { + uint8 level = getLevel(); + // talents base at level diff (talents = level - 9 but some can be used already) + if (level < 15) + { + // Remove all talent points + if (GetUsedTalentCount() > 0) // Free any used talents + { + ResetTalents(true); + } + } + else + { + if (level < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL) || GetTalentGroupsCount() == 0) + { + SetTalentGroupsCount(1); + SetActiveTalentGroup(0); + } + } + + SetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS, CalculateTalentsPoints()); + if (!GetSession()->PlayerLoading()) SendTalentsInfoData(); // update at client } @@ -3164,9 +3192,10 @@ void Player::InitStatsForLevel(bool reapplyMods) void Player::SendKnownSpells() { - WorldPackets::Spell::SendKnownSpells knownSpells; + WorldPackets::Spells::SendKnownSpells knownSpells; knownSpells.InitialLogin = false; /// @todo + knownSpells.KnownSpells.reserve(m_spells.size()); for (PlayerSpellMap::value_type const& spell : m_spells) { if (spell.second->state == PLAYERSPELL_REMOVED) @@ -3266,7 +3295,7 @@ void DeleteSpellFromAllPlayers(uint32 spellId) } } -bool Player::AddTalent(uint32 talentId, uint8 spec) +bool Player::AddTalent(uint32 talentId, uint8 spec, bool learning) { TalentEntry const* talentEntry = sTalentStore.LookupEntry(talentId); @@ -3308,15 +3337,28 @@ bool Player::AddTalent(uint32 talentId, uint8 spec) return false; } - TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(spec); + PlayerTalentMap::iterator itr = GetTalentMap(spec)->find(talentId); + if (itr == GetTalentMap(spec)->end()) + { + //if (GetTalentBySpellID(talentEntry->SpellID)) + { + PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED; + PlayerTalent* newtalent = new PlayerTalent(); - // Check if player already has this talent - if (talentGroupInfo->HasTalent(talentId)) - return false; + newtalent->state = state; + newtalent->spec = spec; - talentGroupInfo->Talents[talentEntry->TierID] = talentId; + (*GetTalentMap(spec))[talentId] = newtalent; - return true; + return true; + } + //else + // TC_LOG_ERROR("spells", "Player::addTalent: Talent %u not found in talent store.", talentId); + } + else + itr->second->state = PLAYERSPELL_UNCHANGED; + + return false; } bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, bool fromSkill /*= false*/) @@ -3420,9 +3462,9 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent SendSupercededSpell(spellId, next_active_spell_id); else { - WorldPacket data(SMSG_REMOVED_SPELL, 4); - data << uint32(spellId); - GetSession()->SendPacket(&data); + WorldPackets::Spells::SendRemovedSpell removedSpells; + removedSpells.Spells.push_back(spellId); + GetSession()->SendPacket(removedSpells.Write()); } } @@ -3528,9 +3570,11 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent return false; } + uint32 talentCost = GetTalentSpellCost(spellId); + // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned) // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive - if (!loading && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL)) + if (!loading && talentCost > 0 && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL)) { // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show) CastSpell(this, spellId, true); @@ -3547,6 +3591,9 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent return false; } + // update used talent points count + SetUsedTalentCount(GetUsedTalentCount() + talentCost); + // update free primary prof.points (if any, can be none in case GM .learn prof. learning) if (uint32 freeProfs = GetFreePrimaryProfessionPoints()) { @@ -3554,38 +3601,62 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent SetFreePrimaryProfessions(freeProfs-1); } + // add dependent skills + uint16 maxskill = GetMaxSkillValueForLevel(); + + SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId); + SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId); - // add dependent skills if this spell is not learned from adding skill already - if (!fromSkill) + if (spellLearnSkill) { - if (SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId)) - { - uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill); - uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill); + uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill); + uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill); - if (skill_value < spellLearnSkill->value) - skill_value = spellLearnSkill->value; + if (skill_value < spellLearnSkill->value) + skill_value = spellLearnSkill->value; - uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : spellLearnSkill->maxvalue; + uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? maxskill : spellLearnSkill->maxvalue; - if (skill_max_value < new_skill_max_value) - skill_max_value = new_skill_max_value; + if (skill_max_value < new_skill_max_value) + skill_max_value = new_skill_max_value; - SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value); - } - else + SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value); + } + else + { + // not ranked skills + for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx) { - // not ranked skills - for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx) - { - SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine); - if (!pSkill) - continue; + SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine); + if (!pSkill) + continue; + + if (HasSkill(pSkill->ID)) + continue; - ///@todo: confirm if rogues start with lockpicking skill at level 1 but only receive the spell to use it at level 16 - if ((_spell_idx->second->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->ID)) || (pSkill->ID == SKILL_LOCKPICKING && _spell_idx->second->TrivialSkillLineRankHigh == 0)) - LearnDefaultSkill(pSkill->ID, 0); + SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pSkill->ID, getRace(), getClass()); + if (!rcEntry) + continue; + + if (_spell_idx->second->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN || + // lockpicking/runeforging special case, not have SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN + ((pSkill->ID == SKILL_LOCKPICKING || pSkill->ID == SKILL_RUNEFORGING) && (_spell_idx->second->TrivialSkillLineRankHigh == 0 || _spell_idx->second->TrivialSkillLineRankHigh == 1))) + { + switch (GetSkillRangeType(rcEntry)) + { + case SKILL_RANGE_LANGUAGE: + SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 300, 300); + break; + case SKILL_RANGE_LEVEL: + SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 1, GetMaxSkillValueForLevel()); + break; + case SKILL_RANGE_MONO: + SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 1, 1); + break; + default: + break; + } } } } @@ -3664,6 +3735,7 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const { + if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec())) return spellInfo->Id == chrSpec->MasterySpellID[0] || spellInfo->Id == chrSpec->MasterySpellID[1]; @@ -3682,10 +3754,9 @@ void Player::LearnSpell(uint32 spell_id, bool dependent, bool fromSkill /*= fals // prevent duplicated entires in spell book, also not send if not in world (loading) if (learning && IsInWorld()) { - WorldPacket data(SMSG_LEARNED_SPELL, 8); - data << uint32(spell_id); - data << uint32(0); - GetSession()->SendPacket(&data); + WorldPackets::Spells::LearnedSpells packet; + packet.SpellID.push_back(spell_id); + GetSession()->SendPacket(packet.Write()); } // learn all disabled higher ranks and required spells (recursive) @@ -3848,18 +3919,11 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) if (spell_id == 46917 && m_canTitanGrip) SetCanTitanGrip(false); + if (m_canDualWield) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); - if (spellInfo->IsPassive()) - { - for (int i = 0; i < MAX_SPELL_EFFECTS; i++) - if (spellInfo->Effects[i].Effect == SPELL_EFFECT_DUAL_WIELD) - { - SetCanDualWield(false); - break; - } - } + if (spellInfo && spellInfo->IsPassive() && spellInfo->HasEffect(SPELL_EFFECT_DUAL_WIELD)) + SetCanDualWield(false); } if (sWorld->getBoolConfig(CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN)) @@ -3868,9 +3932,9 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) // remove from spell book if not replaced by lesser rank if (!prev_activate) { - WorldPacket data(SMSG_REMOVED_SPELL, 4); - data << uint32(spell_id); - GetSession()->SendPacket(&data); + WorldPackets::Spells::SendRemovedSpell removedSpells; + removedSpells.Spells.push_back(spell_id); + GetSession()->SendPacket(removedSpells.Write()); } } @@ -4055,9 +4119,12 @@ uint32 Player::GetNextResetTalentsCost() const } } -bool Player::ResetTalents(bool no_cost) +bool Player::ResetTalents(bool noCost, bool resetTalents, bool resetSpecialization) { - sScriptMgr->OnPlayerTalentsReset(this, no_cost); + if (!resetTalents && !resetSpecialization) + return false; + + sScriptMgr->OnPlayerTalentsReset(this, noCost); // not need after this call if (HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) @@ -4065,7 +4132,7 @@ bool Player::ResetTalents(bool no_cost) uint32 cost = 0; - if (!no_cost && !sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST)) + if (!noCost && !sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST)) { cost = GetNextResetTalentsCost(); @@ -4078,66 +4145,54 @@ bool Player::ResetTalents(bool no_cost) RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); - uint8 group = GetActiveTalentGroup(); - uint32 specID = GetActiveTalentSpec(); - - for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) + if (resetTalents) { - TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); + for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) + { + TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); - if (!talentInfo) - continue; + if (!talentInfo) + continue; - // unlearn only talents for character class - // some spell learned by one class as normal spells or know at creation but another class learn it as talent, - // to prevent unexpected lost normal learned spell skip another class talents - if (getClass() != talentInfo->ClassID) - continue; + // unlearn only talents for character class + // some spell learned by one class as normal spells or know at creation but another class learn it as talent, + // to prevent unexpected lost normal learned spell skip another class talents + if (talentInfo->ClassID != getClass()) + continue; - const SpellInfo* _spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + if (!spellEntry) + continue; - if (!_spellEntry) - continue; + RemoveSpell(spellEntry->Id, false); - RemoveSpell(talentInfo->SpellID, true); + // search for spells that the talent teaches and unlearn them, 6.x remove? + for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE)) + if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL) + RemoveSpell(effect->TriggerSpell, true); - // search for spells that the talent teaches and unlearn them - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (_spellEntry->Effects[i].TriggerSpell > 0 && _spellEntry->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL) - RemoveSpell(_spellEntry->Effects[i].TriggerSpell, true); + GetTalentMap(GetActiveTalentGroup())->erase(talentId); + } } - // Remove all specialization specific spells and give default ones which were overriden - auto specSpells = sSpecializationSpellsBySpecStore.find(specID); - if (specSpells != sSpecializationSpellsBySpecStore.end()) + if (resetSpecialization) { - for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it) + std::list<uint32> learnList = GetSpellsForLevels(0, getRaceMask(), GetTalentSpec(GetActiveTalentGroup()), 0, getLevel()); + for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++) { - SpecializationSpellsEntry const* specSpell = *it; - if (HasSpell(specSpell->SpellID)) { - RemoveSpell(specSpell->SpellID, true); - if (specSpell->OverridesSpellID) - LearnSpell(specSpell->OverridesSpellID, false); - } + if (HasSpell(*iter)) + RemoveSpell(*iter, true); } + SetTalentSpec(GetActiveTalentGroup(), 0); + SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0); } - // Unlearn masteries - if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(specID)) - for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) - if (uint32 mastery = chrSpec->MasterySpellID[i]) - RemoveAurasDueToSpell(mastery); - - // Reset talents store - GetTalentGroupInfo(group)->Reset(); - SetTalentSpec(group, 0); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); _SaveTalents(trans); _SaveSpells(trans); CharacterDatabase.CommitTransaction(trans); - if (!no_cost) + if (!noCost) { ModifyMoney(-(int64)cost); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS, cost); @@ -4158,6 +4213,35 @@ bool Player::ResetTalents(bool no_cost) return true; } +bool Player::RemoveTalent(uint32 talentId) +{ + TalentEntry const* talent = sTalentStore.LookupEntry(talentId); + if (!talent) + return false; + + uint32 spellId = talent->SpellID; + + SpellInfo const* unlearnSpellProto = sSpellMgr->GetSpellInfo(spellId); + + RemoveSpell(spellId, false); + + // 6.x remove? + for (SpellEffectInfo const* effect : unlearnSpellProto->GetEffectsForDifficulty(DIFFICULTY_NONE)) + if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL) + RemoveSpell(effect->TriggerSpell, false); + + GetTalentMap(GetActiveTalentSpec())->erase(talentId); + + // Needs to be executed orthewise the talents will be screwedsx + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + _SaveTalents(trans); + _SaveSpells(trans); + CharacterDatabase.CommitTransaction(trans); + + SendTalentsInfoData(); + return true; +} + Mail* Player::GetMail(uint32 id) { for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) @@ -4224,7 +4308,8 @@ bool Player::HasSpell(uint32 spell) const bool Player::HasTalent(uint32 talentId, uint8 group) { - return GetTalentGroupInfo(group)->HasTalent(talentId); + PlayerTalentMap::const_iterator itr = GetTalentMap(group)->find(talentId); + return (itr != GetTalentMap(group)->end()); } bool Player::HasActiveSpell(uint32 spell) const @@ -4872,7 +4957,7 @@ void Player::CreateCorpse() // prevent existence 2 corpse for player SpawnCorpseBones(); - uint32 _uf, _pb, _pb2, _cfb1, _cfb2; + uint32 _pb, _pb2, _cfb1, _cfb2; Corpse* corpse = new Corpse((m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) ? CORPSE_RESURRECTABLE_PVP : CORPSE_RESURRECTABLE_PVE); SetPvPDeath(false); @@ -4883,18 +4968,16 @@ void Player::CreateCorpse() return; } - _uf = GetUInt32Value(UNIT_FIELD_BYTES_0); _pb = GetUInt32Value(PLAYER_BYTES); _pb2 = GetUInt32Value(PLAYER_BYTES_2); - uint8 race = (uint8)(_uf); uint8 skin = (uint8)(_pb); uint8 face = (uint8)(_pb >> 8); uint8 hairstyle = (uint8)(_pb >> 16); uint8 haircolor = (uint8)(_pb >> 24); uint8 facialhair = (uint8)(_pb2); - _cfb1 = ((0x00) | (race << 8) | (getGender() << 16) | (skin << 24)); + _cfb1 = ((0x00) | (getRace() << 8) | (getGender() << 16) | (skin << 24)); _cfb2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24)); corpse->SetUInt32Value(CORPSE_FIELD_BYTES_1, _cfb1); @@ -5225,8 +5308,8 @@ void Player::CleanupChannels() { Channel* ch = *m_channels.begin(); m_channels.erase(m_channels.begin()); // remove from player's channel list - ch->LeaveChannel(this, false); // not send to client, not remove from player's channel list - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetTeam())) + ch->LeaveChannel(this, false); // not send to client, not remove from player's channel list + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetTeam())) cMgr->LeftChannel(ch->GetName()); // deleted channel if empty } TC_LOG_DEBUG("chat.system", "Player %s: channels cleaned up!", GetName().c_str()); @@ -5241,12 +5324,10 @@ void Player::UpdateLocalChannels(uint32 newZone) if (!current_zone) return; - ChannelMgr* cMgr = ChannelMgr::forTeam(GetTeam()); + ChannelMgr* cMgr = ChannelMgr::ForTeam(GetTeam()); if (!cMgr) return; - std::string current_zone_name = current_zone->ZoneName; - for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i) { if (ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i)) @@ -5279,7 +5360,7 @@ void Player::UpdateLocalChannels(uint32 newZone) if (channel->Flags & CHANNEL_DBC_FLAG_CITY_ONLY) currentNameExt = sObjectMgr->GetTrinityStringForDBCLocale(LANG_CHANNEL_CITY); else - currentNameExt = current_zone_name.c_str(); + currentNameExt = current_zone->ZoneName; snprintf(new_channel_name_buf, 100, channel->Name_lang, currentNameExt); @@ -5385,11 +5466,11 @@ float Player::GetMeleeCritFromAgility() uint8 level = getLevel(); uint32 pclass = getClass(); - if (level > GT_MAX_LEVEL) - level = GT_MAX_LEVEL; + if (level >= sGtChanceToMeleeCritStore.GetTableRowCount()) + level = sGtChanceToMeleeCritStore.GetTableRowCount() - 1; - GtChanceToMeleeCritBaseEntry const* critBase = sGtChanceToMeleeCritBaseStore.LookupEntry(pclass-1); - GtChanceToMeleeCritEntry const* critRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + GtChanceToMeleeCritBaseEntry const* critBase = sGtChanceToMeleeCritBaseStore.EvaluateTable(pclass - 1, 0); + GtChanceToMeleeCritEntry const* critRatio = sGtChanceToMeleeCritStore.EvaluateTable(level - 1, pclass - 1); if (critBase == NULL || critRatio == NULL) return 0.0f; @@ -5433,11 +5514,11 @@ void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) uint8 level = getLevel(); uint32 pclass = getClass(); - if (level > GT_MAX_LEVEL) - level = GT_MAX_LEVEL; + if (level >= sGtChanceToMeleeCritStore.GetTableRowCount()) + level = sGtChanceToMeleeCritStore.GetTableRowCount() - 1; // Dodge per agility is proportional to crit per agility, which is available from DBC files - GtChanceToMeleeCritEntry const* dodgeRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + GtChanceToMeleeCritEntry const* dodgeRatio = sGtChanceToMeleeCritStore.EvaluateTable(level - 1, pclass - 1); if (dodgeRatio == NULL || pclass > MAX_CLASSES) return; @@ -5455,11 +5536,11 @@ float Player::GetSpellCritFromIntellect() uint8 level = getLevel(); uint32 pclass = getClass(); - if (level > GT_MAX_LEVEL) - level = GT_MAX_LEVEL; + if (level >= sGtChanceToSpellCritStore.GetTableRowCount()) + level = sGtChanceToSpellCritStore.GetTableRowCount() - 1; - GtChanceToSpellCritBaseEntry const* critBase = sGtChanceToSpellCritBaseStore.LookupEntry(pclass - 1); - GtChanceToSpellCritEntry const* critRatio = sGtChanceToSpellCritStore.LookupEntry((pclass - 1) * GT_MAX_LEVEL + level - 1); + GtChanceToSpellCritBaseEntry const* critBase = sGtChanceToSpellCritBaseStore.EvaluateTable(pclass - 1, 0); + GtChanceToSpellCritEntry const* critRatio = sGtChanceToSpellCritStore.EvaluateTable(level - 1, pclass - 1); if (critBase == NULL || critRatio == NULL) return 0.0f; @@ -5471,12 +5552,12 @@ float Player::GetRatingMultiplier(CombatRating cr) const { uint8 level = getLevel(); - if (level > GT_MAX_LEVEL) - level = GT_MAX_LEVEL; + if (level >= sGtCombatRatingsStore.GetTableRowCount()) + level = sGtCombatRatingsStore.GetTableRowCount() - 1; - GtCombatRatingsEntry const* Rating = sGtCombatRatingsStore.LookupEntry(cr*GT_MAX_LEVEL+level-1); + GtCombatRatingsEntry const* Rating = sGtCombatRatingsStore.EvaluateTable(level - 1, cr); // gtOCTClassCombatRatingScalarStore.dbc starts with 1, CombatRating with zero, so cr+1 - GtOCTClassCombatRatingScalarEntry const* classRating = sGtOCTClassCombatRatingScalarStore.LookupEntry((getClass()-1)*GT_MAX_RATING+cr+1); + GtOCTClassCombatRatingScalarEntry const* classRating = sGtOCTClassCombatRatingScalarStore.EvaluateTable(cr + 1, getClass() - 1); if (!Rating || !classRating) return 1.0f; // By default use minimum coefficient (not must be called) @@ -5510,11 +5591,10 @@ float Player::OCTRegenMPPerSpirit() uint8 level = getLevel(); uint32 pclass = getClass(); - if (level > GT_MAX_LEVEL) - level = GT_MAX_LEVEL; + if (level >= sGtRegenMPPerSptStore.GetTableRowCount()) + level = sGtRegenMPPerSptStore.GetTableRowCount() - 1; -// GtOCTRegenMPEntry const* baseRatio = sGtOCTRegenMPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - GtRegenMPPerSptEntry const* moreRatio = sGtRegenMPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + GtRegenMPPerSptEntry const* moreRatio = sGtRegenMPPerSptStore.EvaluateTable(level - 1, pclass - 1); if (moreRatio == NULL) return 0.0f; @@ -6203,20 +6283,20 @@ int16 Player::GetSkillTempBonusValue(uint32 skill) const void Player::SendActionButtons(uint32 state) const { - WorldPackets::Spell::UpdateActionButtons packet; + WorldPackets::Spells::UpdateActionButtons packet; for (uint8 button = 0; button < MAX_ACTION_BUTTONS; ++button) { ActionButtonList::const_iterator itr = m_actionButtons.find(button); if (itr != m_actionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED) - packet.ActionButtons[button] = uint32(itr->second.packedData); + packet.ActionButtons[button] = uint64(itr->second.packedData); else packet.ActionButtons[button] = 0; } packet.Reason = state; - GetSession()->SendPacket(packet.Write()); + SendDirectMessage(packet.Write()); TC_LOG_INFO("network", "Action Buttons for '%s' group '%u' Sent", GetGUID().ToString().c_str(), GetActiveTalentGroup()); } @@ -6346,7 +6426,7 @@ void Player::SaveRecallPosition() m_recallO = GetOrientation(); } -void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self) +void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) { if (self) GetSession()->SendPacket(data); @@ -6355,7 +6435,7 @@ void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self) VisitNearbyWorldObject(dist, notifier); } -void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only) +void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool own_team_only) { if (self) GetSession()->SendPacket(data); @@ -6364,7 +6444,7 @@ void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self, b VisitNearbyWorldObject(dist, notifier); } -void Player::SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) +void Player::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) { if (skipped_rcvr != this) GetSession()->SendPacket(data); @@ -6375,7 +6455,7 @@ void Player::SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) VisitNearbyWorldObject(GetVisibilityRange(), notifier); } -void Player::SendDirectMessage(WorldPacket const* data) +void Player::SendDirectMessage(WorldPacket const* data) const { m_session->SendPacket(data); } @@ -8263,7 +8343,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 } // not allow proc extra attack spell at extra attack - if (m_extraAttacks && spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + if (m_extraAttacks && spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_ADD_EXTRA_ATTACKS)) return; float chance = (float)spellInfo->ProcChance; @@ -9494,6 +9574,16 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(4131) << uint32(0); // 10 WORLDSTATE_ALGALON_DESPAWN_TIMER } break; + // Halls of Refection + case 4820: + if (instance && mapid == 668) + instance->FillInitialWorldStates(data); + else + { + data << uint32(4884) << uint32(0); // 9 WORLD_STATE_HOR_WAVES_ENABLED + data << uint32(4882) << uint32(0); // 10 WORLD_STATE_HOR_WAVE_COUNT + } + break; // Zul Aman case 3805: if (instance && mapid == 568) @@ -9528,20 +9618,7 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) // Wintergrasp case 4197: if (bf && bf->GetTypeId() == BATTLEFIELD_WG) - { bf->FillInitialWorldStates(data); - break; - } - // Halls of Refection - case 4820: - if (instance && mapid == 668) - instance->FillInitialWorldStates(data); - else - { - data << uint32(4884) << uint32(0); // 9 WORLD_STATE_HOR_WAVES_ENABLED - data << uint32(4882) << uint32(0); // 10 WORLD_STATE_HOR_WAVE_COUNT - } - break; // No break here, intended. default: data << uint32(0x914) << uint32(0x0); // 7 @@ -15127,7 +15204,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, if (quest->GetRewSpellCast() > 0) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpellCast()); - if (questGiver->isType(TYPEMASK_UNIT) && !spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(SPELL_EFFECT_CREATE_ITEM)) + if (questGiver->isType(TYPEMASK_UNIT) && !spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_CREATE_ITEM)) { if (Creature* creature = GetMap()->GetCreature(questGiver->GetGUID())) creature->CastSpell(this, quest->GetRewSpellCast(), true); @@ -15138,7 +15215,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, else if (quest->GetRewSpell() > 0) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpell()); - if (questGiver->isType(TYPEMASK_UNIT) && !spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(SPELL_EFFECT_CREATE_ITEM)) + if (questGiver->isType(TYPEMASK_UNIT) && !spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_CREATE_ITEM)) { if (Creature* creature = GetMap()->GetCreature(questGiver->GetGUID())) creature->CastSpell(this, quest->GetRewSpell(), true); @@ -16744,28 +16821,26 @@ void Player::_LoadEquipmentSets(PreparedQueryResult result) if (!result) return; - uint32 count = 0; do { Field* fields = result->Fetch(); - EquipmentSet eqSet; + EquipmentSetInfo eqSet; - eqSet.Guid = fields[0].GetUInt64(); - uint8 index = fields[1].GetUInt8(); - eqSet.Name = fields[2].GetString(); - eqSet.IconName = fields[3].GetString(); - eqSet.IgnoreMask = fields[4].GetUInt32(); - eqSet.state = EQUIPMENT_SET_UNCHANGED; + eqSet.Data.Guid = fields[0].GetUInt64(); + eqSet.Data.SetID = fields[1].GetUInt8(); + eqSet.Data.SetName = fields[2].GetString(); + eqSet.Data.SetIcon = fields[3].GetString(); + eqSet.Data.IgnoreMask = fields[4].GetUInt32(); + eqSet.State = EQUIPMENT_SET_UNCHANGED; for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) - eqSet.Items[i] = fields[5 + i].GetUInt64(); - - m_EquipmentSets[index] = eqSet; + if (ObjectGuid::LowType guid = fields[5 + i].GetUInt64()) + eqSet.Data.Pieces[i] = ObjectGuid::Create<HighGuid::Item>(guid); - ++count; + if (eqSet.Data.SetID >= MAX_EQUIPMENT_SET_INDEX) // client limit + continue; - if (count >= MAX_EQUIPMENT_SET_INDEX) // client limit - break; + _equipmentSets[eqSet.Data.SetID] = eqSet; } while (result->NextRow()); } @@ -16830,6 +16905,17 @@ void Player::SetHomebind(WorldLocation const& loc, uint32 areaId) CharacterDatabase.Execute(stmt); } +void Player::SendBindPointUpdate() +{ + WorldPackets::Misc::BindPointUpdate packet; + packet.BindPosition.x = m_homebindX; + packet.BindPosition.y = m_homebindY; + packet.BindPosition.z = m_homebindZ; + packet.BindMapID = m_homebindMapId; + packet.BindAreaID = m_homebindAreaId; + SendDirectMessage(packet.Write()); +} + uint32 Player::GetUInt32ValueFromArray(Tokenizer const& data, uint16 index) { if (index >= data.size()) @@ -16919,12 +17005,9 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) return false; } - // overwrite some data fields - uint32 bytes0 = 0; - bytes0 |= fields[3].GetUInt8(); // race - bytes0 |= fields[4].GetUInt8() << 8; // class - bytes0 |= gender << 16; // gender - SetUInt32Value(UNIT_FIELD_BYTES_0, bytes0); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE, fields[3].GetUInt8()); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, fields[4].GetUInt8()); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, gender); // check if race/class combination is valid PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); @@ -16996,10 +17079,10 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) uint32 dungeonDiff = fields[39].GetUInt8() & 0x0F; if (dungeonDiff >= MAX_DUNGEON_DIFFICULTY) - dungeonDiff = DUNGEON_DIFFICULTY_NORMAL; + dungeonDiff = DIFFICULTY_NORMAL; uint32 raidDiff = (fields[39].GetUInt8() >> 4) & 0x0F; if (raidDiff >= MAX_RAID_DIFFICULTY) - raidDiff = RAID_DIFFICULTY_10MAN_NORMAL; + raidDiff = DIFFICULTY_10_N; SetDungeonDifficulty(Difficulty(dungeonDiff)); // may be changed in _LoadGroup SetRaidDifficulty(Difficulty(raidDiff)); // may be changed in _LoadGroup @@ -17390,13 +17473,18 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) if (i >= talentSpecs.size()) break; - uint32 talentSpec = atol(talentSpecs[i]); - if (sChrSpecializationStore.LookupEntry(talentSpec)) - SetTalentSpec(i, talentSpec); - else - SetAtLoginFlag(AT_LOGIN_RESET_TALENTS); + uint32 talentSpec = atoul(talentSpecs[i]); + if (talentSpec) + { + if (sChrSpecializationStore.LookupEntry(talentSpec)) + SetTalentSpec(i, talentSpec); + else + SetAtLoginFlag(AT_LOGIN_RESET_TALENTS); + } } + SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, GetActiveTalentSpec()); + _LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS)); _LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS)); @@ -17810,7 +17898,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) Field* fields = result->Fetch(); if (Item* item = _LoadItem(trans, zoneId, timeDiff, fields)) { - ObjectGuid bagGuid = ObjectGuid::Create<HighGuid::Item>(fields[11].GetUInt64()); + ObjectGuid bagGuid = fields[11].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[11].GetUInt64()) : ObjectGuid::Empty; uint8 slot = fields[12].GetUInt8(); uint8 err = EQUIP_ERR_OK; @@ -18462,6 +18550,13 @@ void Player::_LoadSpells(PreparedQueryResult result) AddSpell((*result)[0].GetUInt32(), (*result)[1].GetBool(), false, false, (*result)[2].GetBool(), true); while (result->NextRow()); } + + std::list<uint32> learnList = GetSpellsForLevels(getClass(), getRaceMask(), GetActiveTalentSpec(), 0, getLevel()); + for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++) + { + if (!HasSpell(*iter)) + LearnSpell(*iter, true); + } } void Player::_LoadGroup(PreparedQueryResult result) @@ -18710,7 +18805,7 @@ void Player::SendRaidInfo() if (itr->second.perm) { InstanceSave* save = itr->second.save; - bool isHeroic = save->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC || save->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC; + bool isHeroic = save->GetDifficulty() == DIFFICULTY_10_HC || save->GetDifficulty() == DIFFICULTY_25_HC; uint32 completedEncounters = 0; if (Map* map = sMapMgr->FindMap(save->GetMapId(), save->GetInstanceId())) if (InstanceScript* instanceScript = ((InstanceMap*)map)->GetInstanceScript()) @@ -20173,7 +20268,7 @@ void Player::ResetInstances(uint8 method, bool isRaid) if (method == INSTANCE_RESET_ALL) { // the "reset all instances" method can only reset normal maps - if (entry->IsRaid() || diff == DUNGEON_DIFFICULTY_HEROIC) + if (entry->IsRaid() || diff == DIFFICULTY_HEROIC) { ++itr; continue; @@ -20416,9 +20511,9 @@ void Player::Say(std::string const& text, Language language, WorldObject const* std::string _text(text); sScriptMgr->OnPlayerChat(this, CHAT_MSG_SAY, language, _text); - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, language, this, this, _text); - SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_SAY, language, this, this, _text); + SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); } void Player::Yell(std::string const& text, Language language, WorldObject const* /*= nullptr*/) @@ -20426,9 +20521,9 @@ void Player::Yell(std::string const& text, Language language, WorldObject const* std::string _text(text); sScriptMgr->OnPlayerChat(this, CHAT_MSG_YELL, language, _text); - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, language, this, this, _text); - SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_YELL, language, this, this, _text); + SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true); } void Player::TextEmote(std::string const& text, WorldObject const* /*= nullptr*/, bool /*= false*/) @@ -20436,9 +20531,9 @@ void Player::TextEmote(std::string const& text, WorldObject const* /*= nullptr*/ std::string _text(text); sScriptMgr->OnPlayerChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text); - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text); - SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text); + SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)); } void Player::WhisperAddon(std::string const& text, const std::string& prefix, Player* receiver) @@ -20449,9 +20544,9 @@ void Player::WhisperAddon(std::string const& text, const std::string& prefix, Pl if (!receiver->GetSession()->IsAddonRegistered(prefix)) return; - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, LANG_ADDON, this, this, text, 0, "", DEFAULT_LOCALE, prefix); - receiver->GetSession()->SendPacket(&data); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_WHISPER, LANG_ADDON, this, this, text, 0, "", DEFAULT_LOCALE, prefix); + receiver->SendDirectMessage(packet.Write()); } void Player::Whisper(std::string const& text, Language language, Player* target, bool /*= false*/) @@ -20466,16 +20561,16 @@ void Player::Whisper(std::string const& text, Language language, Player* target, std::string _text(text); sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, language, _text, target); - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, Language(language), this, this, _text); - target->GetSession()->SendPacket(&data); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_WHISPER, Language(language), this, this, _text); + target->SendDirectMessage(packet.Write()); // rest stuff shouldn't happen in case of addon message if (isAddonMessage) return; - ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, Language(language), target, target, _text); - GetSession()->SendPacket(&data); + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_WHISPER_INFORM, Language(language), target, target, _text); + SendDirectMessage(packet.Write()); if (!isAcceptWhispers() && !IsGameMaster() && !target->IsGameMaster()) { @@ -20791,15 +20886,18 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply) TC_LOG_DEBUG("spells", "Player::AddSpellMod %d", mod->spellId); OpcodeServer opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; + WorldPackets::Spells::SetSpellModifier packet(opcode); + int i = 0; - flag96 _mask; - uint32 modTypeCount = 0; // count of mods per one mod->op - WorldPacket data(opcode); - data << uint32(1); // count of different mod->op's in packet - size_t writePos = data.wpos(); - data << uint32(modTypeCount); - data << uint8(mod->op); - for (int eff = 0; eff < 96; ++eff) + flag128 _mask; + + /// @todo Implement sending of bulk modifiers instead of single + packet.Modifiers.resize(1); + WorldPackets::Spells::SpellModifier& spellMod = packet.Modifiers[0]; + + spellMod.ModIndex = mod->op; + + for (int eff = 0; eff < 128; ++eff) { if (eff != 0 && (eff % 32) == 0) _mask[i++] = 0; @@ -20807,19 +20905,24 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply) _mask[i] = uint32(1) << (eff - (32 * i)); if (mod->mask & _mask) { - int32 val = 0; + WorldPackets::Spells::SpellModifierData modData; + for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr) if ((*itr)->type == mod->type && (*itr)->mask & _mask) - val += (*itr)->value; - val += apply ? mod->value : -(mod->value); + modData.ModifierValue += (*itr)->value; + + modData.ModifierValue += apply ? mod->value : -(mod->value); + if (mod->type == SPELLMOD_PCT) + modData.ModifierValue = 1.0f + (modData.ModifierValue * 0.01f); - data << uint8(eff); - data << float(val); - ++modTypeCount; + modData.ClassIndex = eff; + + spellMod.ModifierData.push_back(modData); } } - data.put<uint32>(writePos, modTypeCount); - SendDirectMessage(&data); + + SendDirectMessage(packet.Write()); + if (apply) m_spellMods[mod->op].push_back(mod); else @@ -20965,9 +21068,10 @@ void Player::SetSpellModTakingSpell(Spell* spell, bool apply) // send Proficiency void Player::SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) { - WorldPacket data(SMSG_SET_PROFICIENCY, 1 + 4); - data << uint8(itemClass) << uint32(itemSubclassMask); - GetSession()->SendPacket(&data); + WorldPackets::Item::SetProficiency packet; + packet.ProficiencyMask = itemSubclassMask; + packet.ProficiencyClass = itemClass; + SendDirectMessage(packet.Write()); } void Player::RemovePetitionsAndSigns(ObjectGuid guid, uint32 type) @@ -21371,12 +21475,7 @@ void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) if (itr->second->state == PLAYERSPELL_REMOVED) continue; uint32 unSpellId = itr->first; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(unSpellId); - if (!spellInfo) - { - ASSERT(spellInfo); - continue; - } + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId); // Not send cooldown for this spells if (spellInfo->IsCooldownStartedOnEvent()) @@ -22781,6 +22880,10 @@ template void Player::UpdateVisibilityOf(AreaTrigger* target, UpdateData& data void Player::UpdateObjectVisibility(bool forced) { + // Prevent updating visibility if player is not in world (example: LoadFromDB sets drunkstate which updates invisibility while player is not in map) + if (!IsInWorld()) + return; + if (!forced) AddToNotify(NOTIFY_VISIBILITY_CHANGED); else @@ -22970,67 +23073,67 @@ void Player::SendInitialPacketsBeforeAddToMap() /// Pass 'this' as argument because we're not stored in ObjectAccessor yet GetSocial()->SendSocialList(this); - // guild bank list wtf? - + /// SMSG_SPELL_CATEGORY_COOLDOWN GetSession()->SendSpellCategoryCooldowns(); - // Homebind - WorldPacket data(SMSG_BINDPOINTUPDATE, 5*4); - data << m_homebindX << m_homebindY << m_homebindZ; - data << (uint32) m_homebindMapId; - data << (uint32) m_homebindAreaId; - GetSession()->SendPacket(&data); + /// SMSG_BINDPOINTUPDATE + SendBindPointUpdate(); // SMSG_SET_PROFICIENCY // SMSG_SET_PCT_SPELL_MODIFIER // SMSG_SET_FLAT_SPELL_MODIFIER - // SMSG_UPDATE_AURA_DURATION + /// SMSG_TALENTS_INFO SendTalentsInfoData(); - - data.Initialize(SMSG_WORLD_SERVER_INFO, 1 + 1 + 4 + 4); - data.WriteBit(0); // HasRestrictedLevel - data.WriteBit(0); // HasRestrictedMoney - data.WriteBit(0); // IneligibleForLoot - data.FlushBits(); - //if (IneligibleForLoot) - // data << uint32(0); // EncounterMask - - data << uint8(0); // IsOnTournamentRealm - //if (HasRestrictedMoney) - // data << uint32(100000); // RestrictedMoney (starter accounts) - //if (HasRestrictedLevel) - // data << uint32(20); // RestrictedLevel (starter accounts) - - data << uint32(sWorld->GetNextWeeklyQuestsResetTime() - WEEK); // LastWeeklyReset (not instance reset) - data << uint32(GetMap()->GetDifficulty()); - GetSession()->SendPacket(&data); - + /// SMSG_INITIAL_SPELLS SendKnownSpells(); - WorldPackets::Spell::SendUnlearnSpells packet; - GetSession()->SendPacket(packet.Write()); + /// SMSG_SEND_UNLEARN_SPELLS + SendDirectMessage(WorldPackets::Spells::SendUnlearnSpells().Write()); + /// @todo: SMSG_SEND_SPELL_HISTORY + /// @todo: SMSG_SEND_SPELL_CHARGES + + /// SMSG_ACTION_BUTTONS SendInitialActionButtons(); - m_reputationMgr->SendInitialReputations(); - m_achievementMgr->SendAllAchievementData(this); + /// SMSG_INITIALIZE_FACTIONS + m_reputationMgr->SendInitialReputations(); + /// SMSG_SET_FORCED_REACTIONS + m_reputationMgr->SendForceReactions(); + /// SMSG_INIT_CURRENCY + SendCurrencies(); + /// SMSG_EQUIPMENT_SET_LIST SendEquipmentSetList(); - data.Initialize(SMSG_LOGIN_SETTIMESPEED, 4 + 4 + 4); - data.AppendPackedTime(sWorld->GetGameTime()); - data << float(0.01666667f); // game speed - data << uint32(0); // added in 3.1.2 - GetSession()->SendPacket(&data); + m_achievementMgr->SendAllAchievementData(this); - GetReputationMgr().SendForceReactions(); // SMSG_SET_FORCED_REACTIONS + /// SMSG_LOGIN_SETTIMESPEED + static float const TimeSpeed = 0.01666667f; + WorldPackets::Misc::LoginSetTimeSpeed loginSetTimeSpeed; + loginSetTimeSpeed.NewSpeed = TimeSpeed; + loginSetTimeSpeed.GameTime = sWorld->GetGameTime(); + loginSetTimeSpeed.ServerTime = sWorld->GetGameTime(); + loginSetTimeSpeed.GameTimeHolidayOffset = 0; /// @todo + loginSetTimeSpeed.ServerTimeHolidayOffset = 0; /// @todo + SendDirectMessage(loginSetTimeSpeed.Write()); + + /// SMSG_WORLD_SERVER_INFO + WorldPackets::Misc::WorldServerInfo worldServerInfo; + worldServerInfo.IneligibleForLootMask.Clear(); /// @todo + worldServerInfo.WeeklyReset = sWorld->GetNextWeeklyQuestsResetTime() - WEEK; + worldServerInfo.InstanceGroupSize.Clear(); /// @todo + worldServerInfo.IsTournamentRealm = 0; /// @todo + worldServerInfo.RestrictedAccountMaxLevel.Clear(); /// @todo + worldServerInfo.RestrictedAccountMaxMoney.Clear(); /// @todo + worldServerInfo.DifficultyID = GetMap()->GetDifficulty(); + SendDirectMessage(worldServerInfo.Write()); // SMSG_TALENTS_INFO x 2 for pet (unspent points and talents in separate packets...) // SMSG_PET_GUIDS // SMSG_UPDATE_WORLD_STATE // SMSG_POWER_UPDATE - SendCurrencies(); SetMover(this); } @@ -23105,11 +23208,11 @@ void Player::SendUpdateToOutOfRangeGroupMembers() void Player::SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg) { - WorldPacket data(SMSG_TRANSFER_ABORTED, 4+2); - data << uint32(mapid); - data << uint8(reason); // transfer abort reason - data << uint8(arg); - GetSession()->SendPacket(&data); + WorldPackets::Movement::TransferAborted transferAborted; + transferAborted.MapID = mapid; + transferAborted.Arg = arg; + transferAborted.TransfertAbort = reason; + GetSession()->SendPacket(transferAborted.Write()); } void Player::SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time) @@ -23256,7 +23359,6 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank) if (!rcInfo) return; - TC_LOG_DEBUG("entities.player.loading", "PLAYER (Class: %u Race: %u): Adding initial skill, id = %u", uint32(getClass()), uint32(getRace()), skillId); switch (GetSkillRangeType(rcInfo)) { case SKILL_RANGE_LANGUAGE: @@ -23302,6 +23404,7 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank) } } + void Player::LearnQuestRewardedSpells(Quest const* quest) { int32 spell_id = quest->GetRewSpellCast(); @@ -23324,9 +23427,9 @@ void Player::LearnQuestRewardedSpells(Quest const* quest) // check learned spells state bool found = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && !HasSpell(spellInfo->Effects[i].TriggerSpell)) + if (effect && effect->Effect == SPELL_EFFECT_LEARN_SPELL && !HasSpell(effect->TriggerSpell)) { found = true; break; @@ -23337,8 +23440,12 @@ void Player::LearnQuestRewardedSpells(Quest const* quest) if (!found) return; + SpellEffectInfo const* effect = spellInfo->GetEffect(DIFFICULTY_NONE, EFFECT_0); + if (!effect) + return; + // prevent learn non first rank unknown profession and second specialization for same profession) - uint32 learned_0 = spellInfo->Effects[0].TriggerSpell; + uint32 learned_0 = effect->TriggerSpell; if (sSpellMgr->GetSpellRank(learned_0) > 1 && !HasSpell(learned_0)) { SpellInfo const* learnedInfo = sSpellMgr->GetSpellInfo(learned_0); @@ -23354,8 +23461,15 @@ void Player::LearnQuestRewardedSpells(Quest const* quest) { uint32 profSpell = itr2->second; + SpellEffectInfo const* effect0 = learnedInfo->GetEffect(DIFFICULTY_NONE, EFFECT_0); + if (!effect0) + continue; + SpellEffectInfo const* effect1 = learnedInfo->GetEffect(DIFFICULTY_NONE, EFFECT_1); + if (!effect1) + continue; + // specialization - if (learnedInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effects[1].Effect == 0 && profSpell) + if (effect0->Effect == SPELL_EFFECT_TRADE_SKILL && effect1->Effect == 0 && profSpell) { // search other specialization for same prof for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) @@ -23367,8 +23481,16 @@ void Player::LearnQuestRewardedSpells(Quest const* quest) if (!itrInfo) return; + + SpellEffectInfo const* itrEffect0 = itrInfo->GetEffect(DIFFICULTY_NONE, EFFECT_0); + if (!itrEffect0) + continue; + SpellEffectInfo const* itrEffect1 = itrInfo->GetEffect(DIFFICULTY_NONE, EFFECT_1); + if (!itrEffect1) + continue; + // compare only specializations - if (itrInfo->Effects[0].Effect != SPELL_EFFECT_TRADE_SKILL || itrInfo->Effects[1].Effect != 0) + if (itrEffect0->Effect != SPELL_EFFECT_TRADE_SKILL || itrEffect1->Effect != 0) continue; // compare same chain spells @@ -23405,7 +23527,8 @@ void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue) if (!ability || ability->SkillLine != skillId) continue; - if (!sSpellMgr->GetSpellInfo(ability->SpellID)) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ability->SpellID); + if (!spellInfo) continue; if (ability->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE && ability->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) @@ -23419,6 +23542,10 @@ void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue) if (ability->ClassMask && !(ability->ClassMask & classMask)) continue; + // check level, skip class spells if not high enough + if (getLevel() < spellInfo->SpellLevel) + continue; + // need unlearn spell if (skillValue < ability->MinSkillLineRank && ability->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE) RemoveSpell(ability->SpellID); @@ -23447,17 +23574,18 @@ void Player::SendAurasForTarget(Unit* target) if (target->HasAuraType(SPELL_AURA_HOVER)) target->SetHover(true, true); - WorldPacket data(SMSG_AURA_UPDATE_ALL); - data << target->GetPackGUID(); - Unit::VisibleAuraMap const* visibleAuras = target->GetVisibleAuras(); + + WorldPackets::Spells::SendAuraUpdate update; + update.Init(true, GetGUID(), visibleAuras->size()); + for (Unit::VisibleAuraMap::const_iterator itr = visibleAuras->begin(); itr != visibleAuras->end(); ++itr) { AuraApplication * auraApp = itr->second; - auraApp->BuildUpdatePacket(data, false); + update.BuildUpdatePacket(auraApp, false, getLevel()); // TODO 6.x should be caster's level } - GetSession()->SendPacket(&data); + GetSession()->SendPacket(const_cast<WorldPacket*>(update.Write())); } void Player::SetDailyQuestStatus(uint32 quest_id) @@ -24676,8 +24804,8 @@ uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 n { uint8 level = getLevel(); - if (level > GT_MAX_LEVEL) - level = GT_MAX_LEVEL; // max level in this dbc + if (level >= sGtBarberShopCostBaseStore.GetTableRowCount()) + level = sGtBarberShopCostBaseStore.GetTableRowCount() - 1; uint8 hairstyle = GetByteValue(PLAYER_BYTES, 2); uint8 haircolor = GetByteValue(PLAYER_BYTES, 3); @@ -24687,7 +24815,7 @@ uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 n if ((hairstyle == newhairstyle) && (haircolor == newhaircolor) && (facialhair == newfacialhair) && (!newSkin || (newSkin->Data == skincolor))) return 0; - GtBarberShopCostBaseEntry const* bsc = sGtBarberShopCostBaseStore.LookupEntry(level - 1); + GtBarberShopCostBaseEntry const* bsc = sGtBarberShopCostBaseStore.EvaluateTable(level - 1, 0); if (!bsc) // shouldn't happen return 0xFFFFFFFF; @@ -25416,37 +25544,36 @@ void Player::CompletedAchievement(AchievementEntry const* entry) bool Player::LearnTalent(uint32 talentId) { - uint8 group = GetActiveTalentGroup(); - - // check if talent specialization is learnt - if (!GetTalentSpec(group)) - return false; - TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); if (!talentInfo) return false; + uint32 maxTalentTier = GetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS); + // prevent learn talent for different class (cheating) - if (getClass() != talentInfo->ClassID) + if (talentInfo->ClassID != getClass()) return false; - // Check player level - // TODO: fix level requirements for deathknights - uint8 levelReq = std::min(15*talentInfo->TierID + 15, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); - if (getLevel() < levelReq) + // check if we have enough talent points + if (talentInfo->TierID > maxTalentTier) return false; - // Check if such tier talent hasn't been picked already - TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(group); - if (talentGroupInfo->Talents[talentInfo->TierID]) - return false; + // Check if player doesnt have any spell in selected collumn + for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++) + { + if (TalentEntry const* talent = sTalentStore.LookupEntry(i)) + { + if (talentInfo->TierID == talent->TierID && HasSpell(talent->SpellID)) + return false; + } + } // spell not set in talent.dbc uint32 spellid = talentInfo->SpellID; if (spellid == 0) { - TC_LOG_ERROR("entities.player", "Talent.dbc have for talent: %u spell id = 0", talentId); + TC_LOG_ERROR("entities.player", "Talent.dbc has no spellInfo for talent: %u (spell id = 0)", talentId); return false; } @@ -25454,54 +25581,64 @@ bool Player::LearnTalent(uint32 talentId) if (HasSpell(spellid)) return false; - // Check talent spec - if (talentInfo->SpecID != GetTalentSpec(group)) + if (!AddTalent(talentId, GetActiveTalentGroup(), true)) return false; - // learn! (other talent ranks will unlearned at learning) LearnSpell(spellid, false); - AddTalent(talentId, group); - TC_LOG_INFO("misc", "TalentID: %u Spell: %u Group: %u\n", talentId, spellid, group); + TC_LOG_INFO("misc", "TalentID: %u Spell: %u Group: %u\n", talentId, spellid, GetActiveTalentGroup()); return true; } void Player::LearnTalentSpecialization(uint32 talentSpec) { + if (GetActiveTalentSpec()) + return; + SetTalentSpec(GetActiveTalentGroup(), talentSpec); - // Replace default spells by specialization spells - auto specSpells = sSpecializationSpellsBySpecStore.find(talentSpec); - if (specSpells != sSpecializationSpellsBySpecStore.end()) + SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, talentSpec); + + PlayerTalentMap* talents = GetTalentMap(GetActiveTalentGroup()); + + for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) { - for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it) - { - SpecializationSpellsEntry const* specSpell = *it; + TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); - // Unlearn spell if it is replaced by new specialization - if (specSpell->OverridesSpellID) - RemoveSpell(specSpell->OverridesSpellID, true); + if (!talentInfo || talentInfo->ClassID != getClass() || talentInfo->SpecID != talentSpec) + continue; - // Learn new spell - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID)) - if (spellInfo->BaseLevel <= getLevel()) - LearnSpell(specSpell->SpellID, false); + for (PlayerTalentMap::iterator itr = talents->begin(); itr != talents->end();) + { + TalentEntry const* talent = sTalentStore.LookupEntry(itr->first); + if (!talent || talent->TierID != talentInfo->TierID) + { + ++itr; + continue; + } + RemoveSpell(talent->SpellID, false); + itr = talents->erase(itr); + + TC_LOG_DEBUG("spells", "Player %s unlearning talent id: %u tier: %u due to specialization change", GetName().c_str(), talent->ID, talent->TierID); } } - if (CanUseMastery()) + SendTalentsInfoData(); + + std::list<uint32> learnList = GetSpellsForLevels(0, getRaceMask(), GetActiveTalentSpec(), 0, getLevel()); + for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++) { - ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(talentSpec); - for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) - if (SpellInfo const* masterySpell = sSpellMgr->GetSpellInfo(chrSpec->MasterySpellID[i])) - if (masterySpell->IsPassive() && IsNeedCastPassiveSpellAtLearn(masterySpell)) - CastSpell(this, masterySpell->Id, true); + if (!HasSpell(*iter)) + LearnSpell(*iter, true); } - + + SaveToDB(); + SendTalentsInfoData(); } + void Player::AddKnownCurrency(uint32 itemId) { if (CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemId)) @@ -25586,28 +25723,44 @@ void Player::SendTalentsInfoData() for (uint8 i = 0; i < groupsCount; ++i) { - TalentGroupInfo* groupInfo = GetTalentGroupInfo(i); WorldPackets::Talent::TalentGroupInfo groupInfoPkt; - groupInfoPkt.SpecID = groupInfo->SpecID; + groupInfoPkt.SpecID = GetTalentSpec(i); - groupInfoPkt.TalentIDs.reserve(MAX_TALENT_TIERS); - for (uint32 x = 0; x < MAX_TALENT_TIERS; ++x) + groupInfoPkt.TalentIDs.reserve(GetTalentMap(i)->size()); + + for (PlayerTalentMap::const_iterator itr = GetTalentMap(i)->begin(); itr != GetTalentMap(i)->end(); ++itr) { - // Do not send empty talents - if (!groupInfo->Talents[x]) - break; + TalentEntry const* talentInfo = sTalentStore.LookupEntry(itr->first); + if (!talentInfo) + { + TC_LOG_ERROR("entities.player", "Player %s has unknown talent id: %u", GetName().c_str(), itr->first); + continue; + } + + if (talentInfo->ClassID != getClass()) + continue; + + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + if (!spellEntry) + { + TC_LOG_ERROR("entities.player", "Player %s has unknown talent spell: %u", GetName().c_str(), talentInfo->SpellID); + continue; + } - groupInfoPkt.TalentIDs.push_back(groupInfo->Talents[x]); + if (!HasTalent(itr->first, i)) + continue; + + groupInfoPkt.TalentIDs.push_back(uint16(itr->first)); } for (uint32 x = 0; x < MAX_GLYPH_SLOT_INDEX; ++x) - groupInfoPkt.GlyphIDs[x] = groupInfo->Glyphs[x]; + groupInfoPkt.GlyphIDs[x] = uint16(GetGlyph(i, x)); packet.Info.TalentGroups.push_back(groupInfoPkt); } - GetSession()->SendPacket(packet.Write()); + SendDirectMessage(packet.Write()); } void Player::BuildEnchantmentsInfoData(WorldPacket* data) @@ -25655,122 +25808,100 @@ void Player::BuildEnchantmentsInfoData(WorldPacket* data) void Player::SendEquipmentSetList() { - ObjectGuid ignoredItemGuid; - ignoredItemGuid.SetRawValue(0, 1); - uint32 count = 0; - WorldPacket data(SMSG_EQUIPMENT_SET_LIST, 4); - size_t count_pos = data.wpos(); - data << uint32(count); // count placeholder - for (EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end(); ++itr) + WorldPackets::EquipmentSet::LoadEquipmentSet data; + + for (EquipmentSetContainer::value_type const& eqSet : _equipmentSets) { - if (itr->second.state == EQUIPMENT_SET_DELETED) + if (eqSet.second.State == EQUIPMENT_SET_DELETED) continue; - data.AppendPackedUInt64(itr->second.Guid); - data << uint32(itr->first); - data << itr->second.Name; - data << itr->second.IconName; - for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) - { - // ignored slots stored in IgnoreMask, client wants "1" as raw GUID, so no HIGHGUID_ITEM - if (itr->second.IgnoreMask & (1 << i)) - data << ignoredItemGuid; - else - data << ObjectGuid::Create<HighGuid::Item>(itr->second.Items[i]); - } - ++count; // client have limit but it checked at loading and set + data.SetData.push_back(&eqSet.second.Data); } - data.put<uint32>(count_pos, count); - GetSession()->SendPacket(&data); + + SendDirectMessage(data.Write()); } -void Player::SetEquipmentSet(uint32 index, EquipmentSet eqset) +void Player::SetEquipmentSet(EquipmentSetInfo::EquipmentSetData&& newEqSet) { - if (eqset.Guid != 0) + if (newEqSet.Guid != 0) { - bool found = false; - - for (EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end(); ++itr) - { - if ((itr->second.Guid == eqset.Guid) && (itr->first == index)) - { - found = true; - break; - } - } - - if (!found) // something wrong... + // something wrong... + EquipmentSetContainer::const_iterator itr = _equipmentSets.find(newEqSet.SetID); + if (itr == _equipmentSets.end() || itr->second.Data.Guid != newEqSet.Guid) { - TC_LOG_ERROR("entities.player", "Player %s tried to save equipment set " UI64FMTD " (index %u), but that equipment set not found!", GetName().c_str(), eqset.Guid, index); + TC_LOG_ERROR("entities.player", "Player %s tried to save equipment set " UI64FMTD " (index: %u), but that equipment set not found!", GetName().c_str(), newEqSet.Guid, newEqSet.SetID); return; } } - EquipmentSet& eqslot = m_EquipmentSets[index]; + EquipmentSetInfo& eqSlot = _equipmentSets[newEqSet.SetID]; - EquipmentSetUpdateState old_state = eqslot.state; + EquipmentSetUpdateState oldState = eqSlot.State; - eqslot = eqset; + eqSlot.Data = newEqSet; - if (eqset.Guid == 0) + if (eqSlot.Data.Guid == 0) { - eqslot.Guid = sObjectMgr->GenerateEquipmentSetGuid(); + eqSlot.Data.Guid = sObjectMgr->GenerateEquipmentSetGuid(); - WorldPacket data(SMSG_EQUIPMENT_SET_SAVED, 4 + 1); - data << uint32(index); - data.AppendPackedUInt64(eqslot.Guid); - GetSession()->SendPacket(&data); + WorldPackets::EquipmentSet::EquipmentSetID data; + data.GUID = eqSlot.Data.Guid; + data.SetID = eqSlot.Data.SetID; + SendDirectMessage(data.Write()); } - eqslot.state = old_state == EQUIPMENT_SET_NEW ? EQUIPMENT_SET_NEW : EQUIPMENT_SET_CHANGED; + eqSlot.State = oldState == EQUIPMENT_SET_NEW ? EQUIPMENT_SET_NEW : EQUIPMENT_SET_CHANGED; } void Player::_SaveEquipmentSets(SQLTransaction& trans) { - for (EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end();) + for (EquipmentSetContainer::iterator itr = _equipmentSets.begin(); itr != _equipmentSets.end();) { - uint32 index = itr->first; - EquipmentSet& eqset = itr->second; - PreparedStatement* stmt = NULL; + EquipmentSetInfo& eqSet = itr->second; + PreparedStatement* stmt = nullptr; uint8 j = 0; - switch (eqset.state) + switch (eqSet.State) { case EQUIPMENT_SET_UNCHANGED: ++itr; break; // nothing do case EQUIPMENT_SET_CHANGED: stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_EQUIP_SET); - stmt->setString(j++, eqset.Name.c_str()); - stmt->setString(j++, eqset.IconName.c_str()); - stmt->setUInt32(j++, eqset.IgnoreMask); - for (uint8 i=0; i<EQUIPMENT_SLOT_END; ++i) - stmt->setUInt64(j++, eqset.Items[i]); + stmt->setString(j++, eqSet.Data.SetName); + stmt->setString(j++, eqSet.Data.SetIcon); + stmt->setUInt32(j++, eqSet.Data.IgnoreMask); + + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter()); + stmt->setUInt64(j++, GetGUID().GetCounter()); - stmt->setUInt64(j++, eqset.Guid); - stmt->setUInt32(j, index); + stmt->setUInt64(j++, eqSet.Data.Guid); + stmt->setUInt32(j, eqSet.Data.SetID); trans->Append(stmt); - eqset.state = EQUIPMENT_SET_UNCHANGED; + eqSet.State = EQUIPMENT_SET_UNCHANGED; ++itr; break; case EQUIPMENT_SET_NEW: stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_EQUIP_SET); stmt->setUInt64(j++, GetGUID().GetCounter()); - stmt->setUInt64(j++, eqset.Guid); - stmt->setUInt32(j++, index); - stmt->setString(j++, eqset.Name.c_str()); - stmt->setString(j++, eqset.IconName.c_str()); - stmt->setUInt32(j++, eqset.IgnoreMask); - for (uint8 i=0; i<EQUIPMENT_SLOT_END; ++i) - stmt->setUInt64(j++, eqset.Items[i]); + stmt->setUInt64(j++, eqSet.Data.Guid); + stmt->setUInt32(j++, eqSet.Data.SetID); + stmt->setString(j++, eqSet.Data.SetName); + stmt->setString(j++, eqSet.Data.SetIcon); + stmt->setUInt32(j++, eqSet.Data.IgnoreMask); + + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter()); + trans->Append(stmt); - eqset.state = EQUIPMENT_SET_UNCHANGED; + eqSet.State = EQUIPMENT_SET_UNCHANGED; ++itr; break; case EQUIPMENT_SET_DELETED: stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EQUIP_SET); - stmt->setUInt64(0, eqset.Guid); + stmt->setUInt64(0, eqSet.Data.Guid); trans->Append(stmt); - m_EquipmentSets.erase(itr++); + itr = _equipmentSets.erase(itr); break; } } @@ -25799,16 +25930,17 @@ void Player::_SaveBGData(SQLTransaction& trans) void Player::DeleteEquipmentSet(uint64 setGuid) { - for (EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end(); ++itr) + for (EquipmentSetContainer::iterator itr = _equipmentSets.begin(); itr != _equipmentSets.end();) { - if (itr->second.Guid == setGuid) + if (itr->second.Data.Guid == setGuid) { - if (itr->second.state == EQUIPMENT_SET_NEW) - m_EquipmentSets.erase(itr); + if (itr->second.State == EQUIPMENT_SET_NEW) + itr = _equipmentSets.erase(itr); else - itr->second.state = EQUIPMENT_SET_DELETED; + itr->second.State = EQUIPMENT_SET_DELETED; break; } + ++itr; } } @@ -25935,7 +26067,7 @@ void Player::_LoadTalents(PreparedQueryResult result) if (result) { do - AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8()); + AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8(), false); while (result->NextRow()); } } @@ -25948,17 +26080,12 @@ void Player::_SaveTalents(SQLTransaction& trans) for (uint8 group = 0; group < MAX_TALENT_GROUPS; ++group) { - TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(group); - - for (uint32 tier = 0; tier < MAX_TALENT_TIERS; ++tier) + for (PlayerTalentMap::iterator itr = GetTalentMap(group)->begin(); itr != GetTalentMap(group)->end(); ++itr) { - if (!talentGroupInfo->Talents[tier]) - continue; - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT); stmt->setUInt64(0, GetGUID().GetCounter()); - stmt->setUInt32(1, talentGroupInfo->Talents[tier]); - stmt->setUInt8(2, group); + stmt->setUInt32(1, itr->first); + stmt->setUInt8(2, itr->second->spec); trans->Append(stmt); } } @@ -26057,30 +26184,27 @@ void Player::ActivateTalentGroup(uint8 group) if (getClass() != talentInfo->ClassID) continue; + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + if (!spellEntry) + continue; + RemoveSpell(talentInfo->SpellID, true); + + // search for spells that the talent teaches and unlearn them + for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE)) + if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL) + RemoveSpell(effect->TriggerSpell, true); } // Unlearn specialization specific spells - auto specSpells = sSpecializationSpellsBySpecStore.find(GetActiveTalentSpec()); - if (specSpells != sSpecializationSpellsBySpecStore.end()) + std::list<uint32> learnList = GetSpellsForLevels(0, getRaceMask(), GetActiveTalentSpec(), 0, getLevel()); + for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++) { - for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it) - { - SpecializationSpellsEntry const* specSpell = *it; - if (HasSpell(specSpell->SpellID)) { - RemoveSpell(specSpell->SpellID, true); - LearnSpell(specSpell->OverridesSpellID, false); - } - } + if (HasSpell(*iter)) + RemoveSpell(*iter, true); } - // Unlearn mastery spells - ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()); - for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) - if (chrSpec->MasterySpellID[i]) - RemoveSpell(chrSpec->MasterySpellID[i], true); - - // set glyphs + // remove glyphs for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot) // remove secondary glyph if (uint32 oldglyph = GetGlyph(GetActiveTalentGroup(), slot)) @@ -26090,6 +26214,15 @@ void Player::ActivateTalentGroup(uint8 group) // Activate new group SetActiveTalentGroup(group); + uint32 spentTalents = 0; + + learnList = GetSpellsForLevels(getClass(), getRaceMask(), GetActiveTalentSpec(), 0, getLevel()); + for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++) + { + if (!HasSpell(*iter)) + LearnSpell(*iter, true); + } + for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) { TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); @@ -26101,31 +26234,12 @@ void Player::ActivateTalentGroup(uint8 group) if (getClass() != talentInfo->ClassID) continue; - LearnSpell(talentInfo->SpellID, false); - } + ++spentTalents; - // Replace default spells with specialization specific spells - auto newSpecSpells = sSpecializationSpellsBySpecStore.find(GetActiveTalentSpec()); - if (newSpecSpells != sSpecializationSpellsBySpecStore.end()) - { - for (auto it = newSpecSpells->second.begin(); it != newSpecSpells->second.end(); ++it) - { - SpecializationSpellsEntry const* specSpell = *it; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID); - if (getLevel() >= spellInfo->BaseLevel) { - if (specSpell->OverridesSpellID) - RemoveSpell(specSpell->OverridesSpellID, true); - LearnSpell(specSpell->SpellID, false); - } - } + if (HasTalent(talentInfo->SpellID, group)) + LearnSpell(talentInfo->SpellID, false); } - if (CanUseMastery()) - if (ChrSpecializationEntry const* newChrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec())) - for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) - if (newChrSpec->MasterySpellID[i]) - LearnSpell(newChrSpec->MasterySpellID[i], false); - // set glyphs for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot) { @@ -26139,6 +26253,7 @@ void Player::ActivateTalentGroup(uint8 group) SetGlyph(slot, glyph); } + SetUsedTalentCount(spentTalents); InitTalentForLevel(); { @@ -26158,7 +26273,9 @@ void Player::ActivateTalentGroup(uint8 group) SetPower(pw, 0); if (!sChrSpecializationStore.LookupEntry(GetActiveTalentSpec())) + { ResetTalents(true); + } } void Player::ResetTimeSync() @@ -26174,7 +26291,7 @@ void Player::SendTimeSync() WorldPackets::Misc::TimeSyncRequest packet; packet.SequenceIndex = m_timeSyncQueue.back(); - GetSession()->SendPacket(packet.Write()); + SendDirectMessage(packet.Write()); // Schedule next sync in 10 sec m_timeSyncTimer = 10000; @@ -26742,7 +26859,13 @@ std::string Player::GetCoordsMapAreaAndZoneString() Guild* Player::GetGuild() { ObjectGuid::LowType guildId = GetGuildId(); - return guildId ? sGuildMgr->GetGuildById(guildId) : NULL; + return guildId ? sGuildMgr->GetGuildById(guildId) : nullptr; +} + +Guild const* Player::GetGuild() const +{ + ObjectGuid::LowType guildId = GetGuildId(); + return guildId ? sGuildMgr->GetGuildById(guildId) : nullptr; } Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 duration) @@ -26812,7 +26935,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy case SUMMON_PET: // this enables pet details window (Shift+P) pet->GetCharmInfo()->SetPetNumber(pet_number, true); - pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048); + pet->SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, CLASS_MAGE); pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); pet->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000); pet->SetFullHealth(); @@ -27192,3 +27315,9 @@ void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) data << uint32(newSpell) << uint32(oldSpell); GetSession()->SendPacket(&data); } + +uint32 Player::CalculateTalentsPoints() const +{ + // 1 talent point for every 15 levels + return getLevel() >= 100 ? 7 : uint32(floor(getLevel() / 15.f)); +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1dd993e5b5f..6b9e925e28d 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -116,6 +116,12 @@ struct PlayerSpell bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks }; +struct PlayerTalent +{ + PlayerSpellState state : 8; + uint8 spec : 8; +}; + extern uint32 const MasterySpells[MAX_CLASSES]; enum TalentSpecialization // talent tabs @@ -184,6 +190,7 @@ struct PlayerCurrency uint32 weekCount; }; +typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap; typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap; typedef std::list<SpellModifier*> SpellModList; typedef std::unordered_map<uint32, PlayerCurrency> PlayerCurrenciesMap; @@ -329,7 +336,7 @@ enum ReputationSource }; #define ACTION_BUTTON_ACTION(X) (uint64(X) & 0x00000000FFFFFFFF) -#define ACTION_BUTTON_TYPE(X) ((uint64(X) & 0xFFFFFFFF00000000) >> 32) +#define ACTION_BUTTON_TYPE(X) ((uint64(X) & 0xFFFFFFFF00000000) >> 56) #define MAX_ACTION_BUTTON_ACTION_VALUE (0xFFFFFFFF) struct ActionButton @@ -344,7 +351,7 @@ struct ActionButton uint32 GetAction() const { return ACTION_BUTTON_ACTION(packedData); } void SetActionAndType(uint32 action, ActionButtonType type) { - uint64 newData = uint64(action) | (uint64(type) << 32); + uint64 newData = uint64(action) | (uint64(type) << 56); if (newData != packedData || uState == ACTIONBUTTON_DELETED) { packedData = newData; @@ -747,24 +754,26 @@ enum EquipmentSetUpdateState EQUIPMENT_SET_DELETED = 3 }; -struct EquipmentSet +struct EquipmentSetInfo { - EquipmentSet() : Guid(0), IgnoreMask(0), state(EQUIPMENT_SET_NEW) + /// Data sent in EquipmentSet related packets + struct EquipmentSetData { - memset(Items, 0, sizeof(Items)); - } + uint64 Guid = 0; ///< Set Identifier + uint32 SetID = 0; ///< Index + uint32 IgnoreMask = 0; ///< Mask of EquipmentSlot + std::string SetName; + std::string SetIcon; + ObjectGuid Pieces[EQUIPMENT_SLOT_END]; + } Data; - uint64 Guid; - std::string Name; - std::string IconName; - uint32 IgnoreMask; - ObjectGuid::LowType Items[EQUIPMENT_SLOT_END]; - EquipmentSetUpdateState state; + /// Server-side data + EquipmentSetUpdateState State = EQUIPMENT_SET_NEW; }; #define MAX_EQUIPMENT_SET_INDEX 10 // client limit -typedef std::map<uint32, EquipmentSet> EquipmentSets; +typedef std::map<uint32, EquipmentSetInfo> EquipmentSetContainer; struct ItemPosCount { @@ -785,24 +794,45 @@ enum TradeSlots enum TransferAbortReason { - TRANSFER_ABORT_NONE = 0x00, - TRANSFER_ABORT_ERROR = 0x01, - TRANSFER_ABORT_MAX_PLAYERS = 0x02, // Transfer Aborted: instance is full - TRANSFER_ABORT_NOT_FOUND = 0x03, // Transfer Aborted: instance not found - TRANSFER_ABORT_TOO_MANY_INSTANCES = 0x04, // You have entered too many instances recently. - TRANSFER_ABORT_ZONE_IN_COMBAT = 0x06, // Unable to zone in while an encounter is in progress. - TRANSFER_ABORT_INSUF_EXPAN_LVL = 0x07, // You must have <TBC, WotLK> expansion installed to access this area. - TRANSFER_ABORT_DIFFICULTY = 0x08, // <Normal, Heroic, Epic> difficulty mode is not available for %s. - TRANSFER_ABORT_UNIQUE_MESSAGE = 0x09, // Until you've escaped TLK's grasp, you cannot leave this place! - TRANSFER_ABORT_TOO_MANY_REALM_INSTANCES = 0x0A, // Additional instances cannot be launched, please try again later. - TRANSFER_ABORT_NEED_GROUP = 0x0B, // 3.1 - TRANSFER_ABORT_NOT_FOUND1 = 0x0C, // 3.1 - TRANSFER_ABORT_NOT_FOUND2 = 0x0D, // 3.1 - TRANSFER_ABORT_NOT_FOUND3 = 0x0E, // 3.2 - TRANSFER_ABORT_REALM_ONLY = 0x0F, // All players on party must be from the same realm. - TRANSFER_ABORT_MAP_NOT_ALLOWED = 0x10, // Map can't be entered at this time. - TRANSFER_ABORT_LOCKED_TO_DIFFERENT_INSTANCE = 0x12, // 4.2.2 - TRANSFER_ABORT_ALREADY_COMPLETED_ENCOUNTER = 0x13 // 4.2.2 + TRANSFER_ABORT_NONE = 0, + TRANSFER_ABORT_TOO_MANY_REALM_INSTANCES = 1, // Additional instances cannot be launched, please try again later. + TRANSFER_ABORT_DIFFICULTY = 3, // <Normal, Heroic, Epic> difficulty mode is not available for %s. + TRANSFER_ABORT_INSUF_EXPAN_LVL = 8, // You must have <TBC, WotLK> expansion installed to access this area. + TRANSFER_ABORT_NOT_FOUND = 10, // Transfer Aborted: instance not found + TRANSFER_ABORT_TOO_MANY_INSTANCES = 11, // You have entered too many instances recently. + TRANSFER_ABORT_MAX_PLAYERS = 12, // Transfer Aborted: instance is full + TRANSFER_ABORT_XREALM_ZONE_DOWN = 14, // Transfer Aborted: cross-realm zone is down + TRANSFER_ABORT_NOT_FOUND_2 = 15, // Transfer Aborted: instance not found + TRANSFER_ABORT_DIFFICULTY_NOT_FOUND = 16, // client writes to console "Unable to resolve requested difficultyID %u to actual difficulty for map %d" + TRANSFER_ABORT_NOT_FOUND_3 = 17, // Transfer Aborted: instance not found + TRANSFER_ABORT_NOT_FOUND_4 = 18, // Transfer Aborted: instance not found + TRANSFER_ABORT_ZONE_IN_COMBAT = 19, // Unable to zone in while an encounter is in progress. + TRANSFER_ABORT_ALREADY_COMPLETED_ENCOUNTER = 20, // You are ineligible to participate in at least one encounter in this instance because you are already locked to an instance in which it has been defeated. + TRANSFER_ABORT_LOCKED_TO_DIFFERENT_INSTANCE = 24, // You are already locked to %s + TRANSFER_ABORT_REALM_ONLY = 25, // All players in the party must be from the same realm to enter %s. + TRANSFER_ABORT_MAP_NOT_ALLOWED = 27, // Map cannot be entered at this time. + TRANSFER_ABORT_SOLO_PLAYER_SWITCH_DIFFICULTY = 28, // This instance is already in progress. You may only switch difficulties from inside the instance. + TRANSFER_ABORT_NEED_GROUP = 29, // Transfer Aborted: you must be in a raid group to enter this instance + TRANSFER_ABORT_UNIQUE_MESSAGE = 30, // Until you've escaped TLK's grasp, you cannot leave this place! + TRANSFER_ABORT_ERROR = 31, + /* + // Unknown values - not used by the client to display any error + TRANSFER_ABORT_MANY_REALM_INSTANCES + TRANSFER_ABORT_AREA_NOT_ZONED + TRANSFER_ABORT_TIMEOUT + TRANSFER_ABORT_SHUTTING_DOWN + TRANSFER_ABORT_PLAYER_CONDITION + TRANSFER_ABORT_BUSY + TRANSFER_ABORT_DISCONNECTED + TRANSFER_ABORT_LOGGING_OUT + TRANSFER_ABORT_NEED_SERVER + */ +}; + +enum NewWorldReason +{ + NEW_WORLD_NORMAL = 16, // Normal map change + NEW_WORLD_SEAMLESS = 21, // Teleport to another map without a loading screen, used for outdoor scenarios }; enum InstanceResetWarningType @@ -858,18 +888,6 @@ enum EnviromentalDamage DAMAGE_FALL_TO_VOID = 6 // custom case for fall without durability loss }; -enum PlayerChatTag -{ - CHAT_TAG_NONE = 0x00, - CHAT_TAG_AFK = 0x01, - CHAT_TAG_DND = 0x02, - CHAT_TAG_GM = 0x04, - CHAT_TAG_COM = 0x08, // Commentator - CHAT_TAG_DEV = 0x10, - CHAT_TAG_BOSS_SOUND = 0x20, // Plays "RaidBossEmoteWarning" sound on raid boss emote/whisper - CHAT_TAG_MOBILE = 0x40 -}; - enum PlayedTimeIndex { PLAYED_TIME_TOTAL = 0, @@ -1212,48 +1230,36 @@ private: bool _isPvP; }; -struct TalentGroupInfo +struct PlayerTalentInfo { - uint32 Talents[MAX_TALENT_TIERS]; - uint32 Glyphs[MAX_GLYPH_SLOT_INDEX]; - uint32 SpecID; - - bool HasTalent(uint32 talentId) + PlayerTalentInfo() : UsedTalentCount(0), ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), GroupsCount(1) { - for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i) - if (Talents[i] == talentId) - return true; - return false; - } - - uint32 TalentCount() - { - for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i) - if (!Talents[i]) - return i; - return MAX_TALENT_TIERS; - } - - void Reset() - { - for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i) - Talents[i] = 0; + for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i) + { + GroupInfo[i].Talents = new PlayerTalentMap(); + memset(GroupInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32)); + GroupInfo[i].TalentTree = 0; + } } -}; -struct PlayerTalentInfo -{ - PlayerTalentInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), GroupsCount(1) + ~PlayerTalentInfo() { for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i) { - memset(GroupInfo[i].Talents, 0, sizeof(uint32)*MAX_TALENT_TIERS); - memset(GroupInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32)); - GroupInfo[i].SpecID = 0; + for (PlayerTalentMap::const_iterator itr = GroupInfo[i].Talents->begin(); itr != GroupInfo[i].Talents->end(); ++itr) + delete itr->second; + delete GroupInfo[i].Talents; } } - TalentGroupInfo GroupInfo[MAX_TALENT_GROUPS]; + struct TalentGroupInfo + { + PlayerTalentMap* Talents; + uint32 Glyphs[MAX_GLYPH_SLOT_INDEX]; + uint32 TalentTree; + } GroupInfo[MAX_TALENT_GROUPS]; + + uint32 UsedTalentCount; uint32 ResetTalentsCost; time_t ResetTalentsTime; uint8 ActiveGroup; @@ -1314,7 +1320,7 @@ class Player : public Unit, public GridObject<Player> void ToggleDND(); bool isAFK() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); } bool isDND() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); } - uint8 GetChatTag() const; + uint8 GetChatFlags() const; std::string autoReplyMsg; uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin=NULL); @@ -1747,8 +1753,8 @@ class Player : public Unit, public GridObject<Player> Unit* GetSelectedUnit() const; Player* GetSelectedPlayer() const; - void SetTarget(ObjectGuid /*guid*/) override { } /// Used for serverside target changes, does not apply to players - void SetSelection(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_TARGET, guid); } + void SetTarget(ObjectGuid const& /*guid*/) override { } /// Used for serverside target changes, does not apply to players + void SetSelection(ObjectGuid const& guid) { SetGuidValue(UNIT_FIELD_TARGET, guid); } uint8 GetComboPoints() const { return m_comboPoints; } ObjectGuid GetComboTarget() const { return m_comboTarget; } @@ -1822,25 +1828,35 @@ class Player : public Unit, public GridObject<Player> std::string GetGuildName(); // Talents + uint32 GetUsedTalentCount() const { return _talentMgr->UsedTalentCount; } + void SetUsedTalentCount(uint32 talents) { _talentMgr->UsedTalentCount = talents; } uint32 GetTalentResetCost() const { return _talentMgr->ResetTalentsCost; } void SetTalentResetCost(uint32 cost) { _talentMgr->ResetTalentsCost = cost; } uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; } void SetTalentResetTime(time_t time_) { _talentMgr->ResetTalentsTime = time_; } - uint8 GetActiveTalentGroup() const { return _talentMgr->ActiveGroup; } - void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; } + uint8 GetTalentGroupsCount() const { return _talentMgr->GroupsCount; } void SetTalentGroupsCount(uint8 count) { _talentMgr->GroupsCount = count; } - uint32 GetTalentSpec(uint8 group) const { return _talentMgr->GroupInfo[group].SpecID; } - void SetTalentSpec(uint8 group, uint32 talentSpec) const { _talentMgr->GroupInfo[group].SpecID = talentSpec; } - uint32 GetActiveTalentSpec() const { return _talentMgr->GroupInfo[_talentMgr->ActiveGroup].SpecID; } + uint8 GetActiveTalentGroup() const { return _talentMgr->ActiveGroup; } + void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; } + + uint32 GetTalentSpec(uint8 group) const { return _talentMgr->GroupInfo[group].TalentTree; } + void SetTalentSpec(uint8 group, uint32 talentSpec) const { _talentMgr->GroupInfo[group].TalentTree = talentSpec; } + uint32 GetActiveTalentSpec() const { return _talentMgr->GroupInfo[_talentMgr->ActiveGroup].TalentTree; } + + + bool ResetTalents(bool noCost = false, bool resetTalents = true, bool resetSpecialization = true); + bool RemoveTalent(uint32 talentId); - bool ResetTalents(bool no_cost = false); uint32 GetNextResetTalentsCost() const; void InitTalentForLevel(); void SendTalentsInfoData(); bool LearnTalent(uint32 talentId); - bool AddTalent(uint32 talentId, uint8 spec); + bool AddTalent(uint32 talentId, uint8 spec, bool learning); bool HasTalent(uint32 talentId, uint8 spec); + uint32 CalculateTalentsPoints() const; + + void LearnTalentSpecialization(uint32 talentSpec); // Dual Spec @@ -1854,7 +1870,8 @@ class Player : public Unit, public GridObject<Player> void SetGlyph(uint8 slot, uint32 glyph); uint32 GetGlyph(uint8 group, uint8 slot) const { return _talentMgr->GroupInfo[group].Glyphs[slot]; } - TalentGroupInfo* GetTalentGroupInfo(uint8 group) { return &_talentMgr->GroupInfo[group]; } + PlayerTalentMap const* GetTalentMap(uint8 spec) const { return _talentMgr->GroupInfo[spec].Talents; } + PlayerTalentMap* GetTalentMap(uint8 spec) { return _talentMgr->GroupInfo[spec].Talents; } ActionButtonList const& GetActionButtons() const { return m_actionButtons; } uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS); } @@ -1968,6 +1985,7 @@ class Player : public Unit, public GridObject<Player> void SetGuildIdInvited(ObjectGuid::LowType GuildId) { m_GuildIdInvited = GuildId; } ObjectGuid::LowType GetGuildId() const { return GetUInt64Value(OBJECT_FIELD_DATA); /* return only lower part */ } Guild* GetGuild(); + Guild const* GetGuild() const; static ObjectGuid::LowType GetGuildIdFromDB(ObjectGuid guid); static uint8 GetRankFromDB(ObjectGuid guid); ObjectGuid::LowType GetGuildIdInvited() { return m_GuildIdInvited; } @@ -2089,10 +2107,10 @@ class Player : public Unit, public GridObject<Player> bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } void UpdateUnderwaterState(Map* m, float x, float y, float z) override; - void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet - void SendMessageToSetInRange(WorldPacket* data, float fist, bool self) override;// overwrite Object::SendMessageToSetInRange - void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only); - void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) override; + void SendMessageToSet(WorldPacket const* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet + void SendMessageToSetInRange(WorldPacket const* data, float fist, bool self) override;// overwrite Object::SendMessageToSetInRange + void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool own_team_only); + void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) override; Corpse* GetCorpse() const; void SpawnCorpseBones(); @@ -2240,12 +2258,12 @@ class Player : public Unit, public GridObject<Player> void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto); void SendEquipmentSetList(); - void SetEquipmentSet(uint32 index, EquipmentSet eqset); + void SetEquipmentSet(EquipmentSetInfo::EquipmentSetData&& newEqSet); void DeleteEquipmentSet(uint64 setGuid); void SendInitWorldStates(uint32 zone, uint32 area); void SendUpdateWorldState(uint32 variable, uint32 value, bool hidden = false); - void SendDirectMessage(WorldPacket const* data); + void SendDirectMessage(WorldPacket const* data) const; void SendBGWeekendWorldStates(); void SendBattlefieldWorldStates(); @@ -2379,6 +2397,7 @@ class Player : public Unit, public GridObject<Player> void SaveRecallPosition(); void SetHomebind(WorldLocation const& loc, uint32 areaId); + void SendBindPointUpdate(); // Homebind coordinates uint32 m_homebindMapId; @@ -2852,7 +2871,7 @@ class Player : public Unit, public GridObject<Player> DeclinedName *m_declinedname; Runes *m_runes; - EquipmentSets m_EquipmentSets; + EquipmentSetContainer _equipmentSets; bool CanAlwaysSee(WorldObject const* obj) const override; diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp index 54956e591b4..d6aeb5dee9c 100644 --- a/src/server/game/Entities/Totem/Totem.cpp +++ b/src/server/game/Entities/Totem/Totem.cpp @@ -145,9 +145,10 @@ bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) con /// @todo possibly all negative auras immune? if (GetEntry() == 5925) return false; - - switch (spellInfo->Effects[index].ApplyAuraName) + if (SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficulty(), index)) { + switch (effect->ApplyAuraName) + { case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_LEECH: case SPELL_AURA_MOD_FEAR: @@ -155,7 +156,10 @@ bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) con return true; default: break; + } } + else + return true; return Creature::IsImmunedToSpellEffect(spellInfo, index); } diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index ea15daed587..5761fac56e2 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -258,7 +258,7 @@ float Player::GetHealthBonusFromStamina() { // Taken from PaperDollFrame.lua - 4.3.4.15595 float ratio = 10.0f; - if (gtOCTHpPerStaminaEntry const* hpBase = sGtOCTHpPerStaminaStore.LookupEntry((getClass() - 1) * GT_MAX_LEVEL + getLevel() - 1)) + if (gtOCTHpPerStaminaEntry const* hpBase = sGtOCTHpPerStaminaStore.EvaluateTable(getLevel() - 1, 0)) ratio = hpBase->ratio; float stamina = GetStat(STAT_STAMINA); @@ -537,16 +537,16 @@ void Player::UpdateMastery() if (Aura* aura = GetAura(chrSpec->MasterySpellID[i])) { - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : aura->GetSpellEffectInfos()) { - if (!aura->HasEffect(j)) + if (!effect) continue; - float mult = aura->GetSpellInfo()->Effects[j].BonusCoefficient; + float mult = effect->BonusCoefficient; if (G3D::fuzzyEq(mult, 0.0f)) continue; - aura->GetEffect(j)->ChangeAmount(int32(value * aura->GetSpellInfo()->Effects[j].BonusCoefficient)); + aura->GetEffect(effect->EffectIndex)->ChangeAmount(int32(value * effect->BonusCoefficient)); } } } @@ -989,8 +989,9 @@ bool Guardian::UpdateStats(Stats stat) AuraEffect const* aurEff = owner->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DEATHKNIGHT, 3010, 0); if (aurEff) { - SpellInfo const* spellInfo = aurEff->GetSpellInfo(); // Then get the SpellProto and add the dummy effect value - AddPct(mod, spellInfo->Effects[EFFECT_1].CalcValue(owner)); // Ravenous Dead edits the original scale + SpellInfo const* spellInfo = aurEff->GetSpellInfo(); // Then get the SpellProto and add the dummy effect value + if (SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficulty(), EFFECT_1)) + AddPct(mod, effect->CalcValue(owner)); // Ravenous Dead edits the original scale } // Glyph of the Ghoul aurEff = owner->GetAuraEffect(58686, 0); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 89ded594990..be26299f6fd 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -62,6 +62,10 @@ #include "WorldPacket.h" #include "MovementStructures.h" #include "WorldSession.h" +#include "ChatPackets.h" +#include "MovementPackets.h" +#include "CombatPackets.h" +#include "CombatLogPackets.h" #include <cmath> @@ -935,23 +939,6 @@ void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castI CastSpell(targets, spellInfo, NULL, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster); } -// Obsolete func need remove, here only for comotability vs another patches -uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage) -{ - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); - if (!spellInfo) - return 0; - SpellNonMeleeDamage damageInfo(this, victim, spellInfo->Id, spellInfo->SchoolMask); - damage = SpellDamageBonusDone(victim, spellInfo, damage, SPELL_DIRECT_DAMAGE); - damage = victim->SpellDamageBonusTaken(this, spellInfo, damage, SPELL_DIRECT_DAMAGE); - - CalculateSpellDamageTaken(&damageInfo, damage, spellInfo); - DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - SendSpellNonMeleeDamageLog(&damageInfo); - DealSpellDamage(&damageInfo, true); - return damageInfo.damage; -} - void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit) { if (damage < 0) @@ -1383,8 +1370,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) if (Unit* caster = (*dmgShieldItr)->GetCaster()) { - damage = caster->SpellDamageBonusDone(this, i_spellProto, damage, SPELL_DIRECT_DAMAGE); - damage = this->SpellDamageBonusTaken(caster, i_spellProto, damage, SPELL_DIRECT_DAMAGE); + damage = caster->SpellDamageBonusDone(this, i_spellProto, damage, SPELL_DIRECT_DAMAGE, (*dmgShieldItr)->GetSpellEffectInfo()); + damage = this->SpellDamageBonusTaken(caster, i_spellProto, damage, SPELL_DIRECT_DAMAGE, (*dmgShieldItr)->GetSpellEffectInfo()); } // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that @@ -1409,10 +1396,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) void Unit::HandleEmoteCommand(uint32 anim_id) { - WorldPacket data(SMSG_EMOTE, 4 + 8); - data << uint32(anim_id); - data << GetGUID(); - SendMessageToSet(&data, true); + WorldPackets::Chat::Emote packet; + packet.Guid = GetGUID(); + packet.EmoteID = anim_id; + SendMessageToSet(packet.Write(), true); } bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo, uint8 effIndex) @@ -1427,10 +1414,10 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s return false; // bleeding effects are not reduced by armor - if (effIndex != MAX_SPELL_EFFECTS) + if (SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficulty(), effIndex)) { - if (spellInfo->Effects[effIndex].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE || - spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) + if (effect->ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE || + effect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE) if (spellInfo->GetEffectMechanicMask(effIndex) & (1<<MECHANIC_BLEED)) return false; } @@ -1696,7 +1683,7 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe int32 manaReduction = currentAbsorb; // lower absorb amount by talents - if (float manaMultiplier = absorbAurEff->GetSpellInfo()->Effects[absorbAurEff->GetEffIndex()].CalcValueMultiplier(absorbAurEff->GetCaster())) + if (float manaMultiplier = absorbAurEff->GetSpellEffectInfo()->CalcValueMultiplier(absorbAurEff->GetCaster())) manaReduction = int32(float(manaReduction) * manaMultiplier); int32 manaTaken = -victim->ModifyPower(POWER_MANA, -manaReduction); @@ -2108,24 +2095,24 @@ float Unit::CalculateLevelPenalty(SpellInfo const* spellProto) const void Unit::SendMeleeAttackStart(Unit* victim) { - WorldPacket data(SMSG_ATTACKSTART, 8 + 8); - data << GetGUID(); - data << victim->GetGUID(); - SendMessageToSet(&data, true); + WorldPackets::Combat::AttackStart packet; + packet.Attacker = GetGUID(); + packet.Victim = victim->GetGUID(); + SendMessageToSet(packet.Write(), true); TC_LOG_DEBUG("entities.unit", "WORLD: Sent SMSG_ATTACKSTART"); } void Unit::SendMeleeAttackStop(Unit* victim) { - WorldPacket data(SMSG_ATTACKSTOP, (8+8+4)); - data << GetPackGUID(); + WorldPackets::Combat::SAttackStop packet; + packet.Attacker = GetGUID(); if (victim) - data << victim->GetPackGUID(); - else - data << uint8(0); + { + packet.Victim = victim->GetGUID(); + packet.Dead = victim->isDead(); + } - data << uint32(0); //! Can also take the value 0x01, which seems related to updating rotation - SendMessageToSet(&data, true); + SendMessageToSet(packet.Write(), true); TC_LOG_DEBUG("entities.unit", "WORLD: Sent SMSG_ATTACKSTOP"); if (victim) @@ -2166,12 +2153,12 @@ int32 Unit::GetMechanicResistChance(SpellInfo const* spellInfo) const return 0; int32 resistMech = 0; - for (uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - if (!spellInfo->Effects[eff].IsEffect()) + if (!effect || !effect->IsEffect()) break; - int32 effectMech = spellInfo->GetEffectMechanic(eff); + int32 effectMech = spellInfo->GetEffectMechanic(effect->EffectIndex, GetMap()->GetDifficulty()); if (effectMech) { int32 temp = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effectMech); @@ -2226,7 +2213,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo // Get effects mechanic and chance for (uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff) { - int32 effect_mech = spellInfo->GetEffectMechanic(eff); + int32 effect_mech = spellInfo->GetEffectMechanic(eff, GetMap()->GetDifficulty()); if (effect_mech) { int32 temp = victim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); @@ -2990,7 +2977,7 @@ void Unit::DeMorph() SetDisplayId(GetNativeDisplayId()); } -Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= 0*/) +Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint32 effMask, Unit* caster, int32 *baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= 0*/) { ASSERT(!casterGUID.IsEmpty() || caster); @@ -3016,18 +3003,22 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 return NULL; // update basepoints with new values - effect amount will be recalculated in ModStackAmount - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : foundAura->GetSpellEffectInfos()) { - if (!foundAura->HasEffect(i)) + if (!effect) + continue; + + AuraEffect const* eff = foundAura->GetEffect(effect->EffectIndex); + if (!eff) continue; int bp; if (baseAmount) - bp = *(baseAmount + i); + bp = *(baseAmount + effect->EffectIndex); else - bp = foundAura->GetSpellInfo()->Effects[i].BasePoints; + bp = effect->BasePoints; - int32* oldBP = const_cast<int32*>(&(foundAura->GetEffect(i)->m_baseAmount)); + int32* oldBP = const_cast<int32*>(&(foundAura->GetEffect(effect->EffectIndex)->m_baseAmount)); // todo 6.x review GetBaseAmount and GetCastItemGUID in this case *oldBP = bp; } @@ -3087,7 +3078,7 @@ void Unit::_AddAura(UnitAura* aura, Unit* caster) // creates aura application instance and registers it in lists // aura application effects are handled separately to prevent aura list corruption -AuraApplication * Unit::_CreateAuraApplication(Aura* aura, uint8 effMask) +AuraApplication * Unit::_CreateAuraApplication(Aura* aura, uint32 effMask) { // can't apply aura on unit which is going to be deleted - to not create a memory leak ASSERT(!m_cleanupDone); @@ -3116,7 +3107,7 @@ AuraApplication * Unit::_CreateAuraApplication(Aura* aura, uint8 effMask) AddInterruptMask(aurSpellInfo->AuraInterruptFlags); } - if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState()) + if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState(GetMap()->GetDifficulty())) m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp)); aura->_ApplyForTarget(this, caster, aurApp); @@ -3137,7 +3128,7 @@ void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex) // handles effects of aura application // should be done after registering aura in lists -void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) +void Unit::_ApplyAura(AuraApplication * aurApp, uint32 effMask) { Aura* aura = aurApp->GetBase(); @@ -3147,7 +3138,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) return; // Update target aura state flag - if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState()) + if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState(GetMap()->GetDifficulty())) ModifyAuraState(aState, true); if (aurApp->GetRemoveMode()) @@ -3202,7 +3193,7 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMo } bool auraStateFound = false; - AuraStateType auraState = aura->GetSpellInfo()->GetAuraState(); + AuraStateType auraState = aura->GetSpellInfo()->GetAuraState(GetMap()->GetDifficulty()); if (auraState) { bool canBreak = false; @@ -3278,12 +3269,12 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) SpellInfo const* spellProto = aura->GetSpellInfo(); // passive spell special case (only non stackable with ranks) - if (spellProto->IsPassiveStackableWithRanks()) + if (spellProto->IsPassiveStackableWithRanks(GetMap()->GetDifficulty())) return; if (!IsHighestExclusiveAura(aura)) { - if (!aura->GetSpellInfo()->IsAffectingArea()) + if (!aura->GetSpellInfo()->IsAffectingArea(GetMap()->GetDifficulty())) { Unit* caster = aura->GetCaster(); if (caster && caster->GetTypeId() == TYPEID_PLAYER) @@ -3343,7 +3334,7 @@ void Unit::RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode) i = m_ownedAuras.begin(); } -void Unit::RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode) +void Unit::RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode) { for (AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);) if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID)) @@ -3377,7 +3368,7 @@ void Unit::RemoveOwnedAura(Aura* aura, AuraRemoveMode removeMode) ASSERT(false); } -Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, Aura* except) const +Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, Aura* except) const { AuraMapBounds range = m_ownedAuras.equal_range(spellId); for (AuraMap::const_iterator itr = range.first; itr != range.second; ++itr) @@ -3406,7 +3397,7 @@ void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode) aura->Remove(mode); } -void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint8 reqEffMask, AuraRemoveMode removeMode) +void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint32 reqEffMask, AuraRemoveMode removeMode) { AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId); for (AuraApplicationMap::iterator iter = range.first; iter != range.second;) @@ -3466,7 +3457,7 @@ void Unit::RemoveAura(Aura* aura, AuraRemoveMode mode) RemoveAura(aurApp, mode); } -void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode) +void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode) { for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);) { @@ -3875,7 +3866,7 @@ void Unit::RemoveAllAurasExceptType(AuraType type) for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();) { Aura const* aura = iter->second->GetBase(); - if (aura->GetSpellInfo()->HasAura(type)) + if (aura->GetSpellInfo()->HasAura(GetMap()->GetDifficulty(), type)) ++iter; else _UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT); @@ -3884,7 +3875,7 @@ void Unit::RemoveAllAurasExceptType(AuraType type) for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();) { Aura* aura = iter->second; - if (aura->GetSpellInfo()->HasAura(type)) + if (aura->GetSpellInfo()->HasAura(GetMap()->GetDifficulty(), type)) ++iter; else RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT); @@ -3896,7 +3887,7 @@ void Unit::RemoveAllAurasExceptType(AuraType type1, AuraType type2) for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();) { Aura const* aura = iter->second->GetBase(); - if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2)) + if (aura->GetSpellInfo()->HasAura(GetMap()->GetDifficulty(), type1) || aura->GetSpellInfo()->HasAura(GetMap()->GetDifficulty(), type2)) ++iter; else _UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT); @@ -3905,7 +3896,7 @@ void Unit::RemoveAllAurasExceptType(AuraType type1, AuraType type2) for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();) { Aura* aura = iter->second; - if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2)) + if (aura->GetSpellInfo()->HasAura(GetMap()->GetDifficulty(), type1) || aura->GetSpellInfo()->HasAura(GetMap()->GetDifficulty(), type2)) ++iter; else RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT); @@ -4005,7 +3996,7 @@ AuraEffect* Unit::GetDummyAuraEffect(SpellFamilyNames name, uint32 iconId, uint8 return GetAuraEffect(SPELL_AURA_DUMMY, name, iconId, effIndex); } -AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, AuraApplication * except) const +AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication * except) const { AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId); for (; range.first != range.second; ++range.first) @@ -4024,13 +4015,13 @@ AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID return NULL; } -Aura* Unit::GetAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const +Aura* Unit::GetAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const { AuraApplication * aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask); return aurApp ? aurApp->GetBase() : NULL; } -AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, AuraApplication* except) const +AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication* except) const { uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId); while (rankSpell) @@ -4042,7 +4033,7 @@ AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGu return NULL; } -Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const +Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const { AuraApplication * aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask); return aurApp ? aurApp->GetBase() : NULL; @@ -4117,7 +4108,7 @@ uint32 Unit::GetAuraCount(uint32 spellId) const return count; } -bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const +bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const { if (GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask)) return true; @@ -4196,9 +4187,9 @@ bool Unit::HasAuraWithMechanic(uint32 mechanicMask) const if (spellInfo->Mechanic && (mechanicMask & (1 << spellInfo->Mechanic))) return true; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (iter->second->HasEffect(i) && spellInfo->Effects[i].Effect && spellInfo->Effects[i].Mechanic) - if (mechanicMask & (1 << spellInfo->Effects[i].Mechanic)) + for (SpellEffectInfo const* effect : iter->second->GetBase()->GetSpellEffectInfos()) + if (effect && effect->Effect && effect->Mechanic) + if (mechanicMask & (1 << effect->Mechanic)) return true; } @@ -4721,22 +4712,20 @@ void Unit::RemoveAllGameObjects() void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log) { - WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+4+1+4+4+1+1+4+4+1)); // we guess size - data << log->target->GetPackGUID(); - data << log->attacker->GetPackGUID(); - data << uint32(log->SpellID); - data << uint32(log->damage); // damage amount + WorldPackets::CombatLog::SpellNonMeleeDamageLog packet; + packet.Me = log->target->GetGUID(); + packet.CasterGUID = log->attacker->GetGUID(); + packet.SpellID = log->SpellID; + packet.Damage = log->damage; int32 overkill = log->damage - log->target->GetHealth(); - data << uint32(overkill > 0 ? overkill : 0); // overkill - data << uint8 (log->schoolMask); // damage school - data << uint32(log->absorb); // AbsorbedDamage - data << uint32(log->resist); // resist - data << uint8 (log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name - data << uint8 (log->unused); // unused - data << uint32(log->blocked); // blocked - data << uint32(log->HitInfo); - data << uint8 (0); // flag to use extend data - SendMessageToSet(&data, true); + packet.Overkill = (overkill > 0 ? overkill : 0); + packet.SchoolMask = log->schoolMask; + packet.ShieldBlock = log->blocked; + packet.Resisted = log->resist; + packet.Absorbed = log->absorb; + packet.Periodic = false; + packet.Flags = log->HitInfo; + SendMessageToSet(packet.Write(), true); } void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit) @@ -4848,67 +4837,26 @@ void Unit::SendAttackStateUpdate(CalcDamageInfo* damageInfo) { TC_LOG_DEBUG("entities.unit", "WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); - uint32 count = 1; - size_t maxsize = 4+5+5+4+4+1+4+4+4+4+4+1+4+4+4+4+4*12; - WorldPacket data(SMSG_ATTACKERSTATEUPDATE, maxsize); // we guess size - data << uint32(damageInfo->HitInfo); - data << damageInfo->attacker->GetPackGUID(); - data << damageInfo->target->GetPackGUID(); - data << uint32(damageInfo->damage); // Full damage + WorldPackets::Combat::AttackerStateUpdate packet; + packet.HitInfo = damageInfo->HitInfo; + packet.AttackerGUID = damageInfo->attacker->GetGUID(); + packet.VictimGUID = damageInfo->target->GetGUID(); + packet.Damage = damageInfo->damage; int32 overkill = damageInfo->damage - damageInfo->target->GetHealth(); - data << uint32(overkill < 0 ? 0 : overkill); // Overkill - data << uint8(count); // Sub damage count + packet.OverDamage = (overkill < 0 ? -1 : overkill); - for (uint32 i = 0; i < count; ++i) - { - data << uint32(damageInfo->damageSchoolMask); // School of sub damage - data << float(damageInfo->damage); // sub damage - data << uint32(damageInfo->damage); // Sub Damage - } + WorldPackets::Combat::SubDamage& subDmg = packet.SubDmg.Value; + subDmg.SchoolMask = damageInfo->damageSchoolMask; // School of sub damage + subDmg.FDamage = damageInfo->damage; // sub damage + subDmg.Damage = damageInfo->damage; // Sub Damage + subDmg.Absorbed = damageInfo->absorb; + subDmg.Resisted = damageInfo->resist; + packet.SubDmg.HasValue = true; - if (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_PARTIAL_ABSORB)) - { - for (uint32 i = 0; i < count; ++i) - data << uint32(damageInfo->absorb); // Absorb - } + packet.VictimState = damageInfo->TargetState; + packet.BlockAmount = damageInfo->blocked_amount; - if (damageInfo->HitInfo & (HITINFO_FULL_RESIST | HITINFO_PARTIAL_RESIST)) - { - for (uint32 i = 0; i < count; ++i) - data << uint32(damageInfo->resist); // Resist - } - - data << uint8(damageInfo->TargetState); - data << uint32(0); // Unknown attackerstate - data << uint32(0); // Melee spellid - - if (damageInfo->HitInfo & HITINFO_BLOCK) - data << uint32(damageInfo->blocked_amount); - - if (damageInfo->HitInfo & HITINFO_RAGE_GAIN) - data << uint32(0); - - //! Probably used for debugging purposes, as it is not known to appear on retail servers - if (damageInfo->HitInfo & HITINFO_UNK1) - { - data << uint32(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - for (uint8 i = 0; i < 2; ++i) - { - data << float(0); - data << float(0); - } - data << uint32(0); - } - - SendMessageToSet(&data, true); + SendMessageToSet(packet.Write(), true); } void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount) @@ -4926,133 +4874,6 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType SendAttackStateUpdate(&dmgInfo); } -bool Unit::HandleAuraProcOnPowerAmount(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 /*procEx*/, uint32 cooldown) -{ - // Get triggered aura spell info - SpellInfo const* auraSpellInfo = triggeredByAura->GetSpellInfo(); - - // Get effect index used for the proc - uint32 effIndex = triggeredByAura->GetEffIndex(); - - // Power amount required to proc the spell - int32 powerAmountRequired = triggeredByAura->GetAmount(); - // Power type required to proc - Powers powerRequired = Powers(auraSpellInfo->Effects[triggeredByAura->GetEffIndex()].MiscValue); - - // Set trigger spell id, target, custom basepoints - uint32 trigger_spell_id = auraSpellInfo->Effects[triggeredByAura->GetEffIndex()].TriggerSpell; - - Unit* target = NULL; - int32 basepoints0 = 0; - - Item* castItem = !triggeredByAura->GetBase()->GetCastItemGUID().IsEmpty() && GetTypeId() == TYPEID_PLAYER - ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL; - - /* Try handle unknown trigger spells or with invalid power amount or misc value - if (sSpellMgr->GetSpellInfo(trigger_spell_id) == NULL || powerAmountRequired == NULL || powerRequired >= MAX_POWER) - { - switch (auraSpellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - break; - } - } - }*/ - - // All ok. Check current trigger spell - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(trigger_spell_id); - if (triggerEntry == NULL) - { - // Not cast unknown spell - // TC_LOG_ERROR("Unit::HandleAuraProcOnPowerAmount: Spell %u have 0 in EffectTriggered[%d], not handled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex()); - return false; - } - - // not allow proc extra attack spell at extra attack - if (m_extraAttacks && triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - return false; - - if (!powerRequired || !powerAmountRequired) - { - TC_LOG_ERROR("spells", "Unit::HandleAuraProcOnPowerAmount: Spell %u have 0 powerAmountRequired in EffectAmount[%d] or 0 powerRequired in EffectMiscValue, not handled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex()); - return false; - } - - if (GetPower(powerRequired) != powerAmountRequired) - return false; - - // Custom requirements (not listed in procEx) Warning! damage dealing after this - // Custom triggered spells - switch (auraSpellInfo->SpellFamilyName) - { - case SPELLFAMILY_DRUID: - { - // Eclipse Mastery Driver Passive - if (auraSpellInfo->Id == 79577) - { - uint32 solarEclipseMarker = 67483; - uint32 lunarEclipseMarker = 67484; - - switch (effIndex) - { - case 0: - { - if (HasAura(trigger_spell_id)) - return false; - - // Do not proc if proc spell isnt starfire and starsurge - if (procSpell->Id != 2912 && procSpell->Id != 78674) - return false; - - if (HasAura(solarEclipseMarker)) - { - RemoveAurasDueToSpell(solarEclipseMarker); - CastSpell(this, lunarEclipseMarker, true); - } - break; - } - case 1: - { - if (HasAura(trigger_spell_id)) - return false; - - // Do not proc if proc spell isnt wrath and starsurge - if (procSpell->Id != 5176 && procSpell->Id != 78674) - return false; - - if (HasAura(lunarEclipseMarker)) - { - RemoveAurasDueToSpell(lunarEclipseMarker); - CastSpell(this, solarEclipseMarker, true); - } - - break; - } - } - } - break; - } - } - - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id)) - return false; - - // try detect target manually if not set - if (target == NULL) - target = !(procFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)) && triggerEntry && triggerEntry->IsPositive() ? this : victim; - - if (basepoints0) - CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - else - CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura); - - if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown); - - return true; -} - //victim may be NULL bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown) { @@ -5616,18 +5437,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 28810; break; } - // Priest T10 Healer 2P Bonus - case 70770: - // Flash Heal - if (procSpell->SpellFamilyFlags[0] & 0x800) - { - triggered_spell_id = 70772; - SpellInfo const* blessHealing = sSpellMgr->GetSpellInfo(triggered_spell_id); - if (!blessHealing) - return false; - basepoints0 = int32(CalculatePct(damage, triggerAmount) / (blessHealing->GetMaxDuration() / blessHealing->Effects[0].ApplyAuraPeriod)); - } - break; + break; } break; } @@ -5745,7 +5555,10 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere SpellInfo const* triggeredSpell = sSpellMgr->GetSpellInfo(triggered_spell_id); if (!triggeredSpell) return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / triggeredSpell->Effects[0].ApplyAuraPeriod); + SpellEffectInfo const* effect = triggeredSpell->GetEffect(DIFFICULTY_NONE, EFFECT_0); + if (!effect) + return false; + basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / effect->ApplyAuraPeriod); // Add remaining ticks to damage done basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE); } @@ -6129,7 +5942,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere SpellInfo const* triggeredSpell = sSpellMgr->GetSpellInfo(triggered_spell_id); if (!triggeredSpell) return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / triggeredSpell->Effects[0].ApplyAuraPeriod); + if (SpellEffectInfo const* effect = triggeredSpell->GetEffect(DIFFICULTY_NONE, EFFECT_0)) + basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / effect->ApplyAuraPeriod); } break; } @@ -6143,9 +5957,12 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere SpellInfo const* triggeredSpell = sSpellMgr->GetSpellInfo(triggered_spell_id); if (!triggeredSpell) return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / triggeredSpell->Effects[0].ApplyAuraPeriod); - // Add remaining ticks to healing done - basepoints0 += GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_HEAL); + if (SpellEffectInfo const* effect = triggeredSpell->GetEffect(DIFFICULTY_NONE, EFFECT_0)) + { + basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / effect->ApplyAuraPeriod); + // Add remaining ticks to healing done + basepoints0 += GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_HEAL); + } } break; } @@ -6187,53 +6004,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 63685; break; } - // Flametongue Weapon (Passive) - if (dummySpell->SpellFamilyFlags[0] & 0x200000) - { - if (GetTypeId() != TYPEID_PLAYER || !victim || !victim->IsAlive() || !castItem || !castItem->IsEquipped()) - return false; - - WeaponAttackType attType = WeaponAttackType(Player::GetAttackBySlot(castItem->GetSlot())); - if ((attType != BASE_ATTACK && attType != OFF_ATTACK) - || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) - || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)) - return false; - - float fire_onhit = float(CalculatePct(dummySpell->Effects[EFFECT_0]. CalcValue(), 1.0f)); - - float add_spellpower = (float)(SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) - + victim->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE)); - - // 1.3speed = 5%, 2.6speed = 10%, 4.0 speed = 15%, so, 1.0speed = 3.84% - ApplyPct(add_spellpower, 3.84f); - - // Enchant on Off-Hand and ready? - if (castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) - { - float BaseWeaponSpeed = GetAttackTime(OFF_ATTACK) / 1000.0f; - - // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed - basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed)); - triggered_spell_id = 10444; - } - - // Enchant on Main-Hand and ready? - else if (castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) - { - float BaseWeaponSpeed = GetAttackTime(BASE_ATTACK) / 1000.0f; - - // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed - basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed)); - triggered_spell_id = 10444; - } - - // If not ready, we should return, shouldn't we?! - else - return false; - - CastCustomSpell(victim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - return true; - } // Static Shock if (dummySpell->SpellIconID == 3059) { @@ -6255,15 +6025,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } case SPELLFAMILY_DEATHKNIGHT: { - // Blood-Caked Blade - if (dummySpell->SpellIconID == 138) - { - if (!target || !target->IsAlive()) - return false; - - triggered_spell_id = dummySpell->Effects[effIndex].TriggerSpell; - break; - } // Dancing Rune Weapon if (dummySpell->Id == 49028) { @@ -6289,24 +6050,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere else return false; } - // Unholy Blight - if (dummySpell->Id == 49194) - { - triggered_spell_id = 50536; - SpellInfo const* unholyBlight = sSpellMgr->GetSpellInfo(triggered_spell_id); - if (!unholyBlight) - return false; - - basepoints0 = CalculatePct(int32(damage), triggerAmount); - - //Glyph of Unholy Blight - if (AuraEffect* glyph=GetAuraEffect(63332, 0)) - AddPct(basepoints0, glyph->GetAmount()); - - basepoints0 = basepoints0 / (unholyBlight->GetMaxDuration() / unholyBlight->Effects[0].ApplyAuraPeriod); - basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE); - break; - } // Threat of Thassarian if (dummySpell->SpellIconID == 2023) { @@ -6347,26 +6090,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } case SPELLFAMILY_PET: { - switch (dummySpell->SpellIconID) - { - // Guard Dog - case 201: - { - if (!victim) - return false; - - triggered_spell_id = 54445; - target = this; - float addThreat = float(CalculatePct(procSpell->Effects[0].CalcValue(this), triggerAmount)); - victim->AddThreat(this, addThreat); - break; - } - // Silverback - case 1582: - triggered_spell_id = dummySpell->Id == 62765 ? 62801 : 62800; - target = this; - break; - } break; } default: @@ -6375,7 +6098,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // if not handled by custom case, get triggered spell from dummySpell proto if (!triggered_spell_id) - triggered_spell_id = dummySpell->Effects[triggeredByAura->GetEffIndex()].TriggerSpell; + triggered_spell_id = triggeredByAura->GetSpellEffectInfo()->TriggerSpell; // processed charge only counting case if (!triggered_spell_id) @@ -6405,10 +6128,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return true; } - /* - */ - - // Used in case when access to whole aura is needed // All procs should be handled like this... bool Unit::HandleAuraProc(Unit* victim, uint32 /*damage*/, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown, bool * handled) @@ -6459,9 +6178,12 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 /*damage*/, Aura* triggeredByAura // Swift Hand of Justice case 59906: { - int32 bp0 = CalculatePct(GetMaxHealth(), dummySpell->Effects[EFFECT_0]. CalcValue()); - CastCustomSpell(this, 59913, &bp0, NULL, NULL, true); - *handled = true; + if (SpellEffectInfo const* effect = triggeredByAura->GetSpellEffectInfo(EFFECT_0)) + { + int32 bp0 = CalculatePct(GetMaxHealth(), effect->CalcValue()); + CastCustomSpell(this, 59913, &bp0, NULL, NULL, true); + *handled = true; + } break; } } @@ -6476,49 +6198,10 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 /*damage*/, Aura* triggeredByAura CastSpell(victim, 68055, true); return true; } - // Glyph of Divinity - else if (dummySpell->Id == 54939) - { - if (!procSpell) - return false; - *handled = true; - // Check if we are the target and prevent mana gain - if (victim && triggeredByAura->GetCasterGUID() == victim->GetGUID()) - return false; - // Lookup base amount mana restore - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) - { - if (procSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE) - { - // value multiplied by 2 because you should get twice amount - int32 mana = procSpell->Effects[i].CalcValue() * 2; - CastCustomSpell(this, 54986, 0, &mana, NULL, true); - } - } - return true; - } break; } case SPELLFAMILY_MAGE: { - switch (dummySpell->Id) - { - // Empowered Fire - case 31656: - case 31657: - case 31658: - { - *handled = true; - - SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(67545); - if (!spInfo) - return false; - - int32 bp0 = int32(CalculatePct(GetCreateMana(), spInfo->Effects[0].CalcValue())); - CastCustomSpell(this, 67545, &bp0, NULL, NULL, true, NULL, triggeredByAura->GetEffect(EFFECT_0), GetGUID()); - return true; - } - } break; } case SPELLFAMILY_DEATHKNIGHT: @@ -6603,8 +6286,11 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 /*damage*/, Aura* triggeredByAura // Item - Warrior T10 Protection 4P Bonus case 70844: { - int32 basepoints0 = CalculatePct(GetMaxHealth(), dummySpell->Effects[EFFECT_1]. CalcValue()); - CastCustomSpell(this, 70845, &basepoints0, NULL, NULL, true); + if (SpellEffectInfo const* effect = triggeredByAura->GetSpellEffectInfo(EFFECT_1)) + { + int32 basepoints0 = CalculatePct(GetMaxHealth(), effect->CalcValue()); + CastCustomSpell(this, 70845, &basepoints0, NULL, NULL, true); + } break; } // Recklessness @@ -6635,7 +6321,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg int32 triggerAmount = triggeredByAura->GetAmount(); // Set trigger spell id, target, custom basepoints - uint32 trigger_spell_id = auraSpellInfo->Effects[triggeredByAura->GetEffIndex()].TriggerSpell; + uint32 trigger_spell_id = triggeredByAura->GetSpellEffectInfo()->TriggerSpell; Unit* target = NULL; int32 basepoints0 = 0; @@ -6655,11 +6341,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg case SPELLFAMILY_GENERIC: switch (auraSpellInfo->Id) { - case 43820: // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket) - // Pct value stored in dummy - basepoints0 = victim->GetCreateHealth() * auraSpellInfo->Effects[1].CalcValue() / 100; - target = victim; - break; case 57345: // Darkmoon Card: Greatness { float stat = 0.0f; @@ -6760,19 +6441,9 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg } case SPELLFAMILY_HUNTER: { - if (auraSpellInfo->SpellIconID == 3247) // Piercing Shots + /*if (auraSpellInfo->SpellIconID == 3247) // Piercing Shots { - switch (auraSpellInfo->Id) - { - case 53234: // Rank 1 - case 53237: // Rank 2 - case 53238: // Rank 3 - trigger_spell_id = 63468; - break; - default: - TC_LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell %u miss posibly Piercing Shots", auraSpellInfo->Id); - return false; - } + trigger_spell_id = 63468; // 6.x missing from dbc but it is in the tooltip SpellInfo const* TriggerPS = sSpellMgr->GetSpellInfo(trigger_spell_id); if (!TriggerPS) return false; @@ -6780,7 +6451,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg basepoints0 = CalculatePct(int32(damage), triggerAmount) / (TriggerPS->GetMaxDuration() / TriggerPS->Effects[0].ApplyAuraPeriod); basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), trigger_spell_id, SPELL_AURA_PERIODIC_DAMAGE); break; - } + }*/ // Item - Hunter T9 4P Bonus if (auraSpellInfo->Id == 67151) { @@ -6903,7 +6574,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg } // not allow proc extra attack spell at extra attack - if (m_extraAttacks && triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + if (m_extraAttacks && triggerEntry->HasEffect(GetMap()->GetDifficulty(), SPELL_EFFECT_ADD_EXTRA_ATTACKS)) return false; // Custom requirements (not listed in procEx) Warning! damage dealing after this @@ -6983,10 +6654,9 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg break; } // Decimation - case 63156: - case 63158: + case 108869: // Can proc only if target has hp below 25% - if (!victim || !victim->HealthBelowPct(auraSpellInfo->Effects[EFFECT_1].CalcValue())) + if (!victim || !victim->HealthBelowPct(triggeredByAura->GetSpellEffectInfo()->CalcValue())) return false; break; // Deathbringer Saurfang - Blood Beast's Blood Link @@ -7120,7 +6790,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg return false; // extra attack should hit same target - if (triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + if (triggerEntry->HasEffect(GetMap()->GetDifficulty(), SPELL_EFFECT_ADD_EXTRA_ATTACKS)) target = victim; // try detect target manually if not set @@ -7204,7 +6874,7 @@ void Unit::setPowerType(Powers new_powertype) if (getPowerType() == new_powertype) return; - SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype); + SetUInt32Value(UNIT_FIELD_DISPLAY_POWER, new_powertype); if (GetTypeId() == TYPEID_PLAYER) { @@ -7961,14 +7631,14 @@ void Unit::SetMinion(Minion *minion, bool apply) else if (minion->IsTotem()) { // All summoned by totem minions must disappear when it is removed. - if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell())) - for (int i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (spInfo->Effects[i].Effect != SPELL_EFFECT_SUMMON) - continue; + if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell())) + for (SpellEffectInfo const* effect : spInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + { + if (!effect || effect->Effect != SPELL_EFFECT_SUMMON) + continue; - RemoveAllMinionsByEntry(spInfo->Effects[i].MiscValue); - } + RemoveAllMinionsByEntry(effect->MiscValue); + } } if (GetTypeId() == TYPEID_PLAYER) @@ -8419,7 +8089,7 @@ void Unit::EnergizeBySpell(Unit* victim, uint32 spellId, int32 damage, Powers po victim->getHostileRefManager().threatAssist(this, float(damage) * 0.5f, spellInfo); } -uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) const +uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const* effect, uint32 stack) const { if (!spellProto || !victim || damagetype == DIRECT_DAMAGE) return pdamage; @@ -8431,7 +8101,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin // For totems get damage bonus from owner if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTotem()) if (Unit* owner = GetOwner()) - return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype); + return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, effect, stack); float ApCoeffMod = 1.0f; int32 DoneTotal = 0; @@ -8462,32 +8132,11 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin } // Custom scripted damage - switch (spellProto->SpellFamilyName) + /*switch (spellProto->SpellFamilyName) { case SPELLFAMILY_DEATHKNIGHT: - // Impurity (dummy effect) - if (GetTypeId() == TYPEID_PLAYER) - { - PlayerSpellMap playerSpells = ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = playerSpells.begin(); itr != playerSpells.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) - continue; - switch (itr->first) - { - case 49220: - case 49633: - case 49635: - case 49636: - case 49638: - if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first)) - AddPct(ApCoeffMod, proto->Effects[0].CalcValue()); - break; - } - } - } break; - } + }*/ // Done fixed damage bonus auras int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask()); @@ -8497,39 +8146,18 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage(); // Check for table values - float coeff = 0; - SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); - if (bonus) + float coeff = effect->BonusCoefficient; + if (effect->BonusCoefficientFromAP > 0) { - if (damagetype == DOT) - { - coeff = bonus->dot_damage; - if (bonus->ap_dot_bonus > 0) - { - WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; - float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); - APbonus += GetTotalAttackPowerValue(attType); - DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus); - } - } - else - { - coeff = bonus->direct_damage; - if (bonus->ap_bonus > 0) - { - WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; - float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); - APbonus += GetTotalAttackPowerValue(attType); - DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus); - } - } + WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; + float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); + APbonus += GetTotalAttackPowerValue(attType); + DoneTotal += int32(effect->BonusCoefficientFromAP * stack * ApCoeffMod * APbonus); } + // Default calculation if (DoneAdvertisedBenefit) { - if (!bonus || coeff < 0) - coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack); - float factorMod = CalculateLevelPenalty(spellProto) * stack; if (Player* modOwner = GetSpellModOwner()) @@ -8627,6 +8255,7 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage // Health at 25% or less (25% stored at effect 2 of the spell) if (victim->HealthBelowPct(CalculateSpellDamage(this, (*i)->GetSpellInfo(), EFFECT_2))) AddPct(DoneTotalMod, (*i)->GetAmount()); + break; } case 6916: // Death's Embrace heal effect case 6925: @@ -8741,7 +8370,7 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage return DoneTotalMod; } -uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) const +uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const* effect, uint32 stack) const { if (!spellProto || damagetype == DIRECT_DAMAGE) return pdamage; @@ -8792,17 +8421,11 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui int32 TakenAdvertisedBenefit = SpellBaseDamageBonusTaken(spellProto->GetSchoolMask()); // Check for table values - float coeff = 0; - SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); - if (bonus) - coeff = (damagetype == DOT) ? bonus->dot_damage : bonus->direct_damage; + float coeff = effect->BonusCoefficient; // Default calculation if (TakenAdvertisedBenefit) { - if (!bonus || coeff < 0) - coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack); - float factorMod = CalculateLevelPenalty(spellProto) * stack; // level penalty still applied on Taken bonus - is it blizzlike? if (Player* modOwner = GetSpellModOwner()) @@ -9130,12 +8753,12 @@ uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* /*spellProto*/, uint32 d return damage; } -uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) const +uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const* effect, uint32 stack) const { // For totems get healing bonus from owner (statue isn't totem in fact) if (GetTypeId() == TYPEID_UNIT && IsTotem()) if (Unit* owner = GetOwner()) - return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, stack); + return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, effect, stack); // No bonus healing for potion spells if (spellProto->SpellFamilyName == SPELLFAMILY_POTION) @@ -9191,27 +8814,14 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask()); // Check for table values - SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); - float coeff = 0; + float coeff = effect->BonusCoefficient; float factorMod = 1.0f; - if (bonus) + if (effect->BonusCoefficientFromAP > 0.0f) { - if (damagetype == DOT) - { - coeff = bonus->dot_damage; - if (bonus->ap_dot_bonus > 0) - DoneTotal += int32(bonus->ap_dot_bonus * stack * GetTotalAttackPowerValue( - (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK)); - } - else - { - coeff = bonus->direct_damage; - if (bonus->ap_bonus > 0) - DoneTotal += int32(bonus->ap_bonus * stack * GetTotalAttackPowerValue( - (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK)); - } + DoneTotal += int32(effect->BonusCoefficientFromAP * stack * GetTotalAttackPowerValue( + (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK)); } - else + else if (coeff <= 0.0f) { // No bonus healing for SPELL_DAMAGE_CLASS_NONE class spells by default if (spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE) @@ -9221,9 +8831,6 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui // Default calculation if (DoneAdvertisedBenefit) { - if (!bonus || coeff < 0) - coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack) * 1.88f; // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells) - factorMod *= CalculateLevelPenalty(spellProto) * stack; if (Player* modOwner = GetSpellModOwner()) @@ -9236,9 +8843,11 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); } - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - switch (spellProto->Effects[i].ApplyAuraName) + if (!effect) + continue; + switch (effect->ApplyAuraName) { // Bonus healing does not apply to these spells case SPELL_AURA_PERIODIC_LEECH: @@ -9246,7 +8855,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui DoneTotal = 0; break; } - if (spellProto->Effects[i].Effect == SPELL_EFFECT_HEALTH_LEECH) + if (effect->Effect == SPELL_EFFECT_HEALTH_LEECH) DoneTotal = 0; } @@ -9331,7 +8940,7 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const return DoneTotalMod; } -uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) const +uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType /*damagetype*/, SpellEffectInfo const* effect, uint32 stack) const { float TakenTotalMod = 1.0f; @@ -9364,12 +8973,9 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u } // Check for table values - SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); - float coeff = 0; + float coeff = effect->BonusCoefficient; float factorMod = 1.0f; - if (bonus) - coeff = (damagetype == DOT) ? bonus->dot_damage : bonus->direct_damage; - else + if (coeff <= 0.0f) { // No bonus healing for SPELL_DAMAGE_CLASS_NONE class spells by default if (spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE) @@ -9382,9 +8988,6 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u // Default calculation if (TakenAdvertisedBenefit) { - if (!bonus || coeff < 0) - coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack) * 1.88f; // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells) - factorMod *= CalculateLevelPenalty(spellProto) * int32(stack); if (Player* modOwner = GetSpellModOwner()) { @@ -9401,17 +9004,19 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u if (caster->GetGUID() == (*i)->GetCasterGUID() && (*i)->IsAffectingSpell(spellProto)) AddPct(TakenTotalMod, (*i)->GetAmount()); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - switch (spellProto->Effects[i].ApplyAuraName) + if (!effect) + continue; + switch (effect->ApplyAuraName) { // Bonus healing does not apply to these spells - case SPELL_AURA_PERIODIC_LEECH: - case SPELL_AURA_PERIODIC_HEALTH_FUNNEL: - TakenTotal = 0; - break; + case SPELL_AURA_PERIODIC_LEECH: + case SPELL_AURA_PERIODIC_HEALTH_FUNNEL: + TakenTotal = 0; + break; } - if (spellProto->Effects[i].Effect == SPELL_EFFECT_HEALTH_LEECH) + if (effect->Effect == SPELL_EFFECT_HEALTH_LEECH) TakenTotal = 0; } @@ -9444,7 +9049,7 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i) { // stat used dependent from misc value (stat index) - Stats usedStat = Stats((*i)->GetSpellInfo()->Effects[(*i)->GetEffIndex()].MiscValue); + Stats usedStat = Stats((*i)->GetSpellEffectInfo()->MiscValue); advertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount())); } @@ -9542,13 +9147,13 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const } bool immuneToAllEffects = true; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { // State/effect immunities applied by aura expect full spell immunity // Ignore effects with mechanic, they are supposed to be checked separately - if (!spellInfo->Effects[i].IsEffect()) + if (!effect || !effect->IsEffect()) continue; - if (!IsImmunedToSpellEffect(spellInfo, i)) + if (!IsImmunedToSpellEffect(spellInfo, effect->EffectIndex)) { immuneToAllEffects = false; break; @@ -9576,20 +9181,24 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const { - if (!spellInfo || !spellInfo->Effects[index].IsEffect()) + if (!spellInfo) + return false; + + SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficulty(), index); + if (!effect || !effect->IsEffect()) return false; if (spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) return false; // If m_immuneToEffect type contain this effect type, IMMUNE effect. - uint32 effect = spellInfo->Effects[index].Effect; + uint32 eff = effect->Effect; SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT]; for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr) - if (itr->type == effect) + if (itr->type == eff) return true; - if (uint32 mechanic = spellInfo->Effects[index].Mechanic) + if (uint32 mechanic = effect->Mechanic) { SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) @@ -9597,7 +9206,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons return true; } - if (uint32 aura = spellInfo->Effects[index].ApplyAuraName) + if (uint32 aura = effect->ApplyAuraName) { SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE]; for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr) @@ -9663,8 +9272,8 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType { bool normalized = false; if (spellProto) - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (spellProto->Effects[i].Effect == SPELL_EFFECT_NORMALIZED_WEAPON_DMG) + for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficulty())) + if (effect && effect->Effect == SPELL_EFFECT_NORMALIZED_WEAPON_DMG) { normalized = true; break; @@ -10269,7 +9878,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo return false; // can't attack invisible (ignore stealth for aoe spells) also if the area being looked at is from a spell use the dynamic object created instead of the casting unit. - if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))) + if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea(GetMap()->GetDifficulty())) : !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea(GetMap()->GetDifficulty())))) return false; // can't attack dead @@ -10390,7 +9999,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co return false; // can't assist invisible - if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())) + if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea(GetMap()->GetDifficulty()))) return false; // can't assist dead @@ -10768,6 +10377,7 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) propagateSpeedChange(); + // Spline packets are for creatures and move_update are for players static OpcodeServer const moveTypeToOpcode[MAX_MOVE_TYPE][3] = { {SMSG_SPLINE_MOVE_SET_WALK_SPEED, SMSG_MOVE_SET_WALK_SPEED, SMSG_MOVE_UPDATE_WALK_SPEED }, @@ -10792,11 +10402,28 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) pet->SetSpeed(mtype, m_speed_rate[mtype], forced); } - static MovementStatusElements const speedVal = MSEExtraFloat; - Movement::ExtraMovementStatusElement extra(&speedVal); - extra.Data.floatData = GetSpeed(mtype); + if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER) + { + // Send notification to self + WorldPackets::Movement::MoveSetSpeed selfpacket(moveTypeToOpcode[mtype][1]); + selfpacket.MoverGUID = GetGUID(); + selfpacket.SequenceIndex = m_movementCounter++; + selfpacket.Speed = rate; + ToPlayer()->GetSession()->SendPacket(selfpacket.Write()); - Movement::PacketSender(this, moveTypeToOpcode[mtype][0], moveTypeToOpcode[mtype][1], moveTypeToOpcode[mtype][2], &extra).Send(); + // Send notification to other players + WorldPackets::Movement::MoveUpdateSpeed packet(moveTypeToOpcode[mtype][2]); + packet.movementInfo = &m_movementInfo; + packet.Speed = rate; + SendMessageToSet(packet.Write(), false); + } + else + { + WorldPackets::Movement::MoveSplineSetSpeed packet(moveTypeToOpcode[mtype][0]); + packet.MoverGUID = GetGUID(); + packet.Speed = rate; + SendMessageToSet(packet.Write(), true); + } } void Unit::setDeathState(DeathState s) @@ -11138,9 +10765,13 @@ float Unit::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index } // function uses real base points (typically value - 1) -int32 Unit::CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effect_index, int32 const* basePoints) const +int32 Unit::CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effect_index, int32 const* basePoints /*= nullptr*/, float* variance /*= nullptr*/) const { - return spellProto->Effects[effect_index].CalcValue(this, basePoints, target); + SpellEffectInfo const* effect = spellProto->GetEffect(GetMap()->GetDifficulty(), effect_index); + if (variance) + *variance = 0.0f; + + return effect ? effect->CalcValue(this, basePoints, target, variance) : 0; } int32 Unit::CalcSpellDuration(SpellInfo const* spellProto) @@ -11228,7 +10859,8 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in sSpellMgr->IsSpellMemberOfSpellGroup(spellProto->Id, SPELL_GROUP_ELIXIR_BATTLE) || sSpellMgr->IsSpellMemberOfSpellGroup(spellProto->Id, SPELL_GROUP_ELIXIR_GUARDIAN))) { - if (target->HasAura(53042) && target->HasSpell(spellProto->Effects[0].TriggerSpell)) + SpellEffectInfo const* effect = spellProto->GetEffect(DIFFICULTY_NONE, EFFECT_0); + if (target->HasAura(53042) && effect && target->HasSpell(effect->TriggerSpell)) duration *= 2; } } @@ -12236,7 +11868,7 @@ void CharmInfo::LoadPetActionBar(const std::string& data) // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion ActiveStates type = ActiveStates(atol(*iter)); ++iter; - uint32 action = uint32(atol(*iter)); + uint32 action = atoul(*iter); PetActionBar[index].SetActionAndType(action, type); @@ -12476,10 +12108,17 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo(); // only auras that has triggered spell should proc from fully absorbed damage - if (procExtra & PROC_EX_ABSORB && isVictim) - if (damage || spellProto->Effects[EFFECT_0].TriggerSpell || spellProto->Effects[EFFECT_1].TriggerSpell || spellProto->Effects[EFFECT_2].TriggerSpell) - active = true; - + if (procExtra & PROC_EX_ABSORB && isVictim && damage) + { + for (SpellEffectInfo const* effect : itr->second->GetBase()->GetSpellEffectInfos()) + { + if (effect && effect->TriggerSpell) + { + active = true; + break; + } + } + } if (!IsTriggeredAtSpellProcEvent(target, triggerData.aura, procSpell, procFlag, procExtra, attType, isVictim, active, triggerData.spellProcEvent)) continue; @@ -12497,11 +12136,10 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u bool triggered = !(spellProto->AttributesEx3 & SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED) ? (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION)) : false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (AuraEffect const* aurEff : itr->second->GetBase()->GetAuraEffects()) { - if (itr->second->HasEffect(i)) + if (aurEff) { - AuraEffect* aurEff = itr->second->GetBase()->GetEffect(i); // Skip this auras if (isNonTriggerAura[aurEff->GetAuraType()]) continue; @@ -12510,7 +12148,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u continue; // Some spells must always trigger if (!triggered || isAlwaysTriggeredAura[aurEff->GetAuraType()]) - triggerData.effMask |= 1<<i; + triggerData.effMask |= 1 << aurEff->GetEffIndex(); } } if (triggerData.effMask) @@ -12611,9 +12249,8 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u } case SPELL_AURA_PROC_ON_POWER_AMOUNT: { - TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleAuraProcOnPowerAmount(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; + triggeredByAura->HandleProcTriggerSpellOnPowerAmountAuraProc(aurApp, eventInfo); + takeCharges = true; break; } case SPELL_AURA_OBS_MOD_POWER: @@ -12892,10 +12529,10 @@ void Unit::SendPetAIReaction(ObjectGuid guid) if (!owner || owner->GetTypeId() != TYPEID_PLAYER) return; - WorldPacket data(SMSG_AI_REACTION, 8 + 4); - data << guid; - data << uint32(AI_REACTION_HOSTILE); - owner->ToPlayer()->GetSession()->SendPacket(&data); + WorldPackets::Combat::AIReaction packet; + packet.UnitGUID = guid; + packet.Reaction = AI_REACTION_HOSTILE; + owner->ToPlayer()->SendDirectMessage(packet.Write()); } ///----------End of Pet responses methods---------- @@ -13153,9 +12790,11 @@ uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectTyp bool DirectDamage = false; bool AreaEffect = false; - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; i++) + for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - switch (spellProto->Effects[i].Effect) + if (!effect) + continue; + switch (effect->Effect) { case SPELL_EFFECT_SCHOOL_DAMAGE: case SPELL_EFFECT_POWER_DRAIN: @@ -13166,7 +12805,7 @@ uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectTyp DirectDamage = true; break; case SPELL_EFFECT_APPLY_AURA: - switch (spellProto->Effects[i].ApplyAuraName) + switch (effect->ApplyAuraName) { case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_HEAL: @@ -13183,7 +12822,7 @@ uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectTyp break; } - if (spellProto->Effects[i].IsTargetingArea()) + if (effect->IsTargetingArea()) AreaEffect = true; } @@ -13210,10 +12849,12 @@ uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectTyp CastingTime /= 2; // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - if (spellProto->Effects[j].Effect == SPELL_EFFECT_HEALTH_LEECH || - (spellProto->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA && spellProto->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_LEECH)) + if (!effect) + continue; + if (effect->Effect == SPELL_EFFECT_HEALTH_LEECH || + (effect->Effect == SPELL_EFFECT_APPLY_AURA && effect->ApplyAuraName == SPELL_AURA_PERIODIC_LEECH)) { CastingTime /= 2; break; @@ -13276,7 +12917,7 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect if (!spellInfo->IsChanneled() && DotDuration > 0) DotFactor = DotDuration / 15000.0f; - if (uint32 DotTicks = spellInfo->GetMaxTicks()) + if (uint32 DotTicks = spellInfo->GetMaxTicks(GetMap()->GetDifficulty())) DotFactor /= DotTicks; } @@ -13550,7 +13191,8 @@ bool Unit::HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura) { if (Unit* caster = triggeredByAura->GetCaster()) { - float radius = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcRadius(caster); + SpellEffectInfo const* effect = triggeredByAura->GetSpellEffectInfo(); + float radius = effect->CalcRadius(caster); if (Unit* target = GetNextRandomRaidMemberOrPet(radius)) { @@ -13602,7 +13244,8 @@ bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura) { if (Unit* caster = triggeredByAura->GetCaster()) { - float radius = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcRadius(caster); + SpellEffectInfo const* effect = triggeredByAura->GetSpellEffectInfo(); + float radius = effect->CalcRadius(caster); if (Unit* target= GetNextRandomRaidMemberOrPet(radius)) { CastSpell(target, spellProto, true, NULL, triggeredByAura, caster_guid); @@ -14302,7 +13945,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au if (cinfo && cinfo->type == CREATURE_TYPE_DEMON) { // to prevent client crash - SetByteValue(UNIT_FIELD_BYTES_0, 1, (uint8)CLASS_MAGE); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, (uint8)CLASS_MAGE); // just to enable stat window if (GetCharmInfo()) @@ -14404,7 +14047,7 @@ void Unit::RemoveCharmedBy(Unit* charmer) CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate(); if (cinfo && cinfo->type == CREATURE_TYPE_DEMON) { - SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class)); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, uint8(cinfo->unit_class)); if (GetCharmInfo()) GetCharmInfo()->SetPetNumber(0, true); else @@ -14621,7 +14264,7 @@ Aura* Unit::AddAura(uint32 spellId, Unit* target) return AddAura(spellInfo, MAX_EFFECT_MASK, target); } -Aura* Unit::AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target) +Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target) { if (!spellInfo) return NULL; @@ -15374,9 +15017,12 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) { uint8 i = 0; bool valid = false; - while (i < MAX_SPELL_EFFECTS && !valid) + for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(GetMap()->GetDifficulty())) { - if (spellEntry->Effects[i].ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE) + if (!effect) + continue; + + if (effect->ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE) { valid = true; break; @@ -15395,8 +15041,9 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) else // This can happen during Player::_LoadAuras { int32 bp0[MAX_SPELL_EFFECTS]; - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) - bp0[j] = spellEntry->Effects[j].BasePoints; + for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(GetMap()->GetDifficulty())) + if (effect) + bp0[effect->EffectIndex] = effect->BasePoints; bp0[i] = seatId; Aura::TryRefreshStackOrCreate(spellEntry, MAX_EFFECT_MASK, this, clicker, bp0, NULL, origCasterGUID); @@ -15822,64 +15469,24 @@ void Unit::SendTeleportPacket(Position& pos) if (GetTypeId() == TYPEID_UNIT) Relocate(&pos); // Relocate the unit to its new position in order to build the packets correctly. - ObjectGuid guid = GetGUID(); - ObjectGuid transGuid = GetTransGUID(); - - WorldPacket data(SMSG_MOVE_UPDATE_TELEPORT, 38); - WriteMovementInfo(data); + WorldPackets::Movement::MoveUpdateTeleport packet; + packet.movementInfo = &m_movementInfo; if (GetTypeId() == TYPEID_PLAYER) { - WorldPacket data2(MSG_MOVE_TELEPORT, 38); - data2.WriteBit(guid[6]); - data2.WriteBit(guid[0]); - data2.WriteBit(guid[3]); - data2.WriteBit(guid[2]); - data2.WriteBit(0); // unknown - data2.WriteBit(!transGuid.IsEmpty()); - data2.WriteBit(guid[1]); - if (!transGuid.IsEmpty()) - { - data2.WriteBit(transGuid[1]); - data2.WriteBit(transGuid[3]); - data2.WriteBit(transGuid[2]); - data2.WriteBit(transGuid[5]); - data2.WriteBit(transGuid[0]); - data2.WriteBit(transGuid[7]); - data2.WriteBit(transGuid[6]); - data2.WriteBit(transGuid[4]); - } - data2.WriteBit(guid[4]); - data2.WriteBit(guid[7]); - data2.WriteBit(guid[5]); - data2.FlushBits(); + WorldPackets::Movement::MoveTeleport selfPacket; + selfPacket.MoverGUID = GetGUID(); + + ObjectGuid transGuid = GetTransGUID(); if (!transGuid.IsEmpty()) - { - data2.WriteByteSeq(transGuid[6]); - data2.WriteByteSeq(transGuid[5]); - data2.WriteByteSeq(transGuid[1]); - data2.WriteByteSeq(transGuid[7]); - data2.WriteByteSeq(transGuid[0]); - data2.WriteByteSeq(transGuid[2]); - data2.WriteByteSeq(transGuid[4]); - data2.WriteByteSeq(transGuid[3]); - } - - data2 << uint32(0); // counter - data2.WriteByteSeq(guid[1]); - data2.WriteByteSeq(guid[2]); - data2.WriteByteSeq(guid[3]); - data2.WriteByteSeq(guid[5]); - data2 << float(GetPositionX()); - data2.WriteByteSeq(guid[4]); - data2 << float(GetOrientation()); - data2.WriteByteSeq(guid[7]); - data2 << float(GetPositionZMinusOffset()); - data2.WriteByteSeq(guid[0]); - data2.WriteByteSeq(guid[6]); - data2 << float(GetPositionY()); - ToPlayer()->SendDirectMessage(&data2); // Send the MSG_MOVE_TELEPORT packet to self. + selfPacket.TransportGUID.Set(transGuid); + + selfPacket.Pos.Relocate(GetPositionX(), GetPositionY(), GetPositionZMinusOffset()); + selfPacket.Facing = GetOrientation(); + selfPacket.SequenceIndex = m_movementCounter++; + + ToPlayer()->SendDirectMessage(selfPacket.Write()); } // Relocate the player/creature to its old position, so we can broadcast to nearby players correctly @@ -15889,7 +15496,7 @@ void Unit::SendTeleportPacket(Position& pos) Relocate(&oldPos); // Broadcast the packet to everyone except self. - SendMessageToSet(&data, false); + SendMessageToSet(packet.Write(), false); } bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport) @@ -15953,19 +15560,19 @@ void Unit::SendThreatListUpdate() { if (!getThreatManager().isThreatListEmpty()) { - uint32 count = getThreatManager().getThreatList().size(); - TC_LOG_DEBUG("entities.unit", "WORLD: Send SMSG_THREAT_UPDATE Message"); - WorldPacket data(SMSG_THREAT_UPDATE, 8 + count * 8); - data << GetPackGUID(); - data << uint32(count); + WorldPackets::Combat::ThreatUpdate packet; + packet.UnitGUID = GetGUID(); ThreatContainer::StorageType const &tlist = getThreatManager().getThreatList(); + packet.ThreatList.reserve(tlist.size()); for (ThreatContainer::StorageType::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) { - data << (*itr)->getUnitGuid().WriteAsPacked(); - data << uint32((*itr)->getThreat() * 100); + WorldPackets::Combat::ThreatInfo info; + info.UnitGUID = (*itr)->getUnitGuid(); + info.Threat = (*itr)->getThreat() * 100; + packet.ThreatList.push_back(info); } - SendMessageToSet(&data, false); + SendMessageToSet(packet.Write(), false); } } @@ -15973,20 +15580,20 @@ void Unit::SendChangeCurrentVictimOpcode(HostileReference* pHostileReference) { if (!getThreatManager().isThreatListEmpty()) { - uint32 count = getThreatManager().getThreatList().size(); - TC_LOG_DEBUG("entities.unit", "WORLD: Send SMSG_HIGHEST_THREAT_UPDATE Message"); - WorldPacket data(SMSG_HIGHEST_THREAT_UPDATE, 8 + 8 + count * 8); - data << GetPackGUID(); - data << pHostileReference->getUnitGuid().WriteAsPacked(); - data << uint32(count); + WorldPackets::Combat::HighestThreatUpdate packet; + packet.UnitGUID = GetGUID(); + packet.HighestThreatGUID = pHostileReference->getUnitGuid(); ThreatContainer::StorageType const &tlist = getThreatManager().getThreatList(); + packet.ThreatList.reserve(tlist.size()); for (ThreatContainer::StorageType::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) { - data << (*itr)->getUnitGuid().WriteAsPacked(); - data << uint32((*itr)->getThreat()); + WorldPackets::Combat::ThreatInfo info; + info.UnitGUID = (*itr)->getUnitGuid(); + info.Threat = int32((*itr)->getThreat()); + packet.ThreatList.push_back(info); } - SendMessageToSet(&data, false); + SendMessageToSet(packet.Write(), false); } } @@ -16001,10 +15608,10 @@ void Unit::SendClearThreatListOpcode() void Unit::SendRemoveFromThreatListOpcode(HostileReference* pHostileReference) { TC_LOG_DEBUG("entities.unit", "WORLD: Send SMSG_THREAT_REMOVE Message"); - WorldPacket data(SMSG_THREAT_REMOVE, 8 + 8); - data << GetPackGUID(); - data << pHostileReference->getUnitGuid().WriteAsPacked(); - SendMessageToSet(&data, false); + WorldPackets::Combat::ThreatRemove packet; + packet.UnitGUID = GetGUID(); + packet.AboutGUID = pHostileReference->getUnitGuid(); + SendMessageToSet(packet.Write(), false); } // baseRage means damage taken when attacker = false @@ -16282,10 +15889,27 @@ bool Unit::SetDisableGravity(bool disable, bool packetOnly /*= false*/) } } - if (disable) - Movement::PacketSender(this, SMSG_SPLINE_MOVE_GRAVITY_DISABLE, SMSG_MOVE_GRAVITY_DISABLE).Send(); + static OpcodeServer const gravityOpcodeTable[2][2] = + { + {SMSG_SPLINE_MOVE_GRAVITY_ENABLE, SMSG_MOVE_GRAVITY_ENABLE }, + {SMSG_SPLINE_MOVE_GRAVITY_DISABLE, SMSG_MOVE_GRAVITY_DISABLE } + }; + + bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; + + if (player) + { + WorldPackets::Movement::MoveSetFlag packet(gravityOpcodeTable[disable][1]); + packet.MoverGUID = GetGUID(); + packet.SequenceIndex = m_movementCounter++; + SendMessageToSet(packet.Write(), true); + } else - Movement::PacketSender(this, SMSG_SPLINE_MOVE_GRAVITY_ENABLE, SMSG_MOVE_GRAVITY_ENABLE).Send(); + { + WorldPackets::Movement::MoveSplineSetFlag packet(gravityOpcodeTable[disable][0]); + packet.MoverGUID = GetGUID(); + SendMessageToSet(packet.Write(), true); + } return true; } @@ -16316,10 +15940,11 @@ bool Unit::SetSwim(bool enable) else RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING); - if (enable) - Movement::PacketSender(this, SMSG_SPLINE_MOVE_START_SWIM, static_cast<OpcodeServer>(NULL_OPCODE)).Send(); - else - Movement::PacketSender(this, SMSG_SPLINE_MOVE_STOP_SWIM, static_cast<OpcodeServer>(NULL_OPCODE)).Send(); + static OpcodeServer const swimOpcodeTable[2] = {SMSG_SPLINE_MOVE_STOP_SWIM, SMSG_SPLINE_MOVE_START_SWIM}; + + WorldPackets::Movement::MoveSplineSetFlag packet(swimOpcodeTable[enable]); + packet.MoverGUID = GetGUID(); + SendMessageToSet(packet.Write(), true); return true; } @@ -16342,10 +15967,27 @@ bool Unit::SetCanFly(bool enable) SetFall(true); } - if (enable) - Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_FLYING, SMSG_MOVE_SET_CAN_FLY).Send(); + static OpcodeServer const flyOpcodeTable[2][2] = + { + {SMSG_SPLINE_MOVE_UNSET_FLYING, SMSG_MOVE_UNSET_CAN_FLY }, + {SMSG_SPLINE_MOVE_SET_FLYING, SMSG_MOVE_SET_CAN_FLY } + }; + + bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; + + if (player) + { + WorldPackets::Movement::MoveSetFlag packet(flyOpcodeTable[enable][1]); + packet.MoverGUID = GetGUID(); + packet.SequenceIndex = m_movementCounter++; + SendMessageToSet(packet.Write(), true); + } else - Movement::PacketSender(this, SMSG_SPLINE_MOVE_UNSET_FLYING, SMSG_MOVE_UNSET_CAN_FLY).Send(); + { + WorldPackets::Movement::MoveSplineSetFlag packet(flyOpcodeTable[enable][0]); + packet.MoverGUID = GetGUID(); + SendMessageToSet(packet.Write(), true); + } return true; } @@ -16363,10 +16005,27 @@ bool Unit::SetWaterWalking(bool enable, bool packetOnly /*= false */) RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING); } - if (enable) - Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_WATER_WALK, SMSG_MOVE_WATER_WALK).Send(); + static OpcodeServer const waterWalkingOpcodeTable[2][2] = + { + {SMSG_SPLINE_MOVE_SET_LAND_WALK, SMSG_MOVE_LAND_WALK }, + {SMSG_SPLINE_MOVE_SET_WATER_WALK, SMSG_MOVE_WATER_WALK} + }; + + bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; + + if (player) + { + WorldPackets::Movement::MoveSetFlag packet(waterWalkingOpcodeTable[enable][1]); + packet.MoverGUID = GetGUID(); + packet.SequenceIndex = m_movementCounter++; + SendMessageToSet(packet.Write(), true); + } else - Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_LAND_WALK, SMSG_MOVE_LAND_WALK).Send(); + { + WorldPackets::Movement::MoveSplineSetFlag packet(waterWalkingOpcodeTable[enable][0]); + packet.MoverGUID = GetGUID(); + SendMessageToSet(packet.Write(), true); + } return true; } @@ -16384,10 +16043,27 @@ bool Unit::SetFeatherFall(bool enable, bool packetOnly /*= false */) RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW); } - if (enable) - Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_FEATHER_FALL, SMSG_MOVE_FEATHER_FALL).Send(); + static OpcodeServer const featherFallOpcodeTable[2][2] = + { + {SMSG_SPLINE_MOVE_SET_NORMAL_FALL, SMSG_MOVE_NORMAL_FALL }, + {SMSG_SPLINE_MOVE_SET_FEATHER_FALL, SMSG_MOVE_FEATHER_FALL } + }; + + bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; + + if (player) + { + WorldPackets::Movement::MoveSetFlag packet(featherFallOpcodeTable[enable][1]); + packet.MoverGUID = GetGUID(); + packet.SequenceIndex = m_movementCounter++; + SendMessageToSet(packet.Write(), true); + } else - Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_NORMAL_FALL, SMSG_MOVE_NORMAL_FALL).Send(); + { + WorldPackets::Movement::MoveSplineSetFlag packet(featherFallOpcodeTable[enable][0]); + packet.MoverGUID = GetGUID(); + SendMessageToSet(packet.Write(), true); + } return true; } @@ -16420,10 +16096,27 @@ bool Unit::SetHover(bool enable, bool packetOnly /*= false*/) } } - if (enable) - Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_HOVER, SMSG_MOVE_SET_HOVER).Send(); + static OpcodeServer const hoverOpcodeTable[2][2] = + { + {SMSG_SPLINE_MOVE_UNSET_HOVER, SMSG_MOVE_UNSET_HOVER }, + {SMSG_SPLINE_MOVE_SET_HOVER, SMSG_MOVE_SET_HOVER } + }; + + bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; + + if (player) + { + WorldPackets::Movement::MoveSetFlag packet(hoverOpcodeTable[enable][1]); + packet.MoverGUID = GetGUID(); + packet.SequenceIndex = m_movementCounter++; + SendMessageToSet(packet.Write(), true); + } else - Movement::PacketSender(this, SMSG_SPLINE_MOVE_UNSET_HOVER, SMSG_MOVE_UNSET_HOVER).Send(); + { + WorldPackets::Movement::MoveSplineSetFlag packet(hoverOpcodeTable[enable][0]); + packet.MoverGUID = GetGUID(); + SendMessageToSet(packet.Write(), true); + } return true; } @@ -16557,9 +16250,9 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) // this also applies for transform auras if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(getTransForm())) - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (transform->Effects[i].IsAura(SPELL_AURA_TRANSFORM)) - if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(transform->Effects[i].MiscValue)) + for (SpellEffectInfo const* effect : transform->GetEffectsForDifficulty(GetMap()->GetDifficulty())) + if (effect && effect->IsAura(SPELL_AURA_TRANSFORM)) + if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(effect->MiscValue)) { cinfo = transformInfo; break; @@ -16693,43 +16386,42 @@ int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEf bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/) { - for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i) + for (AuraEffect* aurEff : aura->GetAuraEffects()) { - if (AuraEffect const* aurEff = aura->GetEffect(i)) + if (!aurEff) + continue; + AuraType const auraType = AuraType(aurEff->GetSpellEffectInfo()->ApplyAuraName); + AuraEffectList const& auras = GetAuraEffectsByType(auraType); + for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();) { - AuraType const auraType = AuraType(aura->GetSpellInfo()->Effects[i].ApplyAuraName); - AuraEffectList const& auras = GetAuraEffectsByType(auraType); - for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();) + AuraEffect const* existingAurEff = (*itr); + ++itr; + + if (sSpellMgr->CheckSpellGroupStackRules(aura->GetSpellInfo(), existingAurEff->GetSpellInfo()) + == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST) { - AuraEffect const* existingAurEff = (*itr); - ++itr; + int32 diff = abs(aurEff->GetAmount()) - abs(existingAurEff->GetAmount()); + if (!diff) + diff = int32(aura->GetEffectMask()) - int32(existingAurEff->GetBase()->GetEffectMask()); - if (sSpellMgr->CheckSpellGroupStackRules(aura->GetSpellInfo(), existingAurEff->GetSpellInfo()) - == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST) + if (diff > 0) { - int32 diff = abs(aurEff->GetAmount()) - abs(existingAurEff->GetAmount()); - if (!diff) - diff = int32(aura->GetEffectMask()) - int32(existingAurEff->GetBase()->GetEffectMask()); - - if (diff > 0) + Aura const* base = existingAurEff->GetBase(); + // no removing of area auras from the original owner, as that completely cancels them + if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this)) { - Aura const* base = existingAurEff->GetBase(); - // no removing of area auras from the original owner, as that completely cancels them - if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this)) + if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID())) { - if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID())) - { - bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType); - uint32 removedAuras = m_removedAurasCount; - RemoveAura(aurApp); - if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) - itr = auras.begin(); - } + bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType, GetMap()->GetDifficulty()); + uint32 removedAuras = m_removedAurasCount; + RemoveAura(aurApp); + if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) + itr = auras.begin(); } } - else if (diff < 0) - return false; } + else if (diff < 0) + return false; } } } @@ -16766,9 +16458,9 @@ void Unit::Whisper(std::string const& text, Language language, Player* target, b return; LocaleConstant locale = target->GetSession()->GetSessionDbLocaleIndex(); - WorldPacket data; - ChatHandler::BuildChatPacket(data, isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale); - target->SendDirectMessage(&data); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale); + target->SendDirectMessage(packet.Write()); } void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target) @@ -16813,7 +16505,7 @@ void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/ } LocaleConstant locale = target->GetSession()->GetSessionDbLocaleIndex(); - WorldPacket data; - ChatHandler::BuildChatPacket(data, isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, bct->GetText(locale, getGender()), 0, "", locale); - target->SendDirectMessage(&data); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, bct->GetText(locale, getGender()), 0, "", locale); + target->SendDirectMessage(packet.Write()); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index b28d26af2c9..2b9b4d932ad 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -123,6 +123,36 @@ enum SpellValueMod SPELLVALUE_BASE_POINT0, SPELLVALUE_BASE_POINT1, SPELLVALUE_BASE_POINT2, + SPELLVALUE_BASE_POINT3, + SPELLVALUE_BASE_POINT4, + SPELLVALUE_BASE_POINT5, + SPELLVALUE_BASE_POINT6, + SPELLVALUE_BASE_POINT7, + SPELLVALUE_BASE_POINT8, + SPELLVALUE_BASE_POINT9, + SPELLVALUE_BASE_POINT10, + SPELLVALUE_BASE_POINT11, + SPELLVALUE_BASE_POINT12, + SPELLVALUE_BASE_POINT13, + SPELLVALUE_BASE_POINT14, + SPELLVALUE_BASE_POINT15, + SPELLVALUE_BASE_POINT16, + SPELLVALUE_BASE_POINT17, + SPELLVALUE_BASE_POINT18, + SPELLVALUE_BASE_POINT19, + SPELLVALUE_BASE_POINT20, + SPELLVALUE_BASE_POINT21, + SPELLVALUE_BASE_POINT22, + SPELLVALUE_BASE_POINT23, + SPELLVALUE_BASE_POINT24, + SPELLVALUE_BASE_POINT25, + SPELLVALUE_BASE_POINT26, + SPELLVALUE_BASE_POINT27, + SPELLVALUE_BASE_POINT28, + SPELLVALUE_BASE_POINT29, + SPELLVALUE_BASE_POINT30, + SPELLVALUE_BASE_POINT31, + SPELLVALUE_BASE_POINT_END, SPELLVALUE_RADIUS_MOD, SPELLVALUE_MAX_TARGETS, SPELLVALUE_AURA_STACK @@ -191,6 +221,13 @@ enum UnitStandFlags UNIT_STAND_FLAGS_ALL = 0xFF }; +enum UnitBytes0Offsets +{ + UNIT_BYTES_0_OFFSET_RACE = 0, + UNIT_BYTES_0_OFFSET_CLASS = 1, + UNIT_BYTES_0_OFFSET_GENDER = 3, +}; + // byte flags value (UNIT_FIELD_BYTES_1, 3) enum UnitBytes1_Flags { @@ -309,7 +346,7 @@ enum HitInfo HITINFO_CRITICALHIT = 0x00000200, // critical hit // 0x00000400 // 0x00000800 - // 0x00001000 + HITINFO_UNK12 = 0x00001000, HITINFO_BLOCK = 0x00002000, // blocked damage // 0x00004000 // Hides worldtext for 0 damage // 0x00008000 // Related to blood visual @@ -340,6 +377,7 @@ class AuraEffect; class Creature; class Spell; class SpellInfo; +class SpellEffectInfo; class DynamicObject; class GameObject; class Item; @@ -1373,11 +1411,11 @@ class Unit : public WorldObject uint8 getLevel() const { return uint8(GetUInt32Value(UNIT_FIELD_LEVEL)); } uint8 getLevelForTarget(WorldObject const* /*target*/) const override { return getLevel(); } void SetLevel(uint8 lvl); - uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, 0); } + uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE); } uint32 getRaceMask() const { return 1 << (getRace()-1); } - uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, 1); } + uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS); } uint32 getClassMask() const { return 1 << (getClass()-1); } - uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, 2); } + uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER); } float GetStat(Stats stat) const { return float(GetUInt32Value(UNIT_FIELD_STAT+stat)); } void SetStat(Stats stat, int32 val) { SetStatInt32Value(UNIT_FIELD_STAT+stat, val); } @@ -1406,7 +1444,7 @@ class Unit : public WorldObject int32 ModifyHealth(int32 val); int32 GetHealthGain(int32 dVal); - Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, 3)); } + Powers getPowerType() const { return Powers(GetUInt32Value(UNIT_FIELD_DISPLAY_POWER)); } void setPowerType(Powers power); int32 GetPower(Powers power) const; int32 GetMinPower(Powers power) const { return power == POWER_ECLIPSE ? -100 : 0; } @@ -1583,7 +1621,6 @@ class Unit : public WorldObject int32 HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical = false); void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, Powers powertype); void EnergizeBySpell(Unit* victim, uint32 SpellID, int32 Damage, Powers powertype); - uint32 SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage); void CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo, CustomSpellValues const* value, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); void CastSpell(Unit* victim, uint32 spellId, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); @@ -1597,7 +1634,7 @@ class Unit : public WorldObject void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim = NULL, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* victim = NULL, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); Aura* AddAura(uint32 spellId, Unit* target); - Aura* AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target); + Aura* AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target); void SetAuraStack(uint32 spellId, Unit* target, uint32 stack); void SendPlaySpellVisualKit(uint32 id, uint32 unkParam); void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown); @@ -1730,11 +1767,11 @@ class Unit : public WorldObject bool InitTamedPet(Pet* pet, uint8 level, uint32 spell_id); // aura apply/remove helpers - you should better not use these - Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty); + Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint32 effMask, Unit* caster, int32 *baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty); void _AddAura(UnitAura* aura, Unit* caster); - AuraApplication * _CreateAuraApplication(Aura* aura, uint8 effMask); + AuraApplication * _CreateAuraApplication(Aura* aura, uint32 effMask); void _ApplyAuraEffect(Aura* aura, uint8 effIndex); - void _ApplyAura(AuraApplication * aurApp, uint8 effMask); + void _ApplyAura(AuraApplication * aurApp, uint32 effMask); void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode); void _UnapplyAura(AuraApplication * aurApp, AuraRemoveMode removeMode); void _RemoveNoStackAuraApplicationsDueToAura(Aura* aura); @@ -1747,21 +1784,21 @@ class Unit : public WorldObject AuraMap const& GetOwnedAuras() const { return m_ownedAuras; } void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); - void RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); + void RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); void RemoveOwnedAura(Aura* aura, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); - Aura* GetOwnedAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, Aura* except = NULL) const; + Aura* GetOwnedAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0, Aura* except = NULL) const; // m_appliedAuras container management AuraApplicationMap & GetAppliedAuras() { return m_appliedAuras; } AuraApplicationMap const& GetAppliedAuras() const { return m_appliedAuras; } void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT); - void RemoveAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); + void RemoveAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); void RemoveAura(AuraApplication * aurApp, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT); void RemoveAura(Aura* aur, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT); - void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); + void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, Unit* dispeller, uint8 chargesRemoved = 1); void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, Unit* stealer); @@ -1796,17 +1833,17 @@ class Unit : public WorldObject AuraEffect* GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, ObjectGuid casterGUID = ObjectGuid::Empty) const; AuraEffect* GetDummyAuraEffect(SpellFamilyNames name, uint32 iconId, uint8 effIndex) const; - AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraApplication * except = NULL) const; - Aura* GetAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0) const; + AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0, AuraApplication * except = NULL) const; + Aura* GetAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0) const; - AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraApplication * except = NULL) const; - Aura* GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0) const; + AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0, AuraApplication * except = NULL) const; + Aura* GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0) const; void GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelChargesList& dispelList); bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster = ObjectGuid::Empty) const; uint32 GetAuraCount(uint32 spellId) const; - bool HasAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0) const; + bool HasAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0) const; bool HasAuraType(AuraType auraType) const; bool HasAuraTypeWithCaster(AuraType auratype, ObjectGuid caster) const; bool HasAuraTypeWithMiscvalue(AuraType auratype, int32 miscvalue) const; @@ -1994,14 +2031,14 @@ class Unit : public WorldObject int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const; int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const; - uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; + uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const* effect, uint32 stack = 1) const; float SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const; - uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; + uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const* effect, uint32 stack = 1) const; int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const; int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const; - uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; + uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const* effect, uint32 stack = 1) const; float SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const; - uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; + uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const* effect, uint32 stack = 1) const; uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = NULL); uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto = NULL); @@ -2028,7 +2065,7 @@ class Unit : public WorldObject bool IsImmunedToDamage(SpellInfo const* spellInfo) const; virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const; // redefined in Creature - static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS); + bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS); uint32 CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK); uint32 CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const; void CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo = NULL); @@ -2040,7 +2077,7 @@ class Unit : public WorldObject void SetSpeed(UnitMoveType mtype, float rate, bool forced = false); float ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index, float value) const; - int32 CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effect_index, int32 const* basePoints = NULL) const; + int32 CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effect_index, int32 const* basePoints = nullptr, float* variance = nullptr) const; int32 CalcSpellDuration(SpellInfo const* spellProto); int32 ModSpellDuration(SpellInfo const* spellProto, Unit const* target, int32 duration, bool positive, uint32 effectMask); void ModSpellCastTime(SpellInfo const* spellProto, int32& castTime, Spell* spell = NULL); @@ -2164,7 +2201,7 @@ class Unit : public WorldObject TempSummon const* ToTempSummon() const { if (IsSummon()) return reinterpret_cast<TempSummon const*>(this); else return NULL; } ObjectGuid GetTarget() const { return GetGuidValue(UNIT_FIELD_TARGET); } - virtual void SetTarget(ObjectGuid /*guid*/) = 0; + virtual void SetTarget(ObjectGuid const& /*guid*/) = 0; // Movement info Movement::MoveSpline * movespline; @@ -2265,7 +2302,6 @@ class Unit : public WorldObject void DisableSpline(); private: bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const* & spellProcEvent); - bool HandleAuraProcOnPowerAmount(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool * handled); bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 90a40aa7990..4da985c7bb6 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -155,6 +155,16 @@ bool normalizePlayerName(std::string& name) return true; } +// Extracts player and realm names delimited by - +ExtendedPlayerName ExtractExtendedPlayerName(std::string& name) +{ + size_t pos = name.find('-'); + if (pos != std::string::npos) + return ExtendedPlayerName(name.substr(0, pos), name.substr(pos+1)); + else + return ExtendedPlayerName(name, ""); +} + LanguageDesc lang_description[LANGUAGES_COUNT] = { { LANG_ADDON, 0, 0 }, @@ -472,8 +482,8 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.SubName = fields[12].GetString(); creatureTemplate.IconName = fields[13].GetString(); creatureTemplate.GossipMenuId = fields[14].GetUInt32(); - creatureTemplate.minlevel = fields[15].GetUInt8(); - creatureTemplate.maxlevel = fields[16].GetUInt8(); + creatureTemplate.minlevel = fields[15].GetInt16(); + creatureTemplate.maxlevel = fields[16].GetInt16(); creatureTemplate.expansion = uint32(fields[17].GetInt16()); creatureTemplate.expansionUnknown = uint32(fields[18].GetUInt16()); creatureTemplate.faction = uint32(fields[19].GetUInt16()); @@ -574,17 +584,17 @@ void ObjectMgr::LoadCreatureTemplateAddons() creatureAddon.auras.resize(tokens.size()); for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) { - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(uint32(atol(*itr))); + SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(atoul(*itr)); if (!AdditionalSpellInfo) { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %u defined in `auras` field in `creature_template_addon`.", entry, uint32(atol(*itr))); + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %lu defined in `auras` field in `creature_template_addon`.", entry, atoul(*itr)); continue; } - if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) + if (AdditionalSpellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_CONTROL_VEHICLE)) TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_template_addon`.", entry, uint32(atol(*itr))); - creatureAddon.auras[i++] = uint32(atol(*itr)); + creatureAddon.auras[i++] = atoul(*itr); } if (creatureAddon.mount) @@ -664,18 +674,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) cInfo->Entry, cInfo->expansion, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->expansion); } - if (cInfo->minlevel > difficultyInfo->minlevel) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, minlevel %u) has lower `minlevel` in difficulty %u mode (Entry: %u, minlevel %u).", - cInfo->Entry, cInfo->minlevel, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->minlevel); - } - - if (cInfo->maxlevel > difficultyInfo->maxlevel) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, maxlevel %u) has lower `maxlevel` in difficulty %u mode (Entry: %u, maxlevel %u).", - cInfo->Entry, cInfo->maxlevel, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->maxlevel); - } - if (cInfo->faction != difficultyInfo->faction) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, faction %u) has different `faction` in difficulty %u mode (Entry: %u, faction %u).", @@ -973,6 +971,27 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->flags_extra &= CREATURE_FLAG_EXTRA_DB_ALLOWED; } + // -1 is used in the client for auto-updating the levels + // having their expansion set to it to the latest one + if (cInfo->expansion == -1) + { + const_cast<CreatureTemplate*>(cInfo)->minlevel = (MAX_LEVEL + cInfo->minlevel); + const_cast<CreatureTemplate*>(cInfo)->maxlevel = (MAX_LEVEL + cInfo->maxlevel); + const_cast<CreatureTemplate*>(cInfo)->expansion = EXPANSION_WARLORDS_OF_DRAENOR; + } + + if (cInfo->minlevel < 1 || cInfo->minlevel > STRONG_MAX_LEVEL) + { + TC_LOG_ERROR("sql.sql", "Creature (ID: %u): MinLevel %i is not within [1, 255], value has been set to 1.", cInfo->Entry, cInfo->minlevel); + const_cast<CreatureTemplate*>(cInfo)->minlevel = 1; + } + + if (cInfo->maxlevel < 1 || cInfo->maxlevel > STRONG_MAX_LEVEL) + { + TC_LOG_ERROR("sql.sql", "Creature (ID: %u): MaxLevel %i is not within [1, 255], value has been set to 1.", cInfo->Entry, cInfo->maxlevel); + const_cast<CreatureTemplate*>(cInfo)->maxlevel = 1; + } + const_cast<CreatureTemplate*>(cInfo)->ModDamage *= Creature::_GetDamageMod(cInfo->rank); } @@ -1022,17 +1041,18 @@ void ObjectMgr::LoadCreatureAddons() creatureAddon.auras.resize(tokens.size()); for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) { - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(uint32(atol(*itr))); + SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(atoul(*itr)); if (!AdditionalSpellInfo) { - TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has wrong spell %u defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr))); + TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has wrong spell %lu defined in `auras` field in `creature_addon`.", guid, atoul(*itr)); continue; } - if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) - TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr))); + if (AdditionalSpellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_CONTROL_VEHICLE)) + TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has SPELL_AURA_CONTROL_VEHICLE aura %lu defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr))); + - creatureAddon.auras[i++] = uint32(atol(*itr)); + creatureAddon.auras[i++] = atoul(*itr); } if (creatureAddon.mount) @@ -1222,15 +1242,15 @@ CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32* display return NULL; // If a model for another gender exists, 50% chance to use it - if (modelInfo->modelid_other_gender != 0 && urand(0, 1) == 0) + if (modelInfo->displayId_other_gender != 0 && urand(0, 1) == 0) { - CreatureModelInfo const* minfo_tmp = GetCreatureModelInfo(modelInfo->modelid_other_gender); + CreatureModelInfo const* minfo_tmp = GetCreatureModelInfo(modelInfo->displayId_other_gender); if (!minfo_tmp) - TC_LOG_ERROR("sql.sql", "Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", *displayID, modelInfo->modelid_other_gender); + TC_LOG_ERROR("sql.sql", "Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", *displayID, modelInfo->displayId_other_gender); else { - // Model ID changed - *displayID = modelInfo->modelid_other_gender; + // DisplayID changed + *displayID = modelInfo->displayId_other_gender; return minfo_tmp; } } @@ -1242,7 +1262,7 @@ void ObjectMgr::LoadCreatureModelInfo() { uint32 oldMSTime = getMSTime(); - QueryResult result = WorldDatabase.Query("SELECT modelid, bounding_radius, combat_reach, gender, modelid_other_gender FROM creature_model_info"); + QueryResult result = WorldDatabase.Query("SELECT DisplayID, BoundingRadius, CombatReach, DisplayID_Other_Gender FROM creature_model_info"); if (!result) { @@ -1257,30 +1277,36 @@ void ObjectMgr::LoadCreatureModelInfo() { Field* fields = result->Fetch(); - uint32 modelId = fields[0].GetUInt32(); + uint32 displayId = fields[0].GetUInt32(); + + CreatureDisplayInfoEntry const* creatureDisplay = sCreatureDisplayInfoStore.LookupEntry(displayId); + if (!creatureDisplay) + { + TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has a non-existent DisplayID (ID: %u). Skipped.", displayId); + continue; + } - CreatureModelInfo& modelInfo = _creatureModelStore[modelId]; + CreatureModelInfo& modelInfo = _creatureModelStore[displayId]; - modelInfo.bounding_radius = fields[1].GetFloat(); - modelInfo.combat_reach = fields[2].GetFloat(); - modelInfo.gender = fields[3].GetUInt8(); - modelInfo.modelid_other_gender = fields[4].GetUInt32(); + modelInfo.bounding_radius = fields[1].GetFloat(); + modelInfo.combat_reach = fields[2].GetFloat(); + modelInfo.displayId_other_gender = fields[3].GetUInt32(); + modelInfo.gender = creatureDisplay->Gender; // Checks - if (!sCreatureDisplayInfoStore.LookupEntry(modelId)) - TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has model for nonexistent display id (%u).", modelId); - - if (modelInfo.gender > GENDER_NONE) + // to remove when the purpose of GENDER_UNKNOWN is known + if (modelInfo.gender == GENDER_UNKNOWN) { - TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has wrong gender (%u) for display id (%u).", uint32(modelInfo.gender), modelId); + // We don't need more errors + //TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has an unimplemented Gender (ID: %i) being used by DisplayID (ID: %u). Gender set to GENDER_MALE.", modelInfo.gender, modelId); modelInfo.gender = GENDER_MALE; } - if (modelInfo.modelid_other_gender && !sCreatureDisplayInfoStore.LookupEntry(modelInfo.modelid_other_gender)) + if (modelInfo.displayId_other_gender && !sCreatureDisplayInfoStore.LookupEntry(modelInfo.displayId_other_gender)) { - TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has nonexistent alt.gender model (%u) for existed display id (%u).", modelInfo.modelid_other_gender, modelId); - modelInfo.modelid_other_gender = 0; + TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has a non-existent DisplayID_Other_Gender (ID: %u) being used by DisplayID (ID: %u).", modelInfo.displayId_other_gender, displayId); + modelInfo.displayId_other_gender = 0; } if (modelInfo.combat_reach < 0.1f) @@ -2301,8 +2327,7 @@ void FillItemDamageFields(float* minDamage, float* maxDamage, float* dps, uint32 return; } - if (!store) - return; + ASSERT(store); ItemDamageEntry const* damageInfo = store->LookupEntry(itemLevel); if (!damageInfo) @@ -2492,7 +2517,9 @@ void ObjectMgr::LoadItemTemplates() itemTemplate.SubClass = db2Data->SubClass; itemTemplate.SoundOverrideSubclass = db2Data->SoundOverrideSubclass; itemTemplate.Name1 = sparse->Name->Str[sWorld->GetDefaultDbcLocale()]; - itemTemplate.DisplayInfoID = GetItemDisplayID(db2Data->AppearanceID); + itemTemplate.DisplayInfoID = GetItemDisplayID(db2Data->FileDataID); + itemTemplate.FileDataID = db2Data->FileDataID; + itemTemplate.GroupSoundsID = db2Data->GroupSoundsID; itemTemplate.Quality = sparse->Quality; memcpy(itemTemplate.Flags, sparse->Flags, sizeof(itemTemplate.Flags)); itemTemplate.Unk1 = sparse->Unk1; @@ -2571,6 +2598,7 @@ void ObjectMgr::LoadItemTemplates() itemTemplate.StatScalingFactor = sparse->StatScalingFactor; itemTemplate.CurrencySubstitutionId = sparse->CurrencySubstitutionID; itemTemplate.CurrencySubstitutionCount = sparse->CurrencySubstitutionCount; + itemTemplate.ItemNameDescriptionID = sparse->ItemNameDescriptionID; itemTemplate.ScriptId = 0; itemTemplate.FoodType = 0; itemTemplate.MinMoneyLoot = 0; @@ -2590,7 +2618,7 @@ void ObjectMgr::LoadItemTemplates() continue; ItemTemplate& itemTemplate = itemItr->second; - + ItemEffect effect; effect.SpellID = effectEntry->SpellID; effect.Trigger = effectEntry->Trigger; @@ -3250,7 +3278,6 @@ void ObjectMgr::LoadPlayerInfo() } } - // Load playercreate skills TC_LOG_INFO("server.loading", "Loading Player Create Skill Data..."); { @@ -3325,8 +3352,8 @@ void ObjectMgr::LoadPlayerInfo() } } - // Load playercreate spells - TC_LOG_INFO("server.loading", "Loading Player Create Spell Data..."); + // Load playercreate custom spells + TC_LOG_INFO("server.loading", "Loading Player Create Custom Spell Data..."); { uint32 oldMSTime = getMSTime(); @@ -3334,7 +3361,7 @@ void ObjectMgr::LoadPlayerInfo() if (!result) { - TC_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `playercreateinfo_spell_custom` is empty."); + TC_LOG_ERROR("server.loading", ">> Loaded 0 player create custom spells. DB table `playercreateinfo_spell_custom` is empty."); } else { @@ -3665,8 +3692,8 @@ void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint8 level, uint32& base if (level > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) level = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); - GtOCTBaseHPByClassEntry const* hp = sGtOCTBaseHPByClassStore.LookupEntry((class_-1) * GT_MAX_LEVEL + level-1); - GtOCTBaseMPByClassEntry const* mp = sGtOCTBaseMPByClassStore.LookupEntry((class_-1) * GT_MAX_LEVEL + level-1); + GtOCTBaseHPByClassEntry const* hp = sGtOCTBaseHPByClassStore.EvaluateTable(level - 1, class_ - 1); + GtOCTBaseMPByClassEntry const* mp = sGtOCTBaseMPByClassStore.EvaluateTable(level - 1, class_ - 1); if (!hp || !mp) { @@ -4501,12 +4528,12 @@ void ObjectMgr::LoadQuests() if (!spellInfo) continue; - for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellInfo->Effects[j].Effect != SPELL_EFFECT_QUEST_COMPLETE) + if (!effect || effect->Effect != SPELL_EFFECT_QUEST_COMPLETE) continue; - uint32 quest_id = spellInfo->Effects[j].MiscValue; + uint32 quest_id = effect->MiscValue; Quest const* quest = GetQuestTemplate(quest_id); @@ -4911,7 +4938,8 @@ void ObjectMgr::LoadSpellScripts() uint8 i = (uint8)((uint32(itr->first) >> 24) & 0x000000FF); //check for correct spellEffect - if (!spellInfo->Effects[i].Effect || (spellInfo->Effects[i].Effect != SPELL_EFFECT_SCRIPT_EFFECT && spellInfo->Effects[i].Effect != SPELL_EFFECT_DUMMY)) + SpellEffectInfo const* effect = spellInfo->GetEffect(i); + if (effect && (!effect->Effect || (effect->Effect != SPELL_EFFECT_SCRIPT_EFFECT && effect->Effect != SPELL_EFFECT_DUMMY))) TC_LOG_ERROR("sql.sql", "Table `spell_scripts` - spell %u effect %u is not SPELL_EFFECT_SCRIPT_EFFECT or SPELL_EFFECT_DUMMY", spellId, i); } } @@ -4930,10 +4958,10 @@ void ObjectMgr::LoadEventScripts() // Load all possible script entries from spells for (uint32 i = 1; i < sSpellMgr->GetSpellInfoStoreSize(); ++i) if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(i)) - for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) - if (spell->Effects[j].Effect == SPELL_EFFECT_SEND_EVENT) - if (spell->Effects[j].MiscValue) - evt_scripts.insert(spell->Effects[j].MiscValue); + for (SpellEffectInfo const* effect : spell->GetEffectsForDifficulty(DIFFICULTY_NONE)) + if (effect && effect->Effect == SPELL_EFFECT_SEND_EVENT) + if (effect->MiscValue) + evt_scripts.insert(effect->MiscValue); for (size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx) { @@ -5687,35 +5715,32 @@ void ObjectMgr::LoadAreaTriggerScripts() uint32 oldMSTime = getMSTime(); _areaTriggerScriptStore.clear(); // need for reload case - QueryResult result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts"); + QueryResult result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts"); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 areatrigger scripts. DB table `areatrigger_scripts` is empty."); return; } - uint32 count = 0; - do { - ++count; - Field* fields = result->Fetch(); - uint32 Trigger_ID = fields[0].GetUInt32(); - const char *scriptName = fields[1].GetCString(); + uint32 triggerId = fields[0].GetUInt32(); + char const* scriptName = fields[1].GetCString(); - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(triggerId); if (!atEntry) { - TC_LOG_ERROR("sql.sql", "Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.", Trigger_ID); + TC_LOG_ERROR("sql.sql", "AreaTrigger (ID: %u) does not exist in `AreaTrigger.dbc`.", triggerId); continue; } - _areaTriggerScriptStore[Trigger_ID] = GetScriptId(scriptName); - } while (result->NextRow()); + _areaTriggerScriptStore[triggerId] = GetScriptId(scriptName); + } + while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u areatrigger scripts in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " areatrigger scripts in %u ms", _areaTriggerScriptStore.size(), GetMSTimeDiffToNow(oldMSTime)); } uint32 ObjectMgr::GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team) @@ -8114,25 +8139,25 @@ void ObjectMgr::AddSpellToTrainer(uint32 ID, uint32 SpellID, uint32 MoneyCost, u // calculate learned spell for profession case when stored cast-spell trainerSpell.ReqAbility[0] = SpellID; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellinfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellinfo->Effects[i].Effect != SPELL_EFFECT_LEARN_SPELL) + if (!effect || effect->Effect != SPELL_EFFECT_LEARN_SPELL) continue; if (trainerSpell.ReqAbility[0] == SpellID) trainerSpell.ReqAbility[0] = 0; // player must be able to cast spell on himself - if (spellinfo->Effects[i].TargetA.GetTarget() != 0 && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_TARGET_ALLY - && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_TARGET_ANY && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_CASTER) + if (effect->TargetA.GetTarget() != 0 && effect->TargetA.GetTarget() != TARGET_UNIT_TARGET_ALLY + && effect->TargetA.GetTarget() != TARGET_UNIT_TARGET_ANY && effect->TargetA.GetTarget() != TARGET_UNIT_CASTER) { TC_LOG_ERROR("sql.sql", "Table `npc_trainer` has spell %u for trainer entry %u with learn effect which has incorrect target type, ignoring learn effect!", SpellID, ID); continue; } - trainerSpell.ReqAbility[i] = spellinfo->Effects[i].TriggerSpell; + trainerSpell.ReqAbility[effect->EffectIndex] = effect->TriggerSpell; - if (trainerSpell.ReqAbility[i]) + if (trainerSpell.ReqAbility[effect->EffectIndex]) { - SpellInfo const* learnedSpellInfo = sSpellMgr->GetSpellInfo(trainerSpell.ReqAbility[i]); + SpellInfo const* learnedSpellInfo = sSpellMgr->GetSpellInfo(trainerSpell.ReqAbility[effect->EffectIndex]); if (learnedSpellInfo && learnedSpellInfo->IsProfession()) data.trainerType = 2; } @@ -8529,31 +8554,32 @@ void ObjectMgr::LoadScriptNames() { uint32 oldMSTime = getMSTime(); - _scriptNamesStore.push_back(""); + _scriptNamesStore.emplace_back(""); + QueryResult result = WorldDatabase.Query( - "SELECT DISTINCT(ScriptName) FROM achievement_criteria_data WHERE ScriptName <> '' AND type = 11 " - "UNION " - "SELECT DISTINCT(ScriptName) FROM battleground_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM item_script_names WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM spell_script_names WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM transports WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM game_weather WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM conditions WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM outdoorpvp_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''"); + "SELECT DISTINCT(ScriptName) FROM achievement_criteria_data WHERE ScriptName <> '' AND type = 11 " + "UNION " + "SELECT DISTINCT(ScriptName) FROM battleground_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM item_script_names WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM spell_script_names WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM transports WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM game_weather WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM conditions WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM outdoorpvp_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''"); if (!result) { @@ -8561,20 +8587,23 @@ void ObjectMgr::LoadScriptNames() return; } - uint32 count = 1; - do { - _scriptNamesStore.push_back((*result)[0].GetString()); - ++count; + _scriptNamesStore.emplace_back((*result)[0].GetCString()); } while (result->NextRow()); std::sort(_scriptNamesStore.begin(), _scriptNamesStore.end()); - TC_LOG_INFO("server.loading", ">> Loaded %d Script Names in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + +#ifdef SCRIPTS + for (size_t i = 1; i < _scriptNamesStore.size(); ++i) + UnusedScriptNames.push_back(_scriptNamesStore[i]); +#endif + + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " ScriptNames in %u ms", _scriptNamesStore.size(), GetMSTimeDiffToNow(oldMSTime)); } -uint32 ObjectMgr::GetScriptId(const char *name) +uint32 ObjectMgr::GetScriptId(char const* name) { // use binary search to find the script name in the sorted vector // assume "" is the first element diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index bb392caeffb..14f845dcd1b 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -677,6 +677,15 @@ SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry); bool normalizePlayerName(std::string& name); +struct ExtendedPlayerName +{ + ExtendedPlayerName(std::string const& name, std::string const& realm) : Name(name), Realm(realm) {} + std::string Name; + std::string Realm; +}; + +ExtendedPlayerName ExtractExtendedPlayerName(std::string& name); + struct LanguageDesc { Language lang_id; @@ -1277,9 +1286,8 @@ class ObjectMgr bool IsVendorItemValid(uint32 vendor_entry, uint32 id, int32 maxcount, uint32 ptime, uint32 ExtendedCost, uint8 type, Player* player = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0) const; void LoadScriptNames(); - ScriptNameContainer &GetScriptNames() { return _scriptNamesStore; } - const char * GetScriptName(uint32 id) const { return id < _scriptNamesStore.size() ? _scriptNamesStore[id].c_str() : ""; } - uint32 GetScriptId(const char *name); + char const* GetScriptName(uint32 id) const { return id < _scriptNamesStore.size() ? _scriptNamesStore[id].c_str() : ""; } + uint32 GetScriptId(char const* name); SpellClickInfoMapBounds GetSpellClickInfoMapBounds(uint32 creature_id) const { diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index ae3bef5a8df..b693d2e13ac 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -33,6 +33,7 @@ #include "CreatureAI.h" #include "Spell.h" #include "WorldSession.h" +#include "Packets/ChatPackets.h" class Player; //class Map; @@ -125,11 +126,11 @@ namespace Trinity struct MessageDistDeliverer { WorldObject* i_source; - WorldPacket* i_message; + WorldPacket const* i_message; float i_distSq; uint32 team; Player const* skipped_receiver; - MessageDistDeliverer(WorldObject* src, WorldPacket* msg, float dist, bool own_team_only = false, Player const* skipped = NULL) + MessageDistDeliverer(WorldObject* src, WorldPacket const* msg, float dist, bool own_team_only = false, Player const* skipped = NULL) : i_source(src), i_message(msg), i_distSq(dist * dist) , team(0) , skipped_receiver(skipped) diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index c4e4b6f21ae..9c4a2a5a2d1 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -54,7 +54,7 @@ Loot* Roll::getLoot() } Group::Group() : m_leaderGuid(), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL), -m_dungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL), m_raidDifficulty(RAID_DIFFICULTY_10MAN_NORMAL), +m_dungeonDifficulty(DIFFICULTY_NORMAL), m_raidDifficulty(DIFFICULTY_10_N), m_bgGroup(NULL), m_bfGroup(NULL), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(), m_masterLooterGuid(), m_subGroupsCounts(NULL), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0) { @@ -111,8 +111,8 @@ bool Group::Create(Player* leader) m_looterGuid = leaderGuid; m_masterLooterGuid.Clear(); - m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; - m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; + m_dungeonDifficulty = DIFFICULTY_NORMAL; + m_raidDifficulty = DIFFICULTY_10_N; if (!isBGGroup() && !isBFGroup()) { @@ -182,13 +182,13 @@ void Group::LoadGroupFromDB(Field* fields) uint32 diff = fields[13].GetUInt8(); if (diff >= MAX_DUNGEON_DIFFICULTY) - m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; + m_dungeonDifficulty = DIFFICULTY_NORMAL; else m_dungeonDifficulty = Difficulty(diff); uint32 r_diff = fields[14].GetUInt8(); if (r_diff >= MAX_RAID_DIFFICULTY) - m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; + m_raidDifficulty = DIFFICULTY_10_N; else m_raidDifficulty = Difficulty(r_diff); @@ -1623,7 +1623,7 @@ void Group::UpdatePlayerOutOfRange(Player* player) } } -void Group::BroadcastAddonMessagePacket(WorldPacket* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group /*= -1*/, ObjectGuid ignore /*= ObjectGuid::Empty*/) +void Group::BroadcastAddonMessagePacket(WorldPacket const* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group /*= -1*/, ObjectGuid ignore /*= ObjectGuid::Empty*/) { for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -1638,7 +1638,7 @@ void Group::BroadcastAddonMessagePacket(WorldPacket* packet, const std::string& } } -void Group::BroadcastPacket(WorldPacket* packet, bool ignorePlayersInBGRaid, int group, ObjectGuid ignoredPlayer) +void Group::BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRaid, int group, ObjectGuid ignoredPlayer) { for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -1651,7 +1651,7 @@ void Group::BroadcastPacket(WorldPacket* packet, bool ignorePlayersInBGRaid, int } } -void Group::BroadcastReadyCheck(WorldPacket* packet) +void Group::BroadcastReadyCheck(WorldPacket const* packet) { for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -2008,7 +2008,7 @@ void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo) if (method == INSTANCE_RESET_ALL) { // the "reset all instances" method can only reset normal maps - if (entry->IsRaid() || diff == DUNGEON_DIFFICULTY_HEROIC) + if (entry->IsRaid() || diff == DIFFICULTY_HEROIC) { ++itr; continue; diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 0bdfbf24a71..6216b7323b0 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -288,9 +288,9 @@ class Group worker(itr->GetSource()); } - void BroadcastPacket(WorldPacket* packet, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignoredPlayer = ObjectGuid::Empty); - void BroadcastAddonMessagePacket(WorldPacket* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignore = ObjectGuid::Empty); - void BroadcastReadyCheck(WorldPacket* packet); + void BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignoredPlayer = ObjectGuid::Empty); + void BroadcastAddonMessagePacket(WorldPacket const* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignore = ObjectGuid::Empty); + void BroadcastReadyCheck(WorldPacket const* packet); void OfflineReadyCheck(); /*********************************************************/ diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 4fb361209c1..0b703d4bcb2 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -30,6 +30,7 @@ #include "ScriptMgr.h" #include "SocialMgr.h" #include "Opcodes.h" +#include "ChatPackets.h" #define MAX_GUILD_BANK_TAB_TEXT_LEN 500 #define EMBLEM_PRICE 10 * GOLD @@ -1481,23 +1482,23 @@ void Guild::SendQueryResponse(WorldSession* session) response.GuildGuid = GetGUID(); response.Info.HasValue = true; - response.Info.value.GuildGUID = GetGUID(); - response.Info.value.VirtualRealmAddress = GetVirtualRealmAddress(); + response.Info.Value.GuildGUID = GetGUID(); + response.Info.Value.VirtualRealmAddress = GetVirtualRealmAddress(); - response.Info.value.EmblemStyle = m_emblemInfo.GetStyle(); - response.Info.value.EmblemColor = m_emblemInfo.GetColor(); - response.Info.value.BorderStyle = m_emblemInfo.GetBorderStyle(); - response.Info.value.BorderColor = m_emblemInfo.GetBorderColor(); - response.Info.value.BackgroundColor = m_emblemInfo.GetBackgroundColor(); + response.Info.Value.EmblemStyle = m_emblemInfo.GetStyle(); + response.Info.Value.EmblemColor = m_emblemInfo.GetColor(); + response.Info.Value.BorderStyle = m_emblemInfo.GetBorderStyle(); + response.Info.Value.BorderColor = m_emblemInfo.GetBorderColor(); + response.Info.Value.BackgroundColor = m_emblemInfo.GetBackgroundColor(); for (uint8 i = 0; i < _GetRanksSize(); ++i) { WorldPackets::Guild::QueryGuildInfoResponse::GuildInfo::GuildInfoRank info (m_ranks[i].GetId(), i, m_ranks[i].GetName()); - response.Info.value.Ranks.insert(info); + response.Info.Value.Ranks.insert(info); } - response.Info.value.GuildName = m_name; + response.Info.Value.GuildName = m_name; session->SendPacket(response.Write()); TC_LOG_DEBUG("guild", "SMSG_GUILD_QUERY_RESPONSE [%s]", session->GetPlayerInfo().c_str()); @@ -2593,13 +2594,14 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin { if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { - WorldPacket data; - ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), NULL, msg); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), NULL, msg); + WorldPacket const* data = packet.Write(); for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindConnectedPlayer()) if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID())) - player->GetSession()->SendPacket(&data); + player->GetSession()->SendPacket(data); } } @@ -2607,14 +2609,15 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std:: { if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { - WorldPacket data; - ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, LANG_ADDON, session->GetPlayer(), NULL, msg, 0, "", DEFAULT_LOCALE, prefix); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, LANG_ADDON, session->GetPlayer(), NULL, msg, 0, "", DEFAULT_LOCALE, prefix); + WorldPacket const* data = packet.Write(); for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindPlayer()) if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID()) && player->GetSession()->IsAddonRegistered(prefix)) - player->GetSession()->SendPacket(&data); + player->GetSession()->SendPacket(data); } } diff --git a/src/server/game/Guilds/GuildFinderMgr.cpp b/src/server/game/Guilds/GuildFinderMgr.cpp index 67a00d3dff8..40e2bc1613e 100644 --- a/src/server/game/Guilds/GuildFinderMgr.cpp +++ b/src/server/game/Guilds/GuildFinderMgr.cpp @@ -129,11 +129,11 @@ void GuildFinderMgr::AddMembershipRequest(ObjectGuid const& guildGuid, Membershi // Notify the applicant his submittion has been added if (Player* player = ObjectAccessor::FindPlayer(request.GetPlayerGUID())) - SendMembershipRequestListUpdate(*player); + SendMembershipRequestListUpdate(player); // Notify the guild master and officers the list changed if (Guild* guild = sGuildMgr->GetGuildByGuid(guildGuid)) - SendApplicantListUpdate(*guild); + SendApplicantListUpdate(guild); } void GuildFinderMgr::RemoveAllMembershipRequestsFromPlayer(ObjectGuid const& playerId) @@ -159,7 +159,7 @@ void GuildFinderMgr::RemoveAllMembershipRequestsFromPlayer(ObjectGuid const& pla // Notify the guild master and officers the list changed if (Guild* guild = sGuildMgr->GetGuildByGuid(itr->first)) - SendApplicantListUpdate(*guild); + SendApplicantListUpdate(guild); } } @@ -182,15 +182,15 @@ void GuildFinderMgr::RemoveMembershipRequest(ObjectGuid const& playerId, ObjectG CharacterDatabase.CommitTransaction(trans); - _membershipRequests[guildId].erase(itr); - // Notify the applicant his submittion has been removed if (Player* player = ObjectAccessor::FindPlayer(itr->GetPlayerGUID())) - SendMembershipRequestListUpdate(*player); + SendMembershipRequestListUpdate(player); // Notify the guild master and officers the list changed if (Guild* guild = sGuildMgr->GetGuildByGuid(guildId)) - SendApplicantListUpdate(*guild); + SendApplicantListUpdate(guild); + + _membershipRequests[guildId].erase(itr); } std::list<MembershipRequest> GuildFinderMgr::GetAllMembershipRequestsForPlayer(ObjectGuid const& playerGuid) @@ -302,7 +302,7 @@ void GuildFinderMgr::DeleteGuild(ObjectGuid const& guildId) // Notify the applicant his submition has been removed if (Player* player = ObjectAccessor::FindPlayer(itr->GetPlayerGUID())) - SendMembershipRequestListUpdate(*player); + SendMembershipRequestListUpdate(player); ++itr; } @@ -312,19 +312,19 @@ void GuildFinderMgr::DeleteGuild(ObjectGuid const& guildId) // Notify the guild master the list changed (even if he's not a GM any more, not sure if needed) if (Guild* guild = sGuildMgr->GetGuildByGuid(guildId)) - SendApplicantListUpdate(*guild); + SendApplicantListUpdate(guild); } -void GuildFinderMgr::SendApplicantListUpdate(Guild& guild) +void GuildFinderMgr::SendApplicantListUpdate(Guild* guild) { WorldPacket data(SMSG_LF_GUILD_APPLICANT_LIST_UPDATED, 0); - if (Player* player = ObjectAccessor::FindPlayer(guild.GetLeaderGUID())) + if (Player* player = ObjectAccessor::FindPlayer(guild->GetLeaderGUID())) player->SendDirectMessage(&data); - guild.BroadcastPacketToRank(&data, GR_OFFICER); + guild->BroadcastPacketToRank(&data, GR_OFFICER); } -void GuildFinderMgr::SendMembershipRequestListUpdate(Player& player) +void GuildFinderMgr::SendMembershipRequestListUpdate(Player* player) { WorldPacket data(SMSG_LF_GUILD_APPLICATIONS_LIST_CHANGED, 0); - player.SendDirectMessage(&data); + player->SendDirectMessage(&data); } diff --git a/src/server/game/Guilds/GuildFinderMgr.h b/src/server/game/Guilds/GuildFinderMgr.h index 45228957b55..763d9285b31 100644 --- a/src/server/game/Guilds/GuildFinderMgr.h +++ b/src/server/game/Guilds/GuildFinderMgr.h @@ -262,8 +262,8 @@ class GuildFinderMgr /// Counts the amount of pending membership requests, given the player's db guid. uint8 CountRequestsFromPlayer(ObjectGuid const& playerId); - void SendApplicantListUpdate(Guild& guild); - void SendMembershipRequestListUpdate(Player& player); + static void SendApplicantListUpdate(Guild* guild); + static void SendMembershipRequestListUpdate(Player* player); static GuildFinderMgr* instance() { diff --git a/src/server/game/Handlers/AuthHandler.cpp b/src/server/game/Handlers/AuthHandler.cpp index c9e1e6508b9..d8b8f4fe018 100644 --- a/src/server/game/Handlers/AuthHandler.cpp +++ b/src/server/game/Handlers/AuthHandler.cpp @@ -27,20 +27,20 @@ void WorldSession::SendAuthResponse(uint8 code, bool queued, uint32 queuePos) response.SuccessInfo.HasValue = code == AUTH_OK; response.Result = code; response.WaitInfo.HasValue = queued; - response.WaitInfo.value.WaitCount = queuePos; + response.WaitInfo.Value.WaitCount = queuePos; if (code == AUTH_OK) { - response.SuccessInfo.value.AccountExpansionLevel = Expansion(); - response.SuccessInfo.value.ActiveExpansionLevel = Expansion(); - response.SuccessInfo.value.VirtualRealmAddress = GetVirtualRealmAddress(); + response.SuccessInfo.Value.AccountExpansionLevel = Expansion(); + response.SuccessInfo.Value.ActiveExpansionLevel = Expansion(); + response.SuccessInfo.Value.VirtualRealmAddress = GetVirtualRealmAddress(); std::string realmName = sObjectMgr->GetRealmName(realmHandle.Index); // Send current home realm. Also there is no need to send it later in realm queries. - response.SuccessInfo.value.VirtualRealms.emplace_back(GetVirtualRealmAddress(), true, false, realmName, realmName); + response.SuccessInfo.Value.VirtualRealms.emplace_back(GetVirtualRealmAddress(), true, false, realmName, realmName); - response.SuccessInfo.value.AvailableClasses = &sObjectMgr->GetClassExpansionRequirements(); - response.SuccessInfo.value.AvailableRaces = &sObjectMgr->GetRaceExpansionRequirements(); + response.SuccessInfo.Value.AvailableClasses = &sObjectMgr->GetClassExpansionRequirements(); + response.SuccessInfo.Value.AvailableRaces = &sObjectMgr->GetRaceExpansionRequirements(); } SendPacket(response.Write()); @@ -60,7 +60,7 @@ void WorldSession::SendAuthWaitQue(uint32 position) { response.WaitInfo.HasValue = true; response.SuccessInfo.HasValue = false; - response.WaitInfo.value.WaitCount = position; + response.WaitInfo.Value.WaitCount = position; response.Result = AUTH_WAIT_QUEUE; } diff --git a/src/server/game/Handlers/BattlefieldHandler.cpp b/src/server/game/Handlers/BattlefieldHandler.cpp index 649e5ff171f..14928e1efdc 100644 --- a/src/server/game/Handlers/BattlefieldHandler.cpp +++ b/src/server/game/Handlers/BattlefieldHandler.cpp @@ -27,7 +27,7 @@ #include "BattlefieldMgr.h" /** - * @fn void WorldSession::SendBfInvitePlayerToWar(uint64 guid, uint32 zoneId, uint32 acceptTime) + * @fn void WorldSession::SendBfInvitePlayerToWar(ObjectGuid guid, uint32 zoneId, uint32 acceptTime) * * @brief This send to player windows for invite player to join the war. * @@ -62,7 +62,7 @@ void WorldSession::SendBfInvitePlayerToWar(ObjectGuid guid, uint32 zoneId, uint3 } /** - * @fn void WorldSession::SendBfInvitePlayerToQueue(uint64 guid) + * @fn void WorldSession::SendBfInvitePlayerToQueue(ObjectGuid guid) * * @brief This send invitation to player to join the queue. * @@ -103,7 +103,7 @@ void WorldSession::SendBfInvitePlayerToQueue(ObjectGuid guid) } /** - * @fn void WorldSession::SendBfQueueInviteResponse(uint64 guid, uint32 zoneId, bool canQueue, bool full) + * @fn void WorldSession::SendBfQueueInviteResponse(ObjectGuid guid, uint32 zoneId, bool canQueue, bool full) * * @brief This send packet for inform player that he join queue. * @@ -157,7 +157,7 @@ void WorldSession::SendBfQueueInviteResponse(ObjectGuid guid, uint32 zoneId, boo } /** - * @fn void WorldSession::SendBfEntered(uint64 guid) + * @fn void WorldSession::SendBfEntered(ObjectGuid guid) * * @brief This is call when player accept to join war. * @@ -196,7 +196,7 @@ void WorldSession::SendBfEntered(ObjectGuid guid) } /** - * @fn void WorldSession::SendBfLeaveMessage(uint64 guid, BFLeaveReason reason) + * @fn void WorldSession::SendBfLeaveMessage(ObjectGuid guid, BFLeaveReason reason) * * @brief This is call when player leave battlefield zone. * diff --git a/src/server/game/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp index 5826415a201..c6cd5337c5b 100644 --- a/src/server/game/Handlers/ChannelHandler.cpp +++ b/src/server/game/Handlers/ChannelHandler.cpp @@ -18,31 +18,20 @@ #include "ObjectMgr.h" // for normalizePlayerName #include "ChannelMgr.h" +#include "ChannelPackets.h" #include "Player.h" #include "WorldSession.h" #include <cctype> -void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) +void WorldSession::HandleJoinChannel(WorldPackets::Channel::JoinChannel& packet) { - uint32 channelId; - uint32 channelLength, passLength; - std::string channelName, password; + TC_LOG_DEBUG("chat.system", "CMSG_JOIN_CHANNEL %s ChatChannelId: %u, CreateVoiceSession: %u, Internal: %u, ChannelName: %s, Password: %s", + GetPlayerInfo().c_str(), packet.ChatChannelId, packet.CreateVoiceSession, packet.Internal, packet.ChannelName.c_str(), packet.Password.c_str()); - recvPacket >> channelId; - uint8 unknown1 = recvPacket.ReadBit(); // unknowns - uint8 unknown2 = recvPacket.ReadBit(); - channelLength = recvPacket.ReadBits(8); - passLength = recvPacket.ReadBits(8); - channelName = recvPacket.ReadString(channelLength); - password = recvPacket.ReadString(passLength); - - TC_LOG_DEBUG("chat.system", "CMSG_JOIN_CHANNEL %s Channel: %u, unk1: %u, unk2: %u, channel: %s, password: %s", - GetPlayerInfo().c_str(), channelId, unknown1, unknown2, channelName.c_str(), password.c_str()); - - if (channelId) + if (packet.ChatChannelId) { - ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(channelId); + ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(packet.ChatChannelId); if (!channel) return; @@ -51,53 +40,43 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) return; } - if (channelName.empty()) + if (packet.ChannelName.empty()) return; - if (isdigit(channelName[0])) + if (isdigit(packet.ChannelName[0])) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) { - cMgr->setTeam(GetPlayer()->GetTeam()); - if (Channel* channel = cMgr->GetJoinChannel(channelName, channelId)) - channel->JoinChannel(GetPlayer(), password); + cMgr->SetTeam(GetPlayer()->GetTeam()); + if (Channel* channel = cMgr->GetJoinChannel(packet.ChannelName, packet.ChatChannelId)) + channel->JoinChannel(GetPlayer(), packet.Password); } } -void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket) +void WorldSession::HandleLeaveChannel(WorldPackets::Channel::LeaveChannel& packet) { - uint32 unk; - std::string channelName; - recvPacket >> unk; // channel id? - uint32 length = recvPacket.ReadBits(8); - channelName = recvPacket.ReadString(length); + TC_LOG_DEBUG("chat.system", "CMSG_LEAVE_CHANNEL %s ChannelName: %s, ZoneChannelID: %u", + GetPlayerInfo().c_str(), packet.ChannelName.c_str(), packet.ZoneChannelID); - TC_LOG_DEBUG("chat.system", "CMSG_LEAVE_CHANNEL %s Channel: %s, unk1: %u", - GetPlayerInfo().c_str(), channelName.c_str(), unk); - - if (channelName.empty()) + if (packet.ChannelName.empty()) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) { - if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) + if (Channel* channel = cMgr->GetChannel(packet.ChannelName, GetPlayer())) channel->LeaveChannel(GetPlayer(), true); - cMgr->LeftChannel(channelName); + cMgr->LeftChannel(packet.ChannelName); } } -void WorldSession::HandleChannelList(WorldPacket& recvPacket) +void WorldSession::HandleChannelList(WorldPackets::Channel::ChannelListRequest& packet) { - uint32 length = recvPacket.ReadBits(8); - std::string channelName = recvPacket.ReadString(length); - - TC_LOG_DEBUG("chat.system", "%s %s Channel: %s", - recvPacket.GetOpcode() == CMSG_CHANNEL_DISPLAY_LIST ? "CMSG_CHANNEL_DISPLAY_LIST" : "CMSG_CHANNEL_LIST", - GetPlayerInfo().c_str(), channelName.c_str()); + TC_LOG_DEBUG("chat.system", "%s %s ChannelName: %s", + GetOpcodeNameForLogging(packet.GetOpcode()).c_str(), GetPlayerInfo().c_str(), packet.ChannelName.c_str()); - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) - if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) + if (Channel* channel = cMgr->GetChannel(packet.ChannelName, GetPlayer())) channel->List(GetPlayer()); } @@ -115,7 +94,7 @@ void WorldSession::HandleChannelPassword(WorldPacket& recvPacket) if (password.length() > MAX_CHANNEL_PASS_STR) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->Password(GetPlayer(), password); } @@ -134,7 +113,7 @@ void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->SetOwner(GetPlayer(), targetName); } @@ -147,9 +126,9 @@ void WorldSession::HandleChannelOwner(WorldPacket& recvPacket) TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_OWNER %s Channel: %s", GetPlayerInfo().c_str(), channelName.c_str()); - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) - channel->SendWhoOwner(GetPlayer()->GetGUID()); + channel->SendWhoOwner(GetPlayer()); } void WorldSession::HandleChannelModerator(WorldPacket& recvPacket) @@ -166,7 +145,7 @@ void WorldSession::HandleChannelModerator(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->SetModerator(GetPlayer(), targetName); } @@ -185,7 +164,7 @@ void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->UnsetModerator(GetPlayer(), targetName); } @@ -204,7 +183,7 @@ void WorldSession::HandleChannelMute(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->SetMute(GetPlayer(), targetName); } @@ -223,7 +202,7 @@ void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->UnsetMute(GetPlayer(), targetName); } @@ -242,7 +221,7 @@ void WorldSession::HandleChannelInvite(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->Invite(GetPlayer(), targetName); } @@ -261,7 +240,7 @@ void WorldSession::HandleChannelKick(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->Kick(GetPlayer(), targetName); } @@ -283,7 +262,7 @@ void WorldSession::HandleChannelBan(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->Ban(GetPlayer(), targetName); } @@ -302,7 +281,7 @@ void WorldSession::HandleChannelUnban(WorldPacket& recvPacket) if (!normalizePlayerName(targetName)) return; - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->UnBan(GetPlayer(), targetName); } @@ -315,17 +294,11 @@ void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket) TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_ANNOUNCEMENTS %s Channel: %s", GetPlayerInfo().c_str(), channelName.c_str()); - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) channel->Announce(GetPlayer()); } -void WorldSession::HandleChannelDisplayListQuery(WorldPacket &recvPacket) -{ - // this should be OK because the 2 function _were_ the same - HandleChannelList(recvPacket); -} - void WorldSession::HandleGetChannelMemberCount(WorldPacket &recvPacket) { std::string channelName; @@ -334,7 +307,7 @@ void WorldSession::HandleGetChannelMemberCount(WorldPacket &recvPacket) TC_LOG_DEBUG("chat.system", "CMSG_GET_CHANNEL_MEMBER_COUNT %s Channel: %s", GetPlayerInfo().c_str(), channelName.c_str()); - if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetPlayer()->GetTeam())) { if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer())) { diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index a2e6f4b0340..de7d44bdc69 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -29,6 +29,7 @@ #include "ClientConfigPackets.h" #include "Common.h" #include "DatabaseEnv.h" +#include "EquipmentSetPackets.h" #include "Group.h" #include "Guild.h" #include "GuildFinderMgr.h" @@ -36,6 +37,7 @@ #include "Language.h" #include "LFGMgr.h" #include "Log.h" +#include "MiscPackets.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -835,6 +837,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) return; } + SendTutorialsData(); + pCurrChar->GetMotionMaster()->Initialize(); pCurrChar->SendDungeonDifficulty(false); @@ -857,6 +861,16 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) /// Send FeatureSystemStatus { WorldPackets::System::FeatureSystemStatus features; + + /// START OF DUMMY VALUES + features.ComplaintStatus = 2; + features.ScrollOfResurrectionRequestsRemaining = 1; + features.ScrollOfResurrectionMaxRequestsPerDay = 1; + features.CfgRealmID = 2; + features.CfgRealmRecID = 0; + features.VoiceEnabled = true; + /// END OF DUMMY VALUES + features.CharUndeleteEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED); features.BpayStoreEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED); @@ -1096,32 +1110,35 @@ void WorldSession::HandleSetFactionCheat(WorldPacket& /*recvData*/) GetPlayer()->GetReputationMgr().SendStates(); } -void WorldSession::HandleTutorialFlag(WorldPacket& recvData) -{ - uint32 data; - recvData >> data; - - uint8 index = uint8(data / 32); - if (index >= MAX_ACCOUNT_TUTORIAL_VALUES) - return; - - uint32 value = (data % 32); - - uint32 flag = GetTutorialInt(index); - flag |= (1 << value); - SetTutorialInt(index, flag); -} - -void WorldSession::HandleTutorialClear(WorldPacket& /*recvData*/) -{ - for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) - SetTutorialInt(i, 0xFFFFFFFF); -} - -void WorldSession::HandleTutorialReset(WorldPacket& /*recvData*/) +void WorldSession::HandleTutorialFlag(WorldPackets::Misc::TutorialSetFlag& packet) { - for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) - SetTutorialInt(i, 0x00000000); + switch (packet.Action) + { + case TUTORIAL_ACTION_UPDATE: + { + uint8 index = uint8(packet.TutorialBit >> 5); + if (index >= MAX_ACCOUNT_TUTORIAL_VALUES) + { + TC_LOG_ERROR("network", "CMSG_TUTORIAL_FLAG received bad TutorialBit %u.", packet.TutorialBit); + return; + } + uint32 flag = GetTutorialInt(index); + flag |= (1 << (packet.TutorialBit & 0x1F)); + SetTutorialInt(index, flag); + break; + } + case TUTORIAL_ACTION_CLEAR: + for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) + SetTutorialInt(i, 0xFFFFFFFF); + break; + case TUTORIAL_ACTION_RESET: + for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) + SetTutorialInt(i, 0x00000000); + break; + default: + TC_LOG_ERROR("network", "CMSG_TUTORIAL_FLAG received unknown TutorialAction %u.", packet.Action); + return; + } } void WorldSession::HandleSetWatchedFactionOpcode(WorldPacket& recvData) @@ -1525,59 +1542,36 @@ void WorldSession::HandleCharCustomizeCallback(PreparedQueryResult result, World GetAccountId(), GetRemoteAddress().c_str(), oldName.c_str(), customizeInfo->CharGUID.ToString().c_str(), customizeInfo->CharName.c_str()); } -void WorldSession::HandleEquipmentSetSave(WorldPacket& recvData) +void WorldSession::HandleEquipmentSetSave(WorldPackets::EquipmentSet::SaveEquipmentSet& packet) { TC_LOG_DEBUG("network", "CMSG_EQUIPMENT_SET_SAVE"); - uint64 setGuid; - recvData.ReadPackedUInt64(setGuid); - - uint32 index; - recvData >> index; - if (index >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount + if (packet.Set.SetID >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount return; - std::string name; - recvData >> name; - - std::string iconName; - recvData >> iconName; - - EquipmentSet eqSet; - - eqSet.Guid = setGuid; - eqSet.Name = name; - eqSet.IconName = iconName; - eqSet.state = EQUIPMENT_SET_NEW; - - ObjectGuid ignoredItemGuid; - ignoredItemGuid.SetRawValue(0, 1); - - for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) { - ObjectGuid itemGuid; - recvData >> itemGuid.ReadAsPacked(); - - // equipment manager sends "1" (as raw GUID) for slots set to "ignore" (don't touch slot at equip set) - if (itemGuid == ignoredItemGuid) + if (!(packet.Set.IgnoreMask & (1 << i))) { - // ignored slots saved as bit mask because we have no free special values for Items[i] - eqSet.IgnoreMask |= 1 << i; - continue; - } - - Item* item = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + ObjectGuid const& itemGuid = packet.Set.Pieces[i]; - if (!item && !itemGuid.IsEmpty()) // cheating check 1 - return; + Item* item = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (item && item->GetGUID() != itemGuid) // cheating check 2 - return; + /// cheating check 1 (item equipped but sent empty guid) + if (!item && !itemGuid.IsEmpty()) + return; - eqSet.Items[i] = itemGuid.GetCounter(); + /// cheating check 2 (sent guid does not match equipped item) + if (item && item->GetGUID() != itemGuid) + return; + } + else + packet.Set.Pieces[i].Clear(); } - _player->SetEquipmentSet(index, eqSet); + packet.Set.IgnoreMask &= 0x7FFFF; /// clear invalid bits (i > EQUIPMENT_SLOT_END) + + _player->SetEquipmentSet(std::move(packet.Set)); } void WorldSession::HandleEquipmentSetDelete(WorldPacket& recvData) @@ -1799,7 +1793,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res if (factionChangeInfo->SkinID.HasValue) { playerBytes &= ~uint32(0xFF); - playerBytes |= factionChangeInfo->SkinID.value; + playerBytes |= factionChangeInfo->SkinID.Value; } else factionChangeInfo->SkinID.Set(uint8(playerBytes & 0xFF)); @@ -1807,7 +1801,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res if (factionChangeInfo->FaceID.HasValue) { playerBytes &= ~(uint32(0xFF) << 8); - playerBytes |= uint32(factionChangeInfo->FaceID.value) << 8; + playerBytes |= uint32(factionChangeInfo->FaceID.Value) << 8; } else factionChangeInfo->FaceID.Set(uint8((playerBytes2 >> 8) & 0xFF)); @@ -1815,7 +1809,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res if (factionChangeInfo->HairStyleID.HasValue) { playerBytes &= ~(uint32(0xFF) << 16); - playerBytes |= uint32(factionChangeInfo->HairStyleID.value) << 16; + playerBytes |= uint32(factionChangeInfo->HairStyleID.Value) << 16; } else factionChangeInfo->HairStyleID.Set(uint8((playerBytes2 >> 16) & 0xFF)); @@ -1823,7 +1817,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res if (factionChangeInfo->HairColorID.HasValue) { playerBytes &= ~(uint32(0xFF) << 24); - playerBytes |= uint32(factionChangeInfo->HairColorID.value) << 24; + playerBytes |= uint32(factionChangeInfo->HairColorID.Value) << 24; } else factionChangeInfo->HairColorID.Set(uint8((playerBytes2 >> 24) & 0xFF)); @@ -1831,7 +1825,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res if (factionChangeInfo->FacialHairStyleID.HasValue) { playerBytes2 &= ~0xFF; - playerBytes2 |= factionChangeInfo->FacialHairStyleID.value; + playerBytes2 |= factionChangeInfo->FacialHairStyleID.Value; } else factionChangeInfo->FacialHairStyleID.Set(uint8(playerBytes2 & 0xFF)); @@ -2181,7 +2175,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res } for (uint32 index = 0; index < ktcount; ++index) - knownTitles[index] = atol(tokens[index]); + knownTitles[index] = atoul(tokens[index]); for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeTitles.begin(); it != sObjectMgr->FactionChangeTitles.end(); ++it) { @@ -2526,14 +2520,14 @@ void WorldSession::SendCharFactionChange(ResponseCodes result, WorldPackets::Cha if (result == RESPONSE_SUCCESS) { packet.Display.HasValue = true; - packet.Display.value.Name = factionChangeInfo->Name; - packet.Display.value.SexID = factionChangeInfo->SexID; - packet.Display.value.SkinID = factionChangeInfo->SkinID.value; - packet.Display.value.HairColorID = factionChangeInfo->HairColorID.value; - packet.Display.value.HairStyleID = factionChangeInfo->HairStyleID.value; - packet.Display.value.FacialHairStyleID = factionChangeInfo->FacialHairStyleID.value; - packet.Display.value.FaceID = factionChangeInfo->FaceID.value; - packet.Display.value.RaceID = factionChangeInfo->RaceID; + packet.Display.Value.Name = factionChangeInfo->Name; + packet.Display.Value.SexID = factionChangeInfo->SexID; + packet.Display.Value.SkinID = factionChangeInfo->SkinID.Value; + packet.Display.Value.HairColorID = factionChangeInfo->HairColorID.Value; + packet.Display.Value.HairStyleID = factionChangeInfo->HairStyleID.Value; + packet.Display.Value.FacialHairStyleID = factionChangeInfo->FacialHairStyleID.Value; + packet.Display.Value.FaceID = factionChangeInfo->FaceID.Value; + packet.Display.Value.RaceID = factionChangeInfo->RaceID; } SendPacket(packet.Write()); diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index a2fc248bb61..81248519994 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -39,261 +39,165 @@ #include "Util.h" #include "ScriptMgr.h" #include "AccountMgr.h" +#include "ChatPackets.h" -void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) +void WorldSession::HandleChatMessageOpcode(WorldPackets::Chat::ChatMessage& packet) { - uint32 type = 0; - uint32 lang; + ChatMsg type; - switch (recvData.GetOpcode()) + switch (packet.GetOpcode()) { - /* case CMSG_MESSAGECHAT_SAY: type = CHAT_MSG_SAY; break; case CMSG_MESSAGECHAT_YELL: type = CHAT_MSG_YELL; break; - case CMSG_MESSAGECHAT_CHANNEL: - type = CHAT_MSG_CHANNEL; - break; - case CMSG_MESSAGECHAT_WHISPER: - type = CHAT_MSG_WHISPER; - break; case CMSG_MESSAGECHAT_GUILD: type = CHAT_MSG_GUILD; break; case CMSG_MESSAGECHAT_OFFICER: type = CHAT_MSG_OFFICER; break; - case CMSG_MESSAGECHAT_AFK: - type = CHAT_MSG_AFK; - break; - case CMSG_MESSAGECHAT_DND: - type = CHAT_MSG_DND; - break; - case CMSG_MESSAGECHAT_EMOTE: - type = CHAT_MSG_EMOTE; - break; case CMSG_MESSAGECHAT_PARTY: type = CHAT_MSG_PARTY; break; case CMSG_MESSAGECHAT_RAID: type = CHAT_MSG_RAID; break; - case CMSG_MESSAGECHAT_BATTLEGROUND: - type = CHAT_MSG_BATTLEGROUND; - break; case CMSG_MESSAGECHAT_RAID_WARNING: type = CHAT_MSG_RAID_WARNING; break; - */ default: - TC_LOG_ERROR("network", "HandleMessagechatOpcode : Unknown chat opcode (%u)", recvData.GetOpcode()); - recvData.hexlike(); + TC_LOG_ERROR("network", "HandleMessagechatOpcode : Unknown chat opcode (%u)", packet.GetOpcode()); return; } - if (type >= MAX_CHAT_MSG_TYPE) - { - TC_LOG_ERROR("network", "CHAT: Wrong message type received: %u", type); - recvData.rfinish(); - return; - } + HandleChatMessage(type, packet.Language, packet.Text); +} + +void WorldSession::HandleChatMessageWhisperOpcode(WorldPackets::Chat::ChatMessageWhisper& packet) +{ + HandleChatMessage(CHAT_MSG_WHISPER, packet.Language, packet.Text, packet.Target); +} +void WorldSession::HandleChatMessageChannelOpcode(WorldPackets::Chat::ChatMessageChannel& packet) +{ + HandleChatMessage(CHAT_MSG_CHANNEL, packet.Language, packet.Text, packet.Target); +} + +void WorldSession::HandleChatMessageEmoteOpcode(WorldPackets::Chat::ChatMessageEmote& packet) +{ + HandleChatMessage(CHAT_MSG_EMOTE, LANG_UNIVERSAL, packet.Text); +} + +void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, std::string target /*= ""*/) +{ Player* sender = GetPlayer(); - //TC_LOG_DEBUG("misc", "CHAT: packet received. type %u, lang %u", type, lang); + if (lang == LANG_UNIVERSAL && type != CHAT_MSG_EMOTE) + { + TC_LOG_ERROR("network", "CMSG_MESSAGECHAT: Possible hacking-attempt: %s tried to send a message in universal language", GetPlayerInfo().c_str()); + SendNotification(LANG_UNKNOWN_LANGUAGE); + return; + } - // no language sent with emote packet. - if (type != CHAT_MSG_EMOTE && type != CHAT_MSG_AFK && type != CHAT_MSG_DND) + // prevent talking at unknown language (cheating) + LanguageDesc const* langDesc = GetLanguageDescByID(lang); + if (!langDesc) { - recvData >> lang; + SendNotification(LANG_UNKNOWN_LANGUAGE); + return; + } - if (lang == LANG_UNIVERSAL) + if (langDesc->skill_id != 0 && !sender->HasSkill(langDesc->skill_id)) + { + // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) + Unit::AuraEffectList const& langAuras = sender->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); + bool foundAura = false; + for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) { - TC_LOG_ERROR("network", "CMSG_MESSAGECHAT: Possible hacking-attempt: %s tried to send a message in universal language", GetPlayerInfo().c_str()); - SendNotification(LANG_UNKNOWN_LANGUAGE); - recvData.rfinish(); - return; + if ((*i)->GetMiscValue() == int32(lang)) + { + foundAura = true; + break; + } } - - // prevent talking at unknown language (cheating) - LanguageDesc const* langDesc = GetLanguageDescByID(lang); - if (!langDesc) + if (!foundAura) { - SendNotification(LANG_UNKNOWN_LANGUAGE); - recvData.rfinish(); + SendNotification(LANG_NOT_LEARNED_LANGUAGE); return; } + } - if (langDesc->skill_id != 0 && !sender->HasSkill(langDesc->skill_id)) - { - // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) - Unit::AuraEffectList const& langAuras = sender->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); - bool foundAura = false; - for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) - { - if ((*i)->GetMiscValue() == int32(lang)) - { - foundAura = true; - break; - } - } - if (!foundAura) - { - SendNotification(LANG_NOT_LEARNED_LANGUAGE); - recvData.rfinish(); - return; - } - } - - if (lang == LANG_ADDON) + // send in universal language if player in .gm on mode (ignore spell effects) + if (sender->IsGameMaster()) + lang = LANG_UNIVERSAL; + else + { + // send in universal language in two side iteration allowed mode + if (HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)) + lang = LANG_UNIVERSAL; + else { - // LANG_ADDON is only valid for the following message types switch (type) { case CHAT_MSG_PARTY: case CHAT_MSG_RAID: + case CHAT_MSG_RAID_WARNING: + // allow two side chat at group channel if two side group allowed + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) + lang = LANG_UNIVERSAL; + break; case CHAT_MSG_GUILD: - case CHAT_MSG_BATTLEGROUND: - case CHAT_MSG_WHISPER: - // check if addon messages are disabled - if (!sWorld->getBoolConfig(CONFIG_ADDON_CHANNEL)) - { - recvData.rfinish(); - return; - } + case CHAT_MSG_OFFICER: + // allow two side chat at guild channel if two side guild allowed + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) + lang = LANG_UNIVERSAL; break; default: - TC_LOG_ERROR("network", "Player %s (%s) sent a chatmessage with an invalid language/message type combination", - GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); - - recvData.rfinish(); - return; + break; } } - // LANG_ADDON should not be changed nor be affected by flood control - else - { - // send in universal language if player in .gm on mode (ignore spell effects) - if (sender->IsGameMaster()) - lang = LANG_UNIVERSAL; - else - { - // send in universal language in two side iteration allowed mode - if (HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)) - lang = LANG_UNIVERSAL; - else - { - switch (type) - { - case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: - case CHAT_MSG_RAID: - case CHAT_MSG_RAID_LEADER: - case CHAT_MSG_RAID_WARNING: - // allow two side chat at group channel if two side group allowed - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) - lang = LANG_UNIVERSAL; - break; - case CHAT_MSG_GUILD: - case CHAT_MSG_OFFICER: - // allow two side chat at guild channel if two side guild allowed - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) - lang = LANG_UNIVERSAL; - break; - } - } - - // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used) - Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); - if (!ModLangAuras.empty()) - lang = ModLangAuras.front()->GetMiscValue(); - } - if (!sender->CanSpeak()) - { - std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); - SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); - recvData.rfinish(); // Prevent warnings - return; - } - } + // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used) + Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); + if (!ModLangAuras.empty()) + lang = ModLangAuras.front()->GetMiscValue(); } - else - lang = LANG_UNIVERSAL; - if (sender->HasAura(1852) && type != CHAT_MSG_WHISPER) + if (!sender->CanSpeak()) { - SendNotification(GetTrinityString(LANG_GM_SILENCE), sender->GetName().c_str()); - recvData.rfinish(); + std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); + SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); return; } - uint32 textLength = 0; - uint32 receiverLength = 0; - std::string to, channel, msg; - bool ignoreChecks = false; - switch (type) + if (sender->HasAura(GM_SILENCE_AURA) && type != CHAT_MSG_WHISPER) { - case CHAT_MSG_SAY: - case CHAT_MSG_EMOTE: - case CHAT_MSG_YELL: - case CHAT_MSG_PARTY: - case CHAT_MSG_GUILD: - case CHAT_MSG_OFFICER: - case CHAT_MSG_RAID: - case CHAT_MSG_RAID_WARNING: - case CHAT_MSG_BATTLEGROUND: - textLength = recvData.ReadBits(9); - msg = recvData.ReadString(textLength); - break; - case CHAT_MSG_WHISPER: - receiverLength = recvData.ReadBits(10); - textLength = recvData.ReadBits(9); - to = recvData.ReadString(receiverLength); - msg = recvData.ReadString(textLength); - break; - case CHAT_MSG_CHANNEL: - receiverLength = recvData.ReadBits(10); - textLength = recvData.ReadBits(9); - msg = recvData.ReadString(textLength); - channel = recvData.ReadString(receiverLength); - break; - case CHAT_MSG_AFK: - case CHAT_MSG_DND: - textLength = recvData.ReadBits(9); - msg = recvData.ReadString(textLength); - ignoreChecks = true; - break; + SendNotification(GetTrinityString(LANG_GM_SILENCE), sender->GetName().c_str()); + return; } - if (!ignoreChecks) - { - if (msg.empty()) - return; + if (msg.empty()) + return; - if (ChatHandler(this).ParseCommands(msg.c_str())) - return; + if (ChatHandler(this).ParseCommands(msg.c_str())) + return; - if (lang != LANG_ADDON) - { - // Strip invisible characters for non-addon messages - if (sWorld->getBoolConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + // Strip invisible characters for non-addon messages + if (sWorld->getBoolConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) + stripLineInvisibleChars(msg); - if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && !ChatHandler(this).isValidChatMessage(msg.c_str())) - { - TC_LOG_ERROR("network", "Player %s (%s) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName().c_str(), - GetPlayer()->GetGUID().ToString().c_str(), msg.c_str()); + if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && !ChatHandler(this).isValidChatMessage(msg.c_str())) + { + TC_LOG_ERROR("network", "Player %s (%s) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName().c_str(), + GetPlayer()->GetGUID().ToString().c_str(), msg.c_str()); - if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) - KickPlayer(); + if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) + KickPlayer(); - return; - } - } + return; } switch (type) @@ -322,16 +226,19 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } case CHAT_MSG_WHISPER: { - if (!normalizePlayerName(to)) + /// @todo implement cross realm whispers (someday) + ExtendedPlayerName extName = ExtractExtendedPlayerName(target); + + if (!normalizePlayerName(extName.Name)) { - SendPlayerNotFoundNotice(to); + SendPlayerNotFoundNotice(target); break; } - Player* receiver = ObjectAccessor::FindConnectedPlayerByName(to); + Player* receiver = ObjectAccessor::FindConnectedPlayerByName(extName.Name); if (!receiver || (lang != LANG_ADDON && !receiver->isAcceptWhispers() && receiver->GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS) && !receiver->IsInWhisperWhiteList(sender->GetGUID()))) { - SendPlayerNotFoundNotice(to); + SendPlayerNotFoundNotice(target); return; } if (!sender->IsGameMaster() && sender->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) && !receiver->IsInWhisperWhiteList(sender->GetGUID())) @@ -362,7 +269,6 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) break; } case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: { // if player is in battleground, he cannot say to battleground members by /p Group* group = GetPlayer()->GetOriginalGroup(); @@ -378,9 +284,9 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - WorldPacket data; - ChatHandler::BuildChatPacket(data, ChatMsg(type), Language(lang), sender, NULL, msg); - group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID())); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, ChatMsg(type), Language(lang), sender, NULL, msg); + group->BroadcastPacket(packet.Write(), false, group->GetMemberGroup(GetPlayer()->GetGUID())); break; } case CHAT_MSG_GUILD: @@ -410,25 +316,19 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) break; } case CHAT_MSG_RAID: - case CHAT_MSG_RAID_LEADER: { - // if player is in battleground, he cannot say to battleground members by /ra Group* group = GetPlayer()->GetOriginalGroup(); if (!group) - { - group = GetPlayer()->GetGroup(); - if (!group || group->isBGGroup() || !group->isRaidGroup()) - return; - } + return; if (group->IsLeader(GetPlayer()->GetGUID())) type = CHAT_MSG_RAID_LEADER; sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - WorldPacket data; - ChatHandler::BuildChatPacket(data, ChatMsg(type), Language(lang), sender, NULL, msg); - group->BroadcastPacket(&data, false); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, ChatMsg(type), Language(lang), sender, NULL, msg); + group->BroadcastPacket(packet.Write(), false); break; } case CHAT_MSG_RAID_WARNING: @@ -439,28 +339,10 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - WorldPacket data; + WorldPackets::Chat::Chat packet; //in battleground, raid warning is sent only to players in battleground - code is ok - ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_WARNING, Language(lang), sender, NULL, msg); - group->BroadcastPacket(&data, false); - break; - } - case CHAT_MSG_BATTLEGROUND: - case CHAT_MSG_BATTLEGROUND_LEADER: - { - // battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() - Group* group = GetPlayer()->GetGroup(); - if (!group || !group->isBGGroup()) - return; - - if (group->IsLeader(GetPlayer()->GetGUID())) - type = CHAT_MSG_BATTLEGROUND_LEADER; - - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - ChatHandler::BuildChatPacket(data, ChatMsg(type), Language(lang), sender, NULL, msg); - group->BroadcastPacket(&data, false); + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_RAID_WARNING, Language(lang), sender, NULL, msg); + group->BroadcastPacket(packet.Write(), false); break; } case CHAT_MSG_CHANNEL: @@ -474,9 +356,9 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } } - if (ChannelMgr* cMgr = ChannelMgr::forTeam(sender->GetTeam())) + if (ChannelMgr* cMgr = ChannelMgr::ForTeam(sender->GetTeam())) { - if (Channel* chn = cMgr->GetChannel(channel, sender)) + if (Channel* chn = cMgr->GetChannel(target, sender)) { sScriptMgr->OnPlayerChat(sender, type, lang, msg, chn); chn->Say(sender->GetGUID(), msg.c_str(), lang); @@ -484,70 +366,18 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } break; } - case CHAT_MSG_AFK: - { - if (!sender->IsInCombat()) - { - if (sender ->isAFK()) // Already AFK - { - if (msg.empty()) - sender->ToggleAFK(); // Remove AFK - else - sender->autoReplyMsg = msg; // Update message - } - else // New AFK mode - { - sender->autoReplyMsg = msg.empty() ? GetTrinityString(LANG_PLAYER_AFK_DEFAULT) : msg; - - if (sender->isDND()) - sender->ToggleDND(); - - sender->ToggleAFK(); - } - - sScriptMgr->OnPlayerChat(sender, type, lang, msg); - } - break; - } - case CHAT_MSG_DND: - { - if (sender->isDND()) // Already DND - { - if (msg.empty()) - sender->ToggleDND(); // Remove DND - else - sender->autoReplyMsg = msg; // Update message - } - else // New DND mode - { - sender->autoReplyMsg = msg.empty() ? GetTrinityString(LANG_PLAYER_DND_DEFAULT) : msg; - - if (sender->isAFK()) - sender->ToggleAFK(); - - sender->ToggleDND(); - } - - sScriptMgr->OnPlayerChat(sender, type, lang, msg); - break; - } default: TC_LOG_ERROR("network", "CHAT: unknown message type %u, lang: %u", type, lang); break; } } -void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData) +void WorldSession::HandleChatAddonMessageOpcode(WorldPackets::Chat::ChatAddonMessage& packet) { - Player* sender = GetPlayer(); ChatMsg type; - switch (recvData.GetOpcode()) + switch (packet.GetOpcode()) { - /* - case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND: - type = CHAT_MSG_BATTLEGROUND; - break; case CMSG_MESSAGECHAT_ADDON_GUILD: type = CHAT_MSG_GUILD; break; @@ -560,95 +390,50 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData) case CMSG_MESSAGECHAT_ADDON_RAID: type = CHAT_MSG_RAID; break; - case CMSG_MESSAGECHAT_ADDON_WHISPER: - type = CHAT_MSG_WHISPER; - break; - */ default: - TC_LOG_ERROR("network", "HandleAddonMessagechatOpcode: Unknown addon chat opcode (%u)", recvData.GetOpcode()); - recvData.hexlike(); + TC_LOG_ERROR("network", "HandleChatAddonMessageOpcode: Unknown addon chat opcode (%u)", packet.GetOpcode()); return; } - std::string message; - std::string prefix; - std::string targetName; + HandleChatAddonMessage(type, packet.Prefix, packet.Text); +} - switch (type) - { - case CHAT_MSG_WHISPER: - { - uint32 msgLen = recvData.ReadBits(9); - uint32 prefixLen = recvData.ReadBits(5); - uint32 targetLen = recvData.ReadBits(10); - message = recvData.ReadString(msgLen); - prefix = recvData.ReadString(prefixLen); - targetName = recvData.ReadString(targetLen); - break; - } - case CHAT_MSG_PARTY: - case CHAT_MSG_RAID: - case CHAT_MSG_OFFICER: - { - uint32 prefixLen = recvData.ReadBits(5); - uint32 msgLen = recvData.ReadBits(9); - prefix = recvData.ReadString(prefixLen); - message = recvData.ReadString(msgLen); - break; - } - case CHAT_MSG_GUILD: - case CHAT_MSG_BATTLEGROUND: - { - uint32 msgLen = recvData.ReadBits(9); - uint32 prefixLen = recvData.ReadBits(5); - message = recvData.ReadString(msgLen); - prefix = recvData.ReadString(prefixLen); - break; - } - default: - break; - } +void WorldSession::HandleChatAddonMessageWhisperOpcode(WorldPackets::Chat::ChatAddonMessageWhisper& packet) +{ + HandleChatAddonMessage(CHAT_MSG_WHISPER, packet.Prefix, packet.Text, packet.Target); +} + +void WorldSession::HandleChatAddonMessage(ChatMsg type, std::string prefix, std::string text, std::string target /*= ""*/) +{ + Player* sender = GetPlayer(); if (prefix.empty() || prefix.length() > 16) return; // Disabled addon channel? if (!sWorld->getBoolConfig(CONFIG_ADDON_CHANNEL)) - { - recvData.rfinish(); return; - } switch (type) { - case CHAT_MSG_BATTLEGROUND: - { - Group* group = sender->GetGroup(); - if (!group || !group->isBGGroup()) - return; - - WorldPacket data; - ChatHandler::BuildChatPacket(data, type, LANG_ADDON, sender, NULL, message, 0U, "", DEFAULT_LOCALE, prefix); - group->BroadcastAddonMessagePacket(&data, prefix, false); - break; - } case CHAT_MSG_GUILD: case CHAT_MSG_OFFICER: { if (sender->GetGuildId()) if (Guild* guild = sGuildMgr->GetGuildById(sender->GetGuildId())) - guild->BroadcastAddonToGuild(this, type == CHAT_MSG_OFFICER, message, prefix); + guild->BroadcastAddonToGuild(this, type == CHAT_MSG_OFFICER, text, prefix); break; } case CHAT_MSG_WHISPER: { - if (!normalizePlayerName(targetName)) + if (!normalizePlayerName(target)) break; - Player* receiver = sObjectAccessor->FindPlayerByName(targetName); + + Player* receiver = sObjectAccessor->FindPlayerByName(target); if (!receiver) break; - sender->WhisperAddon(message, prefix, receiver); + sender->WhisperAddon(text, prefix, receiver); break; } // Messages sent to "RAID" while in a party will get delivered to "PARTY" @@ -657,12 +442,12 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData) { Group* group = sender->GetGroup(); - if (!group || group->isBGGroup()) + if (!group) break; - WorldPacket data; - ChatHandler::BuildChatPacket(data, type, LANG_ADDON, sender, NULL, message, 0U, "", DEFAULT_LOCALE, prefix); - group->BroadcastAddonMessagePacket(&data, prefix, true, -1, sender->GetGUID()); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, type, LANG_ADDON, sender, NULL, text, 0U, "", DEFAULT_LOCALE, prefix); + group->BroadcastAddonMessagePacket(packet.Write(), prefix, true, -1, sender->GetGUID()); break; } default: @@ -673,6 +458,72 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData) } } +void WorldSession::HandleChatMessageAFKOpcode(WorldPackets::Chat::ChatMessageAFK& packet) +{ + Player* sender = GetPlayer(); + + if (sender->IsInCombat()) + return; + + if (sender->HasAura(GM_SILENCE_AURA)) + { + SendNotification(GetTrinityString(LANG_GM_SILENCE), sender->GetName().c_str()); + return; + } + + if (sender->isAFK()) // Already AFK + { + if (packet.Text.empty()) + sender->ToggleAFK(); // Remove AFK + else + sender->autoReplyMsg = packet.Text; // Update message + } + else // New AFK mode + { + sender->autoReplyMsg = packet.Text.empty() ? GetTrinityString(LANG_PLAYER_AFK_DEFAULT) : packet.Text; + + if (sender->isDND()) + sender->ToggleDND(); + + sender->ToggleAFK(); + } + + sScriptMgr->OnPlayerChat(sender, CHAT_MSG_AFK, LANG_UNIVERSAL, packet.Text); +} + +void WorldSession::HandleChatMessageDNDOpcode(WorldPackets::Chat::ChatMessageDND& packet) +{ + Player* sender = GetPlayer(); + + if (sender->IsInCombat()) + return; + + if (sender->HasAura(GM_SILENCE_AURA)) + { + SendNotification(GetTrinityString(LANG_GM_SILENCE), sender->GetName().c_str()); + return; + } + + if (sender->isDND()) // Already DND + { + if (packet.Text.empty()) + sender->ToggleDND(); // Remove DND + else + sender->autoReplyMsg = packet.Text; // Update message + } + else // New DND mode + { + sender->autoReplyMsg = packet.Text.empty() ? GetTrinityString(LANG_PLAYER_DND_DEFAULT) : packet.Text; + + if (sender->isAFK()) + sender->ToggleAFK(); + + sender->ToggleDND(); + } + + sScriptMgr->OnPlayerChat(sender, CHAT_MSG_DND, LANG_UNIVERSAL, packet.Text); +} + void WorldSession::HandleEmoteOpcode(WorldPacket& recvData) { if (!GetPlayer()->IsAlive() || GetPlayer()->HasUnitState(UNIT_STATE_DIED)) @@ -689,55 +540,46 @@ namespace Trinity class EmoteChatBuilder { public: - EmoteChatBuilder(Player const& player, uint32 text_emote, uint32 emote_num, Unit const* target) - : i_player(player), i_text_emote(text_emote), i_emote_num(emote_num), i_target(target) { } + EmoteChatBuilder(Player const& player, uint32 soundIndex, uint32 emoteID, Unit const* target) + : _player(player), _soundIndex(soundIndex), _emoteID(emoteID), _target(target) { } void operator()(WorldPacket& data, LocaleConstant loc_idx) { - std::string const name(i_target ? i_target->GetNameForLocaleIdx(loc_idx) : ""); - uint32 namlen = name.size(); - - data.Initialize(SMSG_TEXT_EMOTE, 20 + namlen); - data << i_player.GetGUID(); - data << uint32(i_text_emote); - data << uint32(i_emote_num); - data << uint32(namlen); - if (namlen > 1) - data << name; - else - data << uint8(0x00); + WorldPackets::Chat::STextEmote packet; + packet.SourceGUID = _player.GetGUID(); + packet.SourceAccountGUID = _player.GetSession()->GetAccountGUID(); + if (_target) + packet.TargetGUID = _target->GetGUID(); + packet.EmoteID = _emoteID; + packet.SoundIndex = _soundIndex; + data = *packet.Write(); } private: - Player const& i_player; - uint32 i_text_emote; - uint32 i_emote_num; - Unit const* i_target; + Player const& _player; + uint32 _soundIndex; + uint32 _emoteID; + Unit const* _target; }; -} // namespace Trinity +} -void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData) +void WorldSession::HandleTextEmoteOpcode(WorldPackets::Chat::CTextEmote& packet) { - if (!GetPlayer()->IsAlive()) + Player* player = GetPlayer(); + + if (!player->IsAlive()) return; - if (!GetPlayer()->CanSpeak()) + if (!player->CanSpeak()) { std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); return; } - uint32 text_emote, emoteNum; - ObjectGuid guid; - - recvData >> text_emote; - recvData >> emoteNum; - recvData >> guid; - - sScriptMgr->OnPlayerTextEmote(GetPlayer(), text_emote, emoteNum, guid); + sScriptMgr->OnPlayerTextEmote(player, packet.SoundIndex, packet.EmoteID, packet.Target); - EmotesTextEntry const* em = sEmotesTextStore.LookupEntry(text_emote); + EmotesTextEntry const* em = sEmotesTextStore.LookupEntry(packet.EmoteID); if (!em) return; @@ -752,34 +594,34 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData) break; case EMOTE_STATE_DANCE: case EMOTE_STATE_READ: - GetPlayer()->SetUInt32Value(UNIT_NPC_EMOTESTATE, emote_anim); + player->SetUInt32Value(UNIT_NPC_EMOTESTATE, emote_anim); break; default: // Only allow text-emotes for "dead" entities (feign death included) - if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + if (player->HasUnitState(UNIT_STATE_DIED)) break; - GetPlayer()->HandleEmoteCommand(emote_anim); + player->HandleEmoteCommand(emote_anim); break; } - Unit* unit = ObjectAccessor::GetUnit(*_player, guid); + Unit* unit = ObjectAccessor::GetUnit(*_player, packet.Target); - CellCoord p = Trinity::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); + CellCoord p = Trinity::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()); Cell cell(p); cell.SetNoCreate(); - Trinity::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); + Trinity::EmoteChatBuilder emote_builder(*player, packet.SoundIndex, packet.EmoteID, unit); Trinity::LocalizedPacketDo<Trinity::EmoteChatBuilder > emote_do(emote_builder); - Trinity::PlayerDistWorker<Trinity::LocalizedPacketDo<Trinity::EmoteChatBuilder > > emote_worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do); + Trinity::PlayerDistWorker<Trinity::LocalizedPacketDo<Trinity::EmoteChatBuilder > > emote_worker(player, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do); TypeContainerVisitor<Trinity::PlayerDistWorker<Trinity::LocalizedPacketDo<Trinity::EmoteChatBuilder> >, WorldTypeMapContainer> message(emote_worker); - cell.Visit(p, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); + cell.Visit(p, message, *player->GetMap(), *player, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, 0, unit); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, packet.SoundIndex, 0, 0, unit); //Send scripted event call if (unit && unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->AI()) - ((Creature*)unit)->AI()->ReceiveEmote(GetPlayer(), text_emote); + ((Creature*)unit)->AI()->ReceiveEmote(player, packet.SoundIndex); } void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recvData) @@ -811,9 +653,9 @@ void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recvData) if (!player || !player->GetSession()) return; - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_IGNORED, LANG_UNIVERSAL, _player, _player, GetPlayer()->GetName()); - player->GetSession()->SendPacket(&data); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_IGNORED, LANG_UNIVERSAL, _player, _player, GetPlayer()->GetName()); + player->SendDirectMessage(packet.Write()); } void WorldSession::HandleChannelDeclineInvite(WorldPacket &recvPacket) diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index 097c47a228e..07258fbd976 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -1048,7 +1048,7 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke *data << uint32(aurApp->GetBase()->GetId()); *data << uint16(aurApp->GetFlags()); - if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + if (aurApp->GetFlags() & AFLAG_SCALABLE) { for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) { @@ -1150,7 +1150,7 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke *data << uint32(aurApp->GetBase()->GetId()); *data << uint16(aurApp->GetFlags()); - if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + if (aurApp->GetFlags() & AFLAG_SCALABLE) { for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) { @@ -1285,7 +1285,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) data << uint32(aurApp->GetBase()->GetId()); data << uint16(aurApp->GetFlags()); - if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + if (aurApp->GetFlags() & AFLAG_SCALABLE) { for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) { @@ -1338,7 +1338,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) data << uint32(aurApp->GetBase()->GetId()); data << uint16(aurApp->GetFlags()); - if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + if (aurApp->GetFlags() & AFLAG_SCALABLE) { for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) { diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 95bcecbfdeb..54fb865c017 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -28,6 +28,8 @@ #include "ObjectAccessor.h" #include "SpellInfo.h" #include "DB2Stores.h" +#include "NPCPackets.h" +#include "ItemPackets.h" #include <vector> void WorldSession::HandleSplitItemOpcode(WorldPacket& recvData) @@ -560,18 +562,14 @@ void WorldSession::HandleBuyItemOpcode(WorldPacket& recvData) TC_LOG_DEBUG("network", "WORLD: received wrong itemType (%u) in HandleBuyItemOpcode", itemType); } -void WorldSession::HandleListInventoryOpcode(WorldPacket& recvData) +void WorldSession::HandleListInventoryOpcode(WorldPackets::NPC::Hello& packet) { - ObjectGuid guid; - - recvData >> guid; + TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_LIST_INVENTORY"); if (!GetPlayer()->IsAlive()) return; - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_LIST_INVENTORY"); - - SendListInventory(guid); + SendListInventory(packet.Unit); } void WorldSession::SendListInventory(ObjectGuid vendorGuid) @@ -597,12 +595,10 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid) VendorItemData const* vendorItems = vendor->GetVendorItems(); uint32 rawItemCount = vendorItems ? vendorItems->GetItemCount() : 0; - //if (rawItemCount > 300), - // rawItemCount = 300; // client cap but uint8 max value is 255 + WorldPackets::NPC::VendorInventory packet; + packet.Vendor = vendor->GetGUID(); - ByteBuffer itemsData(32 * rawItemCount); - std::vector<bool> enablers; - enablers.reserve(2 * rawItemCount); + packet.Items.resize(rawItemCount); const float discountMod = _player->GetReputationPriceDiscount(vendor); uint8 count = 0; @@ -612,13 +608,15 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid) if (!vendorItem) continue; + WorldPackets::NPC::VendorItem& item = packet.Items[count]; + if (vendorItem->Type == ITEM_VENDOR_TYPE_ITEM) { ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(vendorItem->item); if (!itemTemplate) continue; - uint32 leftInStock = !vendorItem->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(vendorItem); + int32 leftInStock = !vendorItem->maxcount ? -1 : vendor->GetVendorItemCurrentCount(vendorItem); if (!_player->IsGameMaster()) // ignore conditions if GM on { // Respect allowed class @@ -647,29 +645,15 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid) if (int32 priceMod = _player->GetTotalAuraModifier(SPELL_AURA_MOD_VENDOR_ITEMS_PRICES)) price -= CalculatePct(price, priceMod); - itemsData << uint32(slot + 1); // client expects counting to start at 1 - itemsData << uint32(itemTemplate->MaxDurability); + item.MuID = slot + 1; // client expects counting to start at 1 + item.Durability = itemTemplate->MaxDurability; + item.ExtendedCostID = vendorItem->ExtendedCost; + item.Type = vendorItem->Type; + item.Quantity = leftInStock; + item.StackCount = itemTemplate->BuyCount; + item.Price = price; - if (vendorItem->ExtendedCost) - { - enablers.push_back(0); - itemsData << uint32(vendorItem->ExtendedCost); - } - else - enablers.push_back(1); - - enablers.push_back(1); // item is unlocked - - itemsData << uint32(vendorItem->item); - itemsData << uint32(vendorItem->Type); // 1 is items, 2 is currency - itemsData << uint32(price); - itemsData << uint32(itemTemplate->DisplayInfoID); - // if (!unk "enabler") data << uint32(something); - itemsData << int32(leftInStock); - itemsData << uint32(itemTemplate->BuyCount); - - if (++count >= MAX_VENDOR_ITEMS) - break; + item.Item.ItemID = vendorItem->item; } else if (vendorItem->Type == ITEM_VENDOR_TYPE_CURRENCY) { @@ -680,70 +664,23 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid) if (!vendorItem->ExtendedCost) continue; // there's no price defined for currencies, only extendedcost is used - itemsData << uint32(slot + 1); // client expects counting to start at 1 - itemsData << uint32(0); // max durability - - enablers.push_back(0); - itemsData << uint32(vendorItem->ExtendedCost); - - enablers.push_back(1); // item is unlocked - - itemsData << uint32(vendorItem->item); - itemsData << uint32(vendorItem->Type); // 1 is items, 2 is currency - itemsData << uint32(0); // price, only seen currency types that have Extended cost - itemsData << uint32(0); // displayId - // if (!unk "enabler") data << uint32(something); - itemsData << int32(-1); - itemsData << uint32(vendorItem->maxcount); - - if (++count >= MAX_VENDOR_ITEMS) - break; + item.MuID = slot + 1; // client expects counting to start at 1 + item.ExtendedCostID = vendorItem->ExtendedCost; + item.Item.ItemID = vendorItem->item; + item.Type = vendorItem->Type; + item.StackCount = vendorItem->maxcount; } - // else error - } - - ObjectGuid guid = vendorGuid; - - WorldPacket data(SMSG_LIST_INVENTORY, 12 + itemsData.size()); - - data.WriteBit(guid[1]); - data.WriteBit(guid[0]); - - data.WriteBits(count, 21); // item count - - data.WriteBit(guid[3]); - data.WriteBit(guid[6]); - data.WriteBit(guid[5]); - data.WriteBit(guid[2]); - data.WriteBit(guid[7]); - - for (std::vector<bool>::const_iterator itr = enablers.begin(); itr != enablers.end(); ++itr) - data.WriteBit(*itr); - - data.WriteBit(guid[4]); + else + continue; - data.FlushBits(); - data.append(itemsData); - - data.WriteByteSeq(guid[5]); - data.WriteByteSeq(guid[4]); - data.WriteByteSeq(guid[1]); - data.WriteByteSeq(guid[0]); - data.WriteByteSeq(guid[6]); - - // It doesn't matter what value is used here (PROBABLY its full vendor size) - // What matters is that if count of items we can see is 0 and this field is 1 - // then client will open the vendor list, otherwise it won't - if (rawItemCount) - data << uint8(rawItemCount); - else - data << uint8(vendor->IsArmorer()); + if (++count >= MAX_VENDOR_ITEMS) + break; + } - data.WriteByteSeq(guid[2]); - data.WriteByteSeq(guid[3]); - data.WriteByteSeq(guid[7]); + // Resize vector to real size (some items can be skipped due to checks) + packet.Items.resize(count); - SendPacket(&data); + SendPacket(packet.Write()); } void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket& recvData) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 613f1e46d7b..9598ce216fb 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -52,6 +52,7 @@ #include "Group.h" #include "AccountMgr.h" #include "Spell.h" +#include "SpellPackets.h" #include "BattlegroundMgr.h" #include "Battlefield.h" #include "BattlefieldMgr.h" @@ -538,12 +539,9 @@ void WorldSession::HandleRequestCemeteryList(WorldPacket& /*recvPacket*/) SendPacket(&data); } -void WorldSession::HandleSetSelectionOpcode(WorldPacket& recvData) +void WorldSession::HandleSetSelectionOpcode(WorldPackets::Misc::SetSelection& packet) { - ObjectGuid guid; - recvData >> guid; - - _player->SetSelection(guid); + _player->SetSelection(packet.Selection); } void WorldSession::HandleStandStateChangeOpcode(WorldPacket& recvData) @@ -1041,17 +1039,17 @@ int32 WorldSession::HandleEnableNagleAlgorithm() return 0; } -void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recvData) +void WorldSession::HandleSetActionButtonOpcode(WorldPackets::Spells::SetActionButton& packet) { - uint8 button; - uint32 packetData; - recvData >> button >> packetData; - TC_LOG_DEBUG("network", "CMSG_SET_ACTION_BUTTON Button: %u Data: %u", button, packetData); + uint32 action = ACTION_BUTTON_ACTION(packet.Action); + uint32 type = ACTION_BUTTON_TYPE(packet.Action); + + TC_LOG_DEBUG("network", "CMSG_SET_ACTION_BUTTON Button: %u Action: %u Type: %u", packet.Index, action, type); - if (!packetData) - GetPlayer()->removeActionButton(button); + if (!packet.Action) + GetPlayer()->removeActionButton(packet.Index); else - GetPlayer()->addActionButton(button, ACTION_BUTTON_ACTION(packetData), ACTION_BUTTON_TYPE(packetData)); + GetPlayer()->addActionButton(packet.Index, action, type); } void WorldSession::HandleCompleteCinematic(WorldPacket& /*recvData*/) @@ -1867,74 +1865,6 @@ void WorldSession::HandleInstanceLockResponse(WorldPacket& recvPacket) _player->SetPendingBind(0, 0); } -void WorldSession::HandleRequestHotfix(WorldPacket& recvPacket) -{ - uint32 type, count; - recvPacket >> type; - - DB2StorageBase const* store = GetDB2Storage(type); - if (!store) - { - TC_LOG_ERROR("network", "CMSG_REQUEST_HOTFIX: Received unknown hotfix type: %u", type); - recvPacket.rfinish(); - return; - } - - count = recvPacket.ReadBits(23); - - ObjectGuid* guids = new ObjectGuid[count]; - for (uint32 i = 0; i < count; ++i) - { - guids[i][0] = recvPacket.ReadBit(); - guids[i][4] = recvPacket.ReadBit(); - guids[i][7] = recvPacket.ReadBit(); - guids[i][2] = recvPacket.ReadBit(); - guids[i][5] = recvPacket.ReadBit(); - guids[i][3] = recvPacket.ReadBit(); - guids[i][6] = recvPacket.ReadBit(); - guids[i][1] = recvPacket.ReadBit(); - } - - uint32 entry; - for (uint32 i = 0; i < count; ++i) - { - recvPacket.ReadByteSeq(guids[i][5]); - recvPacket.ReadByteSeq(guids[i][6]); - recvPacket.ReadByteSeq(guids[i][7]); - recvPacket.ReadByteSeq(guids[i][0]); - recvPacket.ReadByteSeq(guids[i][1]); - recvPacket.ReadByteSeq(guids[i][3]); - recvPacket.ReadByteSeq(guids[i][4]); - recvPacket >> entry; - recvPacket.ReadByteSeq(guids[i][2]); - - if (!store->HasRecord(entry)) - { - WorldPacket data(SMSG_DB_REPLY, 4 * 4); - data << -int32(entry); - data << uint32(store->GetHash()); - data << uint32(time(NULL)); - data << uint32(0); - SendPacket(&data); - continue; - } - - WorldPacket data(SMSG_DB_REPLY); - data << int32(entry); - data << uint32(store->GetHash()); - data << uint32(sObjectMgr->GetHotfixDate(entry, store->GetHash())); - - size_t sizePos = data.wpos(); - data << uint32(0); // size of next block - store->WriteRecord(entry, uint32(GetSessionDbcLocale()), data); - data.put<uint32>(sizePos, data.wpos() - sizePos - 4); - - SendPacket(&data); - } - - delete[] guids; -} - void WorldSession::HandleUpdateMissileTrajectory(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "WORLD: CMSG_UPDATE_MISSILE_TRAJECTORY"); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index adc2e185591..096eaac26fa 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -36,7 +36,7 @@ #define MOVEMENT_PACKET_TIME_DELAY 0 -void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleMoveWorldportAckOpcode(WorldPackets::Movement::WorldPortAck& /*packet*/) { TC_LOG_DEBUG("network", "WORLD: got MSG_MOVE_WORLDPORT_ACK."); HandleMoveWorldportAckOpcode(); @@ -197,41 +197,16 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->ProcessDelayedOperations(); } -void WorldSession::HandleMoveTeleportAck(WorldPacket& recvPacket) +void WorldSession::HandleMoveTeleportAck(WorldPackets::Movement::MoveTeleportAck& packet) { - TC_LOG_DEBUG("network", "MSG_MOVE_TELEPORT_ACK"); - - ObjectGuid guid; - uint32 flags, time; - recvPacket >> flags >> time; - - guid[5] = recvPacket.ReadBit(); - guid[0] = recvPacket.ReadBit(); - guid[1] = recvPacket.ReadBit(); - guid[6] = recvPacket.ReadBit(); - guid[3] = recvPacket.ReadBit(); - guid[7] = recvPacket.ReadBit(); - guid[2] = recvPacket.ReadBit(); - guid[4] = recvPacket.ReadBit(); - - recvPacket.ReadByteSeq(guid[4]); - recvPacket.ReadByteSeq(guid[2]); - recvPacket.ReadByteSeq(guid[7]); - recvPacket.ReadByteSeq(guid[6]); - recvPacket.ReadByteSeq(guid[5]); - recvPacket.ReadByteSeq(guid[1]); - recvPacket.ReadByteSeq(guid[3]); - recvPacket.ReadByteSeq(guid[0]); - - TC_LOG_DEBUG("network", "%s ", guid.ToString().c_str()); - TC_LOG_DEBUG("network", "Flags %u, time %u", flags, time/IN_MILLISECONDS); + TC_LOG_DEBUG("network", "CMSG_MOVE_TELEPORT_ACK: Guid: %s, Sequence: %u, Time: %u", packet.MoverGUID.ToString().c_str(), packet.AckIndex, packet.MoveTime); Player* plMover = _player->m_mover->ToPlayer(); if (!plMover || !plMover->IsBeingTeleportedNear()) return; - if (guid != plMover->GetGUID()) + if (packet.MoverGUID != plMover->GetGUID()) return; plMover->SetSemaphoreTeleportNear(false); @@ -384,7 +359,7 @@ void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMov mover->UpdatePosition(movementInfo.pos); WorldPackets::Movement::ServerPlayerMovement playerMovement; - playerMovement.mover = mover; + playerMovement.movementInfo = &mover->m_movementInfo; mover->SendMessageToSet(const_cast<WorldPacket*>(playerMovement.Write()), _player); if (plrMover) // nothing is charmed, or player charmed diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index cc82063e074..90af94f9754 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -37,6 +37,7 @@ #include "ScriptMgr.h" #include "CreatureAI.h" #include "SpellInfo.h" +#include "NPCPackets.h" enum StableResultCode { @@ -75,18 +76,14 @@ void WorldSession::SendTabardVendorActivate(ObjectGuid guid) SendPacket(&data); } -void WorldSession::HandleBankerActivateOpcode(WorldPacket& recvData) +void WorldSession::HandleBankerActivateOpcode(WorldPackets::NPC::Hello& packet) { - ObjectGuid guid; - TC_LOG_DEBUG("network", "WORLD: Received CMSG_BANKER_ACTIVATE"); - recvData >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_BANKER); if (!unit) { - TC_LOG_DEBUG("network", "WORLD: HandleBankerActivateOpcode - %s not found or you can not interact with him.", guid.ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleBankerActivateOpcode - %s not found or you can not interact with him.", packet.Unit.ToString().c_str()); return; } @@ -94,7 +91,7 @@ void WorldSession::HandleBankerActivateOpcode(WorldPacket& recvData) if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - SendShowBank(guid); + SendShowBank(packet.Unit); } void WorldSession::SendShowBank(ObjectGuid guid) @@ -112,12 +109,9 @@ void WorldSession::SendShowMailBox(ObjectGuid guid) SendPacket(&data); } -void WorldSession::HandleTrainerListOpcode(WorldPacket& recvData) +void WorldSession::HandleTrainerListOpcode(WorldPackets::NPC::Hello& packet) { - ObjectGuid guid; - - recvData >> guid; - SendTrainerList(guid); + SendTrainerList(packet.Unit); } void WorldSession::SendTrainerList(ObjectGuid guid) @@ -148,18 +142,16 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) return; } - WorldPacket data(SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); - data << guid; - data << uint32(trainer_spells->trainerType); - data << uint32(1); // different value for each trainer, also found in CMSG_TRAINER_BUY_SPELL - - size_t count_pos = data.wpos(); - data << uint32(trainer_spells->spellList.size()); + WorldPackets::NPC::TrainerList packet; + packet.TrainerGUID = guid; + packet.TrainerType = trainer_spells->trainerType; + packet.Greeting = strTitle; // reputation discount float fDiscountMod = _player->GetReputationPriceDiscount(unit); bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0; + packet.Spells.resize(trainer_spells->spellList.size()); uint32 count = 0; for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) { @@ -185,22 +177,23 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) TrainerSpellState state = _player->GetTrainerSpellState(tSpell); - data << uint32(tSpell->SpellID); // learned spell (or cast-spell in profession case) - data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state); - data << uint32(floor(tSpell->MoneyCost * fDiscountMod)); + WorldPackets::NPC::TrainerListSpell& spell = packet.Spells[count]; + spell.SpellID = tSpell->SpellID; + spell.MoneyCost = floor(tSpell->MoneyCost * fDiscountMod); + spell.ReqSkillLine = tSpell->ReqSkillLine; + spell.ReqSkillRank = tSpell->ReqSkillRank; + spell.ReqLevel = tSpell->ReqLevel; + spell.Usable = (state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state); - data << uint8(tSpell->ReqLevel); - data << uint32(tSpell->ReqSkillLine); - data << uint32(tSpell->ReqSkillRank); - //prev + req or req + 0 uint8 maxReq = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + /// @todo Update this when new spell system is ready + /*for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (!tSpell->ReqAbility[i]) continue; if (uint32 prevSpellId = sSpellMgr->GetPrevSpellInChain(tSpell->ReqAbility[i])) { - data << uint32(prevSpellId); + spell.ReqAbility[maxReq] = prevSpellId; ++maxReq; } if (maxReq == 2) @@ -208,29 +201,25 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) SpellsRequiringSpellMapBounds spellsRequired = sSpellMgr->GetSpellsRequiredForSpellBounds(tSpell->ReqAbility[i]); for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2) { - data << uint32(itr2->second); + spell.ReqAbility[maxReq] = itr2->second; ++maxReq; } if (maxReq == 2) break; - } - while (maxReq < 2) + }*/ + while (maxReq < MAX_TRAINERSPELL_ABILITY_REQS) { - data << uint32(0); + spell.ReqAbility[maxReq] = 0; ++maxReq; } - data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); - // primary prof. learn confirmation dialog - data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state - ++count; } - data << strTitle; + // Shrink to actual data size + packet.Spells.resize(count); - data.put<uint32>(count_pos, count); - SendPacket(&data); + SendPacket(packet.Write()); } void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) @@ -312,17 +301,14 @@ void WorldSession::SendTrainerBuyFailed(ObjectGuid guid, uint32 spellId, uint32 SendPacket(&data); } -void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData) +void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_GOSSIP_HELLO"); - ObjectGuid guid; - recvData >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_NONE); if (!unit) { - TC_LOG_DEBUG("network", "WORLD: HandleGossipHelloOpcode - %s not found or you can not interact with him.", guid.ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleGossipHelloOpcode - %s not found or you can not interact with him.", packet.Unit.ToString().c_str()); return; } @@ -453,18 +439,15 @@ void WorldSession::SendSpiritResurrect() _player->UpdateObjectVisibility(); } -void WorldSession::HandleBinderActivateOpcode(WorldPacket& recvData) +void WorldSession::HandleBinderActivateOpcode(WorldPackets::NPC::Hello& packet) { - ObjectGuid npcGUID; - recvData >> npcGUID; - if (!GetPlayer()->IsInWorld() || !GetPlayer()->IsAlive()) return; - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_INNKEEPER); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_INNKEEPER); if (!unit) { - TC_LOG_DEBUG("network", "WORLD: HandleBinderActivateOpcode - %s not found or you can not interact with him.", npcGUID.ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleBinderActivateOpcode - %s not found or you can not interact with him.", packet.Unit.ToString().c_str()); return; } diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 699d91c4cc9..652b548b3a2 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -312,9 +312,9 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe return; } - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect: spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) + if (effect && (effect->TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || effect->TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || effect->TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY)) return; } @@ -752,10 +752,10 @@ void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket) charmInfo->SetSpellAutocast(spellInfo, state != 0); } -void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) +void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest) { TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL"); - + /* ObjectGuid guid; uint8 castCount; uint32 spellId; @@ -835,7 +835,7 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) spell->finish(false); delete spell; - } + }*/ } void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName) diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index f432ff70275..fb8e45f5f42 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -239,88 +239,27 @@ void WorldSession::HandleCorpseQueryOpcode(WorldPacket& /*recvData*/) SendPacket(&data); } -void WorldSession::HandleNpcTextQueryOpcode(WorldPacket& recvData) +void WorldSession::HandleNpcTextQueryOpcode(WorldPackets::Query::QueryNPCText& packet) { - uint32 textID; - uint64 guid; + TC_LOG_DEBUG("network", "WORLD: CMSG_NPC_TEXT_QUERY TextId: %u", packet.TextID); - recvData >> textID; - TC_LOG_DEBUG("network", "WORLD: CMSG_NPC_TEXT_QUERY TextId: %u", textID); + GossipText const* gossip = sObjectMgr->GetGossipText(packet.TextID); - recvData >> guid; - - GossipText const* gossip = sObjectMgr->GetGossipText(textID); - - WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size - data << textID; - - if (!gossip) + WorldPackets::Query::QueryNPCTextResponse response; + response.TextID = packet.TextID; + + if (gossip) { for (uint8 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) { - data << float(0); - data << "Greetings $N"; - data << "Greetings $N"; - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); + response.Probabilities[i] = gossip->Options[i].Probability; + response.BroadcastTextID[i] = gossip->Options[i].BroadcastTextID; } - } - else - { - std::string text0[MAX_GOSSIP_TEXT_OPTIONS], text1[MAX_GOSSIP_TEXT_OPTIONS]; - LocaleConstant locale = GetSessionDbLocaleIndex(); - - for (uint8 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) - { - BroadcastText const* bct = sObjectMgr->GetBroadcastText(gossip->Options[i].BroadcastTextID); - if (bct) - { - text0[i] = bct->GetText(locale, GENDER_MALE, true); - text1[i] = bct->GetText(locale, GENDER_FEMALE, true); - } - else - { - text0[i] = gossip->Options[i].Text_0; - text1[i] = gossip->Options[i].Text_1; - } - - if (locale != DEFAULT_LOCALE && !bct) - { - if (NpcTextLocale const* npcTextLocale = sObjectMgr->GetNpcTextLocale(textID)) - { - ObjectMgr::GetLocaleString(npcTextLocale->Text_0[i], locale, text0[i]); - ObjectMgr::GetLocaleString(npcTextLocale->Text_1[i], locale, text1[i]); - } - } - - data << gossip->Options[i].Probability; - - if (text0[i].empty()) - data << text1[i]; - else - data << text0[i]; - - if (text1[i].empty()) - data << text0[i]; - else - data << text1[i]; - - data << gossip->Options[i].Language; - for (uint8 j = 0; j < MAX_GOSSIP_TEXT_EMOTES; ++j) - { - data << gossip->Options[i].Emotes[j]._Delay; - data << gossip->Options[i].Emotes[j]._Emote; - } - } + response.Allow = true; } - SendPacket(&data); + SendPacket(response.Write()); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_NPC_TEXT_UPDATE"); } @@ -492,3 +431,35 @@ void WorldSession::HandleQuestPOIQuery(WorldPacket& recvData) SendPacket(&data); } + +void WorldSession::HandleDBQueryBulk(WorldPackets::Query::DBQueryBulk& packet) +{ + DB2StorageBase const* store = GetDB2Storage(packet.TableHash); + if (!store) + { + TC_LOG_ERROR("network", "CMSG_DB_QUERY_BULK: Received unknown hotfix type: %u", packet.TableHash); + return; + } + + for (WorldPackets::Query::DBQueryRecord const& rec : packet.Queries) + { + WorldPackets::Query::DBReply response; + response.TableHash = packet.TableHash; + + if (store->HasRecord(rec.RecordID)) + { + response.RecordID = rec.RecordID; + response.Locale = GetSessionDbcLocale(); + response.Timestamp = sObjectMgr->GetHotfixDate(rec.RecordID, packet.TableHash); + response.Data = store; + } + else + { + TC_LOG_ERROR("network", "CMSG_DB_QUERY_BULK: Entry %u does not exist in datastore: %u", rec.RecordID, packet.TableHash); + response.RecordID = -int32(rec.RecordID); + response.Timestamp = time(NULL); + } + + SendPacket(response.Write()); + } +} diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 26451751b5d..f591a5fa988 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -31,17 +31,16 @@ #include "Battleground.h" #include "ScriptMgr.h" #include "GameObjectAI.h" +#include "QuestPackets.h" -void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket& recvData) +void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestGiverStatusQuery& packet) { - ObjectGuid guid; - recvData >> guid; uint32 questStatus = DIALOG_STATUS_NONE; - Object* questGiver = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT); + Object* questGiver = ObjectAccessor::GetObjectByTypeMask(*_player, packet.QuestGiverGUID, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT); if (!questGiver) { - TC_LOG_INFO("network", "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver (%s)", guid.ToString().c_str()); + TC_LOG_INFO("network", "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver (%s)", packet.QuestGiverGUID.ToString().c_str()); return; } @@ -66,7 +65,7 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket& recvData) } //inform client about status of quest - _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, guid); + _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, packet.QuestGiverGUID); } void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket& recvData) @@ -639,19 +638,14 @@ void WorldSession::HandleQuestPushResult(WorldPacket& recvPacket) } } -void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket*/) +void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPackets::Quest::QuestGiverStatusMultipleQuery& /*packet*/) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY"); - uint32 count = 0; - - WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4 + 8 + 4); - data << uint32(count); // placeholder + WorldPackets::Quest::QuestGiverStatusMultiple response; for (GuidSet::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) { - uint32 questStatus = DIALOG_STATUS_NONE; - if (itr->IsAnyTypeCreature()) { // need also pet quests case support @@ -661,11 +655,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) continue; - questStatus = _player->GetQuestDialogStatus(questgiver); - - data << questgiver->GetGUID(); - data << uint32(questStatus); - ++count; + response.QuestGiver.emplace_back(questgiver->GetGUID(), _player->GetQuestDialogStatus(questgiver)); } else if (itr->IsGameObject()) { @@ -673,16 +663,11 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket if (!questgiver || questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) continue; - questStatus = _player->GetQuestDialogStatus(questgiver); - - data << questgiver->GetGUID(); - data << uint32(questStatus); - ++count; + response.QuestGiver.emplace_back(questgiver->GetGUID(), _player->GetQuestDialogStatus(questgiver)); } } - data.put<uint32>(0, count); // write real count - SendPacket(&data); + SendPacket(response.Write()); } void WorldSession::HandleQueryQuestsCompleted(WorldPacket& /*recvData*/) diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp index f0c1b28117b..278169c2d63 100644 --- a/src/server/game/Handlers/SkillHandler.cpp +++ b/src/server/game/Handlers/SkillHandler.cpp @@ -28,59 +28,22 @@ #include "WorldSession.h" #include "TalentPackets.h" -void WorldSession::HandleLearnTalentOpcode(WorldPacket& recvData) +void WorldSession::HandleLearnTalentOpcode(WorldPackets::Talent::LearnTalent& packet) { - /* TODO: 6.x update packet struct (note: LearnTalent no longer has rank argument) - uint32 talentId, requestedRank; - recvData >> talentId >> requestedRank; - - if (_player->LearnTalent(talentId, requestedRank)) - _player->SendTalentsInfoData(false);*/ + bool anythingLearned = false; + for (uint32 talentId : packet.Talents) + { + if (_player->LearnTalent(talentId)) + anythingLearned = true; + } + + if (anythingLearned) + _player->SendTalentsInfoData(); } void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket) { - /* TODO: 6.x update packet struct TC_LOG_DEBUG("network", "CMSG_LEARN_PREVIEW_TALENTS"); - - int32 tabPage; - uint32 talentsCount; - recvPacket >> tabPage; // talent tree - - // prevent cheating (selecting new tree with points already in another) - if (tabPage >= 0) // -1 if player already has specialization - { - if (TalentTabEntry const* talentTabEntry = sTalentTabStore.LookupEntry(_player->GetPrimaryTalentTree(_player->GetActiveSpec()))) - { - if (talentTabEntry->tabpage != uint32(tabPage)) - { - recvPacket.rfinish(); - return; - } - } - } - - recvPacket >> talentsCount; - - uint32 talentId, talentRank; - - // Client has max 21 talents for tree for 3 trees, rounded up : 70 - uint32 const MaxTalentsCount = 70; - - for (uint32 i = 0; i < talentsCount && i < MaxTalentsCount; ++i) - { - recvPacket >> talentId >> talentRank; - - if (!_player->LearnTalent(talentId, talentRank)) - { - recvPacket.rfinish(); - break; - } - } - - _player->SendTalentsInfoData(false); - - recvPacket.rfinish();*/ } void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recvData) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 05f600e1207..a6bd43f72c6 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -153,7 +153,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) if (pUser->IsInCombat()) { - for (int i = 0; i < proto->Effects.size(); ++i) + for (uint32 i = 0; i < proto->Effects.size(); ++i) { if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Effects[i].SpellID)) { @@ -329,60 +329,71 @@ void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); } -void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) +void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest) { - uint32 spellId, glyphIndex; - uint8 castCount, castFlags; - recvPacket >> castCount; - recvPacket >> spellId; - recvPacket >> glyphIndex; - recvPacket >> castFlags; - - TC_LOG_DEBUG("network", "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u, data length = %u", castCount, spellId, castFlags, (uint32)recvPacket.size()); + TC_LOG_DEBUG("network", "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u", castRequest.CastID, castRequest.SpellID, castRequest.SendCastFlags); // ignore for remote control state (for player case) Unit* mover = _player->m_mover; if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) { - recvPacket.rfinish(); // prevent spam at ignore packet return; } - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(castRequest.SpellID); if (!spellInfo) { - TC_LOG_ERROR("network", "WORLD: unknown spell id %u", spellId); - recvPacket.rfinish(); // prevent spam at ignore packet + TC_LOG_ERROR("network", "WORLD: unknown spell id %u", castRequest.SpellID); return; } if (spellInfo->IsPassive()) { - recvPacket.rfinish(); // prevent spam at ignore packet return; } Unit* caster = mover; - if (caster->GetTypeId() == TYPEID_UNIT && !caster->ToCreature()->HasSpell(spellId)) + if (caster->GetTypeId() == TYPEID_UNIT && !caster->ToCreature()->HasSpell(castRequest.SpellID)) { // If the vehicle creature does not have the spell but it allows the passenger to cast own spells // change caster to player and let him cast if (!_player->IsOnVehicle(caster) || spellInfo->CheckVehicle(_player) != SPELL_CAST_OK) { - recvPacket.rfinish(); // prevent spam at ignore packet return; } caster = _player; } - if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellId)) + if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(castRequest.SpellID)) { // not have spell in spellbook - recvPacket.rfinish(); // prevent spam at ignore packet return; } + + if (Player* plr = caster->ToPlayer()) + { + uint32 specId = plr->GetActiveTalentSpec(); + if (specId) + { + if (sSpecializationOverrideSpellMap.find(specId) != sSpecializationOverrideSpellMap.end()) + { + if (sSpecializationOverrideSpellMap[specId].find(castRequest.SpellID) != sSpecializationOverrideSpellMap[specId].end()) + { + SpellInfo const* newSpellInfo = sSpellMgr->GetSpellInfo(sSpecializationOverrideSpellMap[specId][castRequest.SpellID]); + if (newSpellInfo) + { + if (newSpellInfo->SpellLevel <= caster->getLevel()) + { + spellInfo = newSpellInfo; + castRequest.SpellID = newSpellInfo->Id; + } + } + } + } + } + } Unit::AuraEffectList swaps = mover->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS); Unit::AuraEffectList const& swaps2 = mover->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2); @@ -398,7 +409,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo((*itr)->GetAmount())) { spellInfo = newInfo; - spellId = newInfo->Id; + castRequest.SpellID = newInfo->Id; } break; } @@ -410,21 +421,20 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) if (spellInfo->IsAutoRepeatRangedSpell() && caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) && caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) { - recvPacket.rfinish(); return; } // can't use our own spells when we're in possession of another unit, if (_player->isPossessing()) { - recvPacket.rfinish(); // prevent spam at ignore packet return; } // client provided targets - SpellCastTargets targets; - targets.Read(recvPacket, caster); - HandleClientCastFlags(recvPacket, castFlags, targets); + SpellCastTargets targets(caster, castRequest.TargetFlags, castRequest.UnitGuid, castRequest.ItemGuid, castRequest.SrcTransportGuid, castRequest.DstTransportGuid, castRequest.SrcPos, castRequest.DstPos, castRequest.Pitch, castRequest.Speed, castRequest.Name); + + + //HandleClientCastFlags(recvPacket, castFlags, targets); // auto-selection buff level base at target level (in spellInfo) if (targets.GetUnitTarget()) @@ -437,8 +447,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) } Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, ObjectGuid::Empty, false); - spell->m_cast_count = castCount; // set count of casts - spell->m_glyphIndex = glyphIndex; + spell->m_cast_count = castRequest.CastID; // set count of casts + spell->m_glyphIndex = castRequest.Misc; // 6.x Misc is just a guess spell->prepare(&targets); } @@ -458,6 +468,10 @@ void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket) uint32 spellId; recvPacket >> spellId; + ObjectGuid guid; + recvPacket >> guid; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) return; @@ -485,7 +499,7 @@ void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket) _player->RemoveOwnedAura(spellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_CANCEL); // If spell being removed is a resource tracker, see if player was tracking both (herbs / minerals) and remove the other - if (sWorld->getBoolConfig(CONFIG_ALLOW_TRACK_BOTH_RESOURCES) && spellInfo->HasAura(SPELL_AURA_TRACK_RESOURCES)) + if (sWorld->getBoolConfig(CONFIG_ALLOW_TRACK_BOTH_RESOURCES) && spellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_TRACK_RESOURCES)) { Unit::AuraEffectList const& auraEffects = _player->GetAuraEffectsByType(SPELL_AURA_TRACK_RESOURCES); if (!auraEffects.empty()) @@ -760,14 +774,14 @@ void WorldSession::HandleRequestCategoryCooldowns(WorldPacket& /*recvPacket*/) void WorldSession::SendSpellCategoryCooldowns() { - WorldPackets::Spell::CategoryCooldown cooldowns; + WorldPackets::Spells::CategoryCooldown cooldowns; Unit::AuraEffectList const& categoryCooldownAuras = _player->GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN); for (AuraEffect* aurEff : categoryCooldownAuras) { uint32 categoryId = aurEff->GetMiscValue(); auto cItr = std::find_if(cooldowns.CategoryCooldowns.begin(), cooldowns.CategoryCooldowns.end(), - [categoryId](WorldPackets::Spell::CategoryCooldown::CategoryCooldownInfo const& cooldown) + [categoryId](WorldPackets::Spells::CategoryCooldown::CategoryCooldownInfo const& cooldown) { return cooldown.Category == categoryId; }); diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 9aef1b62f7c..27b362faf90 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -96,7 +96,7 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instance { // initialize reset time // for normal instances if no creatures are killed the instance will reset in two hours - if (entry->IsRaid() || difficulty > DUNGEON_DIFFICULTY_NORMAL) + if (entry->IsRaid() || difficulty > DIFFICULTY_NORMAL) resetTime = GetResetTimeFor(mapId, difficulty); else { @@ -213,7 +213,7 @@ time_t InstanceSave::GetResetTimeForDB() { // only save the reset time for normal instances const MapEntry* entry = sMapStore.LookupEntry(GetMapId()); - if (!entry || entry->IsRaid() || GetDifficulty() == DUNGEON_DIFFICULTY_HEROIC) + if (!entry || entry->IsRaid() || GetDifficulty() == DIFFICULTY_HEROIC) return 0; else return GetResetTime(); diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h index b2c86d5152b..70db53ced8d 100644 --- a/src/server/game/Instances/InstanceSaveMgr.h +++ b/src/server/game/Instances/InstanceSaveMgr.h @@ -175,7 +175,7 @@ class InstanceSaveManager uint16 mapid; uint16 instanceId; - InstResetEvent() : type(0), difficulty(DUNGEON_DIFFICULTY_NORMAL), mapid(0), instanceId(0) { } + InstResetEvent() : type(0), difficulty(DIFFICULTY_NORMAL), mapid(0), instanceId(0) { } InstResetEvent(uint8 t, uint32 _mapid, Difficulty d, uint16 _instanceid) : type(t), difficulty(d), mapid(_mapid), instanceId(_instanceid) { } bool operator == (const InstResetEvent& e) const { return e.instanceId == instanceId; } diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index a8255d62777..1c968a495e9 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -128,7 +128,7 @@ void InstanceScript::LoadObjectData(ObjectData const* creatureData, ObjectData c if (gameObjectData) LoadObjectData(gameObjectData, _gameObjectInfo); - TC_LOG_ERROR("scripts", "InstanceScript::LoadObjectData: " SZFMTD " objects loaded.", _creatureInfo.size() + _gameObjectInfo.size()); + TC_LOG_DEBUG("scripts", "InstanceScript::LoadObjectData: " SZFMTD " objects loaded.", _creatureInfo.size() + _gameObjectInfo.size()); } void InstanceScript::LoadObjectData(ObjectData const* data, ObjectInfoMap& objectInfo) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 091fbb95aa5..7b7a0d5558d 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -386,15 +386,15 @@ class Map : public GridRefManager<NGridType> // have meaning only for instanced map (that have set real difficulty) Difficulty GetDifficulty() const { return Difficulty(GetSpawnMode()); } - bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; } + bool IsRegularDifficulty() const { return GetDifficulty() == DIFFICULTY_NONE; } MapDifficulty const* GetMapDifficulty() const; bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); } bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } bool IsNonRaidDungeon() const { return i_mapEntry && i_mapEntry->IsNonRaidDungeon(); } bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } - bool IsRaidOrHeroicDungeon() const { return IsRaid() || i_spawnMode > DUNGEON_DIFFICULTY_NORMAL; } - bool IsHeroic() const { return IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; } + bool IsRaidOrHeroicDungeon() const { return IsRaid() || i_spawnMode > DIFFICULTY_NORMAL; } + bool IsHeroic() const { return IsRaid() ? i_spawnMode >= DIFFICULTY_10_HC : i_spawnMode >= DIFFICULTY_HEROIC; } bool Is25ManRaid() const { return IsRaid() && i_spawnMode & RAID_DIFFICULTY_MASK_25MAN; } // since 25man difficulties are 1 and 3, we can check them like that bool IsBattleground() const { return i_mapEntry && i_mapEntry->IsBattleground(); } bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 8dfa4449e12..48e5161bcf1 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -27,7 +27,7 @@ #include "Group.h" #include "Player.h" -MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL) +MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DIFFICULTY_NORMAL) { // fill with zero memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_GRIDS*sizeof(uint16)); @@ -227,7 +227,7 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun TC_LOG_DEBUG("maps", "MapInstanced::CreateBattleground: map bg %d for %d created.", InstanceId, GetId()); - BattlegroundMap* map = new BattlegroundMap(GetId(), GetGridExpiry(), InstanceId, this, REGULAR_DIFFICULTY); + BattlegroundMap* map = new BattlegroundMap(GetId(), GetGridExpiry(), InstanceId, this, DIFFICULTY_NONE); ASSERT(map->IsBattlegroundOrArena()); map->SetBG(bg); bg->SetBgMap(map); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index ac9e5918442..92d7335c7de 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -78,7 +78,7 @@ Map* MapManager::CreateBaseMap(uint32 id) map = new MapInstanced(id, i_gridCleanUpDelay); else { - map = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); + map = new Map(id, i_gridCleanUpDelay, 0, DIFFICULTY_NONE); map->LoadRespawnTimes(); } diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 34733613c28..ede70719652 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -22,6 +22,7 @@ #include "Spline.h" #include "DBCStores.h" #include "ObjectGuid.h" +#include "DB2Structure.h" struct KeyFrame; struct GameObjectTemplate; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 68c30716ad9..c81ba4f4bbe 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -27,7 +27,36 @@ enum SpellEffIndex { EFFECT_0 = 0, EFFECT_1 = 1, - EFFECT_2 = 2 + EFFECT_2 = 2, + EFFECT_3 = 3, + EFFECT_4 = 4, + EFFECT_5 = 5, + EFFECT_6 = 6, + EFFECT_7 = 7, + EFFECT_8 = 8, + EFFECT_9 = 9, + EFFECT_10 = 10, + EFFECT_11 = 11, + EFFECT_12 = 12, + EFFECT_13 = 13, + EFFECT_14 = 14, + EFFECT_15 = 15, + EFFECT_16 = 16, + EFFECT_17 = 17, + EFFECT_18 = 18, + EFFECT_19 = 19, + EFFECT_20 = 20, + EFFECT_21 = 21, + EFFECT_22 = 22, + EFFECT_23 = 23, + EFFECT_24 = 24, + EFFECT_25 = 25, + EFFECT_26 = 26, + EFFECT_27 = 27, + EFFECT_28 = 28, + EFFECT_29 = 29, + EFFECT_30 = 30, + EFFECT_31 = 31 }; // used in script definitions @@ -58,9 +87,10 @@ enum Expansions enum Gender { - GENDER_MALE = 0, - GENDER_FEMALE = 1, - GENDER_NONE = 2 + GENDER_UNKNOWN = -1, + GENDER_MALE = 0, + GENDER_FEMALE = 1, + GENDER_NONE = 2 }; // ChrRaces.dbc (6.0.2.18988) @@ -819,7 +849,7 @@ enum SpellAttr13 #define MAX_TALENT_GROUP 1 #define MIN_TALENT_GROUPS 1 #define MAX_TALENT_GROUPS 2 -#define MAX_GLYPH_SLOT_INDEX 9 +#define MAX_GLYPH_SLOT_INDEX 6 #define MIN_SPECIALIZATION_LEVEL 10 #define MAX_SPECIALIZATIONS 4 @@ -974,7 +1004,7 @@ enum Team TEAM_OTHER = 0 // if ReputationListId > 0 && Flags != FACTION_FLAG_TEAM_HEADER }; -enum SpellEffects +enum SpellEffectName { SPELL_EFFECT_INSTAKILL = 1, SPELL_EFFECT_SCHOOL_DAMAGE = 2, @@ -1158,10 +1188,72 @@ enum SpellEffects SPELL_EFFECT_180 = 180, // Unused (4.3.4) SPELL_EFFECT_181 = 181, // Unused (4.3.4) SPELL_EFFECT_182 = 182, - TOTAL_SPELL_EFFECTS = 183, + SPELL_EFFECT_183 = 183, + SPELL_EFFECT_184 = 184, + SPELL_EFFECT_185 = 185, + SPELL_EFFECT_186 = 186, + SPELL_EFFECT_187 = 187, + SPELL_EFFECT_188 = 188, + SPELL_EFFECT_189 = 189, + SPELL_EFFECT_190 = 190, + SPELL_EFFECT_191 = 191, + SPELL_EFFECT_192 = 192, + SPELL_EFFECT_193 = 193, + SPELL_EFFECT_194 = 194, + SPELL_EFFECT_195 = 195, + SPELL_EFFECT_196 = 196, + SPELL_EFFECT_197 = 197, + SPELL_EFFECT_198 = 198, + SPELL_EFFECT_199 = 199, + SPELL_EFFECT_200 = 200, + SPELL_EFFECT_201 = 201, + SPELL_EFFECT_202 = 202, + SPELL_EFFECT_203 = 203, + SPELL_EFFECT_204 = 204, + SPELL_EFFECT_205 = 205, + SPELL_EFFECT_206 = 206, + SPELL_EFFECT_207 = 207, + SPELL_EFFECT_208 = 208, + SPELL_EFFECT_209 = 209, + SPELL_EFFECT_210 = 210, + SPELL_EFFECT_211 = 211, + SPELL_EFFECT_212 = 212, + SPELL_EFFECT_213 = 213, + SPELL_EFFECT_214 = 214, + SPELL_EFFECT_215 = 215, + SPELL_EFFECT_216 = 216, + SPELL_EFFECT_217 = 217, + SPELL_EFFECT_218 = 218, + SPELL_EFFECT_219 = 219, + SPELL_EFFECT_220 = 220, + SPELL_EFFECT_221 = 221, + SPELL_EFFECT_222 = 222, + SPELL_EFFECT_223 = 223, + SPELL_EFFECT_224 = 224, + SPELL_EFFECT_225 = 225, + SPELL_EFFECT_226 = 226, + SPELL_EFFECT_227 = 227, + SPELL_EFFECT_228 = 228, + SPELL_EFFECT_229 = 229, + SPELL_EFFECT_230 = 230, + SPELL_EFFECT_231 = 231, + SPELL_EFFECT_232 = 232, + SPELL_EFFECT_233 = 233, + SPELL_EFFECT_234 = 234, + SPELL_EFFECT_235 = 235, + SPELL_EFFECT_236 = 236, + SPELL_EFFECT_237 = 237, + SPELL_EFFECT_238 = 238, + SPELL_EFFECT_239 = 239, + SPELL_EFFECT_240 = 240, + SPELL_EFFECT_241 = 241, + SPELL_EFFECT_242 = 242, + SPELL_EFFECT_243 = 243, + SPELL_EFFECT_244 = 244, + TOTAL_SPELL_EFFECTS = 245, }; -enum SpellCastResult // (6.0) +enum SpellCastResult // 19116 { SPELL_FAILED_SUCCESS = 0, SPELL_FAILED_AFFECTING_COMBAT = 1, @@ -1207,203 +1299,224 @@ enum SpellCastResult // (6.0) SPELL_FAILED_GARRISON_OWNED = 41, SPELL_FAILED_GARRISON_MAX_LEVEL = 42, SPELL_FAILED_GARRISON_NOT_UPGRADEABLE = 43, - SPELL_FAILED_HIGHLEVEL = 44, - SPELL_FAILED_HUNGER_SATIATED = 45, - SPELL_FAILED_IMMUNE = 46, - SPELL_FAILED_INCORRECT_AREA = 47, - SPELL_FAILED_INTERRUPTED = 48, - SPELL_FAILED_INTERRUPTED_COMBAT = 49, - SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 50, - SPELL_FAILED_ITEM_GONE = 51, - SPELL_FAILED_ITEM_NOT_FOUND = 52, - SPELL_FAILED_ITEM_NOT_READY = 53, - SPELL_FAILED_LEVEL_REQUIREMENT = 54, - SPELL_FAILED_LINE_OF_SIGHT = 55, - SPELL_FAILED_LOWLEVEL = 56, - SPELL_FAILED_LOW_CASTLEVEL = 57, - SPELL_FAILED_MAINHAND_EMPTY = 58, - SPELL_FAILED_MOVING = 59, - SPELL_FAILED_NEED_AMMO = 60, - SPELL_FAILED_NEED_AMMO_POUCH = 61, - SPELL_FAILED_NEED_EXOTIC_AMMO = 62, - SPELL_FAILED_NEED_MORE_ITEMS = 63, - SPELL_FAILED_NOPATH = 64, - SPELL_FAILED_NOT_BEHIND = 65, - SPELL_FAILED_NOT_FISHABLE = 66, - SPELL_FAILED_NOT_FLYING = 67, - SPELL_FAILED_NOT_HERE = 68, - SPELL_FAILED_NOT_INFRONT = 69, - SPELL_FAILED_NOT_IN_CONTROL = 70, - SPELL_FAILED_NOT_KNOWN = 71, - SPELL_FAILED_NOT_MOUNTED = 72, - SPELL_FAILED_NOT_ON_TAXI = 73, - SPELL_FAILED_NOT_ON_TRANSPORT = 74, - SPELL_FAILED_NOT_READY = 75, - SPELL_FAILED_NOT_SHAPESHIFT = 76, - SPELL_FAILED_NOT_STANDING = 77, - SPELL_FAILED_NOT_TRADEABLE = 78, - SPELL_FAILED_NOT_TRADING = 79, - SPELL_FAILED_NOT_UNSHEATHED = 80, - SPELL_FAILED_NOT_WHILE_GHOST = 81, - SPELL_FAILED_NOT_WHILE_LOOTING = 82, - SPELL_FAILED_NO_AMMO = 83, - SPELL_FAILED_NO_CHARGES_REMAIN = 84, - SPELL_FAILED_NO_CHAMPION = 85, - SPELL_FAILED_NO_COMBO_POINTS = 86, - SPELL_FAILED_NO_DUELING = 87, - SPELL_FAILED_NO_ENDURANCE = 88, - SPELL_FAILED_NO_FISH = 89, - SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 90, - SPELL_FAILED_NO_MOUNTS_ALLOWED = 91, - SPELL_FAILED_NO_PET = 92, - SPELL_FAILED_NO_POWER = 93, - SPELL_FAILED_NOTHING_TO_DISPEL = 94, - SPELL_FAILED_NOTHING_TO_STEAL = 95, - SPELL_FAILED_ONLY_ABOVEWATER = 96, - SPELL_FAILED_ONLY_DAYTIME = 97, - SPELL_FAILED_ONLY_INDOORS = 98, - SPELL_FAILED_ONLY_MOUNTED = 99, - SPELL_FAILED_ONLY_NIGHTTIME = 100, - SPELL_FAILED_ONLY_OUTDOORS = 101, - SPELL_FAILED_ONLY_SHAPESHIFT = 102, - SPELL_FAILED_ONLY_STEALTHED = 103, - SPELL_FAILED_ONLY_UNDERWATER = 104, - SPELL_FAILED_OUT_OF_RANGE = 105, - SPELL_FAILED_PACIFIED = 106, - SPELL_FAILED_POSSESSED = 107, - SPELL_FAILED_REAGENTS = 108, - SPELL_FAILED_REQUIRES_AREA = 109, - SPELL_FAILED_REQUIRES_SPELL_FOCUS = 110, - SPELL_FAILED_ROOTED = 111, - SPELL_FAILED_SILENCED = 112, - SPELL_FAILED_SPELL_IN_PROGRESS = 113, - SPELL_FAILED_SPELL_LEARNED = 114, - SPELL_FAILED_SPELL_UNAVAILABLE = 115, - SPELL_FAILED_STUNNED = 116, - SPELL_FAILED_TARGETS_DEAD = 117, - SPELL_FAILED_TARGET_AFFECTING_COMBAT = 118, - SPELL_FAILED_TARGET_AURASTATE = 119, - SPELL_FAILED_TARGET_DUELING = 120, - SPELL_FAILED_TARGET_ENEMY = 121, - SPELL_FAILED_TARGET_ENRAGED = 122, - SPELL_FAILED_TARGET_FRIENDLY = 123, - SPELL_FAILED_TARGET_IN_COMBAT = 124, - SPELL_FAILED_TARGET_IN_PET_BATTLE = 125, - SPELL_FAILED_TARGET_IS_PLAYER = 126, - SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 127, - SPELL_FAILED_TARGET_NOT_DEAD = 128, - SPELL_FAILED_TARGET_NOT_IN_PARTY = 129, - SPELL_FAILED_TARGET_NOT_LOOTED = 130, - SPELL_FAILED_TARGET_NOT_PLAYER = 131, - SPELL_FAILED_TARGET_NO_POCKETS = 132, - SPELL_FAILED_TARGET_NO_WEAPONS = 133, - SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 134, - SPELL_FAILED_TARGET_UNSKINNABLE = 135, - SPELL_FAILED_THIRST_SATIATED = 136, - SPELL_FAILED_TOO_CLOSE = 137, - SPELL_FAILED_TOO_MANY_OF_ITEM = 138, - SPELL_FAILED_TOTEM_CATEGORY = 139, - SPELL_FAILED_TOTEMS = 140, - SPELL_FAILED_TRY_AGAIN = 141, - SPELL_FAILED_UNIT_NOT_BEHIND = 142, - SPELL_FAILED_UNIT_NOT_INFRONT = 143, - SPELL_FAILED_VISION_OBSCURED = 144, - SPELL_FAILED_WRONG_PET_FOOD = 145, - SPELL_FAILED_NOT_WHILE_FATIGUED = 146, - SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 147, - SPELL_FAILED_NOT_WHILE_TRADING = 148, - SPELL_FAILED_TARGET_NOT_IN_RAID = 149, - SPELL_FAILED_TARGET_FREEFORALL = 150, - SPELL_FAILED_NO_EDIBLE_CORPSES = 151, - SPELL_FAILED_ONLY_BATTLEGROUNDS = 152, - SPELL_FAILED_TARGET_NOT_GHOST = 153, - SPELL_FAILED_TRANSFORM_UNUSABLE = 154, - SPELL_FAILED_WRONG_WEATHER = 155, - SPELL_FAILED_DAMAGE_IMMUNE = 156, - SPELL_FAILED_PREVENTED_BY_MECHANIC = 157, - SPELL_FAILED_PLAY_TIME = 158, - SPELL_FAILED_REPUTATION = 159, - SPELL_FAILED_MIN_SKILL = 160, - SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND = 161, - SPELL_FAILED_NOT_ON_SHAPESHIFT = 162, - SPELL_FAILED_NOT_ON_STEALTHED = 163, - SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 164, - SPELL_FAILED_NOT_ON_MOUNTED = 165, - SPELL_FAILED_TOO_SHALLOW = 166, - SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 167, - SPELL_FAILED_TARGET_IS_TRIVIAL = 168, - SPELL_FAILED_BM_OR_INVISGOD = 169, - SPELL_FAILED_GROUND_MOUNT_NOT_ALLOWED = 170, - SPELL_FAILED_FLOATING_MOUNT_NOT_ALLOWED = 171, - SPELL_FAILED_UNDERWATER_MOUNT_NOT_ALLOWED = 172, - SPELL_FAILED_FLYING_MOUNT_NOT_ALLOWED = 173, - SPELL_FAILED_APPRENTICE_RIDING_REQUIREMENT = 174, - SPELL_FAILED_JOURNEYMAN_RIDING_REQUIREMENT = 175, - SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 176, - SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 177, - SPELL_FAILED_MASTER_RIDING_REQUIREMENT = 178, - SPELL_FAILED_COLD_RIDING_REQUIREMENT = 179, - SPELL_FAILED_FLIGHT_MASTER_RIDING_REQUIREMENT = 180, - SPELL_FAILED_CS_RIDING_REQUIREMENT = 181, - SPELL_FAILED_PANDA_RIDING_REQUIREMENT = 182, - SPELL_FAILED_MOUNT_NO_FLOAT_HERE = 183, - SPELL_FAILED_MOUNT_NO_UNDERWATER_HERE = 184, - SPELL_FAILED_MOUNT_ABOVE_WATER_HERE = 185, - SPELL_FAILED_MOUNT_COLLECTED_ON_OTHER_CHAR = 186, - SPELL_FAILED_NOT_IDLE = 187, - SPELL_FAILED_NOT_INACTIVE = 188, - SPELL_FAILED_PARTIAL_PLAYTIME = 189, - SPELL_FAILED_NO_PLAYTIME = 190, - SPELL_FAILED_NOT_IN_BATTLEGROUND = 191, - SPELL_FAILED_NOT_IN_RAID_INSTANCE = 192, - SPELL_FAILED_ONLY_IN_ARENA = 193, - SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 194, - SPELL_FAILED_ON_USE_ENCHANT = 195, - SPELL_FAILED_NOT_ON_GROUND = 196, - SPELL_FAILED_CUSTOM_ERROR = 197, - SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 198, - SPELL_FAILED_TOO_MANY_SOCKETS = 199, - SPELL_FAILED_INVALID_GLYPH = 200, - SPELL_FAILED_UNIQUE_GLYPH = 201, - SPELL_FAILED_GLYPH_SOCKET_LOCKED = 202, - SPELL_FAILED_GLYPH_EXCLUSIVE_CATEGORY = 203, - SPELL_FAILED_GLYPH_INVALID_SPEC = 204, - SPELL_FAILED_GLYPH_NO_SPEC = 205, - SPELL_FAILED_NO_VALID_TARGETS = 206, - SPELL_FAILED_ITEM_AT_MAX_CHARGES = 207, - SPELL_FAILED_NOT_IN_BARBERSHOP = 208, - SPELL_FAILED_FISHING_TOO_LOW = 209, - SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 210, - SPELL_FAILED_SUMMON_PENDING = 211, - SPELL_FAILED_MAX_SOCKETS = 212, - SPELL_FAILED_PET_CAN_RENAME = 213, - SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED = 214, - SPELL_FAILED_TARGET_HAS_RESURRECT_PENDING = 215, - SPELL_FAILED_NO_ACTIONS = 216, - SPELL_FAILED_CURRENCY_WEIGHT_MISMATCH = 217, - SPELL_FAILED_WEIGHT_NOT_ENOUGH = 218, - SPELL_FAILED_WEIGHT_TOO_MUCH = 219, - SPELL_FAILED_NO_VACANT_SEAT = 220, - SPELL_FAILED_NO_LIQUID = 221, - SPELL_FAILED_ONLY_NOT_SWIMMING = 222, - SPELL_FAILED_BY_NOT_MOVING = 223, - SPELL_FAILED_IN_COMBAT_RES_LIMIT_REACHED = 224, - SPELL_FAILED_NOT_IN_ARENA = 225, - SPELL_FAILED_TARGET_NOT_GROUNDED = 226, - SPELL_FAILED_EXCEEDED_WEEKLY_USAGE = 227, - SPELL_FAILED_NOT_IN_LFG_DUNGEON = 228, - SPELL_FAILED_BAD_TARGET_FILTER = 229, - SPELL_FAILED_NOT_ENOUGH_TARGETS = 230, - SPELL_FAILED_NO_SPEC = 231, - SPELL_FAILED_CANT_ADD_BATTLE_PET = 232, - SPELL_FAILED_CANT_UPGRADE_BATTLE_PET = 233, - SPELL_FAILED_WRONG_BATTLE_PET_TYPE = 234, - SPELL_FAILED_NO_DUNGEON_ENCOUNTER = 235, - SPELL_FAILED_NO_TELEPORT_FROM_DUNGEON = 236, - SPELL_FAILED_MAX_LEVEL_TOO_LOW = 237, - SPELL_FAILED_CANT_REPLACE_ITEM_BONUS = 238, - SPELL_FAILED_UNKNOWN = 254, // custom value, default case - SPELL_CAST_OK = 255 // custom value, must not be sent to client + SPELL_FAILED_GARRISON_FOLLOWER_ON_MISSION = 44, + SPELL_FAILED_GARRISON_FOLLOWER_IN_BUILDING = 45, + SPELL_FAILED_GARRISON_FOLLOWER_MAX_LEVEL = 46, + SPELL_FAILED_GARRISON_FOLLOWER_MAX_ITEM_LEVEL = 47, + SPELL_FAILED_GARRISON_FOLLOWER_MAX_QUALITY = 48, + SPELL_FAILED_GARRISON_FOLLOWER_NOT_MAX_LEVEL = 49, + SPELL_FAILED_GARRISON_FOLLOWER_HAS_ABILITY = 50, + SPELL_FAILED_GARRISON_FOLLOWER_NO_OVERRIDEABLE_ABILITY = 51, + SPELL_FAILED_HIGHLEVEL = 52, + SPELL_FAILED_HUNGER_SATIATED = 53, + SPELL_FAILED_IMMUNE = 54, + SPELL_FAILED_INCORRECT_AREA = 55, + SPELL_FAILED_INTERRUPTED = 56, + SPELL_FAILED_INTERRUPTED_COMBAT = 57, + SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 58, + SPELL_FAILED_ITEM_GONE = 59, + SPELL_FAILED_ITEM_NOT_FOUND = 60, + SPELL_FAILED_ITEM_NOT_READY = 61, + SPELL_FAILED_LEVEL_REQUIREMENT = 62, + SPELL_FAILED_LINE_OF_SIGHT = 63, + SPELL_FAILED_LOWLEVEL = 64, + SPELL_FAILED_LOW_CASTLEVEL = 65, + SPELL_FAILED_MAINHAND_EMPTY = 66, + SPELL_FAILED_MOVING = 67, + SPELL_FAILED_NEED_AMMO = 68, + SPELL_FAILED_NEED_AMMO_POUCH = 69, + SPELL_FAILED_NEED_EXOTIC_AMMO = 70, + SPELL_FAILED_NEED_MORE_ITEMS = 71, + SPELL_FAILED_NOPATH = 72, + SPELL_FAILED_NOT_BEHIND = 73, + SPELL_FAILED_NOT_FISHABLE = 74, + SPELL_FAILED_NOT_FLYING = 75, + SPELL_FAILED_NOT_HERE = 76, + SPELL_FAILED_NOT_INFRONT = 77, + SPELL_FAILED_NOT_IN_CONTROL = 78, + SPELL_FAILED_NOT_KNOWN = 79, + SPELL_FAILED_NOT_MOUNTED = 80, + SPELL_FAILED_NOT_ON_TAXI = 81, + SPELL_FAILED_NOT_ON_TRANSPORT = 82, + SPELL_FAILED_NOT_READY = 83, + SPELL_FAILED_NOT_SHAPESHIFT = 84, + SPELL_FAILED_NOT_STANDING = 85, + SPELL_FAILED_NOT_TRADEABLE = 86, + SPELL_FAILED_NOT_TRADING = 87, + SPELL_FAILED_NOT_UNSHEATHED = 88, + SPELL_FAILED_NOT_WHILE_GHOST = 89, + SPELL_FAILED_NOT_WHILE_LOOTING = 90, + SPELL_FAILED_NO_AMMO = 91, + SPELL_FAILED_NO_CHARGES_REMAIN = 92, + SPELL_FAILED_NO_CHAMPION = 93, + SPELL_FAILED_NO_COMBO_POINTS = 94, + SPELL_FAILED_NO_DUELING = 95, + SPELL_FAILED_NO_ENDURANCE = 96, + SPELL_FAILED_NO_FISH = 97, + SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 98, + SPELL_FAILED_NO_MOUNTS_ALLOWED = 99, + SPELL_FAILED_NO_PET = 100, + SPELL_FAILED_NO_POWER = 101, + SPELL_FAILED_NOTHING_TO_DISPEL = 102, + SPELL_FAILED_NOTHING_TO_STEAL = 103, + SPELL_FAILED_ONLY_ABOVEWATER = 104, + SPELL_FAILED_ONLY_DAYTIME = 105, + SPELL_FAILED_ONLY_INDOORS = 106, + SPELL_FAILED_ONLY_MOUNTED = 107, + SPELL_FAILED_ONLY_NIGHTTIME = 108, + SPELL_FAILED_ONLY_OUTDOORS = 109, + SPELL_FAILED_ONLY_SHAPESHIFT = 110, + SPELL_FAILED_ONLY_STEALTHED = 111, + SPELL_FAILED_ONLY_UNDERWATER = 112, + SPELL_FAILED_OUT_OF_RANGE = 113, + SPELL_FAILED_PACIFIED = 114, + SPELL_FAILED_POSSESSED = 115, + SPELL_FAILED_REAGENTS = 116, + SPELL_FAILED_REQUIRES_AREA = 117, + SPELL_FAILED_REQUIRES_SPELL_FOCUS = 118, + SPELL_FAILED_ROOTED = 119, + SPELL_FAILED_SILENCED = 120, + SPELL_FAILED_SPELL_IN_PROGRESS = 121, + SPELL_FAILED_SPELL_LEARNED = 122, + SPELL_FAILED_SPELL_UNAVAILABLE = 123, + SPELL_FAILED_STUNNED = 124, + SPELL_FAILED_TARGETS_DEAD = 125, + SPELL_FAILED_TARGET_AFFECTING_COMBAT = 126, + SPELL_FAILED_TARGET_AURASTATE = 127, + SPELL_FAILED_TARGET_DUELING = 128, + SPELL_FAILED_TARGET_ENEMY = 129, + SPELL_FAILED_TARGET_ENRAGED = 130, + SPELL_FAILED_TARGET_FRIENDLY = 131, + SPELL_FAILED_TARGET_IN_COMBAT = 132, + SPELL_FAILED_TARGET_IN_PET_BATTLE = 133, + SPELL_FAILED_TARGET_IS_PLAYER = 134, + SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 135, + SPELL_FAILED_TARGET_NOT_DEAD = 136, + SPELL_FAILED_TARGET_NOT_IN_PARTY = 137, + SPELL_FAILED_TARGET_NOT_LOOTED = 138, + SPELL_FAILED_TARGET_NOT_PLAYER = 139, + SPELL_FAILED_TARGET_NO_POCKETS = 140, + SPELL_FAILED_TARGET_NO_WEAPONS = 141, + SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 142, + SPELL_FAILED_TARGET_UNSKINNABLE = 143, + SPELL_FAILED_THIRST_SATIATED = 144, + SPELL_FAILED_TOO_CLOSE = 145, + SPELL_FAILED_TOO_MANY_OF_ITEM = 146, + SPELL_FAILED_TOTEM_CATEGORY = 147, + SPELL_FAILED_TOTEMS = 148, + SPELL_FAILED_TRY_AGAIN = 149, + SPELL_FAILED_UNIT_NOT_BEHIND = 150, + SPELL_FAILED_UNIT_NOT_INFRONT = 151, + SPELL_FAILED_VISION_OBSCURED = 152, + SPELL_FAILED_WRONG_PET_FOOD = 153, + SPELL_FAILED_NOT_WHILE_FATIGUED = 154, + SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 155, + SPELL_FAILED_NOT_WHILE_TRADING = 156, + SPELL_FAILED_TARGET_NOT_IN_RAID = 157, + SPELL_FAILED_TARGET_FREEFORALL = 158, + SPELL_FAILED_NO_EDIBLE_CORPSES = 159, + SPELL_FAILED_ONLY_BATTLEGROUNDS = 160, + SPELL_FAILED_TARGET_NOT_GHOST = 161, + SPELL_FAILED_TRANSFORM_UNUSABLE = 162, + SPELL_FAILED_WRONG_WEATHER = 163, + SPELL_FAILED_DAMAGE_IMMUNE = 164, + SPELL_FAILED_PREVENTED_BY_MECHANIC = 165, + SPELL_FAILED_PLAY_TIME = 166, + SPELL_FAILED_REPUTATION = 167, + SPELL_FAILED_MIN_SKILL = 168, + SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND = 169, + SPELL_FAILED_NOT_ON_SHAPESHIFT = 170, + SPELL_FAILED_NOT_ON_STEALTHED = 171, + SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 172, + SPELL_FAILED_NOT_ON_MOUNTED = 173, + SPELL_FAILED_TOO_SHALLOW = 174, + SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 175, + SPELL_FAILED_TARGET_IS_TRIVIAL = 176, + SPELL_FAILED_BM_OR_INVISGOD = 177, + SPELL_FAILED_GROUND_MOUNT_NOT_ALLOWED = 178, + SPELL_FAILED_FLOATING_MOUNT_NOT_ALLOWED = 179, + SPELL_FAILED_UNDERWATER_MOUNT_NOT_ALLOWED = 180, + SPELL_FAILED_FLYING_MOUNT_NOT_ALLOWED = 181, + SPELL_FAILED_APPRENTICE_RIDING_REQUIREMENT = 182, + SPELL_FAILED_JOURNEYMAN_RIDING_REQUIREMENT = 183, + SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 184, + SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 185, + SPELL_FAILED_MASTER_RIDING_REQUIREMENT = 186, + SPELL_FAILED_COLD_RIDING_REQUIREMENT = 187, + SPELL_FAILED_FLIGHT_MASTER_RIDING_REQUIREMENT = 188, + SPELL_FAILED_CS_RIDING_REQUIREMENT = 189, + SPELL_FAILED_PANDA_RIDING_REQUIREMENT = 190, + SPELL_FAILED_MOUNT_NO_FLOAT_HERE = 191, + SPELL_FAILED_MOUNT_NO_UNDERWATER_HERE = 192, + SPELL_FAILED_MOUNT_ABOVE_WATER_HERE = 193, + SPELL_FAILED_MOUNT_COLLECTED_ON_OTHER_CHAR = 194, + SPELL_FAILED_NOT_IDLE = 195, + SPELL_FAILED_NOT_INACTIVE = 196, + SPELL_FAILED_PARTIAL_PLAYTIME = 197, + SPELL_FAILED_NO_PLAYTIME = 198, + SPELL_FAILED_NOT_IN_BATTLEGROUND = 199, + SPELL_FAILED_NOT_IN_RAID_INSTANCE = 200, + SPELL_FAILED_ONLY_IN_ARENA = 201, + SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 202, + SPELL_FAILED_ON_USE_ENCHANT = 203, + SPELL_FAILED_NOT_ON_GROUND = 204, + SPELL_FAILED_CUSTOM_ERROR = 205, + SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 206, + SPELL_FAILED_TOO_MANY_SOCKETS = 207, + SPELL_FAILED_INVALID_GLYPH = 208, + SPELL_FAILED_UNIQUE_GLYPH = 209, + SPELL_FAILED_GLYPH_SOCKET_LOCKED = 210, + SPELL_FAILED_GLYPH_EXCLUSIVE_CATEGORY = 211, + SPELL_FAILED_GLYPH_INVALID_SPEC = 212, + SPELL_FAILED_GLYPH_NO_SPEC = 213, + SPELL_FAILED_NO_VALID_TARGETS = 214, + SPELL_FAILED_ITEM_AT_MAX_CHARGES = 215, + SPELL_FAILED_NOT_IN_BARBERSHOP = 216, + SPELL_FAILED_FISHING_TOO_LOW = 217, + SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 218, + SPELL_FAILED_SUMMON_PENDING = 219, + SPELL_FAILED_MAX_SOCKETS = 220, + SPELL_FAILED_PET_CAN_RENAME = 221, + SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED = 222, + SPELL_FAILED_TARGET_HAS_RESURRECT_PENDING = 223, + SPELL_FAILED_NO_ACTIONS = 224, + SPELL_FAILED_CURRENCY_WEIGHT_MISMATCH = 225, + SPELL_FAILED_WEIGHT_NOT_ENOUGH = 226, + SPELL_FAILED_WEIGHT_TOO_MUCH = 227, + SPELL_FAILED_NO_VACANT_SEAT = 228, + SPELL_FAILED_NO_LIQUID = 229, + SPELL_FAILED_ONLY_NOT_SWIMMING = 230, + SPELL_FAILED_BY_NOT_MOVING = 231, + SPELL_FAILED_IN_COMBAT_RES_LIMIT_REACHED = 232, + SPELL_FAILED_NOT_IN_ARENA = 233, + SPELL_FAILED_TARGET_NOT_GROUNDED = 234, + SPELL_FAILED_EXCEEDED_WEEKLY_USAGE = 235, + SPELL_FAILED_NOT_IN_LFG_DUNGEON = 236, + SPELL_FAILED_BAD_TARGET_FILTER = 237, + SPELL_FAILED_NOT_ENOUGH_TARGETS = 238, + SPELL_FAILED_NO_SPEC = 239, + SPELL_FAILED_CANT_ADD_BATTLE_PET = 240, + SPELL_FAILED_CANT_UPGRADE_BATTLE_PET = 241, + SPELL_FAILED_WRONG_BATTLE_PET_TYPE = 242, + SPELL_FAILED_NO_DUNGEON_ENCOUNTER = 243, + SPELL_FAILED_NO_TELEPORT_FROM_DUNGEON = 244, + SPELL_FAILED_MAX_LEVEL_TOO_LOW = 245, + SPELL_FAILED_CANT_REPLACE_ITEM_BONUS = 246, + SPELL_FAILED_GRANT_PET_LEVEL_FAIL = 247, + SPELL_FAILED_SKILL_LINE_NOT_KNOWN = 248, + SPELL_FAILED_BLUEPRINT_KNOWN = 249, + SPELL_FAILED_FOLLOWER_KNOWN = 250, + SPELL_FAILED_CANT_OVERRIDE_ENCHANT_VISUAL = 251, + SPELL_FAILED_ITEM_NOT_A_WEAPON = 252, + SPELL_FAILED_SAME_ENCHANT_VISUAL = 253, + SPELL_FAILED_TOY_USE_LIMIT_REACHED = 254, + SPELL_FAILED_SHIPMENTS_FULL = 255, + SPELL_FAILED_HAS_MISSION = 256, + SPELL_FAILED_BUILDING_ACTIVATE_NOT_READY = 257, + SPELL_FAILED_NOT_SOULBOUND = 258, + SPELL_FAILED_RIDING_VEHICLE = 259, + SPELL_FAILED_UNKNOWN = 260, // custom value, default case + SPELL_CAST_OK = 0xFFFF // custom value, must not be sent to client }; enum SpellCustomErrors @@ -4128,8 +4241,22 @@ enum ChatMsg CHAT_MSG_CURRENCY = 0x40 }; +#define GM_SILENCE_AURA 1852 + #define MAX_CHAT_MSG_TYPE 0x41 +enum ChatFlags +{ + CHAT_FLAG_NONE = 0x00, + CHAT_FLAG_AFK = 0x01, + CHAT_FLAG_DND = 0x02, + CHAT_FLAG_GM = 0x04, + CHAT_FLAG_COM = 0x08, // Commentator + CHAT_FLAG_DEV = 0x10, + CHAT_FLAG_BOSS_SOUND = 0x20, // Plays "RaidBossEmoteWarning" sound on raid boss emote/whisper + CHAT_FLAG_MOBILE = 0x40 +}; + enum ChatLinkColors { CHAT_LINK_COLOR_TRADE = 0xffffd000, // orange @@ -4605,7 +4732,7 @@ enum GroupJoinBattlegroundResult ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND = 8, // You can't do that in a battleground. ERR_BATTLEGROUND_JOIN_XP_GAIN = 9, // wtf, doesn't exist in client... ERR_BATTLEGROUND_JOIN_RANGE_INDEX = 10, // Cannot join the queue unless all members of your party are in the same battleground level range. - ERR_BATTLEGROUND_JOIN_TIMED_OUT = 11, // %s was unavailable to join the queue. (uint64 guid exist in client cache) + ERR_BATTLEGROUND_JOIN_TIMED_OUT = 11, // %s was unavailable to join the queue. (ObjectGuid exist in client cache) //ERR_BATTLEGROUND_JOIN_TIMED_OUT = 12, // same as 11 //ERR_BATTLEGROUND_TEAM_LEFT_QUEUE = 13, // same as 7 ERR_LFG_CANT_USE_BATTLEGROUND = 14, // You cannot queue for a battleground or arena while using the dungeon system. diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp index 749b6be4ee5..560f40143bb 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.cpp +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -24,6 +24,7 @@ #include "Vehicle.h" #include "WorldPacket.h" #include "Opcodes.h" +#include "MovementPackets.h" namespace Movement { @@ -115,17 +116,11 @@ namespace Movement unit->m_movementInfo.SetMovementFlags(moveFlags); move_spline.Initialize(args); - WorldPacket data(SMSG_MONSTER_MOVE, 64); - data << unit->GetPackGUID(); - if (!unit->GetTransGUID().IsEmpty()) - { - data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); - data << unit->GetTransGUID().WriteAsPacked(); - data << int8(unit->GetTransSeat()); - } - - PacketBuilder::WriteMonsterMove(move_spline, data); - unit->SendMessageToSet(&data, true); + WorldPackets::Movement::MonsterMove packet; + packet.MoverGUID = unit->GetGUID(); + packet.Pos = real_position; + PacketBuilder::WriteMonsterMove(move_spline, packet.SplineData); + unit->SendMessageToSet(packet.Write(), true); return move_spline.Duration(); } @@ -161,17 +156,18 @@ namespace Movement move_spline.onTransport = transport; move_spline.Initialize(args); - WorldPacket data(SMSG_MONSTER_MOVE, 64); - data << unit->GetPackGUID(); + WorldPackets::Movement::MonsterMove packet; + packet.MoverGUID = unit->GetGUID(); + packet.Pos = loc; + packet.SplineData.ID = move_spline.GetId(); + if (transport) { - data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); - data << unit->GetTransGUID().WriteAsPacked(); - data << int8(unit->GetTransSeat()); + packet.SplineData.Move.TransportGUID = unit->GetTransGUID(); + packet.SplineData.Move.VehicleSeat = unit->GetTransSeat(); } - PacketBuilder::WriteStopMovement(loc, args.splineId, data); - unit->SendMessageToSet(&data, true); + unit->SendMessageToSet(packet.Write(), true); } MoveSplineInit::MoveSplineInit(Unit* m) : unit(m) diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp index 02fdabb3938..f13c69b97fd 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -21,132 +21,90 @@ #include "MoveSpline.h" #include "WorldPacket.h" #include "Object.h" +#include "MovementPackets.h" namespace Movement { - inline void operator << (ByteBuffer& b, const Vector3& v) + void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, WorldPackets::Movement::MovementMonsterSpline& movementMonsterSpline) { - b << v.x << v.y << v.z; - } - - inline void operator >> (ByteBuffer& b, Vector3& v) - { - b >> v.x >> v.y >> v.z; - } + movementMonsterSpline.ID = move_spline.m_Id; + WorldPackets::Movement::MovementSpline& movementSpline = movementMonsterSpline.Move; - enum MonsterMoveType - { - MonsterMoveNormal = 0, - MonsterMoveStop = 1, - MonsterMoveFacingSpot = 2, - MonsterMoveFacingTarget = 3, - MonsterMoveFacingAngle = 4 - }; - - void PacketBuilder::WriteCommonMonsterMovePart(const MoveSpline& move_spline, WorldPacket& data) - { MoveSplineFlag splineflags = move_spline.splineflags; + splineflags.enter_cycle = move_spline.isCyclic(); + movementSpline.Flags = uint32(splineflags & uint32(~MoveSplineFlag::Mask_No_Monster_Move)); - data << uint8(0); // sets/unsets MOVEMENTFLAG2_UNK7 (0x40) - data << move_spline.spline.getPoint(move_spline.spline.first()); - data << move_spline.GetId(); - - switch (splineflags & MoveSplineFlag::Mask_Final_Facing) + switch (move_spline.splineflags & MoveSplineFlag::Mask_Final_Facing) { + case MoveSplineFlag::Final_Point: + movementSpline.Face = MONSTER_MOVE_FACING_SPOT; + movementSpline.FaceSpot = move_spline.facing.f; + break; case MoveSplineFlag::Final_Target: - data << uint8(MonsterMoveFacingTarget); - data << move_spline.facing.target; + movementSpline.Face = MONSTER_MOVE_FACING_TARGET; + movementSpline.FaceGUID = move_spline.facing.target; break; case MoveSplineFlag::Final_Angle: - data << uint8(MonsterMoveFacingAngle); - data << move_spline.facing.angle; - break; - case MoveSplineFlag::Final_Point: - data << uint8(MonsterMoveFacingSpot); - data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z; + movementSpline.Face = MONSTER_MOVE_FACING_ANGLE; + movementSpline.FaceDirection = move_spline.facing.angle; break; default: - data << uint8(MonsterMoveNormal); + movementSpline.Face = MONSTER_MOVE_NORMAL; break; } - // add fake Enter_Cycle flag - needed for client-side cyclic movement (client will erase first spline vertex after first cycle done) - splineflags.enter_cycle = move_spline.isCyclic(); - data << uint32(splineflags & uint32(~MoveSplineFlag::Mask_No_Monster_Move)); - if (splineflags.animation) { - data << splineflags.getAnimationId(); - data << move_spline.effect_start_time; + movementSpline.AnimTier = splineflags.getAnimationId(); + movementSpline.TierTransStartTime = move_spline.effect_start_time; } - data << move_spline.Duration(); + movementSpline.MoveTime = move_spline.Duration(); if (splineflags.parabolic) { - data << move_spline.vertical_acceleration; - data << move_spline.effect_start_time; + movementSpline.JumpGravity = move_spline.vertical_acceleration; + movementSpline.SpecialTime = move_spline.effect_start_time; } - } - - void PacketBuilder::WriteStopMovement(Vector3 const& pos, uint32 splineId, ByteBuffer& data) - { - data << uint8(0); // sets/unsets MOVEMENTFLAG2_UNK7 (0x40) - data << pos; - data << splineId; - data << uint8(MonsterMoveStop); - } - - void WriteLinearPath(Spline<int32> const& spline, ByteBuffer& data) - { - uint32 last_idx = spline.getPointCount() - 3; - Vector3 const* real_path = &spline.getPoint(1); - - data << last_idx; - data << real_path[last_idx]; // destination - if (last_idx > 1) - { - Vector3 middle = (real_path[0] + real_path[last_idx]) / 2.f; - Vector3 offset; - // first and last points already appended - for (uint32 i = 1; i < last_idx; ++i) - { - offset = middle - real_path[i]; - data.appendPackXYZ(offset.x, offset.y, offset.z); - } - } - } - - void WriteUncompressedPath(Spline<int32> const& spline, ByteBuffer& data) - { - uint32 count = spline.getPointCount() - 3; - data << count; - data.append<Vector3>(&spline.getPoint(2), count); - } - - void WriteUncompressedCyclicPath(Spline<int32> const& spline, ByteBuffer& data) - { - uint32 count = spline.getPointCount() - 3; - data << uint32(count + 1); - data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done - data.append<Vector3>(&spline.getPoint(1), count); - } - - void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, WorldPacket& data) - { - WriteCommonMonsterMovePart(move_spline, data); Spline<int32> const& spline = move_spline.spline; - MoveSplineFlag splineflags = move_spline.splineflags; + std::vector<Vector3> const& array = spline.getPoints(); + if (splineflags & MoveSplineFlag::UncompressedPath) { if (!splineflags.cyclic) - WriteUncompressedPath(spline, data); + { + uint32 count = spline.getPointCount() - 3; + for (uint32 i = 2; i < count; ++i) + movementSpline.Points.push_back(array[i]); + } else - WriteUncompressedCyclicPath(spline, data); + { + uint32 count = spline.getPointCount() - 3; + movementSpline.Points.push_back(array[1]); + for (uint32 i = 1; i < count; ++i) + movementSpline.Points.push_back(array[i]); + } } else - WriteLinearPath(spline, data); + { + uint32 last_idx = spline.getPointCount() - 3; + Vector3 const* real_path = &spline.getPoint(1); + + movementSpline.Points.push_back(real_path[last_idx]); + + if (last_idx > 1) + { + Vector3 middle = (real_path[0] + real_path[last_idx]) / 2.f; + Vector3 offset; + // first and last points already appended + for (uint32 i = 1; i < last_idx; ++i) + { + offset = middle - real_path[i]; + movementSpline.PackedDeltas.push_back(offset); + } + } + } } void PacketBuilder::WriteCreate(MoveSpline const& moveSpline, ByteBuffer& data) diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.h b/src/server/game/Movement/Spline/MovementPacketBuilder.h index 2878a330f67..720c0b3b244 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.h +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.h @@ -22,6 +22,7 @@ #include "Define.h" // for uint32 #include "G3D/Vector3.h" +#include "MovementPackets.h" using G3D::Vector3; class ByteBuffer; @@ -32,11 +33,8 @@ namespace Movement class MoveSpline; class PacketBuilder { - static void WriteCommonMonsterMovePart(const MoveSpline& mov, WorldPacket& data); public: - - static void WriteMonsterMove(const MoveSpline& mov, WorldPacket& data); - static void WriteStopMovement(Vector3 const& loc, uint32 splineId, ByteBuffer& data); + static void WriteMonsterMove(const MoveSpline& mov, WorldPackets::Movement::MovementMonsterSpline& movementMonsterSpline); static void WriteCreate(MoveSpline const& moveSpline, ByteBuffer& data); }; } diff --git a/src/server/game/Movement/Spline/MovementTypedefs.h b/src/server/game/Movement/Spline/MovementTypedefs.h index a69af9e3a83..14c4e19b19b 100644 --- a/src/server/game/Movement/Spline/MovementTypedefs.h +++ b/src/server/game/Movement/Spline/MovementTypedefs.h @@ -21,6 +21,14 @@ #include "Common.h" +enum MonsterMoveType +{ + MONSTER_MOVE_NORMAL = 0, + MONSTER_MOVE_FACING_SPOT = 1, + MONSTER_MOVE_FACING_TARGET = 2, + MONSTER_MOVE_FACING_ANGLE = 3 +}; + namespace G3D { class Vector3; diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 89ca3749a05..f39314ba119 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -360,9 +360,6 @@ bool Quest::IsAllowedInRaid(Difficulty difficulty) const uint32 Quest::CalculateHonorGain(uint8 level) const { - if (level > GT_MAX_LEVEL) - level = GT_MAX_LEVEL; - uint32 honor = 0; /*if (GetRewHonorAddition() > 0 || GetRewHonorMultiplier() > 0.0f) diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp index 359a8f3946a..3bf3464f016 100644 --- a/src/server/game/Reputation/ReputationMgr.cpp +++ b/src/server/game/Reputation/ReputationMgr.cpp @@ -18,6 +18,7 @@ #include "DatabaseEnv.h" #include "ReputationMgr.h" +#include "ReputationPackets.h" #include "DBCStores.h" #include "Player.h" #include "WorldPacket.h" @@ -199,38 +200,17 @@ void ReputationMgr::SendState(FactionState const* faction) void ReputationMgr::SendInitialReputations() { - uint16 count = 256; - WorldPacket data(SMSG_INITIALIZE_FACTIONS, 4 + count * 5); - data << uint32(count); - - RepListID a = 0; + WorldPackets::Reputation::InitializeFactions initFactions; for (FactionStateList::iterator itr = _factions.begin(); itr != _factions.end(); ++itr) { - // fill in absent fields - for (; a != itr->first; ++a) - { - data << uint8(0); - data << uint32(0); - } - - // fill in encountered data - data << uint8(itr->second.Flags); - data << uint32(itr->second.Standing); - + initFactions.FactionFlags[itr->first] = itr->second.Flags; + initFactions.FactionStandings[itr->first] = itr->second.Standing; + /// @todo faction bonus itr->second.needSend = false; - - ++a; } - // fill in absent fields - for (; a != count; ++a) - { - data << uint8(0); - data << uint32(0); - } - - _player->SendDirectMessage(&data); + _player->SendDirectMessage(initFactions.Write()); } void ReputationMgr::SendStates() diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index ac0b5bbf2e6..95ac2d275da 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -34,6 +34,12 @@ #include "WorldPacket.h" #include "WorldSession.h" +// namespace +// { + UnusedScriptContainer UnusedScripts; + UnusedScriptNamesContainer UnusedScriptNames; +// } + // This is the global static registry of scripts. template<class TScript> class ScriptRegistry @@ -89,6 +95,12 @@ class ScriptRegistry { ScriptPointerList[id] = script; sScriptMgr->IncrementScriptCount(); + + #ifdef SCRIPTS + UnusedScriptNamesContainer::iterator itr = std::lower_bound(UnusedScriptNames.begin(), UnusedScriptNames.end(), script->GetName()); + if (itr != UnusedScriptNames.end() && *itr == script->GetName()) + UnusedScriptNames.erase(itr); + #endif } else { @@ -106,8 +118,7 @@ class ScriptRegistry // Avoid calling "delete script;" because we are currently in the script constructor // In a valid scenario this will not happen because every script has a name assigned in the database - // If that happens, it's acceptable to just leak a few bytes - + UnusedScripts.push_back(script); return; } } @@ -189,6 +200,15 @@ void ScriptMgr::Initialize() FillSpellSummary(); AddScripts(); +#ifdef SCRIPTS + for (std::string const& scriptName : UnusedScriptNames) + { + TC_LOG_ERROR("sql.sql", "ScriptName '%s' exists in database, but no core script found!", scriptName.c_str()); + } +#endif + + UnloadUnusedScripts(); + TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms", GetScriptCount(), GetMSTimeDiffToNow(oldMSTime)); } @@ -229,10 +249,19 @@ void ScriptMgr::Unload() #undef SCR_CLEAR + UnloadUnusedScripts(); + delete[] SpellSummary; delete[] UnitAI::AISpellInfo; } +void ScriptMgr::UnloadUnusedScripts() +{ + for (size_t i = 0; i < UnusedScripts.size(); ++i) + delete UnusedScripts[i]; + UnusedScripts.clear(); +} + void ScriptMgr::LoadDatabase() { sScriptSystemMgr->LoadScriptWaypoints(); @@ -256,70 +285,73 @@ void ScriptMgr::FillSpellSummary() if (!pTempSpell) continue; - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : pTempSpell->GetEffectsForDifficulty(DIFFICULTY_NONE)) { + if (!effect) + continue; + // Spell targets self. - if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER) + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); // Spell targets a single enemy. - if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY) + if (effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || + effect->TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1); // Spell targets AoE at enemy. - if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_SRC_CASTER || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) + if (effect->TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || + effect->TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || + effect->TargetA.GetTarget() == TARGET_SRC_CASTER || + effect->TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); // Spell targets an enemy. - if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_SRC_CASTER || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) + if (effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || + effect->TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY || + effect->TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || + effect->TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || + effect->TargetA.GetTarget() == TARGET_SRC_CASTER || + effect->TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1); // Spell targets a single friend (or self). - if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY) + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER || + effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY || + effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1); // Spell targets AoE friends. - if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_SRC_CASTER) + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY || + effect->TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY || + effect->TargetA.GetTarget() == TARGET_SRC_CASTER) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); // Spell targets any friend (or self). - if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY || - pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_SRC_CASTER) + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER || + effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY || + effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY || + effect->TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY || + effect->TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY || + effect->TargetA.GetTarget() == TARGET_SRC_CASTER) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); // Make sure that this spell includes a damage effect. - if (pTempSpell->Effects[j].Effect == SPELL_EFFECT_SCHOOL_DAMAGE || - pTempSpell->Effects[j].Effect == SPELL_EFFECT_INSTAKILL || - pTempSpell->Effects[j].Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || - pTempSpell->Effects[j].Effect == SPELL_EFFECT_HEALTH_LEECH) + if (effect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE || + effect->Effect == SPELL_EFFECT_INSTAKILL || + effect->Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || + effect->Effect == SPELL_EFFECT_HEALTH_LEECH) SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE-1); // Make sure that this spell includes a healing effect (or an apply aura with a periodic heal). - if (pTempSpell->Effects[j].Effect == SPELL_EFFECT_HEAL || - pTempSpell->Effects[j].Effect == SPELL_EFFECT_HEAL_MAX_HEALTH || - pTempSpell->Effects[j].Effect == SPELL_EFFECT_HEAL_MECHANICAL || - (pTempSpell->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA && pTempSpell->Effects[j].ApplyAuraName == 8)) + if (effect->Effect == SPELL_EFFECT_HEAL || + effect->Effect == SPELL_EFFECT_HEAL_MAX_HEALTH || + effect->Effect == SPELL_EFFECT_HEAL_MECHANICAL || + (effect->Effect == SPELL_EFFECT_APPLY_AURA && effect->ApplyAuraName == 8)) SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1); // Make sure that this spell applies an aura. - if (pTempSpell->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA) + if (effect->Effect == SPELL_EFFECT_APPLY_AURA) SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); } } diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 5957f3a511a..4431f710976 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -872,6 +872,15 @@ class GroupScript : public ScriptObject // Placed here due to ScriptRegistry::AddScript dependency. #define sScriptMgr ScriptMgr::instance() +// namespace +// { + typedef std::vector<ScriptObject*> UnusedScriptContainer; + typedef std::list<std::string> UnusedScriptNamesContainer; + + extern UnusedScriptContainer UnusedScripts; + extern UnusedScriptNamesContainer UnusedScriptNames; +// } + // Manages registration, loading, and execution of scripts. class ScriptMgr { @@ -900,6 +909,7 @@ class ScriptMgr public: /* Unloading */ void Unload(); + void UnloadUnusedScripts(); public: /* SpellScriptLoader */ diff --git a/src/server/game/Server/Packet.cpp b/src/server/game/Server/Packet.cpp index ee805c18610..10b472bee67 100644 --- a/src/server/game/Server/Packet.cpp +++ b/src/server/game/Server/Packet.cpp @@ -17,164 +17,6 @@ #include "Packet.h" -inline bool IsInstanceOnlyOpcode(uint32 opcode) -{ - // TODO: Use names when known - switch (opcode) - { - case 0x000F: // Client - case 0x0111: // Client - case 0x03E4: // Client - case 0x0549: // Client - case 0x054C: // Client - case 0x055A: // Client - case 0x056C: // Client - case 0x057A: // Client - case 0x057B: // Client - case 0x05CC: // Client - case 0x05EA: // Client - case 0x05EC: // Client - case 0x05F9: // Client - case 0x05FB: // Client - case 0x074C: // Client - case 0x075B: // Client - case 0x076C: // Client - case 0x077B: // Client - case 0x077C: // Client - case 0x07CC: // Client - case 0x07DB: // Client - case 0x07EC: // Client - case 0x07FB: // Client - case 0x07FC: // Client - case 0x0827: // Client - case 0x0935: // Client - case 0x0F0C: // ClientSpell - case 0x0F10: // ClientSpell - case 0x0F1B: // ClientSpell - case 0x0F1C: // ClientSpell - case 0x0F20: // ClientSpell - case 0x0F2C: // ClientSpell - case 0x0F2F: // ClientSpell - case 0x0F3B: // ClientSpell - case 0x0F8B: // ClientSpell - case 0x0F8C: // ClientSpell - case 0x0F90: // ClientSpell - case 0x0F9F: // ClientSpell - case 0x0FA0: // ClientSpell - case SMSG_ATTACKSTOP: // Client - case 0x14C9: // Client - case 0x154A: // Client - case 0x155A: // Client - case 0x155C: // Client - case SMSG_QUESTGIVER_STATUS: // ClientQuest - case 0x156A: // Client - case 0x156B: // Client - case 0x157A: // Client - case 0x157B: // Client - case 0x15DC: // Client - case 0x15EB: // Client - case 0x15FB: // Client - case 0x170C: // ClientSpell - case 0x171C: // ClientSpell - case 0x171F: // ClientSpell - case 0x172C: // ClientSpell - case 0x172F: // ClientSpell - case 0x173C: // ClientSpell - case 0x173F: // ClientSpell - case 0x1740: // ClientSpell - case 0x1790: // ClientSpell - case 0x179B: // ClientSpell - case 0x179F: // ClientSpell - case SMSG_ATTACKSTART: // Client - case 0x1D82: // ClientQuest - case 0x1D83: // ClientQuest - case 0x1D85: // ClientQuest - case 0x1D87: // ClientQuest - case 0x1D93: // ClientQuest - case 0x1D96: // ClientQuest - case 0x1D97: // ClientQuest - case 0x1DA1: // ClientQuest - case 0x1DA2: // ClientQuest - case 0x1DA3: // ClientQuest - case 0x1DA4: // ClientQuest - case 0x1DA5: // ClientQuest - case 0x1DA7: // ClientQuest - case SMSG_QUERY_TIME_RESPONSE: // Client - case 0x1DC2: // ClientQuest - case 0x1DC6: // ClientQuest - case 0x1DC7: // ClientQuest - case 0x1DD2: // ClientQuest - case 0x1DD3: // ClientQuest - case 0x1DD6: // ClientQuest - case 0x1DD7: // ClientQuest - case 0x1DD8: // ClientQuest - case 0x1DE4: // ClientQuest - case 0x1DE5: // ClientQuest - case 0x1DE7: // ClientQuest - case 0x1F02: // ClientQuest - case 0x1F06: // ClientQuest - case 0x1F07: // ClientQuest - case 0x1F0C: // ClientSpell - case 0x1F12: // ClientQuest - case 0x1F13: // ClientQuest - case 0x1F16: // ClientQuest - case 0x1F17: // ClientQuest - case 0x1F18: // ClientQuest - case 0x1F1C: // ClientSpell - case 0x1F1F: // ClientSpell - case 0x1F24: // ClientQuest - case 0x1F25: // ClientQuest - case 0x1F27: // ClientQuest - case 0x1F2C: // ClientSpell - case 0x1F2F: // ClientSpell - case 0x1F3C: // ClientSpell - case 0x1F3F: // ClientSpell - case 0x1F40: // ClientSpell - case 0x1F44: // ClientQuest - case 0x1F48: // ClientQuest - case 0x1F51: // ClientQuest - case 0x1F55: // ClientQuest - case 0x1F57: // ClientQuest - case 0x1F61: // ClientQuest - case 0x1F63: // ClientQuest - case 0x1F64: // ClientQuest - case 0x1F65: // ClientQuest - case 0x1F67: // ClientQuest - case 0x1F85: // ClientQuest - case 0x1F86: // ClientQuest - case 0x1F87: // ClientQuest - case 0x1F90: // ClientSpell - case 0x1F92: // ClientQuest - case 0x1F94: // ClientQuest - case 0x1F96: // ClientQuest - case 0x1F97: // ClientQuest - case 0x1F9B: // ClientSpell - case 0x1F9F: // ClientSpell - case 0x1FA1: // ClientQuest - case 0x1FA2: // ClientQuest - case 0x1FA3: // ClientQuest - case 0x1FA4: // ClientQuest - case 0x1FA5: // ClientQuest - case 0x1FA7: // ClientQuest - case 0x1FC2: // ClientQuest - case 0x1FC6: // ClientQuest - case 0x1FC7: // ClientQuest - case 0x1FD2: // ClientQuest - case 0x1FD3: // ClientQuest - case 0x1FD6: // ClientQuest - case 0x1FD7: // ClientQuest - case 0x1FD8: // ClientQuest - case 0x1FE4: // ClientQuest - case 0x1FE5: // ClientQuest - case 0x1FE7: // ClientQuest - return true; - default: - return false; - } -} - WorldPackets::ServerPacket::ServerPacket(OpcodeServer opcode, size_t initialSize /*= 200*/) : Packet(WorldPacket(opcode, initialSize)) { - if (IsInstanceOnlyOpcode(opcode)) - _connectionIndex = CONNECTION_TYPE_INSTANCE; } diff --git a/src/server/game/Server/Packets/AuthenticationPackets.cpp b/src/server/game/Server/Packets/AuthenticationPackets.cpp index 2bb1760b31c..a69e684438f 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.cpp +++ b/src/server/game/Server/Packets/AuthenticationPackets.cpp @@ -65,20 +65,20 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() if (SuccessInfo.HasValue) { - _worldPacket << uint32(SuccessInfo.value.VirtualRealmAddress); - _worldPacket << uint32(SuccessInfo.value.VirtualRealms.size()); - _worldPacket << uint32(SuccessInfo.value.TimeRemain); - _worldPacket << uint32(SuccessInfo.value.TimeOptions); - _worldPacket << uint32(SuccessInfo.value.TimeRested); - _worldPacket << uint8(SuccessInfo.value.ActiveExpansionLevel); - _worldPacket << uint8(SuccessInfo.value.AccountExpansionLevel); - _worldPacket << uint32(SuccessInfo.value.TimeSecondsUntilPCKick); - _worldPacket << uint32(SuccessInfo.value.AvailableRaces->size()); - _worldPacket << uint32(SuccessInfo.value.AvailableClasses->size()); - _worldPacket << uint32(SuccessInfo.value.Templates.size()); - _worldPacket << uint32(SuccessInfo.value.CurrencyID); - - for (auto& realm : SuccessInfo.value.VirtualRealms) + _worldPacket << uint32(SuccessInfo.Value.VirtualRealmAddress); + _worldPacket << uint32(SuccessInfo.Value.VirtualRealms.size()); + _worldPacket << uint32(SuccessInfo.Value.TimeRemain); + _worldPacket << uint32(SuccessInfo.Value.TimeOptions); + _worldPacket << uint32(SuccessInfo.Value.TimeRested); + _worldPacket << uint8(SuccessInfo.Value.ActiveExpansionLevel); + _worldPacket << uint8(SuccessInfo.Value.AccountExpansionLevel); + _worldPacket << uint32(SuccessInfo.Value.TimeSecondsUntilPCKick); + _worldPacket << uint32(SuccessInfo.Value.AvailableRaces->size()); + _worldPacket << uint32(SuccessInfo.Value.AvailableClasses->size()); + _worldPacket << uint32(SuccessInfo.Value.Templates.size()); + _worldPacket << uint32(SuccessInfo.Value.CurrencyID); + + for (auto& realm : SuccessInfo.Value.VirtualRealms) { _worldPacket << uint32(realm.RealmAddress); _worldPacket.WriteBit(realm.IsLocal); @@ -89,19 +89,19 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() _worldPacket.WriteString(realm.RealmNameNormalized); } - for (auto& race : *SuccessInfo.value.AvailableRaces) + for (auto& race : *SuccessInfo.Value.AvailableRaces) { _worldPacket << uint8(race.first); /// the current race _worldPacket << uint8(race.second); /// the required Expansion } - for (auto& klass : *SuccessInfo.value.AvailableClasses) + for (auto& klass : *SuccessInfo.Value.AvailableClasses) { _worldPacket << uint8(klass.first); /// the current class _worldPacket << uint8(klass.second); /// the required Expansion } - for (auto& templat : SuccessInfo.value.Templates) + for (auto& templat : SuccessInfo.Value.Templates) { _worldPacket << uint32(templat.TemplateSetId); _worldPacket << uint32(templat.TemplateClasses.size()); @@ -117,23 +117,23 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() _worldPacket.WriteString(templat.Description); } - _worldPacket.WriteBit(SuccessInfo.value.IsExpansionTrial); - _worldPacket.WriteBit(SuccessInfo.value.ForceCharacterTemplate); - _worldPacket.WriteBit(SuccessInfo.value.NumPlayersHorde != 0); - _worldPacket.WriteBit(SuccessInfo.value.NumPlayersAlliance != 0); - _worldPacket.WriteBit(SuccessInfo.value.IsVeteranTrial); + _worldPacket.WriteBit(SuccessInfo.Value.IsExpansionTrial); + _worldPacket.WriteBit(SuccessInfo.Value.ForceCharacterTemplate); + _worldPacket.WriteBit(SuccessInfo.Value.NumPlayersHorde.HasValue); + _worldPacket.WriteBit(SuccessInfo.Value.NumPlayersAlliance.HasValue); + _worldPacket.WriteBit(SuccessInfo.Value.IsVeteranTrial); - if (SuccessInfo.value.NumPlayersHorde) - _worldPacket << uint16(SuccessInfo.value.NumPlayersHorde); + if (SuccessInfo.Value.NumPlayersHorde.HasValue) + _worldPacket << uint16(SuccessInfo.Value.NumPlayersHorde.Value); - if (SuccessInfo.value.NumPlayersAlliance) - _worldPacket << uint16(SuccessInfo.value.NumPlayersAlliance); + if (SuccessInfo.Value.NumPlayersAlliance.HasValue) + _worldPacket << uint16(SuccessInfo.Value.NumPlayersAlliance.Value); } if (WaitInfo.HasValue) { - _worldPacket << uint32(WaitInfo.value.WaitCount); - _worldPacket.WriteBit(WaitInfo.value.HasFCM); + _worldPacket << uint32(WaitInfo.Value.WaitCount); + _worldPacket.WriteBit(WaitInfo.Value.HasFCM); } _worldPacket.FlushBits(); diff --git a/src/server/game/Server/Packets/AuthenticationPackets.h b/src/server/game/Server/Packets/AuthenticationPackets.h index e24c06396e0..dcc9a908539 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.h +++ b/src/server/game/Server/Packets/AuthenticationPackets.h @@ -34,13 +34,13 @@ namespace WorldPackets class AuthChallenge final : public ServerPacket { public: - AuthChallenge() : ServerPacket(SMSG_AUTH_CHALLENGE, 4 + 32 + 1), Challenge(0) { } + AuthChallenge() : ServerPacket(SMSG_AUTH_CHALLENGE, 4 + 32 + 1) { } WorldPacket const* Write() override; - uint32 Challenge; + uint32 Challenge = 0; uint32 DosChallenge[8]; ///< Encryption seeds - uint8 DosZeroBits; + uint8 DosZeroBits = 0; }; class AuthSession final : public ClientPacket @@ -118,8 +118,8 @@ namespace WorldPackets bool IsExpansionTrial = false; bool ForceCharacterTemplate = false; ///< forces the client to always use a character template when creating a new character. @see Templates. @todo implement - uint16 NumPlayersHorde = 0; ///< number of horde players in this realm. @todo implement - uint16 NumPlayersAlliance = 0; ///< number of alliance players in this realm. @todo implement + Optional<uint16> NumPlayersHorde; ///< number of horde players in this realm. @todo implement + Optional<uint16> NumPlayersAlliance; ///< number of alliance players in this realm. @todo implement bool IsVeteranTrial = false; ///< @todo research }; diff --git a/src/server/game/Server/Packets/ChannelPackets.cpp b/src/server/game/Server/Packets/ChannelPackets.cpp index 8aa4ac51d42..bd1e62eadd6 100644 --- a/src/server/game/Server/Packets/ChannelPackets.cpp +++ b/src/server/game/Server/Packets/ChannelPackets.cpp @@ -18,14 +18,37 @@ #include "ChannelPackets.h" #include "Channel.h" +void WorldPackets::Channel::ChannelListRequest::Read() +{ + ChannelName = _worldPacket.ReadString(_worldPacket.ReadBits(7)); +} + +WorldPacket const* WorldPackets::Channel::ChannelListResponse::Write() +{ + _worldPacket.WriteBit(_Display); + _worldPacket.WriteBits(_Channel.length(), 7); + _worldPacket << uint8(_ChannelFlags); + _worldPacket << uint32(_Members.size()); + _worldPacket.WriteString(_Channel); + + for (ChannelPlayer const& player : _Members) + { + _worldPacket << player.Guid; + _worldPacket << uint32(player.VirtualRealmAddress); + _worldPacket << uint8(player.Flags); + } + + return &_worldPacket; +} + WorldPacket const* WorldPackets::Channel::ChannelNotify::Write() { _worldPacket.WriteBits(Type, 6); - _worldPacket.WriteBits(Channel.length(), 7); + _worldPacket.WriteBits(_Channel.length(), 7); _worldPacket.WriteBits(Sender.length(), 6); _worldPacket << SenderGuid; - _worldPacket << SenderBnetAccountID; + _worldPacket << SenderAccountID; _worldPacket << uint32(SenderVirtualRealm); _worldPacket << TargetGuid; _worldPacket << uint32(TargetVirtualRealm); @@ -37,7 +60,7 @@ WorldPacket const* WorldPackets::Channel::ChannelNotify::Write() _worldPacket << uint8(NewFlags); } - _worldPacket.WriteString(Channel); + _worldPacket.WriteString(_Channel); _worldPacket.WriteString(Sender); return &_worldPacket; @@ -45,12 +68,12 @@ WorldPacket const* WorldPackets::Channel::ChannelNotify::Write() WorldPacket const* WorldPackets::Channel::ChannelNotifyJoined::Write() { - _worldPacket.WriteBits(Channel.length(), 7); + _worldPacket.WriteBits(_Channel.length(), 7); _worldPacket.WriteBits(ChannelWelcomeMsg.length(), 10); - _worldPacket << uint8(ChannelFlags); + _worldPacket << uint8(_ChannelFlags); _worldPacket << int32(ChatChannelID); _worldPacket << uint64(InstanceID); - _worldPacket.WriteString(Channel); + _worldPacket.WriteString(_Channel); _worldPacket.WriteString(ChannelWelcomeMsg); return &_worldPacket; @@ -76,3 +99,9 @@ void WorldPackets::Channel::JoinChannel::Read() ChannelName = _worldPacket.ReadString(channelLength); Password = _worldPacket.ReadString(passwordLength); } + +void WorldPackets::Channel::LeaveChannel::Read() +{ + _worldPacket >> ZoneChannelID; + ChannelName = _worldPacket.ReadString(_worldPacket.ReadBits(7)); +} diff --git a/src/server/game/Server/Packets/ChannelPackets.h b/src/server/game/Server/Packets/ChannelPackets.h index b6c8eb3b928..e3d96c5c453 100644 --- a/src/server/game/Server/Packets/ChannelPackets.h +++ b/src/server/game/Server/Packets/ChannelPackets.h @@ -25,6 +25,42 @@ namespace WorldPackets { namespace Channel { + class ChannelListRequest final : public ClientPacket + { + public: + ChannelListRequest(WorldPacket&& packet) : ClientPacket(std::move(packet)) + { + ASSERT(packet.GetOpcode() == CMSG_CHANNEL_LIST || packet.GetOpcode() == CMSG_CHANNEL_DISPLAY_LIST); + } + + void Read() override; + + std::string ChannelName; + }; + + class ChannelListResponse final : public ServerPacket + { + public: + struct ChannelPlayer + { + ChannelPlayer(ObjectGuid const& guid, uint32 realm, uint8 flags) : + Guid(guid), VirtualRealmAddress(realm), Flags(flags) { } + + ObjectGuid Guid; ///< Player Guid + uint32 VirtualRealmAddress; + uint8 Flags = 0; ///< @see enum ChannelMemberFlags + }; + + ChannelListResponse() : ServerPacket(SMSG_CHANNEL_LIST) { } + + WorldPacket const* Write() override; + + std::vector<ChannelPlayer> _Members; + std::string _Channel; ///< Channel Name + uint8 _ChannelFlags = 0; ///< @see enum ChannelFlags + bool _Display = false; + }; + class ChannelNotify final : public ServerPacket { public: @@ -34,11 +70,11 @@ namespace WorldPackets std::string Sender; ObjectGuid SenderGuid; - ObjectGuid SenderBnetAccountID; + ObjectGuid SenderAccountID; uint8 Type = 0; ///< @see enum ChatNotify uint8 OldFlags = 0; ///< @see enum ChannelMemberFlags uint8 NewFlags = 0; ///< @see enum ChannelMemberFlags - std::string Channel; + std::string _Channel; ///< Channel Name uint32 SenderVirtualRealm = 0; ObjectGuid TargetGuid; uint32 TargetVirtualRealm = 0; @@ -55,8 +91,8 @@ namespace WorldPackets std::string ChannelWelcomeMsg; int32 ChatChannelID = 0; int32 InstanceID = 0; - uint8 ChannelFlags = 0; ///< @see enum ChannelFlags - std::string Channel; + uint8 _ChannelFlags = 0; ///< @see enum ChannelFlags + std::string _Channel; ///< Channel Name }; class ChannelNotifyLeft final : public ServerPacket @@ -66,9 +102,9 @@ namespace WorldPackets WorldPacket const* Write() override; - std::string Channel; + std::string Channel; ///< Channel Name int32 ChatChannelID = 0; - bool Suspended = false; + bool Suspended = false; ///< User Leave - false, On Zone Change - true }; class JoinChannel final : public ClientPacket @@ -84,6 +120,17 @@ namespace WorldPackets int32 ChatChannelId = 0; bool Internal = false; }; + + class LeaveChannel final : public ClientPacket + { + public: + LeaveChannel(WorldPacket&& packet) : ClientPacket(CMSG_LEAVE_CHANNEL, std::move(packet)) { } + + void Read() override; + + int32 ZoneChannelID = 0; + std::string ChannelName; + }; } } diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index 8fae98cf8f2..b5d26bf2968 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -200,7 +200,7 @@ void WorldPackets::Character::CreateChar::Read() _worldPacket >> CreateInfo->OutfitId; CreateInfo->Name = _worldPacket.ReadString(nameLength); if (CreateInfo->TemplateSet.HasValue) - _worldPacket >> CreateInfo->TemplateSet.value; + _worldPacket >> CreateInfo->TemplateSet.Value; } WorldPacket const* WorldPackets::Character::CharacterCreateResponse::Write() @@ -234,7 +234,7 @@ WorldPacket const* WorldPackets::Character::CharacterRenameResult::Write() _worldPacket.WriteBits(Name.length(), 6); if (Guid.HasValue) - _worldPacket << Guid.value; + _worldPacket << Guid.Value; _worldPacket.WriteString(Name); return &_worldPacket; @@ -274,19 +274,19 @@ void WorldPackets::Character::CharRaceOrFactionChange::Read() RaceOrFactionChangeInfo->Name = _worldPacket.ReadString(nameLength); if (RaceOrFactionChangeInfo->SkinID.HasValue) - _worldPacket >> RaceOrFactionChangeInfo->SkinID.value; + _worldPacket >> RaceOrFactionChangeInfo->SkinID.Value; if (RaceOrFactionChangeInfo->HairColorID.HasValue) - _worldPacket >> RaceOrFactionChangeInfo->HairColorID.value; + _worldPacket >> RaceOrFactionChangeInfo->HairColorID.Value; if (RaceOrFactionChangeInfo->HairStyleID.HasValue) - _worldPacket >> RaceOrFactionChangeInfo->HairStyleID.value; + _worldPacket >> RaceOrFactionChangeInfo->HairStyleID.Value; if (RaceOrFactionChangeInfo->FacialHairStyleID.HasValue) - _worldPacket >> RaceOrFactionChangeInfo->FacialHairStyleID.value; + _worldPacket >> RaceOrFactionChangeInfo->FacialHairStyleID.Value; if (RaceOrFactionChangeInfo->FaceID.HasValue) - _worldPacket >> RaceOrFactionChangeInfo->FaceID.value; + _worldPacket >> RaceOrFactionChangeInfo->FaceID.Value; } WorldPacket const* WorldPackets::Character::CharFactionChangeResult::Write() @@ -298,15 +298,15 @@ WorldPacket const* WorldPackets::Character::CharFactionChangeResult::Write() if (Display.HasValue) { - _worldPacket.WriteBits(Display.value.Name.length(), 6); - _worldPacket << uint8(Display.value.SexID); - _worldPacket << uint8(Display.value.SkinID); - _worldPacket << uint8(Display.value.HairColorID); - _worldPacket << uint8(Display.value.HairStyleID); - _worldPacket << uint8(Display.value.FacialHairStyleID); - _worldPacket << uint8(Display.value.FaceID); - _worldPacket << uint8(Display.value.RaceID); - _worldPacket.WriteString(Display.value.Name); + _worldPacket.WriteBits(Display.Value.Name.length(), 6); + _worldPacket << uint8(Display.Value.SexID); + _worldPacket << uint8(Display.Value.SkinID); + _worldPacket << uint8(Display.Value.HairColorID); + _worldPacket << uint8(Display.Value.HairStyleID); + _worldPacket << uint8(Display.Value.FacialHairStyleID); + _worldPacket << uint8(Display.Value.FaceID); + _worldPacket << uint8(Display.Value.RaceID); + _worldPacket.WriteString(Display.Value.Name); } return &_worldPacket; diff --git a/src/server/game/Server/Packets/ChatPackets.cpp b/src/server/game/Server/Packets/ChatPackets.cpp new file mode 100644 index 00000000000..7590a092b2c --- /dev/null +++ b/src/server/game/Server/Packets/ChatPackets.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ChatPackets.h" + +void WorldPackets::Chat::ChatMessage::Read() +{ + _worldPacket >> Language; + uint32 len = _worldPacket.ReadBits(8); + Text = _worldPacket.ReadString(len); +} + +void WorldPackets::Chat::ChatMessageWhisper::Read() +{ + _worldPacket >> Language; + uint32 targetLen = _worldPacket.ReadBits(9); + uint32 textLen = _worldPacket.ReadBits(8); + Target = _worldPacket.ReadString(targetLen); + Text = _worldPacket.ReadString(textLen); +} + +void WorldPackets::Chat::ChatMessageChannel::Read() +{ + _worldPacket >> Language; + uint32 targetLen = _worldPacket.ReadBits(9); + uint32 textLen = _worldPacket.ReadBits(8); + _worldPacket.ResetBitPos(); + Target = _worldPacket.ReadString(targetLen); + Text = _worldPacket.ReadString(textLen); +} + +void WorldPackets::Chat::ChatAddonMessage::Read() +{ + uint32 prefixLen = _worldPacket.ReadBits(5); + uint32 textLen = _worldPacket.ReadBits(8); + Prefix = _worldPacket.ReadString(prefixLen); + Text = _worldPacket.ReadString(textLen); +} + +void WorldPackets::Chat::ChatAddonMessageWhisper::Read() +{ + uint32 targetLen = _worldPacket.ReadBits(9); + uint32 prefixLen = _worldPacket.ReadBits(5); + uint32 textLen = _worldPacket.ReadBits(8); + Target = _worldPacket.ReadString(targetLen); + Prefix = _worldPacket.ReadString(prefixLen); + Text = _worldPacket.ReadString(textLen); +} + +void WorldPackets::Chat::ChatMessageDND::Read() +{ + uint32 len = _worldPacket.ReadBits(8); + Text = _worldPacket.ReadString(len); +} + +void WorldPackets::Chat::ChatMessageAFK::Read() +{ + uint32 len = _worldPacket.ReadBits(8); + Text = _worldPacket.ReadString(len); +} + +void WorldPackets::Chat::ChatMessageEmote::Read() +{ + uint32 len = _worldPacket.ReadBits(8); + Text = _worldPacket.ReadString(len); +} + +WorldPacket const* WorldPackets::Chat::Chat::Write() +{ + _worldPacket << SlashCmd; + _worldPacket << Language; + _worldPacket << SenderGUID; + _worldPacket << SenderGuildGUID; + _worldPacket << SenderAccountGUID; + _worldPacket << TargetGUID; + _worldPacket << TargetVirtualAddress; + _worldPacket << SenderVirtualAddress; + _worldPacket << PartyGUID; + _worldPacket << AchievementID; + _worldPacket << DisplayTime; + _worldPacket.WriteBits(SenderName.length(), 11); + _worldPacket.WriteBits(TargetName.length(), 11); + _worldPacket.WriteBits(Prefix.length(), 5); + _worldPacket.WriteBits(Channel.length(), 7); + _worldPacket.WriteBits(ChatText.length(), 12); + _worldPacket.WriteBits(ChatFlags, 10); + _worldPacket.WriteBit(HideChatLog); + _worldPacket.WriteBit(FakeSenderName); + _worldPacket.WriteString(SenderName); + _worldPacket.WriteString(TargetName); + _worldPacket.WriteString(Prefix); + _worldPacket.WriteString(Channel); + _worldPacket.WriteString(ChatText); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Chat::Emote::Write() +{ + _worldPacket << Guid; + _worldPacket << EmoteID; + + return &_worldPacket; +} + +void WorldPackets::Chat::CTextEmote::Read() +{ + _worldPacket >> Target; + _worldPacket >> EmoteID; + _worldPacket >> SoundIndex; +} + +WorldPacket const* WorldPackets::Chat::STextEmote::Write() +{ + _worldPacket << SourceGUID; + _worldPacket << SourceAccountGUID; + _worldPacket << EmoteID; + _worldPacket << SoundIndex; + _worldPacket << TargetGUID; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/ChatPackets.h b/src/server/game/Server/Packets/ChatPackets.h new file mode 100644 index 00000000000..9cdc534528f --- /dev/null +++ b/src/server/game/Server/Packets/ChatPackets.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ChatPackets_h__ +#define ChatPackets_h__ + +#include "Packet.h" +#include "SharedDefines.h" +#include "ObjectGuid.h" + +namespace WorldPackets +{ + namespace Chat + { + // CMSG_MESSAGECHAT_GUILD + // CMSG_MESSAGECHAT_OFFICER + // CMSG_MESSAGECHAT_YELL + // CMSG_MESSAGECHAT_SAY + // CMSG_MESSAGECHAT_PARTY + // CMSG_MESSAGECHAT_RAID + // CMSG_MESSAGECHAT_RAID_WARNING + class ChatMessage final : public ClientPacket + { + public: + ChatMessage(WorldPacket&& packet) : ClientPacket(std::move(packet)) { } + + void Read() override; + + std::string Text; + int32 Language = LANG_UNIVERSAL; + }; + + // CMSG_MESSAGECHAT_WHISPER + class ChatMessageWhisper final : public ClientPacket + { + public: + ChatMessageWhisper(WorldPacket&& packet) : ClientPacket(std::move(packet)) { } + + void Read() override; + + int32 Language = LANG_UNIVERSAL; + std::string Text; + std::string Target; + }; + + // CMSG_MESSAGECHAT_CHANNEL + class ChatMessageChannel final : public ClientPacket + { + public: + ChatMessageChannel(WorldPacket&& packet) : ClientPacket(std::move(packet)) { } + + void Read() override; + + int32 Language = LANG_UNIVERSAL; + std::string Text; + std::string Target; + }; + + // CMSG_MESSAGECHAT_ADDON_GUILD + // CMSG_MESSAGECHAT_ADDON_OFFICER + // CMSG_MESSAGECHAT_ADDON_PARTY + // CMSG_MESSAGECHAT_ADDON_RAID + class ChatAddonMessage final : public ClientPacket + { + public: + ChatAddonMessage(WorldPacket&& packet) : ClientPacket(std::move(packet)) { } + + void Read() override; + + std::string Prefix; + std::string Text; + }; + + // CMSG_MESSAGECHAT_ADDON_WHISPER + class ChatAddonMessageWhisper final : public ClientPacket + { + public: + ChatAddonMessageWhisper(WorldPacket&& packet) : ClientPacket(std::move(packet)) { } + + void Read() override; + + std::string Prefix; + std::string Target; + std::string Text; + }; + + class ChatMessageDND final : public ClientPacket + { + public: + ChatMessageDND(WorldPacket&& packet) : ClientPacket(CMSG_MESSAGECHAT_DND, std::move(packet)) { } + + void Read() override; + + std::string Text; + }; + + class ChatMessageAFK final : public ClientPacket + { + public: + ChatMessageAFK(WorldPacket&& packet) : ClientPacket(CMSG_MESSAGECHAT_AFK, std::move(packet)) { } + + void Read() override; + + std::string Text; + }; + + class ChatMessageEmote final : public ClientPacket + { + public: + ChatMessageEmote(WorldPacket&& packet) : ClientPacket(CMSG_MESSAGECHAT_EMOTE, std::move(packet)) { } + + void Read() override; + + std::string Text; + }; + + // SMSG_MESSAGECHAT + class Chat final : public ServerPacket + { + public: + Chat() : ServerPacket(SMSG_MESSAGECHAT, 100) { } + + WorldPacket const* Write() override; + + uint8 SlashCmd = 0; + uint8 Language = LANG_UNIVERSAL; + ObjectGuid SenderGUID; + ObjectGuid SenderGuildGUID; + ObjectGuid SenderAccountGUID; + ObjectGuid TargetGUID; + ObjectGuid PartyGUID; + uint32 SenderVirtualAddress = 0; + uint32 TargetVirtualAddress = 0; + std::string SenderName; + std::string TargetName; + std::string Prefix; + std::string Channel; + std::string ChatText; + uint32 AchievementID = 0; + uint8 ChatFlags = 0; + float DisplayTime = 0.0f; + bool HideChatLog = false; + bool FakeSenderName = false; + }; + + class Emote final : public ServerPacket + { + public: + Emote() : ServerPacket(SMSG_EMOTE, 18 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid Guid; + int32 EmoteID = 0; + }; + + class CTextEmote final : public ClientPacket + { + public: + CTextEmote(WorldPacket&& packet) : ClientPacket(CMSG_TEXT_EMOTE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Target; + int32 EmoteID = 0; + int32 SoundIndex = -1; + }; + + class STextEmote final : public ServerPacket + { + public: + STextEmote() : ServerPacket(SMSG_TEXT_EMOTE, 3 * 18 + 2 * 4) { } + + WorldPacket const* Write() override; + + ObjectGuid SourceGUID; + ObjectGuid SourceAccountGUID; + ObjectGuid TargetGUID; + int32 SoundIndex = -1; + int32 EmoteID = 0; + }; + } +} + +#endif // ChatPackets_h__ diff --git a/src/server/game/Server/Packets/CombatLogPackets.cpp b/src/server/game/Server/Packets/CombatLogPackets.cpp new file mode 100644 index 00000000000..128cc0d342f --- /dev/null +++ b/src/server/game/Server/Packets/CombatLogPackets.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "CombatLogPackets.h" +#include "SpellPackets.h" + +WorldPacket const* WorldPackets::CombatLog::SpellNonMeleeDamageLog::Write() +{ + _worldPacket << Me; + _worldPacket << CasterGUID; + _worldPacket << SpellID; + _worldPacket << Damage; + _worldPacket << Overkill; + _worldPacket << SchoolMask; + _worldPacket << ShieldBlock; + _worldPacket << Resisted; + _worldPacket << Absorbed; + + _worldPacket.WriteBit(Periodic); + _worldPacket.WriteBits(Flags, 9); + _worldPacket.WriteBit(false); // Debug info + _worldPacket.WriteBit(LogData.HasValue); + _worldPacket.FlushBits(); + + if (LogData.HasValue) + _worldPacket << LogData.Value; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/CombatLogPackets.h b/src/server/game/Server/Packets/CombatLogPackets.h new file mode 100644 index 00000000000..6cca0127ef6 --- /dev/null +++ b/src/server/game/Server/Packets/CombatLogPackets.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef CombatLogPackets_h__ +#define CombatLogPackets_h__ + +#include "Packet.h" +#include "SpellPackets.h" + +namespace WorldPackets +{ + namespace CombatLog + { + class SpellNonMeleeDamageLog final : public ServerPacket + { + public: + SpellNonMeleeDamageLog() : ServerPacket(SMSG_SPELLNONMELEEDAMAGELOG, 60) { } + + WorldPacket const* Write() override; + + int32 Absorbed; + int32 ShieldBlock; + ObjectGuid Me; + int32 SpellID; + int32 Resisted; + bool Periodic; + uint8 SchoolMask; + ObjectGuid CasterGUID; + Optional<Spells::SpellCastLogData> LogData; + int32 Damage; + // Optional<SpellNonMeleeDamageLogDebugInfo> Debug Info; + int32 Flags; + int32 Overkill; + }; + } +} + +#endif // CombatLogPackets_h__ diff --git a/src/server/game/Server/Packets/CombatPackets.cpp b/src/server/game/Server/Packets/CombatPackets.cpp index 17c0599d266..7793ef4ae30 100644 --- a/src/server/game/Server/Packets/CombatPackets.cpp +++ b/src/server/game/Server/Packets/CombatPackets.cpp @@ -16,8 +16,127 @@ */ #include "CombatPackets.h" +#include "SpellPackets.h" void WorldPackets::Combat::AttackSwing::Read() { _worldPacket >> Victim; } + +WorldPacket const* WorldPackets::Combat::AttackStart::Write() +{ + _worldPacket << Attacker; + _worldPacket << Victim; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Combat::SAttackStop::Write() +{ + _worldPacket << Attacker; + _worldPacket << Victim; + _worldPacket.WriteBit(Dead); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Combat::ThreatUpdate::Write() +{ + _worldPacket << UnitGUID; + _worldPacket << int32(ThreatList.size()); + for (WorldPackets::Combat::ThreatInfo const& threatInfo : ThreatList) + { + _worldPacket << threatInfo.UnitGUID; + _worldPacket << threatInfo.Threat; + } + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Combat::HighestThreatUpdate::Write() +{ + _worldPacket << UnitGUID; + _worldPacket << HighestThreatGUID; + _worldPacket << int32(ThreatList.size()); + for (WorldPackets::Combat::ThreatInfo const& threatInfo : ThreatList) + { + _worldPacket << threatInfo.UnitGUID; + _worldPacket << threatInfo.Threat; + } + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Combat::ThreatRemove::Write() +{ + _worldPacket << UnitGUID; + _worldPacket << AboutGUID; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Combat::AIReaction::Write() +{ + _worldPacket << UnitGUID; + _worldPacket << Reaction; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Combat::AttackerStateUpdate::Write() +{ + if (_worldPacket.WriteBit(LogData.HasValue)) + _worldPacket << LogData.Value; + + // Placeholder for size which will be calculated at the end based on packet size + // Client uses this size to copy remaining packet to another CDataStore + _worldPacket << int32(0); + size_t pos = _worldPacket.wpos(); + + _worldPacket << HitInfo; + _worldPacket << AttackerGUID; + _worldPacket << VictimGUID; + _worldPacket << Damage; + _worldPacket << OverDamage; + if (_worldPacket.WriteBit(SubDmg.HasValue)) + { + _worldPacket << SubDmg.Value.SchoolMask; + _worldPacket << SubDmg.Value.FDamage; + _worldPacket << SubDmg.Value.Damage; + if (HitInfo & (HITINFO_FULL_ABSORB | HITINFO_PARTIAL_ABSORB)) + _worldPacket << SubDmg.Value.Absorbed; + if (HitInfo & (HITINFO_FULL_RESIST | HITINFO_PARTIAL_RESIST)) + _worldPacket << SubDmg.Value.Resisted; + } + + _worldPacket << VictimState; + _worldPacket << AttackerState; + _worldPacket << MeleeSpellID; + if (HitInfo & HITINFO_BLOCK) + _worldPacket << BlockAmount; + if (HitInfo & HITINFO_RAGE_GAIN) + _worldPacket << RageGained; + if (HitInfo & HITINFO_UNK1) + { + _worldPacket << UnkState.State1; + _worldPacket << UnkState.State2; + _worldPacket << UnkState.State3; + _worldPacket << UnkState.State4; + _worldPacket << UnkState.State5; + _worldPacket << UnkState.State6; + _worldPacket << UnkState.State7; + _worldPacket << UnkState.State8; + _worldPacket << UnkState.State9; + _worldPacket << UnkState.State10; + _worldPacket << UnkState.State11; + _worldPacket << UnkState.State12; + } + if (HitInfo & (HITINFO_BLOCK|HITINFO_UNK12)) + _worldPacket << Unk; + + // Update size placeholder + _worldPacket.put<int32>(pos - sizeof(int32), _worldPacket.wpos() - pos); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/CombatPackets.h b/src/server/game/Server/Packets/CombatPackets.h index 2402daf6b22..5b2347e3edb 100644 --- a/src/server/game/Server/Packets/CombatPackets.h +++ b/src/server/game/Server/Packets/CombatPackets.h @@ -19,6 +19,8 @@ #define CombatPackets_h__ #include "Packet.h" +#include "ObjectGuid.h" +#include "SpellPackets.h" namespace WorldPackets { @@ -39,7 +41,129 @@ namespace WorldPackets public: AttackStop(WorldPacket&& packet) : ClientPacket(CMSG_ATTACKSTOP, std::move(packet)) { } - void Read() override {}; + void Read() override { } + }; + + class AttackStart final : public ServerPacket + { + public: + AttackStart() : ServerPacket(SMSG_ATTACKSTART, 16) { } + + WorldPacket const* Write() override; + + ObjectGuid Attacker; + ObjectGuid Victim; + }; + + class SAttackStop final : public ServerPacket + { + public: + SAttackStop() : ServerPacket(SMSG_ATTACKSTOP, 17) { } + + WorldPacket const* Write() override; + + ObjectGuid Attacker; + ObjectGuid Victim; + bool Dead = false; + }; + + struct ThreatInfo + { + ObjectGuid UnitGUID; + int32 Threat = 0; + }; + + class ThreatUpdate final : public ServerPacket + { + public: + ThreatUpdate() : ServerPacket(SMSG_THREAT_UPDATE, 24) { } + + WorldPacket const* Write() override; + + ObjectGuid UnitGUID; + std::vector<ThreatInfo> ThreatList; + }; + + class HighestThreatUpdate final : public ServerPacket + { + public: + HighestThreatUpdate() : ServerPacket(SMSG_HIGHEST_THREAT_UPDATE, 44) { } + + WorldPacket const* Write() override; + + ObjectGuid UnitGUID; + std::vector<ThreatInfo> ThreatList; + ObjectGuid HighestThreatGUID; + }; + + class ThreatRemove final : public ServerPacket + { + public: + ThreatRemove() : ServerPacket(SMSG_THREAT_REMOVE, 16) { } + + WorldPacket const* Write() override; + + ObjectGuid AboutGUID; // Unit to remove threat from (e.g. player, pet, guardian) + ObjectGuid UnitGUID; // Unit being attacked (e.g. creature, boss) + }; + + class AIReaction final : public ServerPacket + { + public: + AIReaction() : ServerPacket(SMSG_AI_REACTION, 12) { } + + WorldPacket const* Write() override; + + ObjectGuid UnitGUID; + uint32 Reaction = 0; + }; + + struct SubDamage + { + int32 SchoolMask = 0; + float FDamage = 0.0f; // Float damage (Most of the time equals to Damage) + int32 Damage = 0; + int32 Absorbed = 0; + int32 Resisted = 0; + }; + + struct UnkAttackerState + { + int32 State1 = 0; + float State2 = 0.0f; + float State3 = 0.0f; + float State4 = 0.0f; + float State5 = 0.0f; + float State6 = 0.0f; + float State7 = 0.0f; + float State8 = 0.0f; + float State9 = 0.0f; + float State10 = 0.0f; + float State11 = 0.0f; + int32 State12 = 0; + }; + + class AttackerStateUpdate final : public ServerPacket + { + public: + AttackerStateUpdate() : ServerPacket(SMSG_ATTACKERSTATEUPDATE, 70) { } + + WorldPacket const* Write() override; + + Optional<WorldPackets::Spells::SpellCastLogData> LogData; + uint32 HitInfo = 0; // Flags + ObjectGuid AttackerGUID; + ObjectGuid VictimGUID; + int32 Damage = 0; + int32 OverDamage = -1; // (damage - health) or -1 if unit is still alive + Optional<SubDamage> SubDmg; + uint8 VictimState = 0; + int32 AttackerState = -1; + int32 MeleeSpellID = 0; + int32 BlockAmount = 0; + int32 RageGained = 0; + UnkAttackerState UnkState; + float Unk = 0.0f; }; } } diff --git a/src/server/game/Server/Packets/EquipmentSetPackets.cpp b/src/server/game/Server/Packets/EquipmentSetPackets.cpp new file mode 100644 index 00000000000..07cab20debf --- /dev/null +++ b/src/server/game/Server/Packets/EquipmentSetPackets.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "EquipmentSetPackets.h" + +WorldPacket const* WorldPackets::EquipmentSet::EquipmentSetID::Write() +{ + _worldPacket << uint64(GUID); + _worldPacket << uint32(SetID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::EquipmentSet::LoadEquipmentSet::Write() +{ + _worldPacket << uint32(SetData.size()); + + for (EquipmentSetInfo::EquipmentSetData const* equipSet : SetData) + { + _worldPacket << uint64(equipSet->Guid); + _worldPacket << uint32(equipSet->SetID); + _worldPacket << uint32(equipSet->IgnoreMask); + + for (ObjectGuid const& guid : equipSet->Pieces) + _worldPacket << guid; + + _worldPacket.WriteBits(equipSet->SetName.length(), 8); + _worldPacket.WriteBits(equipSet->SetIcon.length(), 9); + _worldPacket.WriteString(equipSet->SetName); + _worldPacket.WriteString(equipSet->SetIcon); + _worldPacket.FlushBits(); + } + + return &_worldPacket; +} + +void WorldPackets::EquipmentSet::SaveEquipmentSet::Read() +{ + _worldPacket >> Set.Guid; + _worldPacket >> Set.SetID; + _worldPacket >> Set.IgnoreMask; + + for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + _worldPacket >> Set.Pieces[i]; + + uint32 setNameLength = _worldPacket.ReadBits(8); + uint32 setIconLength = _worldPacket.ReadBits(9); + + Set.SetName = _worldPacket.ReadString(setNameLength); + Set.SetIcon = _worldPacket.ReadString(setIconLength); +} diff --git a/src/server/game/Server/Packets/EquipmentSetPackets.h b/src/server/game/Server/Packets/EquipmentSetPackets.h new file mode 100644 index 00000000000..b01c483f5ac --- /dev/null +++ b/src/server/game/Server/Packets/EquipmentSetPackets.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "Packet.h" +#include "Player.h" + +namespace WorldPackets +{ + namespace EquipmentSet + { + class EquipmentSetID final : public ServerPacket + { + public: + EquipmentSetID() : ServerPacket(SMSG_EQUIPMENT_SET_SAVED, 8 + 4) { } + + WorldPacket const* Write() override; + + uint64 GUID = 0; ///< Set Identifier + uint32 SetID = 0; ///< Index + }; + + class LoadEquipmentSet final : public ServerPacket + { + public: + LoadEquipmentSet() : ServerPacket(SMSG_EQUIPMENT_SET_LIST, 4) { } + + WorldPacket const* Write() override; + + std::vector<EquipmentSetInfo::EquipmentSetData const*> SetData; + }; + + class SaveEquipmentSet final : public ClientPacket + { + public: + SaveEquipmentSet(WorldPacket&& packet) : ClientPacket(CMSG_EQUIPMENT_SET_SAVE, std::move(packet)) { } + + void Read() override; + + EquipmentSetInfo::EquipmentSetData Set; + }; + } +} diff --git a/src/server/game/Server/Packets/GuildPackets.cpp b/src/server/game/Server/Packets/GuildPackets.cpp index c853cf4cc19..f4159927543 100644 --- a/src/server/game/Server/Packets/GuildPackets.cpp +++ b/src/server/game/Server/Packets/GuildPackets.cpp @@ -33,16 +33,16 @@ WorldPacket const* WorldPackets::Guild::QueryGuildInfoResponse::Write() if (Info.HasValue) { - _worldPacket << Info.value.GuildGUID; - _worldPacket << uint32(Info.value.VirtualRealmAddress); - _worldPacket << uint32(Info.value.Ranks.size()); - _worldPacket << uint32(Info.value.EmblemStyle); - _worldPacket << uint32(Info.value.EmblemColor); - _worldPacket << uint32(Info.value.BorderStyle); - _worldPacket << uint32(Info.value.BorderColor); - _worldPacket << uint32(Info.value.BackgroundColor); - - for (GuildInfo::GuildInfoRank const& rank : Info.value.Ranks) + _worldPacket << Info.Value.GuildGUID; + _worldPacket << uint32(Info.Value.VirtualRealmAddress); + _worldPacket << uint32(Info.Value.Ranks.size()); + _worldPacket << uint32(Info.Value.EmblemStyle); + _worldPacket << uint32(Info.Value.EmblemColor); + _worldPacket << uint32(Info.Value.BorderStyle); + _worldPacket << uint32(Info.Value.BorderColor); + _worldPacket << uint32(Info.Value.BackgroundColor); + + for (GuildInfo::GuildInfoRank const& rank : Info.Value.Ranks) { _worldPacket << uint32(rank.RankID); _worldPacket << uint32(rank.RankOrder); @@ -51,8 +51,8 @@ WorldPacket const* WorldPackets::Guild::QueryGuildInfoResponse::Write() _worldPacket.WriteString(rank.RankName); } - _worldPacket.WriteBits(Info.value.GuildName.size(), 7); - _worldPacket.WriteString(Info.value.GuildName); + _worldPacket.WriteBits(Info.Value.GuildName.size(), 7); + _worldPacket.WriteString(Info.Value.GuildName); } _worldPacket.FlushBits(); diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp new file mode 100644 index 00000000000..924a9eec352 --- /dev/null +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ItemPackets.h" + +WorldPacket const* WorldPackets::Item::SetProficiency::Write() +{ + _worldPacket << ProficiencyMask; + _worldPacket << ProficiencyClass; + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Item::ItemBonusInstanceData const& itemBonusInstanceData) +{ + data << itemBonusInstanceData.Context; + data << uint32(itemBonusInstanceData.BonusListIDs.size()); + for (uint32 bonusID : itemBonusInstanceData.BonusListIDs) + data << bonusID; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Item::ItemInstance const& itemInstance) +{ + data << itemInstance.ItemID; + data << itemInstance.RandomPropertiesSeed; + data << itemInstance.RandomPropertiesID; + + data.WriteBit(itemInstance.ItemBonus.HasValue); + data.WriteBit(!itemInstance.Modifications.empty()); + data.FlushBits(); + + if (itemInstance.ItemBonus.HasValue) + data << itemInstance.ItemBonus.Value; + + if (!itemInstance.Modifications.empty()) + { + data << uint32(itemInstance.Modifications.size() * sizeof(uint32)); + for (uint32 itemMod : itemInstance.Modifications) + data << itemMod; + } + + return data; +} diff --git a/src/server/game/Server/Packets/ItemPackets.h b/src/server/game/Server/Packets/ItemPackets.h new file mode 100644 index 00000000000..72e2a02fbe2 --- /dev/null +++ b/src/server/game/Server/Packets/ItemPackets.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ItemPackets_h__ +#define ItemPackets_h__ + +#include "Packet.h" + +namespace WorldPackets +{ + namespace Item + { + class SetProficiency final : public ServerPacket + { + public: + SetProficiency() : ServerPacket(SMSG_SET_PROFICIENCY, 5) { } + + WorldPacket const* Write() override; + + uint32 ProficiencyMask = 0; + uint8 ProficiencyClass = 0; + }; + + struct ItemBonusInstanceData + { + uint8 Context = 0; + std::vector<int32> BonusListIDs; + }; + + struct ItemInstance + { + uint32 ItemID = 0; + uint32 RandomPropertiesSeed = 0; + uint32 RandomPropertiesID = 0; + Optional<ItemBonusInstanceData> ItemBonus; + std::vector<int32> Modifications; + }; + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Item::ItemBonusInstanceData const& itemBonusInstanceData); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Item::ItemInstance const& itemInstance); + +#endif // ItemPackets_h__ diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index d223b73e310..154ff134a6a 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -17,6 +17,40 @@ #include "MiscPackets.h" +WorldPacket const* WorldPackets::Misc::BindPointUpdate::Write() +{ + _worldPacket << float(BindPosition.x); + _worldPacket << float(BindPosition.y); + _worldPacket << float(BindPosition.z); + _worldPacket << uint32(BindMapID); + _worldPacket << uint32(BindAreaID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Misc::InvalidatePlayer::Write() +{ + _worldPacket << Guid; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Misc::LoginSetTimeSpeed::Write() +{ + _worldPacket.AppendPackedTime(ServerTime); + _worldPacket.AppendPackedTime(GameTime); + _worldPacket << float(NewSpeed); + _worldPacket << uint32(ServerTimeHolidayOffset); + _worldPacket << uint32(GameTimeHolidayOffset); + + return &_worldPacket; +} + +void WorldPackets::Misc::SetSelection::Read() +{ + _worldPacket >> Selection; +} + void WorldPackets::Misc::ViolenceLevel::Read() { _worldPacket >> ViolenceLvl; @@ -44,8 +78,40 @@ WorldPacket const* WorldPackets::Misc::UITime::Write() WorldPacket const* WorldPackets::Misc::TutorialFlags::Write() { - for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) - _worldPacket << TutorialData[i]; + _worldPacket.append(TutorialData, MAX_ACCOUNT_TUTORIAL_VALUES); + + return &_worldPacket; +} + +void WorldPackets::Misc::TutorialSetFlag::Read() +{ + Action = _worldPacket.ReadBits(2); + _worldPacket >> TutorialBit; +} + +WorldPacket const* WorldPackets::Misc::WorldServerInfo::Write() +{ + _worldPacket << uint32(DifficultyID); + _worldPacket << uint8(IsTournamentRealm); + _worldPacket << uint32(WeeklyReset); + _worldPacket.WriteBit(IneligibleForLootMask.HasValue); + _worldPacket.WriteBit(InstanceGroupSize.HasValue); + _worldPacket.WriteBit(RestrictedAccountMaxLevel.HasValue); + _worldPacket.WriteBit(RestrictedAccountMaxMoney.HasValue); + + if (IneligibleForLootMask.HasValue) + _worldPacket << uint32(IneligibleForLootMask.Value); + + if (InstanceGroupSize.HasValue) + _worldPacket << uint32(InstanceGroupSize.Value); + + if (RestrictedAccountMaxLevel.HasValue) + _worldPacket << uint32(RestrictedAccountMaxLevel.Value); + + if (RestrictedAccountMaxMoney.HasValue) + _worldPacket << uint32(RestrictedAccountMaxMoney.Value); + + _worldPacket.FlushBits(); return &_worldPacket; } diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index 86f2f4c5eb4..dfff0e331fc 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -19,11 +19,61 @@ #define MiscPackets_h__ #include "Packet.h" +#include "ObjectGuid.h" +#include "WorldSession.h" +#include "G3D/Vector3.h" +#include "Object.h" namespace WorldPackets { namespace Misc { + class BindPointUpdate final : public ServerPacket + { + public: + BindPointUpdate() : ServerPacket(SMSG_BINDPOINTUPDATE, 20) { } + + WorldPacket const* Write() override; + + uint32 BindMapID = MAPID_INVALID; + G3D::Vector3 BindPosition; + uint32 BindAreaID = 0; + }; + + class InvalidatePlayer final : public ServerPacket + { + public: + InvalidatePlayer() : ServerPacket(SMSG_INVALIDATE_PLAYER, 18) { } + + WorldPacket const* Write() override; + + ObjectGuid Guid; + }; + + class LoginSetTimeSpeed final : public ServerPacket + { + public: + LoginSetTimeSpeed() : ServerPacket(SMSG_LOGIN_SETTIMESPEED, 20) { } + + WorldPacket const* Write() override; + + float NewSpeed = 0.0f; + int32 ServerTimeHolidayOffset = 0; + uint32 GameTime = 0; + uint32 ServerTime = 0; + int32 GameTimeHolidayOffset = 0; + }; + + class SetSelection final : public ClientPacket + { + public: + SetSelection(WorldPacket&& packet) : ClientPacket(CMSG_SET_SELECTION, std::move(packet)) { } + + void Read() override; + + ObjectGuid Selection; ///< Target + }; + class ViolenceLevel final : public ClientPacket { public: @@ -54,7 +104,7 @@ namespace WorldPackets uint32 ClientTime = 0; // Client ticks in ms uint32 SequenceIndex = 0; // Same index as in request }; - + class UITime final : public ServerPacket { public: @@ -64,15 +114,45 @@ namespace WorldPackets uint32 Time = 0; }; - + class TutorialFlags : public ServerPacket { public: - TutorialFlags() : ServerPacket(SMSG_TUTORIAL_FLAGS, 32) { } + TutorialFlags() : ServerPacket(SMSG_TUTORIAL_FLAGS, 32) + { + std::memset(TutorialData, 0, sizeof(TutorialData)); + } + + WorldPacket const* Write() override; + + uint32 TutorialData[MAX_ACCOUNT_TUTORIAL_VALUES]; + }; + + class TutorialSetFlag final : public ClientPacket + { + public: + TutorialSetFlag(WorldPacket&& packet) : ClientPacket(CMSG_TUTORIAL_FLAG, std::move(packet)) { } + + void Read() override; + + uint8 Action = 0; + uint32 TutorialBit = 0; + }; + + class WorldServerInfo final : public ServerPacket + { + public: + WorldServerInfo() : ServerPacket(SMSG_WORLD_SERVER_INFO, 26) { } WorldPacket const* Write() override; - uint32 TutorialData[8]; + Optional<uint32> IneligibleForLootMask; ///< Encountermask? + uint32 WeeklyReset = 0; ///< UnixTime of last Weekly Reset Time + Optional<uint32> InstanceGroupSize; + uint8 IsTournamentRealm = 0; + Optional<uint32> RestrictedAccountMaxLevel; + Optional<uint32> RestrictedAccountMaxMoney; + uint32 DifficultyID = 0; }; } } diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp index 45d5b86e3fd..0c4d4bcff40 100644 --- a/src/server/game/Server/Packets/MovementPackets.cpp +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -16,162 +16,414 @@ */ #include "MovementPackets.h" +#include "MovementTypedefs.h" +#include "Unit.h" -void WorldPackets::Movement::ClientPlayerMovement::Read() +ByteBuffer& operator<<(ByteBuffer& data, G3D::Vector3 const& v) +{ + data << v.x << v.y << v.z; + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, G3D::Vector3& v) +{ + data >> v.x >> v.y >> v.z; + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, MovementInfo& movementInfo) { - _worldPacket >> movementInfo.guid; - _worldPacket >> movementInfo.time; - _worldPacket >> movementInfo.pos.m_positionX; - _worldPacket >> movementInfo.pos.m_positionY; - _worldPacket >> movementInfo.pos.m_positionZ; - _worldPacket >> movementInfo.pos.m_orientation; - _worldPacket >> movementInfo.pitch; - _worldPacket >> movementInfo.splineElevation; + bool hasTransportData = !movementInfo.transport.guid.IsEmpty(); + bool hasTransportPrevTime = hasTransportData && movementInfo.transport.prevTime != 0; + bool hasTransportVehicleId = hasTransportData && movementInfo.transport.vehicleId != 0; + bool hasFallDirection = movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING | MOVEMENTFLAG_FALLING_FAR); + bool hasFallData = hasFallDirection || movementInfo.jump.fallTime != 0; + + data << movementInfo.guid; + data << movementInfo.time; + data << movementInfo.pos.PositionXYZOStream(); + data << movementInfo.pitch; + data << movementInfo.splineElevation; + + uint32 removeMovementForcesCount = 0; + data << removeMovementForcesCount; + + uint32 int168 = 0; + data << int168; + + /*for (uint32 i = 0; i < removeMovementForcesCount; ++i) + { + data << ObjectGuid; + }*/ + + data.WriteBits(movementInfo.flags, 30); + data.WriteBits(movementInfo.flags2, 15); + + data.WriteBit(hasTransportData); + data.WriteBit(hasFallData); + + data.WriteBit(0); // HeightChangeFailed + data.WriteBit(0); // RemoteTimeValid + + if (hasTransportData) + { + data << movementInfo.transport.guid; + data << movementInfo.transport.pos.PositionXYZOStream(); + data << movementInfo.transport.seat; + data << movementInfo.transport.time; + + data.WriteBit(hasTransportPrevTime); + data.WriteBit(hasTransportVehicleId); + + if (hasTransportPrevTime) + data << movementInfo.transport.prevTime; + + if (hasTransportVehicleId) + data << movementInfo.transport.vehicleId; + } + + if (hasFallData) + { + data << movementInfo.jump.fallTime; + data << movementInfo.jump.zspeed; + + data.WriteBit(hasFallDirection); + if (hasFallDirection) + { + data << movementInfo.jump.sinAngle; + data << movementInfo.jump.cosAngle; + data << movementInfo.jump.xyspeed; + } + } + + data.FlushBits(); + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, MovementInfo& movementInfo) +{ + data >> movementInfo.guid; + data >> movementInfo.time; + data >> movementInfo.pos.PositionXYZOStream(); + data >> movementInfo.pitch; + data >> movementInfo.splineElevation; uint32 removeMovementForcesCount; - _worldPacket >> removeMovementForcesCount; + data >> removeMovementForcesCount; uint32 int168; - _worldPacket >> int168; + data >> int168; for (uint32 i = 0; i < removeMovementForcesCount; ++i) { ObjectGuid guid; - _worldPacket >> guid; + data >> guid; } - // ResetBitReader + movementInfo.flags = data.ReadBits(30); + movementInfo.flags2 = data.ReadBits(15); - movementInfo.flags = _worldPacket.ReadBits(30); - movementInfo.flags2 = _worldPacket.ReadBits(15); + bool hasTransport = data.ReadBit(); + bool hasFall = data.ReadBit(); - bool hasTransport = _worldPacket.ReadBit(); - bool hasFall = _worldPacket.ReadBit(); - - _worldPacket.ReadBit(); // HeightChangeFailed - _worldPacket.ReadBit(); // RemoteTimeValid + data.ReadBit(); // HeightChangeFailed + data.ReadBit(); // RemoteTimeValid if (hasTransport) { - _worldPacket >> movementInfo.transport.guid; - _worldPacket >> movementInfo.transport.pos.m_positionX; - _worldPacket >> movementInfo.transport.pos.m_positionY; - _worldPacket >> movementInfo.transport.pos.m_positionZ; - _worldPacket >> movementInfo.transport.pos.m_orientation; - _worldPacket >> movementInfo.transport.seat; - _worldPacket >> movementInfo.transport.time; + data >> movementInfo.transport.guid; + data >> movementInfo.transport.pos.PositionXYZOStream(); + data >> movementInfo.transport.seat; + data >> movementInfo.transport.time; - bool hasPrevTime = _worldPacket.ReadBit(); - bool hasVehicleId = _worldPacket.ReadBit(); + bool hasPrevTime = data.ReadBit(); + bool hasVehicleId = data.ReadBit(); if (hasPrevTime) - _worldPacket >> movementInfo.transport.prevTime; + data >> movementInfo.transport.prevTime; if (hasVehicleId) - _worldPacket >> movementInfo.transport.vehicleId; + data >> movementInfo.transport.vehicleId; } if (hasFall) { - _worldPacket >> movementInfo.jump.fallTime; - _worldPacket >> movementInfo.jump.zspeed; + data >> movementInfo.jump.fallTime; + data >> movementInfo.jump.zspeed; // ResetBitReader - bool hasFallDirection = _worldPacket.ReadBit(); + bool hasFallDirection = data.ReadBit(); if (hasFallDirection) { - _worldPacket >> movementInfo.jump.sinAngle; - _worldPacket >> movementInfo.jump.cosAngle; - _worldPacket >> movementInfo.jump.xyspeed; + data >> movementInfo.jump.sinAngle; + data >> movementInfo.jump.cosAngle; + data >> movementInfo.jump.xyspeed; } } + + return data; } -WorldPacket const* WorldPackets::Movement::ServerPlayerMovement::Write() +void WorldPackets::Movement::ClientPlayerMovement::Read() { - MovementInfo const movementInfo = mover->m_movementInfo; + _worldPacket >> movementInfo; +} - bool hasMovementFlags = mover->GetUnitMovementFlags() != 0; - bool hasMovementFlags2 = mover->GetExtraUnitMovementFlags() != 0; - bool hasTransportData = !mover->GetTransGUID().IsEmpty(); - bool hasSpline = mover->IsSplineEnabled(); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MonsterSplineFilterKey& monsterSplineFilterKey) +{ + data << monsterSplineFilterKey.Idx; + data << monsterSplineFilterKey.Speed; - bool hasTransportPrevTime = hasTransportData && movementInfo.transport.prevTime != 0; - bool hasTransportVehicleId = hasTransportData && movementInfo.transport.vehicleId != 0; - bool hasPitch = mover->HasUnitMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || mover->HasExtraUnitMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING); - bool hasFallDirection = mover->HasUnitMovementFlag(MOVEMENTFLAG_FALLING); - bool hasFallData = hasFallDirection || movementInfo.jump.fallTime != 0; - bool hasSplineElevation = mover->HasUnitMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION); + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MonsterSplineFilter& monsterSplineFilter) +{ + data << uint32(monsterSplineFilter.FilterKeys.size()); + data << monsterSplineFilter.BaseSpeed; + data << monsterSplineFilter.StartOffset; + data << monsterSplineFilter.DistToPrevFilterKey; + for (WorldPackets::Movement::MonsterSplineFilterKey& filterKey : monsterSplineFilter.FilterKeys) + data << filterKey; + data << monsterSplineFilter.AddedToStart; + data.WriteBits(monsterSplineFilter.FilterFlags, 2); + data.FlushBits(); + + return data; +} - _worldPacket << movementInfo.guid; - _worldPacket << movementInfo.time; - _worldPacket << movementInfo.pos.m_positionX; - _worldPacket << movementInfo.pos.m_positionY; - _worldPacket << movementInfo.pos.m_positionZ; - _worldPacket << movementInfo.pos.m_orientation; - _worldPacket << movementInfo.pitch; - _worldPacket << movementInfo.splineElevation; +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MovementSpline& movementSpline) +{ + data << movementSpline.Flags; + data << movementSpline.AnimTier; + data << movementSpline.TierTransStartTime; + data << movementSpline.Elapsed; + data << movementSpline.MoveTime; + data << movementSpline.JumpGravity; + data << movementSpline.SpecialTime; + data << int32(movementSpline.Points.size()); + data << movementSpline.Mode; + data << movementSpline.VehicleExitVoluntary; + data << movementSpline.TransportGUID; + data << movementSpline.VehicleSeat; + data << int32(movementSpline.PackedDeltas.size()); + for (G3D::Vector3 const& pos : movementSpline.Points) + data << pos; + for (G3D::Vector3 const& pos : movementSpline.PackedDeltas) + data.appendPackXYZ(pos.x, pos.y, pos.z); + data.WriteBits(movementSpline.Face, 2); + data.WriteBit(movementSpline.SplineFilter.HasValue); + data.FlushBits(); + + switch (movementSpline.Face) + { + case MONSTER_MOVE_FACING_SPOT: + data << movementSpline.FaceSpot; + break; + case MONSTER_MOVE_FACING_TARGET: + data << movementSpline.FaceDirection; + data << movementSpline.FaceGUID; + break; + case MONSTER_MOVE_FACING_ANGLE: + data << movementSpline.FaceDirection; + break; + } - uint32 removeMovementForcesCount = 0; - _worldPacket << removeMovementForcesCount; + if (movementSpline.SplineFilter.HasValue) + data << movementSpline.SplineFilter.Value; - uint32 int168 = 0; - _worldPacket << int168; + return data; +} - /*for (uint32 i = 0; i < removeMovementForcesCount; ++i) +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MovementMonsterSpline& movementMonsterSpline) +{ + data << movementMonsterSpline.ID; + data << movementMonsterSpline.Destination; + data << movementMonsterSpline.Move; + data.WriteBit(movementMonsterSpline.CrzTeleport); + + // Unk bits. 0 if monster is moving, 1 or 2 if stopped + if (movementMonsterSpline.Move.Flags) + data.WriteBits(0, 2); + else + data.WriteBits(2, 2); + + data.FlushBits(); + + return data; +} + +WorldPacket const* WorldPackets::Movement::MonsterMove::Write() +{ + _worldPacket << MoverGUID; + _worldPacket << Pos; + _worldPacket << SplineData; + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Movement::MoveSplineSetSpeed::Write() +{ + _worldPacket << MoverGUID; + _worldPacket << Speed; + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Movement::MoveSetSpeed::Write() +{ + _worldPacket << MoverGUID; + _worldPacket << SequenceIndex; + _worldPacket << Speed; + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Movement::MoveUpdateSpeed::Write() +{ + _worldPacket << *movementInfo; + _worldPacket << Speed; + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Movement::MoveSplineSetFlag::Write() +{ + _worldPacket << MoverGUID; + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Movement::MoveSetFlag::Write() +{ + _worldPacket << MoverGUID; + _worldPacket << SequenceIndex; + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Movement::ServerPlayerMovement::Write() +{ + _worldPacket << *movementInfo; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Movement::TransferPending::Write() +{ + _worldPacket << int32(MapID); + _worldPacket.WriteBit(Ship.HasValue); + _worldPacket.WriteBit(TransferSpellID.HasValue); + if (Ship.HasValue) { - _worldPacket << ObjectGuid; - }*/ + _worldPacket << uint32(Ship.Value.ID); + _worldPacket << int32(Ship.Value.OriginMapID); + } + + if (TransferSpellID.HasValue) + _worldPacket << int32(TransferSpellID.Value); + + _worldPacket.FlushBits(); + + return &_worldPacket; +} +WorldPacket const* WorldPackets::Movement::TransferAborted::Write() +{ + _worldPacket << uint32(MapID); + _worldPacket << uint8(Arg); + _worldPacket.WriteBits(TransfertAbort, 5); _worldPacket.FlushBits(); + return &_worldPacket; +} - _worldPacket.WriteBits(movementInfo.flags, 30); - _worldPacket.WriteBits(movementInfo.flags2, 15); +WorldPacket const* WorldPackets::Movement::NewWorld::Write() +{ + _worldPacket << MapID; + _worldPacket << Pos.PositionXYZOStream(); + _worldPacket << Reason; + return &_worldPacket; +} - _worldPacket.WriteBit(hasTransportData); - _worldPacket.WriteBit(hasFallData); +WorldPacket const* WorldPackets::Movement::MoveTeleport::Write() +{ + _worldPacket << MoverGUID; + _worldPacket << SequenceIndex; + _worldPacket << Pos.PositionXYZOStream(); + _worldPacket << Facing; - _worldPacket.WriteBit(0); // HeightChangeFailed - _worldPacket.WriteBit(0); // RemoteTimeValid + _worldPacket.WriteBit(TransportGUID.HasValue); + _worldPacket.WriteBit(Vehicle.HasValue); + _worldPacket.FlushBits(); - if (hasTransportData) + if (TransportGUID.HasValue) + _worldPacket << TransportGUID.Value; + + if (Vehicle.HasValue) { - _worldPacket << movementInfo.transport.guid; - _worldPacket << movementInfo.transport.pos.m_positionX; - _worldPacket << movementInfo.transport.pos.m_positionY; - _worldPacket << movementInfo.transport.pos.m_positionZ; - _worldPacket << movementInfo.transport.pos.m_orientation; - _worldPacket << movementInfo.transport.seat; - _worldPacket << movementInfo.transport.time; + _worldPacket << Vehicle.Value.VehicleSeatIndex; + _worldPacket.WriteBit(Vehicle.Value.VehicleExitVoluntary); + _worldPacket.WriteBit(Vehicle.Value.VehicleExitTeleport); + _worldPacket.FlushBits(); + } - _worldPacket.WriteBit(hasTransportPrevTime); - _worldPacket.WriteBit(hasTransportVehicleId); + return &_worldPacket; +} - if (hasTransportPrevTime) - _worldPacket << movementInfo.transport.prevTime; +WorldPacket const* WorldPackets::Movement::MoveUpdateTeleport::Write() +{ + _worldPacket << *movementInfo; - if (hasTransportVehicleId) - _worldPacket << movementInfo.transport.vehicleId; + _worldPacket << int32(MovementForces.size()); + for (WorldPackets::Movement::MovementForce const& force : MovementForces) + { + _worldPacket << force.ID; + _worldPacket << force.Direction; + _worldPacket << force.TransportID; + _worldPacket << force.Magnitude; + _worldPacket.WriteBits(force.Type, 2); + _worldPacket.FlushBits(); } - if (hasFallData) - { - _worldPacket << movementInfo.jump.fallTime; - _worldPacket << movementInfo.jump.zspeed; + _worldPacket.WriteBit(WalkSpeed.HasValue); + _worldPacket.WriteBit(RunSpeed.HasValue); + _worldPacket.WriteBit(RunBackSpeed.HasValue); + _worldPacket.WriteBit(SwimSpeed.HasValue); + _worldPacket.WriteBit(SwimBackSpeed.HasValue); + _worldPacket.WriteBit(FlightSpeed.HasValue); + _worldPacket.WriteBit(FlightBackSpeed.HasValue); + _worldPacket.WriteBit(TurnRate.HasValue); + _worldPacket.WriteBit(PitchRate.HasValue); - _worldPacket.FlushBits(); + if (WalkSpeed.HasValue) + _worldPacket << WalkSpeed.Value; - _worldPacket.WriteBit(hasFallDirection); - if (hasFallDirection) - { - _worldPacket << movementInfo.jump.sinAngle; - _worldPacket << movementInfo.jump.cosAngle; - _worldPacket << movementInfo.jump.xyspeed; - } - } + if (RunSpeed.HasValue) + _worldPacket << RunSpeed.Value; - _worldPacket.FlushBits(); + if (RunBackSpeed.HasValue) + _worldPacket << RunBackSpeed.Value; + + if (SwimSpeed.HasValue) + _worldPacket << SwimSpeed.Value; + + if (SwimBackSpeed.HasValue) + _worldPacket << SwimBackSpeed.Value; + + if (FlightSpeed.HasValue) + _worldPacket << FlightSpeed.Value; + + if (FlightBackSpeed.HasValue) + _worldPacket << FlightBackSpeed.Value; + + if (TurnRate.HasValue) + _worldPacket << TurnRate.Value; + + if (PitchRate.HasValue) + _worldPacket << PitchRate.Value; return &_worldPacket; } + +void WorldPackets::Movement::MoveTeleportAck::Read() +{ + _worldPacket >> MoverGUID; + _worldPacket >> AckIndex; + _worldPacket >> MoveTime; +} diff --git a/src/server/game/Server/Packets/MovementPackets.h b/src/server/game/Server/Packets/MovementPackets.h index f018757eada..6d5d10526b3 100644 --- a/src/server/game/Server/Packets/MovementPackets.h +++ b/src/server/game/Server/Packets/MovementPackets.h @@ -19,6 +19,8 @@ #define MovementPackets_h__ #include "Packet.h" +#include "Object.h" +#include <G3D/Vector3.h> namespace WorldPackets { @@ -37,13 +39,250 @@ namespace WorldPackets class ServerPlayerMovement final : public ServerPacket { public: - ServerPlayerMovement() : ServerPacket(SMSG_PLAYER_MOVE) {} + ServerPlayerMovement() : ServerPacket(SMSG_PLAYER_MOVE) { } WorldPacket const* Write() override; - Unit* mover; + MovementInfo* movementInfo = nullptr; + }; + + struct MonsterSplineFilterKey + { + int16 Idx = 0; + int16 Speed = 0; + }; + + struct MonsterSplineFilter + { + std::vector<MonsterSplineFilterKey> FilterKeys; + uint8 FilterFlags = 0; + float BaseSpeed = 0.0f; + int16 StartOffset = 0; + float DistToPrevFilterKey = 0.0f; + int16 AddedToStart = 0; + }; + + struct MovementSpline + { + uint32 Flags = 0; // Spline flags + uint8 Face = 0; // Movement direction (see MonsterMoveType enum) + uint8 AnimTier = 0; + uint32 TierTransStartTime = 0; + uint32 Elapsed = 0; + uint32 MoveTime = 0; + float JumpGravity = 0.0f; + uint32 SpecialTime = 0; + std::vector<G3D::Vector3> Points; // Spline path + uint8 Mode = 0; + uint8 VehicleExitVoluntary = 0; + ObjectGuid TransportGUID; + uint8 VehicleSeat = 255; + std::vector<G3D::Vector3> PackedDeltas; + Optional<MonsterSplineFilter> SplineFilter; + float FaceDirection = 0.0f; + ObjectGuid FaceGUID; + G3D::Vector3 FaceSpot; + }; + + struct MovementMonsterSpline + { + uint32 ID = 0; + G3D::Vector3 Destination; + bool CrzTeleport = false; + MovementSpline Move; + }; + + class MonsterMove final : public ServerPacket + { + public: + MonsterMove() : ServerPacket(SMSG_MONSTER_MOVE) { } + + WorldPacket const* Write() override; + + MovementMonsterSpline SplineData; + ObjectGuid MoverGUID; + G3D::Vector3 Pos; + }; + + class MoveSplineSetSpeed : public ServerPacket + { + public: + MoveSplineSetSpeed(OpcodeServer opcode) : ServerPacket(opcode, 12) { } + + WorldPacket const* Write() override; + + ObjectGuid MoverGUID; + float Speed = 1.0f; + }; + + class MoveSetSpeed : public ServerPacket + { + public: + MoveSetSpeed(OpcodeServer opcode) : ServerPacket(opcode) { } + + WorldPacket const* Write() override; + + ObjectGuid MoverGUID; + uint32 SequenceIndex = 0; ///< Unit movement packet index, incremented each time + float Speed = 1.0f; + }; + + class MoveUpdateSpeed : public ServerPacket + { + public: + MoveUpdateSpeed(OpcodeServer opcode) : ServerPacket(opcode) { } + + WorldPacket const* Write() override; + + MovementInfo* movementInfo = nullptr; + float Speed = 1.0f; + }; + + class MoveSplineSetFlag final : public ServerPacket + { + public: + MoveSplineSetFlag(OpcodeServer opcode) : ServerPacket(opcode, 8) { } + + WorldPacket const* Write() override; + + ObjectGuid MoverGUID; + }; + + class MoveSetFlag final : public ServerPacket + { + public: + MoveSetFlag(OpcodeServer opcode) : ServerPacket(opcode, 12) { } + + WorldPacket const* Write() override; + + ObjectGuid MoverGUID; + uint32 SequenceIndex = 0; ///< Unit movement packet index, incremented each time + }; + + class TransferPending final : public ServerPacket + { + struct ShipTransferPending + { + uint32 ID = 0; ///< gameobject_template.entry of the transport the player is teleporting on + int32 OriginMapID = -1; ///< Map id the player is currently on (before teleport) + }; + + public: + TransferPending() : ServerPacket(SMSG_TRANSFER_PENDING, 16) { } + + WorldPacket const* Write() override; + + int32 MapID = -1; + Optional<ShipTransferPending> Ship; + Optional<int32> TransferSpellID; + }; + + class TransferAborted final : public ServerPacket + { + public: + TransferAborted() : ServerPacket(SMSG_TRANSFER_ABORTED, 4 + 1 + 4) { } + + WorldPacket const* Write() override; + + uint32 TransfertAbort = 0; + uint8 Arg = 0; + uint32 MapID = 0; + }; + + class NewWorld final : public ServerPacket + { + public: + NewWorld() : ServerPacket(SMSG_NEW_WORLD, 24) { } + + WorldPacket const* Write() override; + + int32 MapID = 0; + uint32 Reason = 0; + Position Pos; + }; + + class WorldPortAck final : public ClientPacket + { + public: + WorldPortAck(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_WORLDPORT_ACK, std::move(packet)) { } + + void Read() override { } + }; + + struct VehicleTeleport + { + uint8 VehicleSeatIndex = 0; + bool VehicleExitVoluntary = false; + bool VehicleExitTeleport = false; + }; + + class MoveTeleport final : public ServerPacket + { + public: + MoveTeleport() : ServerPacket(SMSG_MOVE_TELEPORT, 12+4+16+16+4) { } + + WorldPacket const* Write() override; + + Position Pos; + Optional<VehicleTeleport> Vehicle; + uint32 SequenceIndex = 0; + ObjectGuid MoverGUID; + Optional<ObjectGuid> TransportGUID; + float Facing = 0.0f; + }; + + struct MovementForce + { + ObjectGuid ID; + G3D::Vector3 Direction; + uint32 TransportID = 0; + float Magnitude = 0; + uint8 Type = 0; + }; + + class MoveUpdateTeleport final : public ServerPacket + { + public: + MoveUpdateTeleport() : ServerPacket(SMSG_MOVE_UPDATE_TELEPORT) { } + + WorldPacket const* Write() override; + + MovementInfo* movementInfo = nullptr; + std::vector<MovementForce> MovementForces; + Optional<float> SwimBackSpeed; + Optional<float> FlightSpeed; + Optional<float> SwimSpeed; + Optional<float> WalkSpeed; + Optional<float> TurnRate; + Optional<float> RunSpeed; + Optional<float> FlightBackSpeed; + Optional<float> RunBackSpeed; + Optional<float> PitchRate; + }; + + class MoveTeleportAck final : public ClientPacket + { + public: + MoveTeleportAck(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_TELEPORT_ACK, std::move(packet)) { } + + void Read() override; + + ObjectGuid MoverGUID; + int32 AckIndex = 0; + int32 MoveTime = 0; }; } } +ByteBuffer& operator<<(ByteBuffer& data, G3D::Vector3 const& v); +ByteBuffer& operator>>(ByteBuffer& data, G3D::Vector3& v); + +ByteBuffer& operator>>(ByteBuffer& data, MovementInfo& movementInfo); +ByteBuffer& operator<<(ByteBuffer& data, MovementInfo& movementInfo); + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MonsterSplineFilterKey const& monsterSplineFilterKey); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MonsterSplineFilter const& monsterSplineFilter); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MovementSpline const& movementSpline); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Movement::MovementMonsterSpline const& movementMonsterSpline); + #endif // MovementPackets_h__ diff --git a/src/server/game/Server/Packets/NPCPackets.cpp b/src/server/game/Server/Packets/NPCPackets.cpp new file mode 100644 index 00000000000..60dbed09f1b --- /dev/null +++ b/src/server/game/Server/Packets/NPCPackets.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "NPCPackets.h" +#include "ItemPackets.h" + +void WorldPackets::NPC::Hello::Read() +{ + _worldPacket >> Unit; +} + +WorldPacket const* WorldPackets::NPC::GossipMessage::Write() +{ + _worldPacket << GossipGUID; + _worldPacket << GossipID; + _worldPacket << FriendshipFactionID; + _worldPacket << TextID; + + _worldPacket << int32(GossipOptions.size()); + _worldPacket << int32(GossipText.size()); + + for (ClientGossipOptions const& options : GossipOptions) + { + _worldPacket << options.ClientOption; + _worldPacket << options.OptionNPC; + _worldPacket << options.OptionFlags; + _worldPacket << options.OptionCost; + + _worldPacket.WriteBits(options.Text.size(), 12); + _worldPacket.WriteBits(options.Confirm.size(), 12); + _worldPacket.FlushBits(); + + _worldPacket.WriteString(options.Text); + _worldPacket.WriteString(options.Confirm); + } + + for (ClientGossipText const& text : GossipText) + { + _worldPacket << text.QuestID; + _worldPacket << text.QuestType; + _worldPacket << text.QuestLevel; + _worldPacket << text.QuestFlags[0]; + _worldPacket << text.QuestFlags[1]; + + _worldPacket.WriteBit(text.Repeatable); + _worldPacket.WriteBits(text.QuestTitle.size(), 9); + _worldPacket.FlushBits(); + + _worldPacket.WriteString(text.QuestTitle); + } + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::NPC::VendorInventory::Write() +{ + _worldPacket << Vendor; + _worldPacket << Reason; + + _worldPacket << int32(Items.size()); + for (VendorItem const& item : Items) + { + _worldPacket << item.MuID; + _worldPacket << item.Type; + _worldPacket << item.Item; + _worldPacket << item.Quantity; + _worldPacket << item.Price; + _worldPacket << item.Durability; + _worldPacket << item.StackCount; + _worldPacket << item.ExtendedCostID; + _worldPacket << item.PlayerConditionFailed; + + _worldPacket.WriteBit(item.DoNotFilterOnVendor); + _worldPacket.FlushBits(); + } + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::NPC::TrainerList::Write() +{ + _worldPacket << TrainerGUID; + _worldPacket << TrainerType; + _worldPacket << TrainerID; + + _worldPacket << int32(Spells.size()); + for (TrainerListSpell const& spell : Spells) + { + _worldPacket << spell.SpellID; + _worldPacket << spell.MoneyCost; + _worldPacket << spell.ReqSkillLine; + _worldPacket << spell.ReqSkillRank; + + for (uint32 i = 0; i < MAX_TRAINERSPELL_ABILITY_REQS; ++i) + _worldPacket << spell.ReqAbility[i]; + + _worldPacket << spell.Usable; + _worldPacket << spell.ReqLevel; + } + + _worldPacket.WriteBits(Greeting.length(), 11); + _worldPacket.FlushBits(); + _worldPacket.WriteString(Greeting); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/NPCPackets.h b/src/server/game/Server/Packets/NPCPackets.h new file mode 100644 index 00000000000..221cb454765 --- /dev/null +++ b/src/server/game/Server/Packets/NPCPackets.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NPCPackets_h__ +#define NPCPackets_h__ + +#include "Packet.h" +#include "ItemPackets.h" +#include "Creature.h" + +namespace WorldPackets +{ + namespace NPC + { + // CMSG_BANKER_ACTIVATE + // CMSG_BINDER_ACTIVATE + // CMSG_BINDER_CONFIRM + // CMSG_GOSSIP_HELLO + // CMSG_LIST_INVENTORY + // CMSG_TRAINER_LIST + class Hello final : public ClientPacket + { + public: + Hello(WorldPacket&& packet) : ClientPacket(std::move(packet)) { } + + void Read() override; + + ObjectGuid Unit; + }; + + struct ClientGossipOptions + { + int32 ClientOption = 0; + uint8 OptionNPC = 0; + uint8 OptionFlags = 0; + int32 OptionCost = 0; + std::string Text; + std::string Confirm; + }; + + struct ClientGossipText + { + int32 QuestID = 0; + int32 QuestType = 0; + int32 QuestLevel = 0; + bool Repeatable = false; + std::string QuestTitle; + int32 QuestFlags[2]; + }; + + class GossipMessage final : public ServerPacket + { + public: + GossipMessage() : ServerPacket(SMSG_GOSSIP_MESSAGE, 200) { } + + WorldPacket const* Write() override; + + std::vector<ClientGossipOptions> GossipOptions; + int32 FriendshipFactionID = 0; + ObjectGuid GossipGUID; + std::vector<ClientGossipText> GossipText; + int32 TextID = 0; + int32 GossipID = 0; + }; + + struct VendorItem + { + int32 MuID = 0; + int32 Type = 0; + WorldPackets::Item::ItemInstance Item; + int32 Quantity = -1; + int32 Price = 0; + int32 Durability = 0; + int32 StackCount = 0; + int32 ExtendedCostID = 0; + int32 PlayerConditionFailed = 0; + bool DoNotFilterOnVendor = false; + }; + + class VendorInventory final : public ServerPacket + { + public: + VendorInventory() : ServerPacket(SMSG_LIST_INVENTORY, 600) { } + + WorldPacket const* Write() override; + + uint8 Reason = 0; + std::vector<VendorItem> Items; + ObjectGuid Vendor; + }; + + struct TrainerListSpell + { + int32 SpellID = 0; + int32 MoneyCost = 0; + int32 ReqSkillLine = 0; + int32 ReqSkillRank = 0; + int32 ReqAbility[MAX_TRAINERSPELL_ABILITY_REQS]; + uint8 Usable = 0; + uint8 ReqLevel = 0; + }; + + class TrainerList final : public ServerPacket + { + public: + TrainerList() : ServerPacket(SMSG_TRAINER_LIST, 150) { } + + WorldPacket const* Write() override; + + std::string Greeting; + int32 TrainerType = 0; + ObjectGuid TrainerGUID; + int32 TrainerID = 1; + std::vector<TrainerListSpell> Spells; + }; + } +} + +#endif // NPCPackets_h__ diff --git a/src/server/game/Server/Packets/QueryPackets.cpp b/src/server/game/Server/Packets/QueryPackets.cpp index 0d1b861a9b5..335d261651a 100644 --- a/src/server/game/Server/Packets/QueryPackets.cpp +++ b/src/server/game/Server/Packets/QueryPackets.cpp @@ -97,10 +97,10 @@ void WorldPackets::Query::QueryPlayerName::Read() Hint.NativeRealmAddress.HasValue = _worldPacket.ReadBit(); if (Hint.VirtualRealmAddress.HasValue) - _worldPacket >> Hint.VirtualRealmAddress.value; + _worldPacket >> Hint.VirtualRealmAddress.Value; if (Hint.NativeRealmAddress.HasValue) - _worldPacket >> Hint.NativeRealmAddress.value; + _worldPacket >> Hint.NativeRealmAddress.Value; } WorldPacket const* WorldPackets::Query::QueryPlayerNameResponse::Write() @@ -153,3 +153,58 @@ WorldPacket const* WorldPackets::Query::QueryPageTextResponse::Write() return &_worldPacket; } + +void WorldPackets::Query::QueryNPCText::Read() +{ + _worldPacket >> TextID; + _worldPacket >> Guid; +} + +WorldPacket const* WorldPackets::Query::QueryNPCTextResponse::Write() +{ + _worldPacket << TextID; + _worldPacket.WriteBit(Allow); + + if (Allow) + { + _worldPacket << int32(MAX_GOSSIP_TEXT_OPTIONS * (4 + 4)); + for (uint32 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) + _worldPacket << Probabilities[i]; + for (uint32 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) + _worldPacket << BroadcastTextID[i]; + } + + return &_worldPacket; +} + +void WorldPackets::Query::DBQueryBulk::Read() +{ + _worldPacket >> TableHash; + + uint32 count = _worldPacket.ReadBits(13); + _worldPacket.ResetBitPos(); + + Queries.resize(count); + for (uint32 i = 0; i < count; ++i) + { + _worldPacket >> Queries[i].GUID; + _worldPacket >> Queries[i].RecordID; + } +} + +WorldPacket const* WorldPackets::Query::DBReply::Write() +{ + _worldPacket << TableHash; + _worldPacket << RecordID; + _worldPacket << Timestamp; + + size_t sizePos = _worldPacket.wpos(); + _worldPacket << int32(0); // size of next block + + if (Data) + Data->WriteRecord(RecordID, Locale, _worldPacket); + + _worldPacket.put<int32>(sizePos, _worldPacket.wpos() - sizePos - 4); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/QueryPackets.h b/src/server/game/Server/Packets/QueryPackets.h index b7c57e94747..8b6eae8db56 100644 --- a/src/server/game/Server/Packets/QueryPackets.h +++ b/src/server/game/Server/Packets/QueryPackets.h @@ -20,6 +20,8 @@ #include "Packet.h" #include "Creature.h" +#include "NPCHandler.h" +#include "DB2Stores.h" namespace WorldPackets { @@ -141,6 +143,63 @@ namespace WorldPackets PageTextInfo Info; uint32 PageTextID = 0; }; + + class QueryNPCText final : public ClientPacket + { + public: + QueryNPCText(WorldPacket&& packet) : ClientPacket(CMSG_NPC_TEXT_QUERY, std::move(packet)) { } + + void Read() override; + + ObjectGuid Guid; + uint32 TextID = 0; + }; + + class QueryNPCTextResponse final : public ServerPacket + { + public: + QueryNPCTextResponse() : ServerPacket(SMSG_NPC_TEXT_UPDATE, 73) { } + + WorldPacket const* Write() override; + + uint32 TextID = 0; + bool Allow = false; + float Probabilities[MAX_GOSSIP_TEXT_OPTIONS]; + uint32 BroadcastTextID[MAX_GOSSIP_TEXT_OPTIONS]; + }; + + struct DBQueryRecord + { + ObjectGuid GUID; + uint32 RecordID; + }; + + class DBQueryBulk final : public ClientPacket + { + public: + DBQueryBulk(WorldPacket&& packet) : ClientPacket(CMSG_DB_QUERY_BULK, std::move(packet)) { } + + void Read() override; + + uint32 TableHash = 0; + std::vector<DBQueryRecord> Queries; + }; + + class DBReply final : public ServerPacket + { + public: + DBReply() : ServerPacket(SMSG_DB_REPLY, 12) { } + + WorldPacket const* Write() override; + + uint32 TableHash = 0; + uint32 Timestamp = 0; + int32 RecordID = 0; + + // These are not sent directly + uint32 Locale = 0; + DB2StorageBase const* Data = nullptr; + }; } } diff --git a/src/server/game/Server/Packets/QuestPackets.cpp b/src/server/game/Server/Packets/QuestPackets.cpp new file mode 100644 index 00000000000..e20023d3dd2 --- /dev/null +++ b/src/server/game/Server/Packets/QuestPackets.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "QuestPackets.h" + +void WorldPackets::Quest::QuestGiverStatusQuery::Read() +{ + _worldPacket >> QuestGiverGUID; +} + +WorldPacket const* WorldPackets::Quest::QuestGiverStatus::Write() +{ + _worldPacket << QuestGiver.Guid; + _worldPacket << QuestGiver.Status; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Quest::QuestGiverStatusMultiple::Write() +{ + _worldPacket << int32(QuestGiver.size()); + for (QuestGiverInfo const& questGiver : QuestGiver) + { + _worldPacket << questGiver.Guid; + _worldPacket << questGiver.Status; + } + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h new file mode 100644 index 00000000000..12410380c3a --- /dev/null +++ b/src/server/game/Server/Packets/QuestPackets.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QuestPackets_h__ +#define QuestPackets_h__ + +#include "Packet.h" +#include "QuestDef.h" +#include "ObjectGuid.h" + +namespace WorldPackets +{ + namespace Quest + { + class QuestGiverStatusQuery final : public ClientPacket + { + public: + QuestGiverStatusQuery(WorldPacket&& packet) : ClientPacket(CMSG_QUESTGIVER_STATUS_QUERY, std::move(packet)) { } + + void Read() override; + + ObjectGuid QuestGiverGUID; + }; + + // Empty packet, server replies with quest giver status of visible creatures + class QuestGiverStatusMultipleQuery final : public ClientPacket + { + public: + QuestGiverStatusMultipleQuery(WorldPacket&& packet) : ClientPacket(CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY, std::move(packet)) { } + + void Read() override { } + }; + + struct QuestGiverInfo + { + QuestGiverInfo() { } + QuestGiverInfo(ObjectGuid const& guid, uint32 status) + : Guid(guid), Status(status) { } + + ObjectGuid Guid; + uint32 Status = DIALOG_STATUS_NONE; + }; + + class QuestGiverStatus final : public ServerPacket + { + public: + QuestGiverStatus() : ServerPacket(SMSG_QUESTGIVER_STATUS, 22) { } + + WorldPacket const* Write() override; + + QuestGiverInfo QuestGiver; + }; + + class QuestGiverStatusMultiple final : public ServerPacket + { + public: + QuestGiverStatusMultiple() : ServerPacket(SMSG_QUESTGIVER_STATUS_MULTIPLE, 24) { } + + WorldPacket const* Write() override; + + std::vector<QuestGiverInfo> QuestGiver; + }; + } +} + +#endif // QuestPackets_h__ diff --git a/src/server/game/Server/Packets/ReputationPackets.cpp b/src/server/game/Server/Packets/ReputationPackets.cpp new file mode 100644 index 00000000000..4acecf851f4 --- /dev/null +++ b/src/server/game/Server/Packets/ReputationPackets.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ReputationPackets.h" + +WorldPacket const* WorldPackets::Reputation::InitializeFactions::Write() +{ + for (uint16 i = 0; i < FactionCount; ++i) + { + _worldPacket << uint8(FactionFlags[i]); + _worldPacket << int32(FactionStandings[i]); + } + + for (uint16 i = 0; i < FactionCount; ++i) + _worldPacket.WriteBit(FactionHasBonus[i]); + + _worldPacket.FlushBits(); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/ReputationPackets.h b/src/server/game/Server/Packets/ReputationPackets.h new file mode 100644 index 00000000000..387ae9b0318 --- /dev/null +++ b/src/server/game/Server/Packets/ReputationPackets.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "Packet.h" + +namespace WorldPackets +{ + namespace Reputation + { + static uint16 const FactionCount = 256; + + class InitializeFactions final : public ServerPacket + { + public: + InitializeFactions() : ServerPacket(SMSG_INITIALIZE_FACTIONS, 1312) + { + for (uint16 i = 0; i < FactionCount; ++i) + { + FactionStandings[i] = 0; + FactionHasBonus[i] = false; + FactionFlags[i] = 0; + } + } + + WorldPacket const* Write() override; + + int32 FactionStandings[FactionCount]; + bool FactionHasBonus[FactionCount]; ///< @todo: implement faction bonus + uint8 FactionFlags[FactionCount]; ///< @see enum FactionFlags + }; + } +} diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index 09914b292bb..233c35f7bbd 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -16,8 +16,10 @@ */ #include "SpellPackets.h" +#include "SpellAuraEffects.h" +#include "MovementPackets.h" -WorldPacket const* WorldPackets::Spell::CategoryCooldown::Write() +WorldPacket const* WorldPackets::Spells::CategoryCooldown::Write() { _worldPacket.reserve(4 + 8 * CategoryCooldowns.size()); @@ -32,7 +34,7 @@ WorldPacket const* WorldPackets::Spell::CategoryCooldown::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Spell::SendKnownSpells::Write() +WorldPacket const* WorldPackets::Spells::SendKnownSpells::Write() { _worldPacket.reserve(1 + 4 * KnownSpells.size()); @@ -45,7 +47,7 @@ WorldPacket const* WorldPackets::Spell::SendKnownSpells::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Spell::UpdateActionButtons::Write() +WorldPacket const* WorldPackets::Spells::UpdateActionButtons::Write() { for (uint32 i = 0; i < MAX_ACTION_BUTTONS; ++i) _worldPacket << ActionButtons[i]; @@ -55,7 +57,13 @@ WorldPacket const* WorldPackets::Spell::UpdateActionButtons::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Spell::SendUnlearnSpells::Write() +void WorldPackets::Spells::SetActionButton::Read() +{ + _worldPacket >> Action; + _worldPacket >> Index; +} + +WorldPacket const* WorldPackets::Spells::SendUnlearnSpells::Write() { _worldPacket << uint32(Spells.size()); for (uint32 spellId : Spells) @@ -64,3 +72,422 @@ WorldPacket const* WorldPackets::Spell::SendUnlearnSpells::Write() return &_worldPacket; } +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellCastLogData const& spellCastLogData) +{ + data << spellCastLogData.Health; + data << spellCastLogData.AttackPower; + data << spellCastLogData.SpellPower; + data << int32(spellCastLogData.PowerData.size()); + for (WorldPackets::Spells::SpellLogPowerData const& powerData : spellCastLogData.PowerData) + { + data << powerData.PowerType; + data << powerData.Amount; + } + data.WriteBit(false); + // data << float // Unk data if bit is true + data.FlushBits(); + + return data; +} + +WorldPacket const* WorldPackets::Spells::SendAuraUpdate::Write() +{ + return &_worldPacket; +} + +void WorldPackets::Spells::SendAuraUpdate::Init(bool IsFullUpdate, ObjectGuid Target, uint32 Count) +{ + _worldPacket.WriteBit(IsFullUpdate); + _worldPacket << Target; + _worldPacket << uint32(Count); +} + +void WorldPackets::Spells::SendAuraUpdate::BuildUpdatePacket(AuraApplication* aurApp, bool remove, uint16 level) +{ + _worldPacket << uint8(aurApp->GetSlot()); + _worldPacket.ResetBitPos(); + _worldPacket.WriteBit(!remove); + + if (remove) + { + _worldPacket.FlushBits(); + return; + } + Aura const* aura = aurApp->GetBase(); + _worldPacket << uint32(aura->GetId()); + + uint8 flags = aurApp->GetFlags(); + if (aura->GetMaxDuration() > 0 && !(aura->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_HIDE_DURATION)) + flags |= AFLAG_DURATION; + _worldPacket << uint8(flags); + + _worldPacket << uint32(aurApp->GetEffectMask()); + + _worldPacket << uint16(level); + + // send stack amount for aura which could be stacked (never 0 - causes incorrect display) or charges + // stack amount has priority over charges (checked on retail with spell 50262) + _worldPacket << uint8(aura->GetSpellInfo()->StackAmount ? aura->GetStackAmount() : aura->GetCharges()); + + uint32 int72 = 0; + _worldPacket << int72; + + size_t pos = _worldPacket.wpos(); + uint32 count = 0; + _worldPacket << count; + + //for (int72) + // float + + if (flags & AFLAG_SCALABLE) + { + for (AuraEffect const* effect : aura->GetAuraEffects()) + { + if (effect && aurApp->HasEffect(effect->GetEffIndex())) // Not all of aura's effects have to be applied on every target + { + _worldPacket << int32(effect->GetAmount()); + count++; + } + } + } + + _worldPacket.put<uint32>(pos, count); + + _worldPacket.ResetBitPos(); + + _worldPacket.WriteBit(!(flags & AFLAG_NOCASTER)); + _worldPacket.WriteBit(aura->GetDuration()); + _worldPacket.WriteBit(aura->GetMaxDuration()); + + if (!(flags & AFLAG_NOCASTER)) + _worldPacket << aura->GetCasterGUID().WriteAsPacked(); + + if (aura->GetDuration()) + { + _worldPacket << uint32(aura->GetDuration()); + } + + if (aura->GetMaxDuration()) + { + _worldPacket << uint32(aura->GetMaxDuration()); + } +} + +void WorldPackets::Spells::SpellCastRequest::Read() +{ + if (_worldPacket.GetOpcode() == CMSG_PET_CAST_SPELL) + _worldPacket >> PetGuid; + + _worldPacket >> CastID; + _worldPacket >> SpellID; + _worldPacket >> Misc; + + _worldPacket.ResetBitPos(); + + TargetFlags = _worldPacket.ReadBits(21); + bool HasSrcLocation = _worldPacket.ReadBit(); + bool HasDstLocation = _worldPacket.ReadBit(); + bool HasOrientation = _worldPacket.ReadBit(); + uint32 NameLen = _worldPacket.ReadBits(7); + + _worldPacket >> UnitGuid; + _worldPacket >> ItemGuid; + + if (HasSrcLocation) + { + _worldPacket >> SrcTransportGuid; + _worldPacket >> SrcPos.m_positionX; + _worldPacket >> SrcPos.m_positionY; + _worldPacket >> SrcPos.m_positionZ; + } + + if (HasDstLocation) + { + _worldPacket >> DstTransportGuid; + _worldPacket >> DstPos.m_positionX; + _worldPacket >> DstPos.m_positionY; + _worldPacket >> DstPos.m_positionZ; + } + + if (HasOrientation) + _worldPacket >> Orientation; + + Name = _worldPacket.ReadString(NameLen); + + _worldPacket >> Pitch; + _worldPacket >> Speed; + + _worldPacket >> Guid; + + _worldPacket.ResetBitPos(); + + SendCastFlags = _worldPacket.ReadBits(5); + + bool HasMoveUpdate = _worldPacket.ReadBit(); + uint32 SpellWeightCount = _worldPacket.ReadBits(2); + + if (HasMoveUpdate) + { + _worldPacket >> movementInfo; + } + + // SpellWeight + for (uint32 i = 0; i < SpellWeightCount; ++i) + { + _worldPacket.ResetBitPos(); + uint32 Type = _worldPacket.ReadBits(2); + uint32 ID; + _worldPacket >> ID; + uint32 Quantity; + _worldPacket >> Quantity; + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::TargetLocation const& targetLocation) +{ + data << targetLocation.Transport; + // data << targetLocation.Location.PositionXYZStream(); + data << targetLocation.Location.m_positionX; + data << targetLocation.Location.m_positionY; + data << targetLocation.Location.m_positionZ; + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellTargetData const& spellTargetData) +{ + data.WriteBits(spellTargetData.Flags, 21); + data.WriteBit(spellTargetData.SrcLocation.HasValue); + data.WriteBit(spellTargetData.DstLocation.HasValue); + data.WriteBit(spellTargetData.Orientation.HasValue); + data.WriteBits(spellTargetData.Name.size(), 7); + data.FlushBits(); + + data << spellTargetData.Unit; + data << spellTargetData.Item; + + if (spellTargetData.SrcLocation.HasValue) + data << spellTargetData.SrcLocation.Value; + + if (spellTargetData.DstLocation.HasValue) + data << spellTargetData.DstLocation.Value; + + if (spellTargetData.Orientation.HasValue) + data << spellTargetData.Orientation.Value; + + data.WriteString(spellTargetData.Name); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellMissStatus const& spellMissStatus) +{ + data.WriteBits(spellMissStatus.Reason, 4); + data.WriteBits(spellMissStatus.ReflectStatus, 4); + // No need to flush bits as we written exactly 8 bits (1 byte) + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellPowerData const& spellPowerData) +{ + data << spellPowerData.Cost; + data << spellPowerData.Type; + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::RuneData const& runeData) +{ + data << runeData.Start; + data << runeData.Count; + + data.WriteBits(runeData.Cooldowns.size(), 3); + data.FlushBits(); + + for (uint8 cd : runeData.Cooldowns) + data << cd; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::MissileTrajectoryResult const& missileTrajectory) +{ + data << missileTrajectory.TravelTime; + data << missileTrajectory.Pitch; + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellAmmo const& spellAmmo) +{ + data << spellAmmo.DisplayID; + data << spellAmmo.InventoryType; + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::ProjectileVisualData const& projectileVisual) +{ + data << projectileVisual.ID[0]; + data << projectileVisual.ID[1]; + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::CreatureImmunities const& immunities) +{ + data << immunities.School; + data << immunities.Value; + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellHealPrediction const& spellPred) +{ + data << spellPred.Points; + data << spellPred.Type; + data << spellPred.BeaconGUID; + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellCastData const& spellCastData) +{ + data << spellCastData.CasterGUID; + data << spellCastData.CasterUnit; + data << spellCastData.CastID; + data << spellCastData.SpellID; + data << spellCastData.CastFlags; + data << spellCastData.CastTime; + data << uint32(spellCastData.HitTargets.size()); + data << uint32(spellCastData.MissTargets.size()); + data << uint32(spellCastData.MissStatus.size()); + data << spellCastData.Target; + data << uint32(spellCastData.RemainingPower.size()); + data << spellCastData.MissileTrajectory; + data << spellCastData.Ammo; + data << spellCastData.DestLocSpellCastIndex; + data << uint32(spellCastData.TargetPoints.size()); + data << spellCastData.Immunities; + data << spellCastData.Predict; + + for (ObjectGuid const& target : spellCastData.HitTargets) + data << target; + + for (ObjectGuid const& target : spellCastData.MissTargets) + data << target; + + for (WorldPackets::Spells::SpellMissStatus const& status : spellCastData.MissStatus) + data << status; + + for (WorldPackets::Spells::SpellPowerData const& power : spellCastData.RemainingPower) + data << power; + + for (WorldPackets::Spells::TargetLocation const& targetLoc : spellCastData.TargetPoints) + data << targetLoc; + + data.WriteBits(spellCastData.CastFlagsEx, 18); + data.WriteBit(spellCastData.RemainingRunes.HasValue); + data.WriteBit(spellCastData.ProjectileVisual.HasValue); + data.FlushBits(); + + if (spellCastData.RemainingRunes.HasValue) + data << spellCastData.RemainingRunes.Value; + + if (spellCastData.ProjectileVisual.HasValue) + data << spellCastData.ProjectileVisual.Value; + + return data; +} + +WorldPacket const* WorldPackets::Spells::SpellStart::Write() +{ + _worldPacket << Cast; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Spells::SpellGo::Write() +{ + _worldPacket << Cast; + + _worldPacket.WriteBit(LogData.HasValue); + _worldPacket.FlushBits(); + + if (LogData.HasValue) + _worldPacket << LogData.Value; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Spells::LearnedSpells::Write() +{ + _worldPacket << uint32(SpellID.size()); + for (int32 spell : SpellID) + _worldPacket << spell; + + _worldPacket.WriteBit(SuppressMessaging); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Spells::SpellFailure::Write() +{ + _worldPacket << CasterUnit; + _worldPacket << CastID; + _worldPacket << SpellID; + _worldPacket << Reason; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Spells::SpellFailedOther::Write() +{ + _worldPacket << CasterUnit; + _worldPacket << CastID; + _worldPacket << SpellID; + _worldPacket << Reason; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Spells::CastFailed::Write() +{ + _worldPacket << SpellID; + _worldPacket << Reason; + _worldPacket << FailedArg1; + _worldPacket << FailedArg2; + _worldPacket << CastID; + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellModifierData const& spellModifierData) +{ + data << spellModifierData.ModifierValue; + data << spellModifierData.ClassIndex; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellModifier const& spellModifier) +{ + data << spellModifier.ModIndex; + data << uint32(spellModifier.ModifierData.size()); + for (WorldPackets::Spells::SpellModifierData const& modData : spellModifier.ModifierData) + data << modData; + + return data; +} + +WorldPacket const* WorldPackets::Spells::SetSpellModifier::Write() +{ + _worldPacket << uint32(Modifiers.size()); + for (WorldPackets::Spells::SpellModifier const& spellMod : Modifiers) + _worldPacket << spellMod; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Spells::SendRemovedSpell::Write() +{ + _worldPacket << uint32(Spells.size()); + for (uint32 spellId : Spells) + _worldPacket << uint32(spellId); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index 2b4e4c3c146..98882fc2e26 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -20,10 +20,12 @@ #include "Packet.h" #include "Player.h" +#include "SpellAuras.h" +#include "Spell.h" namespace WorldPackets { - namespace Spell + namespace Spells { class CategoryCooldown final : public ServerPacket { @@ -58,7 +60,10 @@ namespace WorldPackets class UpdateActionButtons final : public ServerPacket { public: - UpdateActionButtons() : ServerPacket(SMSG_ACTION_BUTTONS, MAX_ACTION_BUTTONS*8+1) { } + UpdateActionButtons() : ServerPacket(SMSG_ACTION_BUTTONS, MAX_ACTION_BUTTONS * 8 + 1) + { + std::memset(ActionButtons, 0, sizeof(ActionButtons)); + } WorldPacket const* Write() override; @@ -72,6 +77,17 @@ namespace WorldPackets */ }; + class SetActionButton final : public ClientPacket + { + public: + SetActionButton(WorldPacket&& packet) : ClientPacket(CMSG_SET_ACTION_BUTTON, std::move(packet)) {} + + void Read() override; + + uint64 Action = 0; ///< two packed uint32 (action and type) + uint8 Index = 0; + }; + class SendUnlearnSpells final : public ServerPacket { public: @@ -81,7 +97,273 @@ namespace WorldPackets std::vector<uint32> Spells; }; + + struct SpellLogPowerData + { + int32 PowerType = 0; + int32 Amount = 0; + }; + + struct SpellCastLogData + { + int32 Health = 0; + int32 AttackPower = 0; + int32 SpellPower = 0; + std::vector<SpellLogPowerData> PowerData; + }; + + class SendAuraUpdate final : public ServerPacket + { + public: + SendAuraUpdate() : ServerPacket(SMSG_AURA_UPDATE) { } + + WorldPacket const* Write() override; + void Init(bool IsFullUpdate, ObjectGuid Target, uint32 Count); + void BuildUpdatePacket(AuraApplication* aurApp, bool remove, uint16 level); + }; + + class SpellCastRequest final : public ClientPacket + { + public: + SpellCastRequest(WorldPacket&& packet) : ClientPacket(std::move(packet)) + { + ASSERT(packet.GetOpcode() == CMSG_CAST_SPELL || packet.GetOpcode() == CMSG_PET_CAST_SPELL); + } + + void Read() override; + + ObjectGuid PetGuid; + uint8 CastID; + uint32 SpellID; + uint32 Misc; + uint32 TargetFlags; + ObjectGuid UnitGuid; + ObjectGuid ItemGuid; + + ObjectGuid SrcTransportGuid; + ObjectGuid DstTransportGuid; + Position SrcPos; + Position DstPos; + float Orientation; + + std::string Name; + float Pitch; + float Speed; + ObjectGuid Guid; + uint32 SendCastFlags; + + MovementInfo movementInfo; + }; + + struct TargetLocation + { + ObjectGuid Transport; + Position Location; + }; + + struct SpellTargetData + { + uint32 Flags = 0; + ObjectGuid Unit; + ObjectGuid Item; + Optional<TargetLocation> SrcLocation; + Optional<TargetLocation> DstLocation; + Optional<float> Orientation; // Not found in JAM structures + std::string Name; + }; + + struct SpellMissStatus + { + uint8 Reason = 0; + uint8 ReflectStatus = 0; + }; + + struct SpellPowerData + { + int32 Cost = 0; + int8 Type = 0; + }; + + struct RuneData + { + uint8 Start = 0; + uint8 Count = 0; + std::vector<uint8> Cooldowns; + }; + + struct MissileTrajectoryResult + { + uint32 TravelTime = 0; + float Pitch = 0.0f; + }; + + struct SpellAmmo + { + int32 DisplayID = 0; + int8 InventoryType = 0; + }; + + struct ProjectileVisualData + { + int32 ID[2]; + }; + + struct CreatureImmunities + { + uint32 School = 0; + uint32 Value = 0; + }; + + struct SpellHealPrediction + { + ObjectGuid BeaconGUID; + uint32 Points = 0; + uint8 Type = 0; + }; + + struct SpellCastData + { + ObjectGuid CasterGUID; + ObjectGuid CasterUnit; + uint8 CastID = 0; + int32 SpellID = 0; + uint32 CastFlags = 0; + uint32 CastFlagsEx = 0; + uint32 CastTime = 0; + std::vector<ObjectGuid> HitTargets; + std::vector<ObjectGuid> MissTargets; + std::vector<SpellMissStatus> MissStatus; + SpellTargetData Target; + std::vector<SpellPowerData> RemainingPower; + Optional<RuneData> RemainingRunes; + MissileTrajectoryResult MissileTrajectory; + SpellAmmo Ammo; + Optional<ProjectileVisualData> ProjectileVisual; + uint8 DestLocSpellCastIndex = 0; + std::vector<TargetLocation> TargetPoints; + CreatureImmunities Immunities; + SpellHealPrediction Predict; + }; + + class SpellGo final : public ServerPacket + { + public: + SpellGo() : ServerPacket(SMSG_SPELL_GO) { } + + WorldPacket const* Write() override; + + Optional<SpellCastLogData> LogData; + SpellCastData Cast; + }; + + class SpellStart final : public ServerPacket + { + public: + SpellStart() : ServerPacket(SMSG_SPELL_START) { } + + WorldPacket const* Write() override; + + SpellCastData Cast; + }; + + class LearnedSpells final : public ServerPacket + { + public: + LearnedSpells() : ServerPacket(SMSG_LEARNED_SPELLS, 9) { } + + WorldPacket const* Write() override; + + std::vector<int32> SpellID; + bool SuppressMessaging = false; + }; + + class SpellFailure final : public ServerPacket + { + public: + SpellFailure() : ServerPacket(SMSG_SPELL_FAILURE, 16+4+1+1) { } + + WorldPacket const* Write() override; + + ObjectGuid CasterUnit; + uint32 SpellID = 0; + uint8 Reason = 0; + uint8 CastID = 0; + }; + + class SpellFailedOther final : public ServerPacket + { + public: + SpellFailedOther() : ServerPacket(SMSG_SPELL_FAILED_OTHER, 16+4+1+1) { } + + WorldPacket const* Write() override; + + ObjectGuid CasterUnit; + uint32 SpellID = 0; + uint16 Reason = 0; + uint8 CastID = 0; + }; + + class CastFailed final : public ServerPacket + { + public: + CastFailed(OpcodeServer opcode) : ServerPacket(opcode, 4+4+4+4+1) { } + + WorldPacket const* Write() override; + + int32 Reason = 0; + int32 FailedArg1 = -1; + int32 FailedArg2 = -1; + int32 SpellID = 0; + uint8 CastID = 0; + }; + + struct SpellModifierData + { + float ModifierValue = 0.0f; + uint8 ClassIndex = 0; + }; + + struct SpellModifier + { + uint8 ModIndex = 0; + std::vector<SpellModifierData> ModifierData; + }; + + class SetSpellModifier final : public ServerPacket + { + public: + SetSpellModifier(OpcodeServer opcode) : ServerPacket(opcode, 20) { } + + WorldPacket const* Write() override; + + std::vector<SpellModifier> Modifiers; + }; + + class SendRemovedSpell final : public ServerPacket + { + public: + SendRemovedSpell() : ServerPacket(SMSG_REMOVED_SPELL, 4) { } + + WorldPacket const* Write() override; + + std::vector<uint32> Spells; + }; } } +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellCastLogData const& spellCastLogData); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::TargetLocation const& targetLocation); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellTargetData const& spellTargetData); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellMissStatus const& spellMissStatus); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellPowerData const& spellPowerData); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::RuneData const& runeData); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::MissileTrajectoryResult const& missileTrajectory); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellAmmo const& spellAmmo); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::ProjectileVisualData const& projectileVisual); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::CreatureImmunities const& immunities); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellHealPrediction const& spellPred); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellCastData const& spellCastData); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellModifierData const& spellModifierData); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellModifier const& spellModifier); + #endif // SpellPackets_h__ diff --git a/src/server/game/Server/Packets/SystemPackets.cpp b/src/server/game/Server/Packets/SystemPackets.cpp index 7c8ecce3db7..4a7be4ed591 100644 --- a/src/server/game/Server/Packets/SystemPackets.cpp +++ b/src/server/game/Server/Packets/SystemPackets.cpp @@ -43,22 +43,22 @@ WorldPacket const* WorldPackets::System::FeatureSystemStatus::Write() if (EuropaTicketSystemStatus.HasValue) { - _worldPacket.WriteBit(EuropaTicketSystemStatus.value.UnkBit0); - _worldPacket.WriteBit(EuropaTicketSystemStatus.value.UnkBit1); - _worldPacket.WriteBit(EuropaTicketSystemStatus.value.TicketSystemEnabled); - _worldPacket.WriteBit(EuropaTicketSystemStatus.value.SubmitBugEnabled); - - _worldPacket << uint32(EuropaTicketSystemStatus.value.ThrottleState.MaxTries); - _worldPacket << uint32(EuropaTicketSystemStatus.value.ThrottleState.PerMilliseconds); - _worldPacket << uint32(EuropaTicketSystemStatus.value.ThrottleState.TryCount); - _worldPacket << uint32(EuropaTicketSystemStatus.value.ThrottleState.LastResetTimeBeforeNow); + _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.UnkBit0); + _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.UnkBit1); + _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.TicketSystemEnabled); + _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.SubmitBugEnabled); + + _worldPacket << uint32(EuropaTicketSystemStatus.Value.ThrottleState.MaxTries); + _worldPacket << uint32(EuropaTicketSystemStatus.Value.ThrottleState.PerMilliseconds); + _worldPacket << uint32(EuropaTicketSystemStatus.Value.ThrottleState.TryCount); + _worldPacket << uint32(EuropaTicketSystemStatus.Value.ThrottleState.LastResetTimeBeforeNow); } if (SessionAlert.HasValue) { - _worldPacket << int32(SessionAlert.value.Delay); - _worldPacket << int32(SessionAlert.value.Period); - _worldPacket << int32(SessionAlert.value.DisplayTime); + _worldPacket << int32(SessionAlert.Value.Delay); + _worldPacket << int32(SessionAlert.Value.Period); + _worldPacket << int32(SessionAlert.Value.DisplayTime); } _worldPacket.FlushBits(); diff --git a/src/server/game/Server/Packets/TalentPackets.cpp b/src/server/game/Server/Packets/TalentPackets.cpp index 4855f663662..d340b476cf9 100644 --- a/src/server/game/Server/Packets/TalentPackets.cpp +++ b/src/server/game/Server/Packets/TalentPackets.cpp @@ -41,3 +41,17 @@ void WorldPackets::Talent::SetSpecialization::Read() { _worldPacket >> SpecGroupIndex; } + + +void WorldPackets::Talent::LearnTalent::Read() +{ + uint32 count; + _worldPacket >> count; + + for (uint32 i = 0; i < count; ++i) + { + uint16 talent; + _worldPacket >> talent; + Talents.push_back(talent); + } +}
\ No newline at end of file diff --git a/src/server/game/Server/Packets/TalentPackets.h b/src/server/game/Server/Packets/TalentPackets.h index 21753e22c8d..2bc8b3934a8 100644 --- a/src/server/game/Server/Packets/TalentPackets.h +++ b/src/server/game/Server/Packets/TalentPackets.h @@ -57,6 +57,19 @@ namespace WorldPackets uint32 SpecGroupIndex = 0; }; + + class LearnTalent final : public ClientPacket + { + public: + LearnTalent(WorldPacket&& packet) : ClientPacket(std::move(packet)) + { + ASSERT(packet.GetOpcode() == CMSG_LEARN_TALENT); + } + + void Read() override; + std::vector<uint16> Talents; + + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 84efecae188..2129633b021 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -19,20 +19,25 @@ #include "Opcodes.h" #include "WorldSession.h" #include "Packets/CharacterPackets.h" +#include "Packets/ChannelPackets.h" +#include "Packets/ChatPackets.h" #include "Packets/ClientConfigPackets.h" #include "Packets/CombatPackets.h" +#include "Packets/EquipmentSetPackets.h" #include "Packets/GuildPackets.h" #include "Packets/MiscPackets.h" #include "Packets/MovementPackets.h" +#include "Packets/NPCPackets.h" #include "Packets/QueryPackets.h" +#include "Packets/QuestPackets.h" #include "Packets/TalentPackets.h" #include "Packets/TradePackets.h" template<class PacketClass, void(WorldSession::*HandlerFunction)(PacketClass&)> -class PacketHandler : public OpcodeHandler +class PacketHandler : public ClientOpcodeHandler { public: - PacketHandler(char const* _name, SessionStatus _status, PacketProcessing _processing) : OpcodeHandler(_name, _status, _processing) { } + PacketHandler(char const* name, SessionStatus status, PacketProcessing processing) : ClientOpcodeHandler(name, status, processing) { } void Call(WorldSession* session, WorldPacket& packet) const override { @@ -43,10 +48,10 @@ public: }; template<void(WorldSession::*HandlerFunction)(WorldPacket&)> -class PacketHandler<WorldPacket, HandlerFunction> : public OpcodeHandler +class PacketHandler<WorldPacket, HandlerFunction> : public ClientOpcodeHandler { public: - PacketHandler(char const* _name, SessionStatus _status, PacketProcessing _processing) : OpcodeHandler(_name, _status, _processing) { } + PacketHandler(char const* name, SessionStatus status, PacketProcessing processing) : ClientOpcodeHandler(name, status, processing) { } void Call(WorldSession* session, WorldPacket& packet) const override { @@ -57,9 +62,9 @@ public: OpcodeTable opcodeTable; template<class PacketClass, void(WorldSession::*HandlerFunction)(PacketClass&)> -void OpcodeTable::ValidateAndSetOpcode(OpcodeClient opcode, char const* name, SessionStatus status, PacketProcessing processing) +void OpcodeTable::ValidateAndSetClientOpcode(OpcodeClient opcode, char const* name, SessionStatus status, PacketProcessing processing) { - if (uint32(opcode) == 0xBADD) + if (uint32(opcode) == NULL_OPCODE) { TC_LOG_ERROR("network", "Opcode %s does not have a value", name); return; @@ -80,9 +85,9 @@ void OpcodeTable::ValidateAndSetOpcode(OpcodeClient opcode, char const* name, Se _internalTableClient[opcode] = new PacketHandler<PacketClass, HandlerFunction>(name, status, processing); } -void OpcodeTable::ValidateAndSetOpcode(OpcodeServer opcode, char const* name, SessionStatus status) +void OpcodeTable::ValidateAndSetServerOpcode(OpcodeServer opcode, char const* name, SessionStatus status, ConnectionType conIdx) { - if (uint32(opcode) == 0xBADD) + if (uint32(opcode) == NULL_OPCODE) { TC_LOG_ERROR("network", "Opcode %s does not have a value", name); return; @@ -94,23 +99,35 @@ void OpcodeTable::ValidateAndSetOpcode(OpcodeServer opcode, char const* name, Se return; } + if (conIdx >= MAX_CONNECTION_TYPES) + { + TC_LOG_ERROR("network", "Tried to set invalid connection type %u for opcode %s", conIdx, name); + return; + } + + if (IsInstanceOnlyOpcode(opcode) && conIdx != CONNECTION_TYPE_INSTANCE) + { + TC_LOG_ERROR("network", "Tried to set invalid connection type %u for instance only opcode %s", conIdx, name); + return; + } + if (_internalTableServer[opcode] != NULL) { TC_LOG_ERROR("network", "Tried to override server handler of %s with %s (opcode %u)", opcodeTable[opcode]->Name, name, opcode); return; } - _internalTableServer[opcode] = new PacketHandler<WorldPacket, &WorldSession::Handle_ServerSide>(name, status, PROCESS_INPLACE); + _internalTableServer[opcode] = new ServerOpcodeHandler(name, status, conIdx); } /// Correspondence between opcodes and their names void OpcodeTable::Initialize() { #define DEFINE_OPCODE_HANDLER_OLD(opcode, status, processing, handler) \ - ValidateAndSetOpcode<WorldPacket, handler>(opcode, #opcode, status, processing); + ValidateAndSetClientOpcode<WorldPacket, handler>(opcode, #opcode, status, processing); #define DEFINE_HANDLER(opcode, status, processing, packetclass, handler) \ - ValidateAndSetOpcode<packetclass, handler>(opcode, #opcode, status, processing); + ValidateAndSetClientOpcode<packetclass, handler>(opcode, #opcode, status, processing); DEFINE_OPCODE_HANDLER_OLD(CMSG_ACCEPT_LEVEL_GRANT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptGrantLevel ); DEFINE_OPCODE_HANDLER_OLD(CMSG_ACCEPT_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptTradeOpcode ); @@ -154,7 +171,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOSTORE_BANK_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBankItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOSTORE_LOOT_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutostoreLootItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTO_DECLINE_GUILD_INVITES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoDeclineGuildInvites ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_BANKER_ACTIVATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBankerActivateOpcode ); + DEFINE_HANDLER(CMSG_BANKER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleBankerActivateOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLEFIELD_LEAVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleBattlefieldLeaveOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLEFIELD_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlefieldListOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleBfEntryInviteResponse ); @@ -175,7 +192,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLE_PET_NAME_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLE_PET_SET_BATTLE_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BEGIN_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBeginTradeOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_BINDER_ACTIVATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBinderActivateOpcode ); + DEFINE_HANDLER(CMSG_BINDER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleBinderActivateOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_BUG, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBugOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BUSY_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBusyTradeOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BUYBACK_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBuybackItem ); @@ -197,7 +214,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_CALENDAR_GUILD_FILTER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGuildFilter ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CALENDAR_REMOVE_EVENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarRemoveEvent ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CALENDAR_UPDATE_EVENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarUpdateEvent ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_AURA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelAuraOpcode ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_AURA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelAuraOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_AUTO_REPEAT_SPELL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelAutoRepeatSpellOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_CAST, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleCancelCastOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_CHANNELLING, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelChanneling ); @@ -206,15 +223,15 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_QUEUED_SPELL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_TEMP_ENCHANTMENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTempEnchantmentOpcode); DEFINE_HANDLER(CMSG_CANCEL_TRADE, STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, WorldPackets::Trade::CancelTrade, &WorldSession::HandleCancelTradeOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CAST_SPELL, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleCastSpellOpcode ); + DEFINE_HANDLER(CMSG_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Spells::SpellCastRequest, &WorldSession::HandleCastSpellOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANGEPLAYER_DIFFICULTY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_ANNOUNCEMENTS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelAnnouncements ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_BAN, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelBan ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_DISPLAY_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelDisplayListQuery ); + DEFINE_HANDLER(CMSG_CHANNEL_DISPLAY_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Channel::ChannelListRequest, &WorldSession::HandleChannelList); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_INVITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelInvite ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_KICK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelKick ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelList ); + DEFINE_HANDLER(CMSG_CHANNEL_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Channel::ChannelListRequest, &WorldSession::HandleChannelList); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_MODERATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_MODERATOR, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelModerator ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANNEL_MUTE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelMute ); @@ -260,7 +277,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_CORPSE_MAP_POSITION_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCorpseMapPositionQuery ); DEFINE_HANDLER(CMSG_CREATURE_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Query::QueryCreature, &WorldSession::HandleCreatureQuery); DEFINE_OPCODE_HANDLER_OLD(CMSG_DANCE_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_DB_QUERY_BULK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_HANDLER(CMSG_DB_QUERY_BULK, STATUS_AUTHED, PROCESS_INPLACE, WorldPackets::Query::DBQueryBulk, &WorldSession::HandleDBQueryBulk); DEFINE_OPCODE_HANDLER_OLD(CMSG_DEL_FRIEND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleDelFriendOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_DEL_IGNORE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleDelIgnoreOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_DEL_MUTE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -275,7 +292,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_ENABLETAXI, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes ); DEFINE_OPCODE_HANDLER_OLD(CMSG_ENABLE_NAGLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess ); DEFINE_OPCODE_HANDLER_OLD(CMSG_EQUIPMENT_SET_DELETE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetDelete ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_EQUIPMENT_SET_SAVE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetSave ); + DEFINE_HANDLER(CMSG_EQUIPMENT_SET_SAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::EquipmentSet::SaveEquipmentSet, &WorldSession::HandleEquipmentSetSave); DEFINE_OPCODE_HANDLER_OLD(CMSG_EQUIPMENT_SET_USE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetUse ); DEFINE_OPCODE_HANDLER_OLD(CMSG_FACTION_BONUS_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_FAR_SIGHT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleFarSightOpcode ); @@ -294,7 +311,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_GMTICKET_SYSTEMSTATUS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketSystemStatusOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_GMTICKET_UPDATETEXT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketUpdateOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_REPORT_LAG, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReportLag ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GOSSIP_HELLO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGossipHelloOpcode ); + DEFINE_HANDLER(CMSG_GOSSIP_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleGossipHelloOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_GOSSIP_SELECT_OPTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGossipSelectOptionOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GRANT_LEVEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGrantLevel ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GROUP_ASSISTANT_LEADER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupAssistantLeaderOpcode); @@ -360,12 +377,12 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_ITEM_REFUND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleItemRefund ); DEFINE_OPCODE_HANDLER_OLD(CMSG_ITEM_REFUND_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleItemRefundInfoRequest ); DEFINE_OPCODE_HANDLER_OLD(CMSG_ITEM_TEXT_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleItemTextQuery ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_JOIN_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleJoinChannel ); + DEFINE_HANDLER(CMSG_JOIN_CHANNEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Channel::JoinChannel, &WorldSession::HandleJoinChannel); DEFINE_OPCODE_HANDLER_OLD(CMSG_KEEP_ALIVE, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); DEFINE_OPCODE_HANDLER_OLD(CMSG_LEARN_PREVIEW_TALENTS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalents ); DEFINE_OPCODE_HANDLER_OLD(CMSG_LEARN_PREVIEW_TALENTS_PET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalentsPet ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_LEARN_TALENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnTalentOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_LEAVE_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLeaveChannel ); + DEFINE_HANDLER(CMSG_LEARN_TALENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Talent::LearnTalent, &WorldSession::HandleLearnTalentOpcode); + DEFINE_HANDLER(CMSG_LEAVE_CHANNEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Channel::LeaveChannel, &WorldSession::HandleLeaveChannel); DEFINE_OPCODE_HANDLER_OLD(CMSG_LFG_GET_STATUS, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleLfgGetStatus ); DEFINE_OPCODE_HANDLER_OLD(CMSG_LFG_JOIN, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgJoinOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_LFG_LEAVE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgLeaveOpcode ); @@ -385,7 +402,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_LF_GUILD_POST_REQUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderPostRequest ); DEFINE_OPCODE_HANDLER_OLD(CMSG_LF_GUILD_REMOVE_RECRUIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderRemoveRecruit ); DEFINE_OPCODE_HANDLER_OLD(CMSG_LF_GUILD_SET_GUILD_POST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderSetGuildPost ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_LIST_INVENTORY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleListInventoryOpcode ); + DEFINE_HANDLER(CMSG_LIST_INVENTORY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleListInventoryOpcode); DEFINE_HANDLER(CMSG_LOAD_SCREEN, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::LoadingScreenNotify, &WorldSession::HandleLoadScreenOpcode); DEFINE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::LogoutCancel, &WorldSession::HandleLogoutCancelOpcode); DEFINE_HANDLER(CMSG_LOGOUT_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::LogoutRequest, &WorldSession::HandleLogoutRequestOpcode); @@ -403,25 +420,23 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_RETURN_TO_SENDER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailReturnToSender ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_TAKE_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailTakeItem ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_TAKE_MONEY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailTakeMoney ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_ADDON_BATTLEGROUND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_ADDON_GUILD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_ADDON_OFFICER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_ADDON_PARTY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_ADDON_RAID, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_ADDON_WHISPER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_AFK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_BATTLEGROUND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_DND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_EMOTE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_GUILD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_OFFICER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_PARTY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_RAID, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_RAID_WARNING, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_SAY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_WHISPER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_YELL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_HANDLER(CMSG_MESSAGECHAT_ADDON_GUILD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatAddonMessage, &WorldSession::HandleChatAddonMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_ADDON_OFFICER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatAddonMessage, &WorldSession::HandleChatAddonMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_ADDON_PARTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatAddonMessage, &WorldSession::HandleChatAddonMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_ADDON_RAID, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatAddonMessage, &WorldSession::HandleChatAddonMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_ADDON_WHISPER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatAddonMessageWhisper, &WorldSession::HandleChatAddonMessageWhisperOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_AFK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessageAFK, &WorldSession::HandleChatMessageAFKOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_CHANNEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessageChannel, &WorldSession::HandleChatMessageChannelOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_DND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessageDND, &WorldSession::HandleChatMessageDNDOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_EMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessageEmote, &WorldSession::HandleChatMessageEmoteOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_GUILD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_OFFICER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_PARTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_RAID, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_RAID_WARNING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_SAY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_YELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); + DEFINE_HANDLER(CMSG_MESSAGECHAT_WHISPER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessageWhisper, &WorldSession::HandleChatMessageWhisperOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_MINIGAME_MOVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MINIMAP_PING, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMinimapPingOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MOUNTSPECIAL_ANIM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMountSpecialAnimOpcode ); @@ -471,12 +486,13 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_MOVE_STOP_STRAFE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::ClientPlayerMovement, &WorldSession::HandleMovementOpcodes); DEFINE_HANDLER(CMSG_MOVE_STOP_SWIM, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::ClientPlayerMovement, &WorldSession::HandleMovementOpcodes); DEFINE_HANDLER(CMSG_MOVE_STOP_TURN, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::ClientPlayerMovement, &WorldSession::HandleMovementOpcodes); + DEFINE_HANDLER(CMSG_MOVE_TELEPORT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::MoveTeleportAck, &WorldSession::HandleMoveTeleportAck); DEFINE_OPCODE_HANDLER_OLD(CMSG_MOVE_TIME_SKIPPED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleMoveTimeSkippedOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MOVE_WATER_WALK_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveWaterWalkAck ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MOVE_WORLDPORT_ACK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMoveWorldportAckOpcode ); + DEFINE_HANDLER(CMSG_MOVE_WORLDPORT_ACK, STATUS_TRANSFER, PROCESS_THREADUNSAFE, WorldPackets::Movement::WorldPortAck, &WorldSession::HandleMoveWorldportAckOpcode); DEFINE_HANDLER(CMSG_NAME_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Query::QueryPlayerName, &WorldSession::HandleNameQueryOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_NEXT_CINEMATIC_CAMERA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleNextCinematicCamera ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_NPC_TEXT_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleNpcTextQueryOpcode ); + DEFINE_HANDLER(CMSG_NPC_TEXT_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Query::QueryNPCText, &WorldSession::HandleNpcTextQueryOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_OBJECT_UPDATE_FAILED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleObjectUpdateFailedOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_OBJECT_UPDATE_RESCUED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_OFFER_PETITION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleOfferPetitionOpcode ); @@ -494,7 +510,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_ABANDON, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetAbandon ); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_ACTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetAction ); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_CANCEL_AURA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCancelAuraOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_CAST_SPELL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCastSpellOpcode ); + DEFINE_HANDLER(CMSG_PET_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::SpellCastRequest, &WorldSession::HandlePetCastSpellOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_LEARN_TALENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetLearnTalent ); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_NAME_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetNameQuery ); DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_RENAME, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetRename ); @@ -523,8 +539,8 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_HELLO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverHelloOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_QUERY_QUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverQueryQuestOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_REQUEST_REWARD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverRequestRewardOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverStatusMultipleQuery); - DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_STATUS_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleQuestgiverStatusQueryOpcode); + DEFINE_HANDLER(CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverStatusMultipleQuery, &WorldSession::HandleQuestgiverStatusMultipleQuery); + DEFINE_HANDLER(CMSG_QUESTGIVER_STATUS_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Quest::QuestGiverStatusQuery, &WorldSession::HandleQuestgiverStatusQueryOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTLOG_REMOVE_QUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestLogRemoveQuest ); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_CONFIRM_ACCEPT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestConfirmAccept ); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_NPC_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestNPCQuery ); @@ -546,7 +562,6 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REQUEST_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::ClientConfig::RequestAccountData, &WorldSession::HandleRequestAccountData); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_CATEGORY_COOLDOWNS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleRequestCategoryCooldowns ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_CEMETERY_LIST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleRequestCemeteryList ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_HOTFIX, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleRequestHotfix ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_INSPECT_RATED_BG_STATS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPartyMemberStatsOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PET_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPetInfoOpcode ); @@ -573,7 +588,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_SEND_SOR_REQUEST_VIA_BNET_ACCOUNT_ID, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SETSHEATHED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleSetSheathedOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTIONBAR_TOGGLES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActionBarToggles ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTION_BUTTON, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActionButtonOpcode ); + DEFINE_HANDLER(CMSG_SET_ACTION_BUTTON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::SetActionButton, &WorldSession::HandleSetActionButtonOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTIVE_MOVER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveMoverOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTIVE_VOICE_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveVoiceChannel ); // STATUS_AUTHED DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ALLOW_LOW_LEVEL_RAID1, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -591,7 +606,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PREFERED_CEMETERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_RELATIVE_POSITION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_SAVED_INSTANCE_EXTEND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetSavedInstanceExtend ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_SELECTION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleSetSelectionOpcode ); + DEFINE_HANDLER(CMSG_SET_SELECTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetSelection, &WorldSession::HandleSetSelectionOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_SKILL_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_SET_SPECIALIZATION, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Talent::SetSpecialization, &WorldSession::HandleSetSpecializationOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_TAXI_BENCHMARK_MODE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTaxiBenchmarkOpcode ); @@ -621,26 +636,24 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_TAXINODE_STATUS_QUERY, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleTaxiNodeStatusQueryOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_TAXIQUERYAVAILABLENODES, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes ); DEFINE_OPCODE_HANDLER_OLD(CMSG_TELEPORT_TO_UNIT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TEXT_EMOTE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTextEmoteOpcode ); + DEFINE_HANDLER(CMSG_TEXT_EMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::CTextEmote, &WorldSession::HandleTextEmoteOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_TIME_ADJUSTMENT_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_TIME_SYNC_RESP, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Misc::TimeSyncResponse, &WorldSession::HandleTimeSyncResp); DEFINE_OPCODE_HANDLER_OLD(CMSG_TIME_SYNC_RESP_FAILED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_TOGGLE_PVP, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTogglePvP ); DEFINE_OPCODE_HANDLER_OLD(CMSG_TOTEM_DESTROYED, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTotemDestroyed ); DEFINE_OPCODE_HANDLER_OLD(CMSG_TRAINER_BUY_SPELL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerBuySpellOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TRAINER_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerListOpcode ); + DEFINE_HANDLER(CMSG_TRAINER_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleTrainerListOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_TRANSMOGRIFY_ITEMS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogrifyItems ); DEFINE_OPCODE_HANDLER_OLD(CMSG_TURN_IN_PETITION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTurnInPetitionOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TUTORIAL_CLEAR, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialClear ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TUTORIAL_FLAG, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialFlag ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TUTORIAL_RESET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialReset ); + DEFINE_HANDLER(CMSG_TUTORIAL_FLAG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::TutorialSetFlag, &WorldSession::HandleTutorialFlag); DEFINE_OPCODE_HANDLER_OLD(CMSG_UNACCEPT_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode ); DEFINE_HANDLER(CMSG_UNDELETE_CHARACTER, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::UndeleteCharacter, &WorldSession::HandleCharUndeleteOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_UNDELETE_COOLDOWN_STATUS_QUERY, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleUndeleteCooldownStatusQuery); DEFINE_OPCODE_HANDLER_OLD(CMSG_UNLEARN_SKILL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnlearnSkillOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_UNLEARN_SPECIALIZATION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_UNREGISTER_ALL_ADDON_PREFIXES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnregisterAddonPrefixesOpcode); - DEFINE_HANDLER(CMSG_UPDATE_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::ClientConfig::UserClientUpdateAccountData, &WorldSession::HandleUpdateAccountData ); + DEFINE_HANDLER(CMSG_UPDATE_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::ClientConfig::UserClientUpdateAccountData, &WorldSession::HandleUpdateAccountData); DEFINE_OPCODE_HANDLER_OLD(CMSG_UPDATE_MISSILE_TRAJECTORY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateMissileTrajectory ); DEFINE_OPCODE_HANDLER_OLD(CMSG_UPDATE_PROJECTILE_POSITION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateProjectilePosition ); DEFINE_OPCODE_HANDLER_OLD(CMSG_USED_FOLLOW, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -664,8 +677,6 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(MSG_INSPECT_ARENA_TEAMS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectArenaTeamsOpcode ); DEFINE_OPCODE_HANDLER_OLD(MSG_LIST_STABLED_PETS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); DEFINE_OPCODE_HANDLER_OLD(MSG_MOVE_CHARM_TELEPORT_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_OPCODE_HANDLER_OLD(MSG_MOVE_TELEPORT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - DEFINE_OPCODE_HANDLER_OLD(MSG_MOVE_TELEPORT_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveTeleportAck ); DEFINE_OPCODE_HANDLER_OLD(MSG_MOVE_TELEPORT_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(MSG_MOVE_TIME_SKIPPED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(MSG_MOVE_TOGGLE_COLLISION_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -689,733 +700,750 @@ void OpcodeTable::Initialize() #undef DEFINE_OPCODE_HANDLER_OLD #undef DEFINE_HANDLER -#define DEFINE_SERVER_OPCODE_HANDLER(opcode, status) \ - ValidateAndSetOpcode(opcode, #opcode, status) +#define DEFINE_SERVER_OPCODE_HANDLER(opcode, status, con) \ + ValidateAndSetServerOpcode(opcode, #opcode, status, con) - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_DATA_TIMES, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_INFO_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_MOUNT_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_RESTRICTED_WARNING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTION_BUTTONS, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVATETAXIREPLY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADDON_INFO, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_RUNE_POWER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AI_REACTION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_SPIRIT_HEALER_TIME, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MESSAGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MOVEMENT_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_ERROR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_UNIT_DESTROYED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_COMMAND_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_EVENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_INVITE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_ROSTER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_STATS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKERSTATEUPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSTART, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSTOP, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_BADFACING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_CANT_ATTACK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_DEADTARGET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_NOTINRANGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_LIST_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_NOTIFICATION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_COMMAND_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_HELLO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_LIST_PENDING_SALES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_LIST_ITEMS_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_OWNER_LIST_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_OWNER_NOTIFICATION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_REMOVED_NOTIFICATION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AURA_POINTS_DEPLETED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AURA_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AURA_UPDATE_ALL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUTH_CHALLENGE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUTH_RESPONSE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AVAILABLE_VOICE_CHANNEL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AVERAGE_ITEM_LEVEL_INFORM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BARBER_SHOP_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EJECTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EJECT_PENDING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_ENTERED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_ENTRY_INVITE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EXIT_REQUEST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_QUEUE_INVITE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_STATE_CHANGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_PLAYER_POSITIONS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_PORT_DENIED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_RATED_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_QUEUED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_ACTIVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_NEEDCONFIRMATION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_WAITFORGROUPS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_INFO_THROTTLED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_JOINED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_LEFT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_DISTRIBUTION_LIST_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_PRODUCT_LIST_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_PURCHASE_LIST_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL_LOCK_ACQUIRED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_NAME_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDER_CONFIRM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDPOINTUPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDZONEREPLY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BREAK_TARGET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BUY_BANK_SLOT_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BUY_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BUY_ITEM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_ARENA_TEAM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_CLEAR_PENDING_ACTION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_COMMAND_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_ALERT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_NOTES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_REMOVED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_REMOVED_ALERT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_UPDATED_ALERT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_FILTER_GUILD, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_ADDED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_REMOVED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_UPDATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_SEND_CALENDAR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_SEND_EVENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_SEND_NUM_PENDING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAMERA_SHAKE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_AUTO_REPEAT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_COMBAT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAST_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_MEMBER_COUNT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY_JOINED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY_LEFT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_START, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_LOGIN_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CREATE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_DELETE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_ENUM, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_FACTION_CHANGE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_RENAME, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_IGNORED_ACCOUNT_MUTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_NOT_IN_PARTY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_AMBIGUOUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_NOT_FOUND, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RESTRICTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_SERVER_DISCONNECTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_SERVER_RECONNECTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_WRONG_FACTION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_BOSS_EMOTES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_COOLDOWN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_COOLDOWNS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_TARGET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLIENTCACHE_VERSION, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLIENT_CONTROL_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COIN_REMOVED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMBAT_EVENT_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_MAP_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_PARTY_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_PLAYER_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_STATE_CHANGED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPLAIN_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPRESSED_MOVES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPRESSED_PACKET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMSAT_CONNECT_FAIL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMSAT_DISCONNECT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMSAT_RECONNECT_TRY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONTACT_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONTACT_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONVERT_RUNE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COOLDOWN_CHEAT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_COOLDOWN_EVENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_NOT_IN_INSTANCE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_RECLAIM_DELAY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CREATURE_QUERY_RESPONSE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_DELETED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CROSSED_INEBRIATION_THRESHOLD, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_REMOVED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_RESTORED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CUSTOM_LOAD_SCREEN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DAMAGE_CALC_LOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DANCE_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DANCE_STUDIO_CREATE_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DB_REPLY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DEATH_RELEASE_LOC, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DEBUG_RUNE_REGEN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DEFENSE_MESSAGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DESTROY_OBJECT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DIFFERENT_INSTANCE_FROM_PARTY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISENCHANT_CREDIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISMOUNT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISMOUNTRESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPEL_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_GAME_ERROR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_PROMOTION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DONT_AUTO_PUSH_SPELLS_TO_ACTION_BAR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DROP_NEW_CONNECTION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_COMPLETE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_COUNTDOWN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_INBOUNDS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_OUTOFBOUNDS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_REQUESTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_WINNER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUMP_RIDE_TICKETS_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DURABILITY_DAMAGE_DEATH, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ECHO_PARTY_SQUELCH, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_EMOTE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENABLE_BARBER_SHOP, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENCHANTMENTLOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENVIRONMENTALDAMAGELOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_SAVED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_USE_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPECTED_SPAM_RECORDS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPLORATION_EXPERIENCE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FAILED_PLAYER_CONDITION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS_GLUE_SCREEN, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEIGN_DEATH_RESISTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_ESCAPED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_NOT_HOOKED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FLIGHT_SPLINE_SYNC, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FLOOD_DETECTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCEACTIONSHOW, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCED_DEATH_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_ANIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_SET_VEHICLE_REC_ID, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORGE_MASTER_SET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FRIEND_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_CUSTOM_ANIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_DESPAWN_ANIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_PAGETEXT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_RESET_STATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMESPEED_SET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMETIME_SET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMETIME_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_EVENT_DEBUG_LOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_ACTIVATE_ANIM_KIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_COMPLETE_MISSION_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMRESPONSE_DB_ERROR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMRESPONSE_RECEIVED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMRESPONSE_STATUS_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_CREATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_DELETETICKET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_GETTICKET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_SYSTEMSTATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_UPDATETEXT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_MESSAGECHAT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_STATUS_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GODMODE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_COMPLETE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_MESSAGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_POI, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUPACTION_THROTTLED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_CANCEL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DECLINE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DESTROYED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_INVITE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_SET_LEADER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_SET_ROLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_UNINVITE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_DATA, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_DELETED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_EARNED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_MEMBERS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_BANK_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_BANK_LOG_QUERY_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_BANK_MONEY_WITHDRAWN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_BANK_QUERY_TEXT_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_COMPLETED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_UPDATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CHANGE_NAME_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_COMMAND_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_COMMAND_RESULT_2, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CRITERIA_DATA, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CRITERIA_DELETED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_DECLINE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_EVENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_EVENT_LOG_QUERY_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_EVENT_PRESENCE_CHANGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_FLAGGED_FOR_RENAME, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_INVITE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_INVITE_CANCEL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MAX_DAILY_XP, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MEMBERS_FOR_RECIPE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MEMBER_DAILY_RESET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MEMBER_RECIPES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MEMBER_UPDATE_NOTE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MOVE_COMPLETE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MOVE_STARTING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_NEWS_DELETED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_NEWS_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_PARTY_STATE_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_PERMISSIONS_QUERY_RESULTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_QUERY_RESPONSE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RANK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RANKS_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RECIPES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RENAMED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_REPUTATION_REACTION_CHANGED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_REPUTATION_WEEKLY_CAP, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RESET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_REWARDS_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ROSTER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_UPDATE_ROSTER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_XP, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_XP_GAIN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_HEALTH_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_HIGHEST_THREAT_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_NOTIFY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIALIZE_FACTIONS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIAL_SETUP, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIAL_SPELLS, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INIT_CURRENCY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INIT_WORLD_STATES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSPECT_HONOR_STATS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSPECT_RATED_BG_STATS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSPECT_RESULTS_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSPECT_TALENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_LOCK_WARNING_QUERY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_SAVE_CREATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVALIDATE_DANCE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVALIDATE_PLAYER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVALID_PROMOTION_CODE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVENTORY_CHANGE_FAILURE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_ADD_PASSIVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_COOLDOWN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_ENCHANT_TIME_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_EXPIRE_PURCHASE_REFUND, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_REFUND_INFO_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_REFUND_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_REMOVE_PASSIVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_SEND_PASSIVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TEXT_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_KICK_REASON, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARNED_DANCE_MOVES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARNED_SPELL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEVELUP_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_BOOT_PROPOSAL_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_DISABLED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_JOIN_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_OFFER_CONTINUE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_PARTY_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_PLAYER_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_PLAYER_REWARD, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_PROPOSAL_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_QUEUE_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_ROLE_CHECK_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_ROLE_CHOSEN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_SLOT_INVALID, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_TELEPORT_DENIED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_UPDATE_SEARCH, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_UPDATE_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_APPLICANT_LIST_UPDATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_APPLICATIONS_LIST_CHANGED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_BROWSE_UPDATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_COMMAND_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_MEMBERSHIP_LIST_UPDATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_POST_UPDATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_RECRUIT_LIST_UPDATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIST_INVENTORY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_CUF_PROFILES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGIN_SETTIMESPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGIN_VERIFY_WORLD, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_CANCEL_ACK, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_COMPLETE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_RESPONSE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOG_XPGAIN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ALL_PASSED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_CLEAR_MONEY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_CONTENTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ITEM_NOTIFY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MASTER_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MONEY_NOTIFY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_REMOVED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL_WON, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_SLOT_CHANGED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_START_ROLL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_LIST_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAP_OBJ_EVENTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MEETINGSTONE_IN_PROGRESS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MESSAGECHAT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MESSAGE_BOX, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIGAME_SETUP, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIGAME_STATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIMAP_PING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MIRRORIMAGE_DATA, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MISSILE_CANCEL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MODIFY_COOLDOWN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MONEY_NOTIFY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MONSTER_MOVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MONSTER_MOVE_TRANSPORT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOTD, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOUNTRESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOUNTSPECIAL_ANIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_COLLISION_DISABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_COLLISION_ENABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_FEATHER_FALL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_FORCE_RUN_SPEED_CHANGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_FORCE_SWIM_SPEED_CHANGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_DISABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_ENABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_KNOCK_BACK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_LAND_WALK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_NORMAL_FALL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_ROOT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_ACTIVE_MOVER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_FLY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_COLLISION_HEIGHT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_COMPOUND_STATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_FLIGHT_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_FLIGHT_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_HOVER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_PITCH_RATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_RUN_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_RUN_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_SWIM_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_SWIM_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_TURN_RATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_WALK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNROOT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNSET_CAN_FLY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNSET_HOVER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_COLLISION_HEIGHT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_FLIGHT_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_KNOCK_BACK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_PITCH_RATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_RUN_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_RUN_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_SWIM_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_SWIM_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_TELEPORT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_TURN_RATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_WALK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_WATER_WALK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MULTIPLE_PACKETS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NAME_QUERY_RESPONSE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_TAXI_PATH, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_WORLD, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_WORLD_ABORT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFICATION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_DANCE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_DEST_LOC_SPELL_CAST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NPC_TEXT_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_OFFER_PETITION_ERROR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_CONTAINER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_LFG_DUNGEON_FINDER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_OVERRIDE_LIGHT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAGE_TEXT_QUERY_RESPONSE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTYKILLLOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_COMMAND_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATS_FULL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAUSE_MIRROR_TIMER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PERIODICAURALOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETGODMODE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_ALREADY_SIGNED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_SHOWLIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_SHOW_SIGNATURES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_SIGN_RESULTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_ACTION_FEEDBACK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_ACTION_SOUND, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_ADDED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_BROKEN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_CAST_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_DISMISS_SOUND, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_GUIDS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_LEARNED_SPELL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_MODE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_NAME_INVALID, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_NAME_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_REMOVED_SPELL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_RENAMEABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_SLOT_UPDATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_SPELLS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_TAME_FAILURE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_UPDATE_COMBO_POINTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYED_TIME, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYERBINDERROR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYERBOUND, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_DIFFICULTY_CHANGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_MOVE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_SKINNED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_VEHICLE_DATA, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_DANCE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_MUSIC, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_OBJECT_SOUND, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_ONE_SHOT_ANIM_KIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SOUND, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SPELL_VISUAL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SPELL_VISUAL_KIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_TIME_WARNING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PONG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_POWER_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PRE_RESURRECT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PROCRESIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PROPOSE_LEVEL_GRANT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_CREDIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_LOG_DATA, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_OPTIONS_ENABLED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_SEASON, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_TIME_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_OFFER_REWARD, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_COMPLETE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_DETAILS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_INVALID, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_REQUEST_ITEMS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_STATUS_MULTIPLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTLOG_FULL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_KILL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_PVP_KILL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_COMPLETE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_FAILEDTIMER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_CONFIRM_ACCEPT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_FORCE_REMOVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_NPC_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_POI_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_GROUP_ONLY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_INSTANCE_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_INSTANCE_MESSAGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_MARKERS_CHANGED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_READY_CHECK_THROTTLED_ERROR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_SUMMON_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RANDOMIZE_CHAR_NAME, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RATED_BG_RATING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RATED_BG_STATS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_READ_ITEM_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_READ_ITEM_OK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REALM_QUERY_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REALM_SPLIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REAL_GROUP_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RECEIVED_MAIL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REDIRECT_CLIENT, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_EXPIRED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_FAILURE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFORGE_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REMOVED_SPELL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REPORT_PVP_AFK_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REQUEST_CEMETERY_LIST_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REQUEST_PVP_REWARDS_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESEARCH_COMPLETE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESEARCH_SETUP_HISTORY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_COMPRESSION_CONTEXT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_FAILED_NOTIFY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_COMMS, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_REQUEST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESYNC_RUNES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_POLL_BEGIN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RWHOIS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SELL_ITEM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_MAIL_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_UNLEARN_SPELLS, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVERTIME, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVER_FIRST_ACHIEVEMENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVER_INFO_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVER_MESSAGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVER_PERF, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_AI_ANIM_KIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_DF_FAST_LAUNCH_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FACTION_ATWAR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FACTION_NOT_VISIBLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FACTION_STANDING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FACTION_VISIBLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FLAT_SPELL_MODIFIER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FORCED_REACTIONS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MELEE_ANIM_KIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MOVEMENT_ANIM_KIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PCT_SPELL_MODIFIER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROJECTILE_POSITION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_TIME_ZONE_INFORMATION, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOWTAXINODES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_BANK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_MAILBOX, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_RATINGS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SOCKET_GEMS_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SOR_START_EXPERIENCE_INCOMPLETE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLBREAKLOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLDAMAGESHIELD, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLDISPELLOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLENERGIZELOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLHEALLOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLINSTAKILLLOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLINTERRUPTLOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLLOGEXECUTE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLLOGMISS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLNONMELEEDAMAGELOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLORDAMAGE_IMMUNE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLSTEALLOG, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_CATEGORY_COOLDOWN, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_COOLDOWN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_DELAYED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_FAILED_OTHER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_FAILURE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_GO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_START, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_UPDATE_CHAIN_TARGETS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPIRIT_HEALER_CONFIRM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_COLLISION_DISABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_COLLISION_ENABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_DISABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_ENABLE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_ROOT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_ANIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FEATHER_FALL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLIGHT_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLIGHT_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLYING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_HOVER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_LAND_WALK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_NORMAL_FALL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_PITCH_RATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_MODE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_SWIM_BACK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_SWIM_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_TURN_RATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WALK_MODE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WALK_SPEED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WATER_WALK, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_START_SWIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_STOP_SWIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNROOT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNSET_FLYING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNSET_HOVER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_STABLE_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_STANDSTATE_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_MIRROR_TIMER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_TIMER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_STOP_DANCE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_STOP_MIRROR_TIMER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_STREAMING_MOVIE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUMMON_CANCEL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUMMON_REQUEST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPPRESS_NPC_GREETINGS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_ERROR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INFO, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TAXINODE_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TEST_DROP_RATE_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TEXT_EMOTE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_THREAT_CLEAR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_THREAT_REMOVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_THREAT_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TIME_ADJUSTMENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TIME_SYNC_REQ, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TITLE_EARNED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TOGGLE_XP_GAIN, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TOTEM_CREATED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_STATUS_EXTENDED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_BUY_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_BUY_SUCCEEDED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_LIST, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_ABORTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_PENDING, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRIGGER_CINEMATIC, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRIGGER_MOVIE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TURN_IN_PETITION_RESULTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TUTORIAL_FLAGS, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNDELETE_CHARACTER_RESPONSE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNDELETE_COOLDOWN_STATUS_RESPONSE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNIT_HEALTH_FREQUENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNIT_SPELLCAST_START, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_ACCOUNT_DATA, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_COMBO_POINTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CURRENCY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CURRENCY_WEEK_LIMIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_DUNGEON_ENCOUNTER_FOR_LOOT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_OWNERSHIP, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_LAST_INSTANCE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_OBJECT, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_SERVER_PLAYER_POSITION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_WORLD_STATE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_ADD, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_REMOVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICESESSION_FULL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_CHAT_STATUS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_PARENTAL_CONTROLS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_SESSION_LEAVE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_SESSION_ROSTER_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_SET_TALKER_MUTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_ITEM_SWAP_RESPONSE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_STORAGE_CONTENTS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_STORAGE_FAILED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_STORAGE_TRANSFER_CHANGES, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_TRANSFER_RESULT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WAIT_QUEUE_FINISH, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WAIT_QUEUE_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARDEN_DATA, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARGAME_CHECK_ENTRY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARGAME_REQUEST_SENT, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEATHER, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_LAST_RESET, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_RESET_CURRENCY, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_SPELL_USAGE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_SPELL_USAGE_UPDATE, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WHO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WHOIS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WORLD_SERVER_INFO, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_WORLD_STATE_UI_TIMER_UPDATE, STATUS_NEVER); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_XP_GAIN_ABORTED, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ZONE_UNDER_ATTACK, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_DATA_TIMES, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_INFO_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_MOUNT_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_RESTRICTED_WARNING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_TOYS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTION_BUTTONS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVATETAXIREPLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADDON_INFO, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_RUNE_POWER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADJUST_SPLINE_DURATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AI_REACTION, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_SPIRIT_HEALER_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MOVEMENT_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_UNIT_DESTROYED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_EVENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_INVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_ROSTER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_STATS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKERSTATEUPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSTART, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSTOP, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_BADFACING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_CANT_ATTACK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_DEADTARGET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_NOTINRANGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_NOTIFICATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_HELLO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_LIST_PENDING_SALES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_LIST_ITEMS_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_OWNER_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_OWNER_NOTIFICATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_REMOVED_NOTIFICATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AURA_POINTS_DEPLETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AURA_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUTH_CHALLENGE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUTH_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AVAILABLE_VOICE_CHANNEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AVERAGE_ITEM_LEVEL_INFORM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BARBER_SHOP_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EJECTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EJECT_PENDING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_ENTERED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_ENTRY_INVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EXIT_REQUEST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_QUEUE_INVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_STATE_CHANGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_PLAYER_POSITIONS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_PORT_DENIED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_RATED_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_QUEUED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_ACTIVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_NEEDCONFIRMATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_WAITFORGROUPS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_INFO_THROTTLED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_JOINED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_LEFT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_DISTRIBUTION_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_DISTRIBUTION_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_PRODUCT_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_PURCHASE_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL_LOCK_ACQUIRED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_NAME_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDER_CONFIRM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDPOINTUPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDZONEREPLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BREAK_TARGET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BUY_BANK_SLOT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BUY_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BUY_ITEM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_ARENA_TEAM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_CLEAR_PENDING_ACTION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_ALERT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_NOTES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_REMOVED_ALERT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_UPDATED_ALERT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_FILTER_GUILD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_ADDED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_SEND_CALENDAR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_SEND_EVENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_SEND_NUM_PENDING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAMERA_SHAKE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_AUTO_REPEAT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_COMBAT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAST_FAILED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_LIST, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_MEMBER_COUNT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY_JOINED, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY_LEFT, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_LOGIN_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CREATE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_DELETE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_ENUM, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_FACTION_CHANGE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_RENAME, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_IGNORED_ACCOUNT_MUTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_NOT_IN_PARTY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_AMBIGUOUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_NOT_FOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RESTRICTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_SERVER_DISCONNECTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_SERVER_RECONNECTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_WRONG_FACTION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_BOSS_EMOTES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_COOLDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_COOLDOWNS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_TARGET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLIENTCACHE_VERSION, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLIENT_CONTROL_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COIN_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMBAT_EVENT_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_MAP_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_PARTY_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_STATE_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPLAIN_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPRESSED_MOVES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMPRESSED_PACKET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMSAT_CONNECT_FAIL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMSAT_DISCONNECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMSAT_RECONNECT_TRY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONTACT_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONTACT_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CONVERT_RUNE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COOLDOWN_CHEAT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_COOLDOWN_EVENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_NOT_IN_INSTANCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_RECLAIM_DELAY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CREATURE_QUERY_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CROSSED_INEBRIATION_THRESHOLD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_RESTORED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CUSTOM_LOAD_SCREEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DAMAGE_CALC_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DANCE_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DANCE_STUDIO_CREATE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DB_REPLY, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DEATH_RELEASE_LOC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DEBUG_RUNE_REGEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DEFENSE_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DESTROY_OBJECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DIFFERENT_INSTANCE_FROM_PARTY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISENCHANT_CREDIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISMOUNT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISMOUNTRESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPEL_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_GAME_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_PROMOTION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DONT_AUTO_PUSH_SPELLS_TO_ACTION_BAR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DROP_NEW_CONNECTION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_COUNTDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_INBOUNDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_OUTOFBOUNDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_REQUESTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUEL_WINNER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DUMP_RIDE_TICKETS_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DURABILITY_DAMAGE_DEATH, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ECHO_PARTY_SQUELCH, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_EMOTE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENABLE_BARBER_SHOP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENCHANTMENTLOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENVIRONMENTALDAMAGELOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_LIST, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_SAVED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_USE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPECTED_SPAM_RECORDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPLORATION_EXPERIENCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FAILED_PLAYER_CONDITION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS_GLUE_SCREEN, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FEIGN_DEATH_RESISTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_ESCAPED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FISH_NOT_HOOKED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FLIGHT_SPLINE_SYNC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FLOOD_DETECTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCEACTIONSHOW, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCED_DEATH_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_SET_VEHICLE_REC_ID, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORGE_MASTER_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_FRIEND_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_ACTIVATE_ANIM_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_CUSTOM_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_DESPAWN_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_DESPAWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_PAGETEXT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_RESET_STATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMESPEED_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMETIME_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMETIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_EVENT_DEBUG_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_COMPLETE_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOTE_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMRESPONSE_DB_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMRESPONSE_RECEIVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMRESPONSE_STATUS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_CREATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_DELETETICKET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_GETTICKET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_SYSTEMSTATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GMTICKET_UPDATETEXT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_MESSAGECHAT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_STATUS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GODMODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_POI, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUPACTION_THROTTLED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_CANCEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DECLINE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DESTROYED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_INVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_SET_LEADER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_SET_ROLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_UNINVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_EARNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_MEMBERS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_BANK_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_BANK_LOG_QUERY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_BANK_MONEY_WITHDRAWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_BANK_QUERY_TEXT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_COMPLETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CHANGE_NAME_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_COMMAND_RESULT_2, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CRITERIA_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CRITERIA_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_CRITERIA_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_DECLINE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_EVENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_EVENT_BANK_MONEY_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_EVENT_LOG_QUERY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_EVENT_PRESENCE_CHANGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_FLAGGED_FOR_RENAME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_INVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_INVITE_CANCEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MAX_DAILY_XP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MEMBERS_FOR_RECIPE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MEMBER_DAILY_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MEMBER_RECIPES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MEMBER_UPDATE_NOTE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MOVE_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_MOVE_STARTING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_NEWS_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_NEWS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_PARTY_STATE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_PERMISSIONS_QUERY_RESULTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_QUERY_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RANK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RANKS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RECIPES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RENAMED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_REPUTATION_REACTION_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_REPUTATION_WEEKLY_CAP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_REWARDS_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ROSTER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_UPDATE_ROSTER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_XP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_XP_GAIN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_HEALTH_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_HIGHEST_THREAT_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIALIZE_FACTIONS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIAL_SETUP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIAL_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INIT_CURRENCY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INIT_WORLD_STATES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSPECT_HONOR_STATS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSPECT_RATED_BG_STATS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSPECT_RESULTS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSPECT_TALENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_LOCK_WARNING_QUERY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_SAVE_CREATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVALIDATE_DANCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVALIDATE_PLAYER, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVALID_PROMOTION_CODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVENTORY_CHANGE_FAILURE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_ADD_PASSIVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_COOLDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_ENCHANT_TIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_EXPIRE_PURCHASE_REFUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_REFUND_INFO_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_REFUND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_REMOVE_PASSIVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_SEND_PASSIVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TEXT_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_KICK_REASON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARNED_DANCE_MOVES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARNED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEVELUP_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_BOOT_PROPOSAL_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_DISABLED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_JOIN_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_OFFER_CONTINUE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_PARTY_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_PLAYER_REWARD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_PROPOSAL_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_QUEUE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_ROLE_CHECK_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_ROLE_CHOSEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_SLOT_INVALID, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_TELEPORT_DENIED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_UPDATE_SEARCH, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LFG_UPDATE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_APPLICANT_LIST_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_APPLICATIONS_LIST_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_BROWSE_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_MEMBERSHIP_LIST_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_POST_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LF_GUILD_RECRUIT_LIST_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIST_INVENTORY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_CUF_PROFILES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGIN_SETTIMESPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGIN_VERIFY_WORLD, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_CANCEL_ACK, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_COMPLETE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOG_XPGAIN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ALL_PASSED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_CLEAR_MONEY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_CONTENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ITEM_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MASTER_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MONEY_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL_WON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_SLOT_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_START_ROLL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_QUERY_NEXT_TIME_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAP_OBJ_EVENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MEETINGSTONE_IN_PROGRESS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MESSAGECHAT, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MESSAGE_BOX, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIGAME_SETUP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIGAME_STATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIMAP_PING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MIRRORIMAGE_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MISSILE_CANCEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MODIFY_COOLDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MONEY_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MONSTER_MOVE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MONSTER_MOVE_TRANSPORT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOTD, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOUNTRESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOUNTSPECIAL_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_COLLISION_DISABLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_COLLISION_ENABLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_FEATHER_FALL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_DISABLE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_ENABLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_KNOCK_BACK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_LAND_WALK, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_NORMAL_FALL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_ROOT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_ACTIVE_MOVER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_FLY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_COLLISION_HEIGHT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_COMPOUND_STATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_FLIGHT_BACK_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_FLIGHT_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_HOVER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_PITCH_RATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_RUN_BACK_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_RUN_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_SWIM_BACK_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_SWIM_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_TURN_RATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_WALK_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_TELEPORT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNROOT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNSET_CAN_FLY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNSET_HOVER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_COLLISION_HEIGHT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_FLIGHT_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_KNOCK_BACK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_PITCH_RATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_RUN_BACK_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_RUN_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_SWIM_BACK_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_SWIM_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_TELEPORT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_TURN_RATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_WALK_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_WATER_WALK, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MULTIPLE_PACKETS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NAME_QUERY_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_TAXI_PATH, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_WORLD, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_WORLD_ABORT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFICATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_DANCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_DEST_LOC_SPELL_CAST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NPC_TEXT_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_OFFER_PETITION_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_CONTAINER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_LFG_DUNGEON_FINDER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_OVERRIDE_LIGHT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAGE_TEXT_QUERY_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTYKILLLOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATS_FULL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAUSE_MIRROR_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PERIODICAURALOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETGODMODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_ALREADY_SIGNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_SHOWLIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_SHOW_SIGNATURES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_SIGN_RESULTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_ACTION_FEEDBACK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_ACTION_SOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_ADDED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_BROKEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_CAST_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_DISMISS_SOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_GUIDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_LEARNED_SPELL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_NAME_INVALID, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_NAME_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_REMOVED_SPELL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_RENAMEABLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_SLOT_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_SPELLS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_TAME_FAILURE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_UPDATE_COMBO_POINTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYED_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYERBINDERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYERBOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_DIFFICULTY_CHANGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_MOVE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_SKINNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_VEHICLE_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_DANCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_MUSIC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_OBJECT_SOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_ONE_SHOT_ANIM_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SPELL_VISUAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_SPELL_VISUAL_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAY_TIME_WARNING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PONG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_POWER_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PRE_RESURRECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PROCRESIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PROPOSE_LEVEL_GRANT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_CREDIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_LOG_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_OPTIONS_ENABLED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_SEASON, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_TIME_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_OFFER_REWARD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_DETAILS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_INVALID, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_REQUEST_ITEMS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_STATUS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_STATUS_MULTIPLE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTLOG_FULL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_KILL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_PVP_KILL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_FAILEDTIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_CONFIRM_ACCEPT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_FORCE_REMOVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_NPC_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_POI_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_GROUP_ONLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_INSTANCE_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_INSTANCE_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_MARKERS_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_READY_CHECK_THROTTLED_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_SUMMON_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RANDOMIZE_CHAR_NAME, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RATED_BG_RATING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RATED_BG_STATS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_READ_ITEM_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_READ_ITEM_OK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REALM_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REALM_SPLIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REAL_GROUP_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RECEIVED_MAIL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REDIRECT_CLIENT, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_EXPIRED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_FAILURE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFORGE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFRESH_SPELL_HISTORY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REMOVED_SPELL, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REPORT_PVP_AFK_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REQUEST_CEMETERY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REQUEST_PVP_REWARDS_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESEARCH_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESEARCH_SETUP_HISTORY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_COMPRESSION_CONTEXT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_FAILED_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_COMMS, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_REQUEST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESYNC_RUNES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_POLL_BEGIN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RWHOIS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SELL_ITEM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_MAIL_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_SPELL_CHARGES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_SPELL_HISTORY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_UNLEARN_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVERTIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVER_FIRST_ACHIEVEMENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVER_INFO_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVER_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SERVER_PERF, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_AI_ANIM_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_ALL_TASK_PROGRESS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_CURRENCY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_DF_FAST_LAUNCH_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FACTION_ATWAR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FACTION_NOT_VISIBLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FACTION_STANDING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FACTION_VISIBLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FLAT_SPELL_MODIFIER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_FORCED_REACTIONS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MAX_WEEKLY_QUANTITY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MELEE_ANIM_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MOVEMENT_ANIM_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PCT_SPELL_MODIFIER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROJECTILE_POSITION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_TIME_ZONE_INFORMATION, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOWTAXINODES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_BANK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_MAILBOX, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_RATINGS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SOCKET_GEMS_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SOR_START_EXPERIENCE_INCOMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLBREAKLOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLDAMAGESHIELD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLDISPELLOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLENERGIZELOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLHEALLOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLINSTAKILLLOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLINTERRUPTLOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLLOGEXECUTE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLLOGMISS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLNONMELEEDAMAGELOG, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLORDAMAGE_IMMUNE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLSTEALLOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_CATEGORY_COOLDOWN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_COOLDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_DELAYED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_FAILED_OTHER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_FAILURE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_GO, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_START, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_UPDATE_CHAIN_TARGETS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPIRIT_HEALER_CONFIRM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_COLLISION_DISABLE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_COLLISION_ENABLE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_DISABLE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_ENABLE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_ROOT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FEATHER_FALL, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLIGHT_BACK_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLIGHT_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLYING, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_HOVER, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_LAND_WALK, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_NORMAL_FALL, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_PITCH_RATE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_SWIM_BACK_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_SWIM_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_TURN_RATE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WALK_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WALK_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WATER_WALK, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_START_SWIM, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_STOP_SWIM, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNROOT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNSET_FLYING, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNSET_HOVER, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_STABLE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_STANDSTATE_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_ELAPSED_TIMERS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_MIRROR_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_STOP_DANCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_STOP_MIRROR_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_STREAMING_MOVIE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUMMON_CANCEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUMMON_REQUEST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPPRESS_NPC_GREETINGS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INFO, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TAXINODE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TEST_DROP_RATE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TEXT_EMOTE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_THREAT_CLEAR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_THREAT_REMOVE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_THREAT_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TIME_ADJUSTMENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TIME_SYNC_REQ, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TITLE_EARNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TOGGLE_XP_GAIN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TOTEM_CREATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_STATUS_EXTENDED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_BUY_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_BUY_SUCCEEDED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_LIST, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_ABORTED, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_PENDING, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRIGGER_CINEMATIC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRIGGER_MOVIE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TURN_IN_PETITION_RESULTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TUTORIAL_FLAGS, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNDELETE_CHARACTER_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNDELETE_COOLDOWN_STATUS_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNIT_HEALTH_FREQUENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNIT_SPELLCAST_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_ACCOUNT_DATA, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_COMBO_POINTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CURRENCY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CURRENCY_WEEK_LIMIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_DUNGEON_ENCOUNTER_FOR_LOOT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_OWNERSHIP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_LAST_INSTANCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_OBJECT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_SERVER_PLAYER_POSITION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_TASK_PROGRESS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_WORLD_STATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_ADD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_REMOVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICESESSION_FULL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_CHAT_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_PARENTAL_CONTROLS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_SESSION_LEAVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_SESSION_ROSTER_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOICE_SET_TALKER_MUTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_ITEM_SWAP_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_STORAGE_CONTENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_STORAGE_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_STORAGE_TRANSFER_CHANGES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_VOID_TRANSFER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WAIT_QUEUE_FINISH, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WAIT_QUEUE_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARDEN_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARGAME_CHECK_ENTRY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARGAME_REQUEST_SENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEATHER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_LAST_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_RESET_CURRENCY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_SPELL_USAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_SPELL_USAGE_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WHO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WHOIS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WORLD_SERVER_INFO, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_WORLD_STATE_UI_TIMER_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_XP_GAIN_ABORTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ZONE_UNDER_ATTACK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); #undef DEFINE_SERVER_OPCODE_HANDLER }; diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index aeb5bada68c..5556a4daf63 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -29,7 +29,10 @@ enum ConnectionType { CONNECTION_TYPE_REALM = 0, - CONNECTION_TYPE_INSTANCE = 1 + CONNECTION_TYPE_INSTANCE = 1, + MAX_CONNECTION_TYPES, + + CONNECTION_TYPE_DEFAULT = -1 }; enum OpcodeMisc : uint32 @@ -144,15 +147,15 @@ enum OpcodeClient : uint32 CMSG_CANCEL_QUEUED_SPELL = 0xBADD, CMSG_CANCEL_TEMP_ENCHANTMENT = 0xBADD, CMSG_CANCEL_TRADE = 0x1159, - CMSG_CAST_SPELL = 0xBADD, + CMSG_CAST_SPELL = 0x08FE, CMSG_CHANGEPLAYER_DIFFICULTY = 0xBADD, CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE = 0xBADD, CMSG_CHANNEL_ANNOUNCEMENTS = 0xBADD, CMSG_CHANNEL_BAN = 0xBADD, - CMSG_CHANNEL_DISPLAY_LIST = 0xBADD, + CMSG_CHANNEL_DISPLAY_LIST = 0x093B, CMSG_CHANNEL_INVITE = 0xBADD, CMSG_CHANNEL_KICK = 0xBADD, - CMSG_CHANNEL_LIST = 0xBADD, + CMSG_CHANNEL_LIST = 0x093B, CMSG_CHANNEL_MODERATE = 0xBADD, CMSG_CHANNEL_MODERATOR = 0xBADD, CMSG_CHANNEL_MUTE = 0xBADD, @@ -193,7 +196,7 @@ enum OpcodeClient : uint32 CMSG_COMPLAIN = 0xBADD, CMSG_COMPLETE_CINEMATIC = 0xBADD, CMSG_COMPLETE_MOVIE = 0xBADD, - CMSG_CONNECT_TO_FAILED = 0xBADD, + CMSG_CONNECT_TO_FAILED = 0x0135, CMSG_CONTACT_LIST = 0xBADD, CMSG_CORPSE_MAP_POSITION_QUERY = 0xBADD, CMSG_CREATURE_QUERY = 0x0505, @@ -314,8 +317,8 @@ enum OpcodeClient : uint32 CMSG_KEEP_ALIVE = 0xBADD, CMSG_LEARN_PREVIEW_TALENTS = 0xBADD, CMSG_LEARN_PREVIEW_TALENTS_PET = 0xBADD, - CMSG_LEARN_TALENT = 0xBADD, - CMSG_LEAVE_CHANNEL = 0xBADD, + CMSG_LEARN_TALENT = 0x0BB6, + CMSG_LEAVE_CHANNEL = 0x19F2, CMSG_LFG_GET_STATUS = 0xBADD, CMSG_LFG_JOIN = 0xBADD, CMSG_LFG_LEAVE = 0xBADD, @@ -335,7 +338,7 @@ enum OpcodeClient : uint32 CMSG_LF_GUILD_POST_REQUEST = 0xBADD, CMSG_LF_GUILD_REMOVE_RECRUIT = 0xBADD, CMSG_LF_GUILD_SET_GUILD_POST = 0xBADD, - CMSG_LIST_INVENTORY = 0xBADD, + CMSG_LIST_INVENTORY = 0x0B39, CMSG_LOAD_SCREEN = 0x0B08, CMSG_LOGOUT_CANCEL = 0x03C2, CMSG_LOGOUT_REQUEST = 0x1911, @@ -354,22 +357,20 @@ enum OpcodeClient : uint32 CMSG_MAIL_TAKE_ITEM = 0xBADD, CMSG_MAIL_TAKE_MONEY = 0xBADD, CMSG_MEETINGSTONE_INFO = 0xBADD, - CMSG_MESSAGECHAT_ADDON_BATTLEGROUND = 0xBADD, - CMSG_MESSAGECHAT_ADDON_GUILD = 0xBADD, - CMSG_MESSAGECHAT_ADDON_OFFICER = 0xBADD, - CMSG_MESSAGECHAT_ADDON_PARTY = 0xBADD, - CMSG_MESSAGECHAT_ADDON_RAID = 0xBADD, - CMSG_MESSAGECHAT_ADDON_WHISPER = 0xBADD, + CMSG_MESSAGECHAT_ADDON_GUILD = 0x137C, + CMSG_MESSAGECHAT_ADDON_OFFICER = 0x188A, + CMSG_MESSAGECHAT_ADDON_PARTY = 0x015C, + CMSG_MESSAGECHAT_ADDON_RAID = 0x082C, + CMSG_MESSAGECHAT_ADDON_WHISPER = 0x18A2, CMSG_MESSAGECHAT_AFK = 0x1BDC, - CMSG_MESSAGECHAT_BATTLEGROUND = 0xBADD, CMSG_MESSAGECHAT_CHANNEL = 0x0913, CMSG_MESSAGECHAT_DND = 0x0AAB, CMSG_MESSAGECHAT_EMOTE = 0x113C, CMSG_MESSAGECHAT_GUILD = 0x0B1B, - CMSG_MESSAGECHAT_OFFICER = 0xBADD, + CMSG_MESSAGECHAT_OFFICER = 0x0114, CMSG_MESSAGECHAT_PARTY = 0x0134, - CMSG_MESSAGECHAT_RAID = 0xBADD, - CMSG_MESSAGECHAT_RAID_WARNING = 0xBADD, + CMSG_MESSAGECHAT_RAID = 0x0B33, + CMSG_MESSAGECHAT_RAID_WARNING = 0x0313, CMSG_MESSAGECHAT_SAY = 0x1884, CMSG_MESSAGECHAT_WHISPER = 0x1829, CMSG_MESSAGECHAT_YELL = 0x1161, @@ -426,6 +427,7 @@ enum OpcodeClient : uint32 CMSG_MOVE_STOP_STRAFE = 0x01D1, CMSG_MOVE_STOP_SWIM = 0x097C, CMSG_MOVE_STOP_TURN = 0x0964, + CMSG_MOVE_TELEPORT_ACK = 0x0D01, CMSG_MOVE_TIME_SKIPPED = 0x19C2, CMSG_MOVE_TOGGLE_COLLISION_ACK = 0xBADD, CMSG_MOVE_WATER_WALK_ACK = 0xBADD, @@ -460,7 +462,7 @@ enum OpcodeClient : uint32 CMSG_PET_SPELL_AUTOCAST = 0xBADD, CMSG_PET_STOP_ATTACK = 0xBADD, CMSG_PING = 0x0416, - CMSG_PLAYED_TIME = 0xBADD, + CMSG_PLAYED_TIME = 0x1BB2, CMSG_PLAYER_DIFFICULTY_CHANGE = 0xBADD, CMSG_PLAYER_LOGIN = 0x0B1D, CMSG_PLAYER_LOGOUT = 0xBADD, @@ -486,7 +488,7 @@ enum OpcodeClient : uint32 CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 0xBADD, CMSG_QUESTGIVER_REQUEST_REWARD = 0xBADD, CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x0131, - CMSG_QUESTGIVER_STATUS_QUERY = 0x0704, + CMSG_QUESTGIVER_STATUS_QUERY = 0x01E2, CMSG_QUESTLOG_REMOVE_QUEST = 0xBADD, CMSG_QUESTLOG_SWAP_QUEST = 0xBADD, CMSG_QUEST_CONFIRM_ACCEPT = 0xBADD, @@ -509,8 +511,7 @@ enum OpcodeClient : uint32 CMSG_REPORT_PVP_AFK = 0xBADD, CMSG_REQUEST_ACCOUNT_DATA = 0x0F3E, CMSG_REQUEST_CATEGORY_COOLDOWNS = 0xBADD, - CMSG_REQUEST_CEMETERY_LIST = 0xBADD, - CMSG_REQUEST_HOTFIX = 0xBADD, + CMSG_REQUEST_CEMETERY_LIST = 0x10A2, CMSG_REQUEST_INSPECT_RATED_BG_STATS = 0xBADD, CMSG_REQUEST_PARTY_MEMBER_STATS = 0xBADD, CMSG_REQUEST_PET_INFO = 0xBADD, @@ -544,7 +545,7 @@ enum OpcodeClient : uint32 CMSG_SET_ACTIONBAR_TOGGLES = 0xBADD, CMSG_SET_ACTION_BUTTON = 0x0599, CMSG_SET_ACTIVE_MOVER = 0xBADD, - CMSG_SET_ACTIVE_VOICE_CHANNEL = 0xBADD, + CMSG_SET_ACTIVE_VOICE_CHANNEL = 0x031E, CMSG_SET_ALLOW_LOW_LEVEL_RAID1 = 0xBADD, CMSG_SET_ALLOW_LOW_LEVEL_RAID2 = 0xBADD, CMSG_SET_CHANNEL_WATCH = 0xBADD, @@ -609,9 +610,7 @@ enum OpcodeClient : uint32 CMSG_TRANSMOGRIFY_ITEMS = 0x0A85, CMSG_TRIGGER_CINEMATIC_CHEAT = 0xBADD, CMSG_TURN_IN_PETITION = 0xBADD, - CMSG_TUTORIAL_CLEAR = 0xBADD, - CMSG_TUTORIAL_FLAG = 0xBADD, - CMSG_TUTORIAL_RESET = 0xBADD, + CMSG_TUTORIAL_FLAG = 0x0B16, CMSG_UNACCEPT_TRADE = 0xBADD, CMSG_UNDELETE_CHARACTER = 0x0D99, CMSG_UNDELETE_COOLDOWN_STATUS_QUERY = 0x19A9, @@ -624,7 +623,7 @@ enum OpcodeClient : uint32 CMSG_USED_FOLLOW = 0xBADD, CMSG_USE_ITEM = 0x08B6, CMSG_VIOLENCE_LEVEL = 0x098D, - CMSG_VOICE_SESSION_ENABLE = 0xBADD, + CMSG_VOICE_SESSION_ENABLE = 0x1102, CMSG_VOID_STORAGE_QUERY = 0x019E, CMSG_VOID_STORAGE_TRANSFER = 0x0463, CMSG_VOID_STORAGE_UNLOCK = 0x13BB, @@ -654,8 +653,6 @@ enum OpcodeClient : uint32 MSG_MOVE_SET_SWIM_SPEED_CHEAT = 0xBADD, MSG_MOVE_SET_TURN_RATE_CHEAT = 0xBADD, MSG_MOVE_SET_WALK_SPEED_CHEAT = 0xBADD, - MSG_MOVE_TELEPORT = 0xBADD, - MSG_MOVE_TELEPORT_ACK = 0xBADD, MSG_MOVE_TELEPORT_CHEAT = 0xBADD, MSG_MOVE_TIME_SKIPPED = 0xBADD, MSG_MOVE_TOGGLE_COLLISION_CHEAT = 0xBADD, @@ -666,7 +663,6 @@ enum OpcodeClient : uint32 MSG_PARTY_ASSIGNMENT = 0xBADD, MSG_PETITION_DECLINE = 0xBADD, MSG_PETITION_RENAME = 0xBADD, - MSG_PVP_LOG_DATA = 0xBADD, MSG_QUERY_NEXT_MAIL_TIME = 0xBADD, MSG_QUEST_PUSH_RESULT = 0xBADD, MSG_RAID_READY_CHECK = 0xBADD, @@ -688,12 +684,14 @@ enum OpcodeServer : uint32 SMSG_ACCOUNT_INFO_RESPONSE = 0xBADD, SMSG_ACCOUNT_MOUNT_UPDATE = 0x0140, SMSG_ACCOUNT_RESTRICTED_WARNING = 0xBADD, + SMSG_ACCOUNT_TOYS_UPDATE = 0x0590, SMSG_ACHIEVEMENT_DELETED = 0xBADD, SMSG_ACHIEVEMENT_EARNED = 0xBADD, SMSG_ACTION_BUTTONS = 0x1D1F, SMSG_ACTIVATETAXIREPLY = 0xBADD, SMSG_ADDON_INFO = 0x1D9F, SMSG_ADD_RUNE_POWER = 0xBADD, + SMSG_ADJUST_SPLINE_DURATION = 0x0104, SMSG_AI_REACTION = 0x0BA1, SMSG_ALL_ACHIEVEMENT_DATA = 0xBADD, SMSG_ALL_ACHIEVEMENT_DATA_ACCOUNT = 0x0123, @@ -727,12 +725,11 @@ enum OpcodeServer : uint32 SMSG_AUCTION_OWNER_NOTIFICATION = 0xBADD, SMSG_AUCTION_REMOVED_NOTIFICATION = 0xBADD, SMSG_AURACASTLOG = 0xBADD, - SMSG_AURA_POINTS_DEPLETED = 0xBADD, + SMSG_AURA_POINTS_DEPLETED = 0x093B, SMSG_AURA_UPDATE = 0x091C, - SMSG_AURA_UPDATE_ALL = 0xBADD, SMSG_AUTH_CHALLENGE = 0x1759, SMSG_AUTH_RESPONSE = 0x0DA9, - SMSG_AVAILABLE_VOICE_CHANNEL = 0xBADD, + SMSG_AVAILABLE_VOICE_CHANNEL = 0x04D4, SMSG_AVERAGE_ITEM_LEVEL_INFORM = 0xBADD, SMSG_BARBER_SHOP_RESULT = 0xBADD, SMSG_BATTLEFIELD_LIST = 0xBADD, @@ -756,6 +753,7 @@ enum OpcodeServer : uint32 SMSG_BATTLEGROUND_INFO_THROTTLED = 0xBADD, SMSG_BATTLEGROUND_PLAYER_JOINED = 0xBADD, SMSG_BATTLEGROUND_PLAYER_LEFT = 0xBADD, + SMSG_BATTLE_PAY_DISTRIBUTION_UPDATE = 0x0BE3, SMSG_BATTLE_PAY_GET_DISTRIBUTION_LIST_RESPONSE = 0x0F2A, SMSG_BATTLE_PAY_GET_PRODUCT_LIST_RESPONSE = 0x12A4, SMSG_BATTLE_PAY_GET_PURCHASE_LIST_RESPONSE = 0x168A, @@ -790,7 +788,7 @@ enum OpcodeServer : uint32 SMSG_CALENDAR_RAID_LOCKOUT_UPDATED = 0xBADD, SMSG_CALENDAR_SEND_CALENDAR = 0xBADD, SMSG_CALENDAR_SEND_EVENT = 0xBADD, - SMSG_CALENDAR_SEND_NUM_PENDING = 0xBADD, + SMSG_CALENDAR_SEND_NUM_PENDING = 0x1B3A, SMSG_CALENDAR_UPDATE_INVITE_LIST = 0xBADD, SMSG_CAMERA_SHAKE = 0xBADD, SMSG_CANCEL_AUTO_REPEAT = 0xBADD, @@ -913,8 +911,10 @@ enum OpcodeServer : uint32 SMSG_FORCE_SET_VEHICLE_REC_ID = 0xBADD, SMSG_FORGE_MASTER_SET = 0xBADD, SMSG_FRIEND_STATUS = 0xBADD, + SMSG_GAMEOBJECT_ACTIVATE_ANIM_KIT = 0x038C, SMSG_GAMEOBJECT_CUSTOM_ANIM = 0x03EB, SMSG_GAMEOBJECT_DESPAWN_ANIM = 0xBADD, + SMSG_GAMEOBJECT_DESPAWN = 0x0D29, SMSG_GAMEOBJECT_PAGETEXT = 0xBADD, SMSG_GAMEOBJECT_QUERY_RESPONSE = 0xBADD, SMSG_GAMEOBJECT_RESET_STATE = 0xBADD, @@ -922,8 +922,8 @@ enum OpcodeServer : uint32 SMSG_GAMETIME_SET = 0xBADD, SMSG_GAMETIME_UPDATE = 0xBADD, SMSG_GAME_EVENT_DEBUG_LOG = 0xBADD, - SMSG_GAME_OBJECT_ACTIVATE_ANIM_KIT = 0xBADD, SMSG_GARRISON_COMPLETE_MISSION_RESULT = 0x0952, + SMSG_GARRISON_REMOTE_INFO = 0x0151, SMSG_GMRESPONSE_DB_ERROR = 0xBADD, SMSG_GMRESPONSE_RECEIVED = 0xBADD, SMSG_GMRESPONSE_STATUS_UPDATE = 0xBADD, @@ -934,7 +934,9 @@ enum OpcodeServer : uint32 SMSG_GMTICKET_UPDATETEXT = 0xBADD, SMSG_GM_MESSAGECHAT = 0xBADD, SMSG_GM_PLAYER_INFO = 0xBADD, + SMSG_GM_TICKET_CASE_STATUS = 0x1D8D, SMSG_GM_TICKET_STATUS_UPDATE = 0xBADD, + SMSG_GM_TICKET_SYSTEM_STATUS = 0x1229, SMSG_GODMODE = 0xBADD, SMSG_GOSSIP_COMPLETE = 0x15D1, SMSG_GOSSIP_MESSAGE = 0x1746, @@ -964,8 +966,10 @@ enum OpcodeServer : uint32 SMSG_GUILD_COMMAND_RESULT_2 = 0xBADD, SMSG_GUILD_CRITERIA_DATA = 0xBADD, SMSG_GUILD_CRITERIA_DELETED = 0xBADD, + SMSG_GUILD_CRITERIA_UPDATE = 0x1208, SMSG_GUILD_DECLINE = 0xBADD, SMSG_GUILD_EVENT = 0x1027, + SMSG_GUILD_EVENT_BANK_MONEY_CHANGED = 0x1077, SMSG_GUILD_EVENT_LOG_QUERY_RESULT = 0xBADD, SMSG_GUILD_EVENT_PRESENCE_CHANGE = 0x1228, SMSG_GUILD_FLAGGED_FOR_RENAME = 0xBADD, @@ -992,7 +996,7 @@ enum OpcodeServer : uint32 SMSG_GUILD_REPUTATION_REACTION_CHANGED = 0xBADD, SMSG_GUILD_REPUTATION_WEEKLY_CAP = 0xBADD, SMSG_GUILD_RESET = 0xBADD, - SMSG_GUILD_REWARDS_LIST = 0xBADD, + SMSG_GUILD_REWARDS_LIST = 0x1818, SMSG_GUILD_ROSTER = 0x1026, SMSG_GUILD_SET_NOTE = 0xBADD, SMSG_GUILD_TRADESKILL_UPDATE = 0xBADD, @@ -1016,12 +1020,13 @@ enum OpcodeServer : uint32 SMSG_INSPECT_RATED_BG_STATS = 0xBADD, SMSG_INSPECT_RESULTS_UPDATE = 0xBADD, SMSG_INSPECT_TALENT = 0xBADD, + SMSG_INSTANCE_INFO = 0x0DA0, SMSG_INSTANCE_LOCK_WARNING_QUERY = 0xBADD, SMSG_INSTANCE_RESET = 0xBADD, SMSG_INSTANCE_RESET_FAILED = 0xBADD, SMSG_INSTANCE_SAVE_CREATED = 0xBADD, SMSG_INVALIDATE_DANCE = 0xBADD, - SMSG_INVALIDATE_PLAYER = 0xBADD, + SMSG_INVALIDATE_PLAYER = 0x0B37, SMSG_INVALID_PROMOTION_CODE = 0xBADD, SMSG_INVENTORY_CHANGE_FAILURE = 0xBADD, SMSG_ITEM_ADD_PASSIVE = 0xBADD, @@ -1038,7 +1043,7 @@ enum OpcodeServer : uint32 SMSG_JOINED_BATTLEGROUND_QUEUE = 0xBADD, SMSG_KICK_REASON = 0xBADD, SMSG_LEARNED_DANCE_MOVES = 0xBADD, - SMSG_LEARNED_SPELL = 0xBADD, + SMSG_LEARNED_SPELLS = 0x08AB, SMSG_LEVELUP_INFO = 0xBADD, SMSG_LFG_BOOT_PROPOSAL_UPDATE = 0xBADD, SMSG_LFG_DISABLED = 0xBADD, @@ -1087,6 +1092,7 @@ enum OpcodeServer : uint32 SMSG_LOOT_SLOT_CHANGED = 0xBADD, SMSG_LOOT_START_ROLL = 0xBADD, SMSG_MAIL_LIST_RESULT = 0x0B3F, + SMSG_MAIL_QUERY_NEXT_TIME_RESULT = 0x153D, SMSG_MAP_OBJ_EVENTS = 0xBADD, SMSG_MEETINGSTONE_COMPLETE = 0xBADD, SMSG_MEETINGSTONE_IN_PROGRESS = 0xBADD, @@ -1101,7 +1107,7 @@ enum OpcodeServer : uint32 SMSG_MISSILE_CANCEL = 0xBADD, SMSG_MODIFY_COOLDOWN = 0xBADD, SMSG_MONEY_NOTIFY = 0xBADD, - SMSG_MONSTER_MOVE = 0xBADD, + SMSG_MONSTER_MOVE = 0x0994, SMSG_MONSTER_MOVE_TRANSPORT = 0xBADD, SMSG_MOTD = 0x0442, SMSG_MOUNTRESULT = 0xBADD, @@ -1109,49 +1115,48 @@ enum OpcodeServer : uint32 SMSG_MOVE_COLLISION_DISABLE = 0xBADD, SMSG_MOVE_COLLISION_ENABLE = 0xBADD, SMSG_MOVE_FEATHER_FALL = 0xBADD, - SMSG_MOVE_FORCE_RUN_SPEED_CHANGE = 0x08F5, - SMSG_MOVE_FORCE_SWIM_SPEED_CHANGE = 0x061A, SMSG_MOVE_GRAVITY_DISABLE = 0x02C6, SMSG_MOVE_GRAVITY_ENABLE = 0xBADD, SMSG_MOVE_KNOCK_BACK = 0xBADD, - SMSG_MOVE_LAND_WALK = 0xBADD, + SMSG_MOVE_LAND_WALK = 0x13DA, SMSG_MOVE_NORMAL_FALL = 0xBADD, SMSG_MOVE_ROOT = 0x1B5A, SMSG_MOVE_SET_ACTIVE_MOVER = 0xBADD, - SMSG_MOVE_SET_CAN_FLY = 0xBADD, + SMSG_MOVE_SET_CAN_FLY = 0x01F6, SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY = 0xBADD, SMSG_MOVE_SET_COLLISION_HEIGHT = 0x008D, SMSG_MOVE_SET_COMPOUND_STATE = 0xBADD, SMSG_MOVE_SET_FLIGHT_BACK_SPEED = 0xBADD, SMSG_MOVE_SET_FLIGHT_SPEED = 0xBADD, - SMSG_MOVE_SET_HOVER = 0xBADD, + SMSG_MOVE_SET_HOVER = 0x0296, SMSG_MOVE_SET_PITCH_RATE = 0xBADD, SMSG_MOVE_SET_RUN_BACK_SPEED = 0xBADD, - SMSG_MOVE_SET_RUN_SPEED = 0xBADD, + SMSG_MOVE_SET_RUN_SPEED = 0x08F5, SMSG_MOVE_SET_SWIM_BACK_SPEED = 0xBADD, - SMSG_MOVE_SET_SWIM_SPEED = 0xBADD, + SMSG_MOVE_SET_SWIM_SPEED = 0x061A, SMSG_MOVE_SET_TURN_RATE = 0xBADD, SMSG_MOVE_SET_VEHICLE_REC_ID = 0xBADD, SMSG_MOVE_SET_WALK_IN_AIR = 0xBADD, SMSG_MOVE_SET_WALK_SPEED = 0xBADD, + SMSG_MOVE_TELEPORT = 0x03A6, SMSG_MOVE_UNROOT = 0xBADD, - SMSG_MOVE_UNSET_CAN_FLY = 0xBADD, + SMSG_MOVE_UNSET_CAN_FLY = 0x0BAE, SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY = 0xBADD, - SMSG_MOVE_UNSET_HOVER = 0xBADD, + SMSG_MOVE_UNSET_HOVER = 0x01A5, SMSG_MOVE_UNSET_WALK_IN_AIR = 0xBADD, SMSG_MOVE_UPDATE_COLLISION_HEIGHT = 0xBADD, SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED = 0xBADD, SMSG_MOVE_UPDATE_FLIGHT_SPEED = 0xBADD, SMSG_MOVE_UPDATE_KNOCK_BACK = 0xBADD, - SMSG_MOVE_UPDATE_PITCH_RATE = 0xBADD, - SMSG_MOVE_UPDATE_RUN_BACK_SPEED = 0xBADD, - SMSG_MOVE_UPDATE_RUN_SPEED = 0xBADD, - SMSG_MOVE_UPDATE_SWIM_BACK_SPEED = 0xBADD, - SMSG_MOVE_UPDATE_SWIM_SPEED = 0xBADD, + SMSG_MOVE_UPDATE_PITCH_RATE = 0x13D9, + SMSG_MOVE_UPDATE_RUN_BACK_SPEED = 0x09DE, + SMSG_MOVE_UPDATE_RUN_SPEED = 0x09AD, + SMSG_MOVE_UPDATE_SWIM_BACK_SPEED = 0x1083, + SMSG_MOVE_UPDATE_SWIM_SPEED = 0x0B95, SMSG_MOVE_UPDATE_TELEPORT = 0x03D5, - SMSG_MOVE_UPDATE_TURN_RATE = 0xBADD, - SMSG_MOVE_UPDATE_WALK_SPEED = 0xBADD, - SMSG_MOVE_WATER_WALK = 0xBADD, + SMSG_MOVE_UPDATE_TURN_RATE = 0x08BE, + SMSG_MOVE_UPDATE_WALK_SPEED = 0x01E5, + SMSG_MOVE_WATER_WALK = 0x02A6, SMSG_MULTIPLE_PACKETS = 0xBADD, SMSG_NAME_QUERY_RESPONSE = 0x0828, SMSG_NEW_TAXI_PATH = 0xBADD, @@ -1265,9 +1270,10 @@ enum OpcodeServer : uint32 SMSG_REFER_A_FRIEND_EXPIRED = 0xBADD, SMSG_REFER_A_FRIEND_FAILURE = 0xBADD, SMSG_REFORGE_RESULT = 0xBADD, - SMSG_REMOVED_SPELL = 0xBADD, + SMSG_REFRESH_SPELL_HISTORY = 0x0A2A, + SMSG_REMOVED_SPELL = 0x0B3B, SMSG_REPORT_PVP_AFK_RESULT = 0xBADD, - SMSG_REQUEST_CEMETERY_LIST_RESPONSE = 0xBADD, + SMSG_REQUEST_CEMETERY_LIST_RESPONSE = 0x059E, SMSG_REQUEST_PVP_REWARDS_RESPONSE = 0xBADD, SMSG_RESEARCH_COMPLETE = 0xBADD, SMSG_RESEARCH_SETUP_HISTORY = 0x0A25, @@ -1283,13 +1289,17 @@ enum OpcodeServer : uint32 SMSG_RWHOIS = 0xBADD, SMSG_SELL_ITEM = 0xBADD, SMSG_SEND_MAIL_RESULT = 0x0302, - SMSG_SEND_UNLEARN_SPELLS = 0x1A82, + SMSG_SEND_SPELL_CHARGES = 0x1A82, + SMSG_SEND_SPELL_HISTORY = 0x1933, + SMSG_SEND_UNLEARN_SPELLS = 0x0BCB, SMSG_SERVERTIME = 0xBADD, SMSG_SERVER_FIRST_ACHIEVEMENT = 0xBADD, SMSG_SERVER_INFO_RESPONSE = 0xBADD, SMSG_SERVER_MESSAGE = 0x0683, SMSG_SERVER_PERF = 0xBADD, SMSG_SET_AI_ANIM_KIT = 0x0335, + SMSG_SET_ALL_TASK_PROGRESS = 0x1B52, + SMSG_SET_CURRENCY = 0x17BE, SMSG_SET_DF_FAST_LAUNCH_RESULT = 0xBADD, SMSG_SET_FACTION_ATWAR = 0xBADD, SMSG_SET_FACTION_NOT_VISIBLE = 0xBADD, @@ -1297,6 +1307,7 @@ enum OpcodeServer : uint32 SMSG_SET_FACTION_VISIBLE = 0x138B, SMSG_SET_FLAT_SPELL_MODIFIER = 0x1884, SMSG_SET_FORCED_REACTIONS = 0x09A9, + SMSG_SET_MAX_WEEKLY_QUANTITY = 0x1489, SMSG_SET_MELEE_ANIM_KIT = 0xBADD, SMSG_SET_MOVEMENT_ANIM_KIT = 0xBADD, SMSG_SET_PCT_SPELL_MODIFIER = 0x113C, @@ -1365,6 +1376,7 @@ enum OpcodeServer : uint32 SMSG_SPLINE_MOVE_WATER_WALK = 0xBADD, SMSG_STABLE_RESULT = 0xBADD, SMSG_STANDSTATE_UPDATE = 0x1311, + SMSG_START_ELAPSED_TIMERS = 0x093F, SMSG_START_MIRROR_TIMER = 0xBADD, SMSG_START_TIMER = 0xBADD, SMSG_STOP_DANCE = 0xBADD, @@ -1379,11 +1391,11 @@ enum OpcodeServer : uint32 SMSG_TALENTS_ERROR = 0xBADD, SMSG_TALENTS_INFO = 0x012D, SMSG_TALENTS_INVOLUNTARILY_RESET = 0xBADD, - SMSG_TAXINODE_STATUS = 0xBADD, + SMSG_TAXINODE_STATUS = 0x0338, SMSG_TEST_DROP_RATE_RESULT = 0xBADD, SMSG_TEXT_EMOTE = 0x0383, SMSG_THREAT_CLEAR = 0xBADD, - SMSG_THREAT_REMOVE = 0xBADD, + SMSG_THREAT_REMOVE = 0x0F3D, SMSG_THREAT_UPDATE = 0x03A9, SMSG_TIME_ADJUSTMENT = 0xBADD, SMSG_TIME_SYNC_REQ = 0x03B1, @@ -1415,6 +1427,7 @@ enum OpcodeServer : uint32 SMSG_UPDATE_LAST_INSTANCE = 0xBADD, SMSG_UPDATE_OBJECT = 0x122C, SMSG_UPDATE_SERVER_PLAYER_POSITION = 0xBADD, + SMSG_UPDATE_TASK_PROGRESS = 0x1209, SMSG_UPDATE_WORLD_STATE = 0x03EC, SMSG_USERLIST_ADD = 0xBADD, SMSG_USERLIST_REMOVE = 0xBADD, @@ -1422,7 +1435,7 @@ enum OpcodeServer : uint32 SMSG_VOICESESSION_FULL = 0xBADD, SMSG_VOICE_CHAT_STATUS = 0xBADD, SMSG_VOICE_PARENTAL_CONTROLS = 0xBADD, - SMSG_VOICE_SESSION_LEAVE = 0xBADD, + SMSG_VOICE_SESSION_LEAVE = 0x0403, SMSG_VOICE_SESSION_ROSTER_UPDATE = 0xBADD, SMSG_VOICE_SET_TALKER_MUTED = 0xBADD, SMSG_VOID_ITEM_SWAP_RESPONSE = 0x1131, @@ -1448,6 +1461,162 @@ enum OpcodeServer : uint32 SMSG_ZONE_UNDER_ATTACK = 0x1401 }; +inline bool IsInstanceOnlyOpcode(uint32 opcode) +{ + // TODO: Use names when known + switch (opcode) + { + case 0x000F: // Client + case 0x0111: // Client + case 0x03E4: // Client + case 0x0549: // Client + case 0x054C: // Client + case 0x055A: // Client + case 0x056C: // Client + case 0x057A: // Client + case 0x057B: // Client + case 0x05CC: // Client + case 0x05EA: // Client + case 0x05EC: // Client + case 0x05F9: // Client + case 0x05FB: // Client + case 0x074C: // Client + case 0x075B: // Client + case 0x076C: // Client + case 0x077B: // Client + case 0x077C: // Client + case 0x07CC: // Client + case 0x07DB: // Client + case 0x07EC: // Client + case 0x07FB: // Client + case 0x07FC: // Client + case 0x0827: // Client + case 0x0935: // Client + case 0x0F0C: // ClientSpell + case 0x0F10: // ClientSpell + case 0x0F1B: // ClientSpell + case 0x0F1C: // ClientSpell + case 0x0F20: // ClientSpell + case 0x0F2C: // ClientSpell + case 0x0F2F: // ClientSpell + case 0x0F3B: // ClientSpell + case 0x0F8B: // ClientSpell + case 0x0F8C: // ClientSpell + case 0x0F90: // ClientSpell + case 0x0F9F: // ClientSpell + case 0x0FA0: // ClientSpell + case SMSG_ATTACKSTOP: // Client + case 0x14C9: // Client + case 0x154A: // Client + case 0x155A: // Client + case 0x155C: // Client + case SMSG_QUESTGIVER_STATUS: // ClientQuest + case 0x156A: // Client + case 0x156B: // Client + case 0x157A: // Client + case 0x157B: // Client + case 0x15DC: // Client + case 0x15EB: // Client + case 0x15FB: // Client + case 0x170C: // ClientSpell + case 0x171C: // ClientSpell + case 0x171F: // ClientSpell + case 0x172C: // ClientSpell + case 0x172F: // ClientSpell + case 0x173C: // ClientSpell + case 0x173F: // ClientSpell + case 0x1740: // ClientSpell + case 0x1790: // ClientSpell + case 0x179B: // ClientSpell + case 0x179F: // ClientSpell + case SMSG_ATTACKSTART: // Client + case 0x1D82: // ClientQuest + case 0x1D83: // ClientQuest + case 0x1D85: // ClientQuest + case 0x1D87: // ClientQuest + case 0x1D93: // ClientQuest + case 0x1D96: // ClientQuest + case 0x1D97: // ClientQuest + case 0x1DA1: // ClientQuest + case 0x1DA2: // ClientQuest + case 0x1DA3: // ClientQuest + case 0x1DA4: // ClientQuest + case 0x1DA5: // ClientQuest + case 0x1DA7: // ClientQuest + case SMSG_QUERY_TIME_RESPONSE: // Client + case 0x1DC2: // ClientQuest + case 0x1DC6: // ClientQuest + case 0x1DC7: // ClientQuest + case 0x1DD2: // ClientQuest + case 0x1DD3: // ClientQuest + case 0x1DD6: // ClientQuest + case 0x1DD7: // ClientQuest + case 0x1DD8: // ClientQuest + case 0x1DE4: // ClientQuest + case 0x1DE5: // ClientQuest + case 0x1DE7: // ClientQuest + case 0x1F02: // ClientQuest + case 0x1F06: // ClientQuest + case 0x1F07: // ClientQuest + case 0x1F0C: // ClientSpell + case 0x1F12: // ClientQuest + case 0x1F13: // ClientQuest + case 0x1F16: // ClientQuest + case 0x1F17: // ClientQuest + case 0x1F18: // ClientQuest + case 0x1F1C: // ClientSpell + case 0x1F1F: // ClientSpell + case 0x1F24: // ClientQuest + case 0x1F25: // ClientQuest + case 0x1F27: // ClientQuest + case 0x1F2C: // ClientSpell + case 0x1F2F: // ClientSpell + case 0x1F3C: // ClientSpell + case 0x1F3F: // ClientSpell + case 0x1F40: // ClientSpell + case 0x1F44: // ClientQuest + case 0x1F48: // ClientQuest + case 0x1F51: // ClientQuest + case 0x1F55: // ClientQuest + case 0x1F57: // ClientQuest + case 0x1F61: // ClientQuest + case 0x1F63: // ClientQuest + case 0x1F64: // ClientQuest + case 0x1F65: // ClientQuest + case 0x1F67: // ClientQuest + case 0x1F85: // ClientQuest + case 0x1F86: // ClientQuest + case 0x1F87: // ClientQuest + case 0x1F90: // ClientSpell + case 0x1F92: // ClientQuest + case 0x1F94: // ClientQuest + case 0x1F96: // ClientQuest + case 0x1F97: // ClientQuest + case 0x1F9B: // ClientSpell + case 0x1F9F: // ClientSpell + case 0x1FA1: // ClientQuest + case 0x1FA2: // ClientQuest + case 0x1FA3: // ClientQuest + case 0x1FA4: // ClientQuest + case 0x1FA5: // ClientQuest + case 0x1FA7: // ClientQuest + case 0x1FC2: // ClientQuest + case 0x1FC6: // ClientQuest + case 0x1FC7: // ClientQuest + case 0x1FD2: // ClientQuest + case 0x1FD3: // ClientQuest + case 0x1FD6: // ClientQuest + case 0x1FD7: // ClientQuest + case 0x1FD8: // ClientQuest + case 0x1FE4: // ClientQuest + case 0x1FE5: // ClientQuest + case 0x1FE7: // ClientQuest + return true; + default: + return false; + } +} + /// Player state enum SessionStatus { @@ -1479,18 +1648,33 @@ class WorldSession; class OpcodeHandler { public: - OpcodeHandler(char const* _name, SessionStatus _status, PacketProcessing _processing) - : Name(_name), Status(_status), ProcessingPlace(_processing) { } - + OpcodeHandler(char const* name, SessionStatus status) : Name(name), Status(status) { } virtual ~OpcodeHandler() { } - virtual void Call(WorldSession* session, WorldPacket& packet) const = 0; - char const* Name; SessionStatus Status; +}; + +class ClientOpcodeHandler : public OpcodeHandler +{ +public: + ClientOpcodeHandler(char const* name, SessionStatus status, PacketProcessing processing) + : OpcodeHandler(name, status), ProcessingPlace(processing) { } + + virtual void Call(WorldSession* session, WorldPacket& packet) const = 0; + PacketProcessing ProcessingPlace; }; +class ServerOpcodeHandler : public OpcodeHandler +{ +public: + ServerOpcodeHandler(char const* name, SessionStatus status, ConnectionType conIdx) + : OpcodeHandler(name, status), ConnectionIndex(conIdx) { } + + ConnectionType ConnectionIndex; +}; + class OpcodeTable { public: @@ -1514,24 +1698,24 @@ class OpcodeTable void Initialize(); - OpcodeHandler const* operator[](OpcodeClient index) const + ClientOpcodeHandler const* operator[](OpcodeClient index) const { return _internalTableClient[index]; } - OpcodeHandler const* operator[](OpcodeServer index) const + ServerOpcodeHandler const* operator[](OpcodeServer index) const { return _internalTableServer[index]; } private: template<class PacketClass, void(WorldSession::*HandlerFunction)(PacketClass&)> - void ValidateAndSetOpcode(OpcodeClient opcode, char const* name, SessionStatus status, PacketProcessing processing); + void ValidateAndSetClientOpcode(OpcodeClient opcode, char const* name, SessionStatus status, PacketProcessing processing); - void ValidateAndSetOpcode(OpcodeServer opcode, char const* name, SessionStatus status); + void ValidateAndSetServerOpcode(OpcodeServer opcode, char const* name, SessionStatus status, ConnectionType conIdx); - OpcodeHandler* _internalTableClient[NUM_OPCODE_HANDLERS]; - OpcodeHandler* _internalTableServer[NUM_OPCODE_HANDLERS]; + ClientOpcodeHandler* _internalTableClient[NUM_OPCODE_HANDLERS]; + ServerOpcodeHandler* _internalTableServer[NUM_OPCODE_HANDLERS]; }; extern OpcodeTable opcodeTable; diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h index 65b2f6fcae1..270f2598553 100644 --- a/src/server/game/Server/WorldPacket.h +++ b/src/server/game/Server/WorldPacket.h @@ -27,11 +27,11 @@ class WorldPacket : public ByteBuffer { public: // just container for later use - WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE), _connection(CONNECTION_TYPE_REALM) + WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE), _connection(CONNECTION_TYPE_DEFAULT) { } - WorldPacket(uint32 opcode, size_t res = 200, ConnectionType connection = CONNECTION_TYPE_REALM) : ByteBuffer(res), + WorldPacket(uint32 opcode, size_t res = 200, ConnectionType connection = CONNECTION_TYPE_DEFAULT) : ByteBuffer(res), m_opcode(opcode), _connection(connection) { } WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode), _connection(packet._connection) @@ -56,7 +56,7 @@ class WorldPacket : public ByteBuffer WorldPacket(uint32 opcode, MessageBuffer&& buffer, ConnectionType connection) : ByteBuffer(std::move(buffer)), m_opcode(opcode), _connection(connection) { } - void Initialize(uint32 opcode, size_t newres = 200, ConnectionType connection = CONNECTION_TYPE_REALM) + void Initialize(uint32 opcode, size_t newres = 200, ConnectionType connection = CONNECTION_TYPE_DEFAULT) { clear(); _storage.reserve(newres); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 18fe28344b0..3a9f5e70204 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -60,7 +60,7 @@ std::string const DefaultPlayerName = "<none>"; bool MapSessionFilter::Process(WorldPacket* packet) { - OpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())]; + ClientOpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())]; //let's check if our opcode can be really processed in Map::Update() if (opHandle->ProcessingPlace == PROCESS_INPLACE) @@ -82,7 +82,8 @@ bool MapSessionFilter::Process(WorldPacket* packet) //OR packet handler is not thread-safe! bool WorldSessionFilter::Process(WorldPacket* packet) { - OpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())]; + ClientOpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())]; + //check if packet handler is supposed to be safe if (opHandle->ProcessingPlace == PROCESS_INPLACE) return true; @@ -121,7 +122,7 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr m_sessionDbLocaleIndex(locale), m_latency(0), m_clientTimeDelay(0), - m_TutorialsChanged(false), + _tutorialsChanged(false), _filterAddonMessages(false), recruiterId(recruiter), isRecruiter(isARecruiter), @@ -130,7 +131,7 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr forceExit(false), m_currentBankerGUID() { - memset(m_Tutorials, 0, sizeof(m_Tutorials)); + memset(_tutorials, 0, sizeof(_tutorials)); if (sock) { @@ -193,9 +194,6 @@ std::string WorldSession::GetPlayerInfo() const /// Send a packet to the client void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/) { - if (!m_Socket[packet->GetConnection()]) - return; - if (packet->GetOpcode() == NULL_OPCODE) { TC_LOG_ERROR("network.opcode", "Prevented sending of NULL_OPCODE to %s", GetPlayerInfo().c_str()); @@ -207,10 +205,38 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/ return; } + ServerOpcodeHandler const* handler = opcodeTable[static_cast<OpcodeServer>(packet->GetOpcode())]; + + if (!handler) + { + TC_LOG_ERROR("network.opcode", "Prevented sending of opcode %u with non existing handler to %s", packet->GetOpcode(), GetPlayerInfo().c_str()); + return; + } + + // Default connection index defined in Opcodes.cpp table + ConnectionType conIdx = handler->ConnectionIndex; + + // Override connection index + if (packet->GetConnection() != CONNECTION_TYPE_DEFAULT) + { + if (packet->GetConnection() != CONNECTION_TYPE_INSTANCE && IsInstanceOnlyOpcode(packet->GetOpcode())) + { + TC_LOG_ERROR("network.opcode", "Prevented sending of instance only opcode %u with connection type %u to %s", packet->GetOpcode(), packet->GetConnection(), GetPlayerInfo().c_str()); + return; + } + + conIdx = packet->GetConnection(); + } + + if (!m_Socket[conIdx]) + { + TC_LOG_ERROR("network.opcode", "Prevented sending of %s to non existent socket %u to %s", GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet->GetOpcode())).c_str(), conIdx, GetPlayerInfo().c_str()); + return; + } + if (!forced) { - OpcodeHandler const* handler = opcodeTable[static_cast<OpcodeServer>(packet->GetOpcode())]; - if (!handler || handler->Status == STATUS_UNHANDLED) + if (handler->Status == STATUS_UNHANDLED) { TC_LOG_ERROR("network.opcode", "Prevented sending disabled opcode %s to %s", GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet->GetOpcode())).c_str(), GetPlayerInfo().c_str()); return; @@ -253,7 +279,7 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/ sScriptMgr->OnPacketSend(this, *packet); - m_Socket[packet->GetConnection()]->SendPacket(*packet); + m_Socket[conIdx]->SendPacket(*packet); } /// Add an incoming packet to the queue @@ -311,7 +337,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (!AntiDOS.EvaluateOpcode(*packet, currentTime)) KickPlayer(); - OpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())]; + ClientOpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())]; try { switch (opHandle->Status) @@ -695,7 +721,7 @@ void WorldSession::LoadAccountData(PreparedQueryResult result, uint32 mask) { for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) if (mask & (1 << i)) - m_accountData[i] = AccountData(); + _accountData[i] = AccountData(); if (!result) return; @@ -718,20 +744,20 @@ void WorldSession::LoadAccountData(PreparedQueryResult result, uint32 mask) continue; } - m_accountData[type].Time = time_t(fields[1].GetUInt32()); - m_accountData[type].Data = fields[2].GetString(); + _accountData[type].Time = time_t(fields[1].GetUInt32()); + _accountData[type].Data = fields[2].GetString(); } while (result->NextRow()); } -void WorldSession::SetAccountData(AccountDataType type, time_t tm, std::string const& data) +void WorldSession::SetAccountData(AccountDataType type, uint32 time, std::string const& data) { if ((1 << type) & GLOBAL_CACHE_MASK) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_ACCOUNT_DATA); stmt->setUInt32(0, GetAccountId()); stmt->setUInt8(1, type); - stmt->setUInt32(2, uint32(tm)); + stmt->setUInt32(2, time); stmt->setString(3, data); CharacterDatabase.Execute(stmt); } @@ -744,38 +770,38 @@ void WorldSession::SetAccountData(AccountDataType type, time_t tm, std::string c PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_PLAYER_ACCOUNT_DATA); stmt->setUInt64(0, m_GUIDLow); stmt->setUInt8(1, type); - stmt->setUInt32(2, uint32(tm)); + stmt->setUInt32(2, time); stmt->setString(3, data); CharacterDatabase.Execute(stmt); } - m_accountData[type].Time = tm; - m_accountData[type].Data = data; + _accountData[type].Time = time_t(time); + _accountData[type].Data = data; } void WorldSession::LoadTutorialsData() { - memset(m_Tutorials, 0, sizeof(uint32) * MAX_ACCOUNT_TUTORIAL_VALUES); + memset(_tutorials, 0, sizeof(uint32) * MAX_ACCOUNT_TUTORIAL_VALUES); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_TUTORIALS); stmt->setUInt32(0, GetAccountId()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) - m_Tutorials[i] = (*result)[i].GetUInt32(); + _tutorials[i] = (*result)[i].GetUInt32(); - m_TutorialsChanged = false; + _tutorialsChanged = false; } void WorldSession::SendTutorialsData() { WorldPackets::Misc::TutorialFlags packet; - memcpy(packet.TutorialData, m_Tutorials, sizeof(packet.TutorialData)); + memcpy(packet.TutorialData, _tutorials, sizeof(_tutorials)); SendPacket(packet.Write()); } -void WorldSession::SaveTutorialsData(SQLTransaction &trans) +void WorldSession::SaveTutorialsData(SQLTransaction& trans) { - if (!m_TutorialsChanged) + if (!_tutorialsChanged) return; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_HAS_TUTORIALS); @@ -784,11 +810,11 @@ void WorldSession::SaveTutorialsData(SQLTransaction &trans) // Modify data in DB stmt = CharacterDatabase.GetPreparedStatement(hasTutorials ? CHAR_UPD_TUTORIALS : CHAR_INS_TUTORIALS); for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) - stmt->setUInt32(i, m_Tutorials[i]); + stmt->setUInt32(i, _tutorials[i]); stmt->setUInt32(MAX_ACCOUNT_TUTORIAL_VALUES, GetAccountId()); trans->Append(stmt); - m_TutorialsChanged = false; + _tutorialsChanged = false; } void WorldSession::ReadAddonsInfo(ByteBuffer& data) diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index b508acb604e..b95b3ce4330 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -102,20 +102,52 @@ namespace WorldPackets class UserClientUpdateAccountData; } + namespace Channel + { + class ChannelListRequest; + class JoinChannel; + class LeaveChannel; + } + + namespace Chat + { + class ChatMessage; + class ChatMessageWhisper; + class ChatMessageChannel; + class ChatAddonMessage; + class ChatAddonMessageWhisper; + class ChatMessageAFK; + class ChatMessageDND; + class ChatMessageEmote; + class CTextEmote; + } + namespace Combat { class AttackSwing; class AttackStop; } + namespace EquipmentSet + { + class SaveEquipmentSet; + } + namespace Guild { class QueryGuildInfo; } - + + namespace Spells + { + class SpellCastRequest; + class SetActionButton; + } + namespace Talent { class SetSpecialization; + class LearnTalent; } namespace Trade @@ -125,8 +157,22 @@ namespace WorldPackets namespace Misc { + class SetSelection; class ViolenceLevel; class TimeSyncResponse; + class TutorialSetFlag; + } + + namespace Movement + { + class ClientPlayerMovement; + class WorldPortAck; + class MoveTeleportAck; + } + + namespace NPC + { + class Hello; } namespace Query @@ -134,11 +180,14 @@ namespace WorldPackets class QueryCreature; class QueryPlayerName; class QueryPageText; + class QueryNPCText; + class DBQueryBulk; } - namespace Movement + namespace Quest { - class ClientPlayerMovement; + class QuestGiverStatusQuery; + class QuestGiverStatusMultipleQuery; } } @@ -161,6 +210,41 @@ enum AccountDataType #define REGISTERED_ADDON_PREFIX_SOFTCAP 64 +enum TutorialAction +{ + TUTORIAL_ACTION_UPDATE = 0, + TUTORIAL_ACTION_CLEAR = 1, + TUTORIAL_ACTION_RESET = 2 +}; + +/* +enum Tutorials +{ + TUTORIAL_TALENT = 0, + TUTORIAL_SPEC = 1, + TUTORIAL_GLYPH = 2, + TUTORIAL_SPELLBOOK = 3, + TUTORIAL_PROFESSIONS = 4, + TUTORIAL_CORE_ABILITITES = 5, + TUTORIAL_PET_JOURNAL = 6, + TUTORIAL_WHAT_HAS_CHANGED = 7, + TUTORIAL_GARRISON_BUILDING = 8, + TUTORIAL_GARRISON_MISSION_LIST = 9, + TUTORIAL_GARRISON_MISSION_PAGE = 10, + TUTORIAL_GARRISON_LANDING = 11, + TUTORIAL_GARRISON_ZONE_ABILITY = 12, + TUTORIAL_WORLD_MAP_FRAME = 13, + TUTORIAL_CLEAN_UP_BAGS = 14, + TUTORIAL_BAG_SETTINGS = 15, + TUTORIAL_REAGENT_BANK_UNLOCK = 16, + TUTORIAL_TOYBOX_FAVORITE = 17, + TUTORIAL_TOYBOX_MOUSEWHEEL_PAGING = 18, + TUTORIAL_LFG_LIST = 19 +}; +*/ + +#define MAX_ACCOUNT_TUTORIAL_VALUES 8 + struct AccountData { time_t Time = 0; @@ -302,7 +386,9 @@ class WorldSession AccountTypes GetSecurity() const { return _security; } uint32 GetAccountId() const { return _accountId; } + ObjectGuid GetAccountGUID() const { return ObjectGuid::Create<HighGuid::WowAccount>(GetAccountId()); } uint32 GetBattlenetAccountId() const { return _battlenetAccountId; } + ObjectGuid GetBattlenetAccountGUID() const { return ObjectGuid::Create<HighGuid::BNetAccount>(GetBattlenetAccountId()); } Player* GetPlayer() const { return _player; } std::string const& GetPlayerName() const; std::string GetPlayerInfo() const; @@ -377,21 +463,21 @@ class WorldSession bool CheckStableMaster(ObjectGuid guid); // Account Data - AccountData const* GetAccountData(AccountDataType type) const { return &m_accountData[type]; } - void SetAccountData(AccountDataType type, time_t tm, std::string const& data); + AccountData const* GetAccountData(AccountDataType type) const { return &_accountData[type]; } + void SetAccountData(AccountDataType type, uint32 time, std::string const& data); void LoadGlobalAccountData(); void LoadAccountData(PreparedQueryResult result, uint32 mask); void LoadTutorialsData(); void SendTutorialsData(); void SaveTutorialsData(SQLTransaction& trans); - uint32 GetTutorialInt(uint8 index) const { return m_Tutorials[index]; } + uint32 GetTutorialInt(uint8 index) const { return _tutorials[index]; } void SetTutorialInt(uint8 index, uint32 value) { - if (m_Tutorials[index] != value) + if (_tutorials[index] != value) { - m_Tutorials[index] = value; - m_TutorialsChanged = true; + _tutorials[index] = value; + _tutorialsChanged = true; } } //used with item_page table @@ -547,7 +633,7 @@ class WorldSession // Knockback void HandleMoveKnockBackAck(WorldPacket& recvPacket); - void HandleMoveTeleportAck(WorldPacket& recvPacket); + void HandleMoveTeleportAck(WorldPackets::Movement::MoveTeleportAck& packet); void HandleForceSpeedChangeAck(WorldPacket& recvData); void HandleSetCollisionHeightAck(WorldPacket& recvPacket); @@ -575,7 +661,7 @@ class WorldSession void HandleTogglePvP(WorldPacket& recvPacket); void HandleZoneUpdateOpcode(WorldPacket& recvPacket); - void HandleSetSelectionOpcode(WorldPacket& recvPacket); + void HandleSetSelectionOpcode(WorldPackets::Misc::SetSelection& packet); void HandleStandStateChangeOpcode(WorldPacket& recvPacket); void HandleEmoteOpcode(WorldPacket& recvPacket); void HandleContactListOpcode(WorldPacket& recvPacket); @@ -597,21 +683,20 @@ class WorldSession void HandleUpdateAccountData(WorldPackets::ClientConfig::UserClientUpdateAccountData& packet); void HandleRequestAccountData(WorldPackets::ClientConfig::RequestAccountData& request); - void HandleSetActionButtonOpcode(WorldPacket& recvPacket); + void HandleSetActionButtonOpcode(WorldPackets::Spells::SetActionButton& packet); void HandleGameObjectUseOpcode(WorldPacket& recPacket); void HandleMeetingStoneInfo(WorldPacket& recPacket); void HandleGameobjectReportUse(WorldPacket& recvPacket); void HandleNameQueryOpcode(WorldPackets::Query::QueryPlayerName& packet); - void HandleQueryTimeOpcode(WorldPacket& recvPacket); - void HandleCreatureQuery(WorldPackets::Query::QueryCreature& packet); + void HandleDBQueryBulk(WorldPackets::Query::DBQueryBulk& packet); void HandleGameObjectQueryOpcode(WorldPacket& recvPacket); - void HandleMoveWorldportAckOpcode(WorldPacket& recvPacket); + void HandleMoveWorldportAckOpcode(WorldPackets::Movement::WorldPortAck& packet); void HandleMoveWorldportAckOpcode(); // for server-side calls void HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMovement& packet); @@ -706,16 +791,16 @@ class WorldSession void SendActivateTaxiReply(ActivateTaxiReply reply); void HandleTabardVendorActivateOpcode(WorldPacket& recvPacket); - void HandleBankerActivateOpcode(WorldPacket& recvPacket); + void HandleBankerActivateOpcode(WorldPackets::NPC::Hello& packet); void HandleBuyBankSlotOpcode(WorldPacket& recvPacket); - void HandleTrainerListOpcode(WorldPacket& recvPacket); + void HandleTrainerListOpcode(WorldPackets::NPC::Hello& packet); void HandleTrainerBuySpellOpcode(WorldPacket& recvPacket); void HandlePetitionShowListOpcode(WorldPacket& recvPacket); - void HandleGossipHelloOpcode(WorldPacket& recvPacket); + void HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet); void HandleGossipSelectOptionOpcode(WorldPacket& recvPacket); void HandleSpiritHealerActivateOpcode(WorldPacket& recvPacket); - void HandleNpcTextQueryOpcode(WorldPacket& recvPacket); - void HandleBinderActivateOpcode(WorldPacket& recvPacket); + void HandleNpcTextQueryOpcode(WorldPackets::Query::QueryNPCText& packet); + void HandleBinderActivateOpcode(WorldPackets::NPC::Hello& packet); void HandleListStabledPetsOpcode(WorldPacket& recvPacket); void HandleStablePet(WorldPacket& recvPacket); void HandleStablePetCallback(PreparedQueryResult result); @@ -770,7 +855,7 @@ class WorldSession void HandleSellItemOpcode(WorldPacket& recvPacket); void HandleBuyItemInSlotOpcode(WorldPacket& recvPacket); void HandleBuyItemOpcode(WorldPacket& recvPacket); - void HandleListInventoryOpcode(WorldPacket& recvPacket); + void HandleListInventoryOpcode(WorldPackets::NPC::Hello& packet); void HandleAutoStoreBagItemOpcode(WorldPacket& recvPacket); void HandleReadItem(WorldPacket& recvPacket); void HandleAutoEquipItemSlotOpcode(WorldPacket& recvPacket); @@ -786,20 +871,20 @@ class WorldSession void HandleUseItemOpcode(WorldPacket& recvPacket); void HandleOpenItemOpcode(WorldPacket& recvPacket); - void HandleCastSpellOpcode(WorldPacket& recvPacket); + void HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest); void HandleCancelCastOpcode(WorldPacket& recvPacket); void HandleCancelAuraOpcode(WorldPacket& recvPacket); void HandleCancelGrowthAuraOpcode(WorldPacket& recvPacket); void HandleCancelAutoRepeatSpellOpcode(WorldPacket& recvPacket); - void HandleLearnTalentOpcode(WorldPacket& recvPacket); + void HandleLearnTalentOpcode(WorldPackets::Talent::LearnTalent& packet); void HandleLearnPreviewTalents(WorldPacket& recvPacket); void HandleTalentWipeConfirmOpcode(WorldPacket& recvPacket); void HandleUnlearnSkillOpcode(WorldPacket& recvPacket); void HandleSetSpecializationOpcode(WorldPackets::Talent::SetSpecialization& packet); - void HandleQuestgiverStatusQueryOpcode(WorldPacket& recvPacket); - void HandleQuestgiverStatusMultipleQuery(WorldPacket& recvPacket); + void HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestGiverStatusQuery& packet); + void HandleQuestgiverStatusMultipleQuery(WorldPackets::Quest::QuestGiverStatusMultipleQuery& packet); void HandleQuestgiverHelloOpcode(WorldPacket& recvPacket); void HandleQuestgiverAcceptQuestOpcode(WorldPacket& recvPacket); void HandleQuestgiverQueryQuestOpcode(WorldPacket& recvPacket); @@ -815,13 +900,21 @@ class WorldSession void HandlePushQuestToParty(WorldPacket& recvPacket); void HandleQuestPushResult(WorldPacket& recvPacket); - void HandleMessagechatOpcode(WorldPacket& recvPacket); - void HandleAddonMessagechatOpcode(WorldPacket& recvPacket); + void HandleChatMessageOpcode(WorldPackets::Chat::ChatMessage& packet); + void HandleChatMessageWhisperOpcode(WorldPackets::Chat::ChatMessageWhisper& packet); + void HandleChatMessageChannelOpcode(WorldPackets::Chat::ChatMessageChannel& packet); + void HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, std::string target = ""); + void HandleChatAddonMessageOpcode(WorldPackets::Chat::ChatAddonMessage& packet); + void HandleChatAddonMessageWhisperOpcode(WorldPackets::Chat::ChatAddonMessageWhisper& packet); + void HandleChatAddonMessage(ChatMsg type, std::string prefix, std::string text, std::string target = ""); + void HandleChatMessageAFKOpcode(WorldPackets::Chat::ChatMessageAFK& packet); + void HandleChatMessageDNDOpcode(WorldPackets::Chat::ChatMessageDND& packet); + void HandleChatMessageEmoteOpcode(WorldPackets::Chat::ChatMessageEmote& packet); void SendPlayerNotFoundNotice(std::string const& name); void SendPlayerAmbiguousNotice(std::string const& name); void SendWrongFactionNotice(); void SendChatRestrictedNotice(ChatRestrictionType restriction); - void HandleTextEmoteOpcode(WorldPacket& recvPacket); + void HandleTextEmoteOpcode(WorldPackets::Chat::CTextEmote& packet); void HandleChatIgnoredOpcode(WorldPacket& recvPacket); void HandleUnregisterAddonPrefixesOpcode(WorldPacket& recvPacket); @@ -833,9 +926,9 @@ class WorldSession void HandleResurrectResponseOpcode(WorldPacket& recvPacket); void HandleSummonResponseOpcode(WorldPacket& recvData); - void HandleJoinChannel(WorldPacket& recvPacket); - void HandleLeaveChannel(WorldPacket& recvPacket); - void HandleChannelList(WorldPacket& recvPacket); + void HandleJoinChannel(WorldPackets::Channel::JoinChannel& packet); + void HandleLeaveChannel(WorldPackets::Channel::LeaveChannel& packet); + void HandleChannelList(WorldPackets::Channel::ChannelListRequest& packet); void HandleChannelPassword(WorldPacket& recvPacket); void HandleChannelSetOwner(WorldPacket& recvPacket); void HandleChannelOwner(WorldPacket& recvPacket); @@ -850,7 +943,6 @@ class WorldSession void HandleChannelAnnouncements(WorldPacket& recvPacket); void HandleChannelModerate(WorldPacket& recvPacket); void HandleChannelDeclineInvite(WorldPacket& recvPacket); - void HandleChannelDisplayListQuery(WorldPacket& recvPacket); void HandleGetChannelMemberCount(WorldPacket& recvPacket); void HandleSetChannelWatch(WorldPacket& recvPacket); @@ -859,9 +951,7 @@ class WorldSession void HandlePageTextQueryOpcode(WorldPackets::Query::QueryPageText& packet); - void HandleTutorialFlag (WorldPacket& recvData); - void HandleTutorialClear(WorldPacket& recvData); - void HandleTutorialReset(WorldPacket& recvData); + void HandleTutorialFlag(WorldPackets::Misc::TutorialSetFlag& packet); //Pet void HandlePetAction(WorldPacket& recvData); @@ -873,7 +963,7 @@ class WorldSession void HandlePetRename(WorldPacket& recvData); void HandlePetCancelAuraOpcode(WorldPacket& recvPacket); void HandlePetSpellAutocastOpcode(WorldPacket& recvPacket); - void HandlePetCastSpellOpcode(WorldPacket& recvPacket); + void HandlePetCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest); void HandlePetLearnTalent(WorldPacket& recvPacket); void HandleLearnPreviewTalentsPet(WorldPacket& recvPacket); @@ -1046,7 +1136,7 @@ class WorldSession void HandleRemoveGlyph(WorldPacket& recvData); void HandleQueryInspectAchievements(WorldPacket& recvData); void HandleGuildAchievementProgressQuery(WorldPacket& recvData); - void HandleEquipmentSetSave(WorldPacket& recvData); + void HandleEquipmentSetSave(WorldPackets::EquipmentSet::SaveEquipmentSet& packet); void HandleEquipmentSetDelete(WorldPacket& recvData); void HandleEquipmentSetUse(WorldPacket& recvData); void HandleWorldStateUITimerUpdate(WorldPacket& recvData); @@ -1056,7 +1146,6 @@ class WorldSession void HandleEjectPassenger(WorldPacket& data); void HandleEnterPlayerVehicle(WorldPacket& data); void HandleUpdateProjectilePosition(WorldPacket& recvPacket); - void HandleRequestHotfix(WorldPacket& recvPacket); void HandleUpdateMissileTrajectory(WorldPacket& recvPacket); void HandleViolenceLevel(WorldPackets::Misc::ViolenceLevel& violenceLevel); void HandleObjectUpdateFailedOpcode(WorldPacket& recvPacket); @@ -1141,7 +1230,7 @@ class WorldSession ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set) Player* _player; - std::shared_ptr<WorldSocket> m_Socket[2]; + std::shared_ptr<WorldSocket> m_Socket[MAX_CONNECTION_TYPES]; std::string m_Address; // Current Remote Address // std::string m_LAddress; // Last Attempted Remote Adress - we can not set attempted ip for a non-existing session! @@ -1165,9 +1254,9 @@ class WorldSession LocaleConstant m_sessionDbLocaleIndex; std::atomic<uint32> m_latency; std::atomic<uint32> m_clientTimeDelay; - AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; - uint32 m_Tutorials[MAX_ACCOUNT_TUTORIAL_VALUES]; - bool m_TutorialsChanged; + AccountData _accountData[NUM_ACCOUNT_DATA_TYPES]; + uint32 _tutorials[MAX_ACCOUNT_TUTORIAL_VALUES]; + bool _tutorialsChanged; AddonsList m_addonsList; std::vector<std::string> _registeredAddonPrefixes; bool _filterAddonMessages; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index aa1426d5fd2..7f4b2cc906e 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -55,8 +55,8 @@ uint32 const SizeOfClientHeader[2][2] = uint32 const SizeOfServerHeader[2] = { sizeof(uint16) + sizeof(uint32), sizeof(uint32) }; WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket)), - _type(CONNECTION_TYPE_REALM), _authSeed(rand32()), - _OverSpeedPings(0), _worldSession(nullptr), _initialized(false) + _type(CONNECTION_TYPE_REALM), _authSeed(rand32()), _OverSpeedPings(0), + _worldSession(nullptr), _compressionStream(nullptr), _initialized(false) { _headerBuffer.Resize(SizeOfClientHeader[0][0]); } diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 628e4e0721d..e75a3424c2f 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -23,14 +23,12 @@ enum AURA_FLAGS { AFLAG_NONE = 0x00, - AFLAG_EFF_INDEX_0 = 0x01, - AFLAG_EFF_INDEX_1 = 0x02, - AFLAG_EFF_INDEX_2 = 0x04, - AFLAG_CASTER = 0x08, - AFLAG_POSITIVE = 0x10, - AFLAG_DURATION = 0x20, - AFLAG_ANY_EFFECT_AMOUNT_SENT = 0x40, // used with AFLAG_EFF_INDEX_0/1/2 - AFLAG_NEGATIVE = 0x80 + AFLAG_NOCASTER = 0x01, + AFLAG_POSITIVE = 0x02, + AFLAG_DURATION = 0x04, + AFLAG_SCALABLE = 0x08, + AFLAG_NEGATIVE = 0x10, + AFLAG_UNK20 = 0x20 }; // these are modes, in which aura effect handler may be called @@ -430,7 +428,114 @@ enum AuraType SPELL_AURA_368 = 368, // Not used in 4.3.4 SPELL_AURA_ENABLE_POWER_BAR_TIMER = 369, SPELL_AURA_SET_FAIR_FAR_CLIP = 370, // Overrides client's View Distance setting to max("Fair", current_setting) - TOTAL_AURAS = 371 // 4.3.4 + SPELL_AURA_371 = 371, + SPELL_AURA_372 = 372, + SPELL_AURA_373 = 373, + SPELL_AURA_374 = 374, + SPELL_AURA_375 = 375, + SPELL_AURA_376 = 376, + SPELL_AURA_377 = 377, + SPELL_AURA_378 = 378, + SPELL_AURA_379 = 379, + SPELL_AURA_380 = 380, + SPELL_AURA_381 = 381, + SPELL_AURA_382 = 382, + SPELL_AURA_383 = 383, + SPELL_AURA_384 = 384, + SPELL_AURA_385 = 385, + SPELL_AURA_386 = 386, + SPELL_AURA_387 = 387, + SPELL_AURA_388 = 388, + SPELL_AURA_389 = 389, + SPELL_AURA_390 = 390, + SPELL_AURA_391 = 391, + SPELL_AURA_392 = 392, + SPELL_AURA_393 = 393, + SPELL_AURA_394 = 394, + SPELL_AURA_395 = 395, + SPELL_AURA_396 = 396, + SPELL_AURA_397 = 397, + SPELL_AURA_398 = 398, + SPELL_AURA_399 = 399, + SPELL_AURA_400 = 400, + SPELL_AURA_401 = 401, + SPELL_AURA_402 = 402, + SPELL_AURA_403 = 403, + SPELL_AURA_404 = 404, + SPELL_AURA_405 = 405, + SPELL_AURA_406 = 406, + SPELL_AURA_407 = 407, + SPELL_AURA_408 = 408, + SPELL_AURA_409 = 409, + SPELL_AURA_410 = 410, + SPELL_AURA_411 = 411, + SPELL_AURA_412 = 412, + SPELL_AURA_413 = 413, + SPELL_AURA_414 = 414, + SPELL_AURA_415 = 415, + SPELL_AURA_416 = 416, + SPELL_AURA_417 = 417, + SPELL_AURA_418 = 418, + SPELL_AURA_419 = 419, + SPELL_AURA_420 = 420, + SPELL_AURA_421 = 421, + SPELL_AURA_422 = 422, + SPELL_AURA_423 = 423, + SPELL_AURA_424 = 424, + SPELL_AURA_425 = 425, + SPELL_AURA_426 = 426, + SPELL_AURA_427 = 427, + SPELL_AURA_428 = 428, + SPELL_AURA_429 = 429, + SPELL_AURA_430 = 430, + SPELL_AURA_431 = 431, + SPELL_AURA_432 = 432, + SPELL_AURA_433 = 433, + SPELL_AURA_434 = 434, + SPELL_AURA_435 = 435, + SPELL_AURA_436 = 436, + SPELL_AURA_437 = 437, + SPELL_AURA_438 = 438, + SPELL_AURA_439 = 439, + SPELL_AURA_440 = 440, + SPELL_AURA_441 = 441, + SPELL_AURA_442 = 442, + SPELL_AURA_443 = 443, + SPELL_AURA_444 = 444, + SPELL_AURA_445 = 445, + SPELL_AURA_446 = 446, + SPELL_AURA_447 = 447, + SPELL_AURA_448 = 448, + SPELL_AURA_449 = 449, + SPELL_AURA_450 = 450, + SPELL_AURA_451 = 451, + SPELL_AURA_452 = 452, + SPELL_AURA_453 = 453, + SPELL_AURA_454 = 454, + SPELL_AURA_455 = 455, + SPELL_AURA_456 = 456, + SPELL_AURA_457 = 457, + SPELL_AURA_458 = 458, + SPELL_AURA_459 = 459, + SPELL_AURA_460 = 460, + SPELL_AURA_461 = 461, + SPELL_AURA_462 = 462, + SPELL_AURA_463 = 463, + SPELL_AURA_464 = 464, + SPELL_AURA_465 = 465, + SPELL_AURA_466 = 466, + SPELL_AURA_467 = 467, + SPELL_AURA_468 = 468, + SPELL_AURA_469 = 469, + SPELL_AURA_471 = 471, + SPELL_AURA_472 = 472, + SPELL_AURA_473 = 473, + SPELL_AURA_474 = 474, + SPELL_AURA_475 = 475, + SPELL_AURA_476 = 476, + SPELL_AURA_477 = 477, + SPELL_AURA_478 = 478, + TOTAL_AURAS = 479 // 4.3.4 }; enum AuraObjectType diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index c55c92d296e..88cb4c942b9 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -429,11 +429,119 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleUnused, //368 unused (4.3.4) &AuraEffect::HandleNULL, //369 SPELL_AURA_ENABLE_POWER_BAR_TIMER &AuraEffect::HandleNULL, //370 SPELL_AURA_SET_FAIR_FAR_CLIP + &AuraEffect::HandleNULL, //371 + &AuraEffect::HandleNULL, //372 + &AuraEffect::HandleNULL, //373 + &AuraEffect::HandleNULL, //374 + &AuraEffect::HandleNULL, //375 + &AuraEffect::HandleNULL, //376 + &AuraEffect::HandleNULL, //377 + &AuraEffect::HandleNULL, //378 + &AuraEffect::HandleNULL, //379 + &AuraEffect::HandleNULL, //380 + &AuraEffect::HandleNULL, //381 + &AuraEffect::HandleNULL, //382 + &AuraEffect::HandleNULL, //383 + &AuraEffect::HandleNULL, //384 + &AuraEffect::HandleNULL, //385 + &AuraEffect::HandleNULL, //386 + &AuraEffect::HandleNULL, //387 + &AuraEffect::HandleNULL, //388 + &AuraEffect::HandleNULL, //389 + &AuraEffect::HandleNULL, //390 + &AuraEffect::HandleNULL, //391 + &AuraEffect::HandleNULL, //392 + &AuraEffect::HandleNULL, //393 + &AuraEffect::HandleNULL, //394 + &AuraEffect::HandleNULL, //395 + &AuraEffect::HandleNULL, //396 + &AuraEffect::HandleNULL, //397 + &AuraEffect::HandleNULL, //398 + &AuraEffect::HandleNULL, //399 + &AuraEffect::HandleNULL, //400 + &AuraEffect::HandleNULL, //401 + &AuraEffect::HandleNULL, //402 + &AuraEffect::HandleNULL, //403 + &AuraEffect::HandleNULL, //404 + &AuraEffect::HandleNULL, //405 + &AuraEffect::HandleNULL, //406 + &AuraEffect::HandleNULL, //407 + &AuraEffect::HandleNULL, //408 + &AuraEffect::HandleNULL, //409 + &AuraEffect::HandleNULL, //410 + &AuraEffect::HandleNULL, //411 + &AuraEffect::HandleNULL, //412 + &AuraEffect::HandleNULL, //413 + &AuraEffect::HandleNULL, //414 + &AuraEffect::HandleNULL, //415 + &AuraEffect::HandleNULL, //416 + &AuraEffect::HandleNULL, //417 + &AuraEffect::HandleNULL, //418 + &AuraEffect::HandleNULL, //419 + &AuraEffect::HandleNULL, //420 + &AuraEffect::HandleNULL, //421 + &AuraEffect::HandleNULL, //422 + &AuraEffect::HandleNULL, //423 + &AuraEffect::HandleNULL, //424 + &AuraEffect::HandleNULL, //425 + &AuraEffect::HandleNULL, //426 + &AuraEffect::HandleNULL, //427 + &AuraEffect::HandleNULL, //428 + &AuraEffect::HandleNULL, //429 + &AuraEffect::HandleNULL, //430 + &AuraEffect::HandleNULL, //431 + &AuraEffect::HandleNULL, //432 + &AuraEffect::HandleNULL, //433 + &AuraEffect::HandleNULL, //434 + &AuraEffect::HandleNULL, //435 + &AuraEffect::HandleNULL, //436 + &AuraEffect::HandleNULL, //437 + &AuraEffect::HandleNULL, //438 + &AuraEffect::HandleNULL, //439 + &AuraEffect::HandleNULL, //440 + &AuraEffect::HandleNULL, //441 + &AuraEffect::HandleNULL, //442 + &AuraEffect::HandleNULL, //443 + &AuraEffect::HandleNULL, //444 + &AuraEffect::HandleNULL, //445 + &AuraEffect::HandleNULL, //446 + &AuraEffect::HandleNULL, //447 + &AuraEffect::HandleNULL, //448 + &AuraEffect::HandleNULL, //449 + &AuraEffect::HandleNULL, //450 + &AuraEffect::HandleNULL, //451 + &AuraEffect::HandleNULL, //452 + &AuraEffect::HandleNULL, //453 + &AuraEffect::HandleNULL, //454 + &AuraEffect::HandleNULL, //455 + &AuraEffect::HandleNULL, //456 + &AuraEffect::HandleNULL, //457 + &AuraEffect::HandleNULL, //458 + &AuraEffect::HandleNULL, //459 + &AuraEffect::HandleNULL, //460 + &AuraEffect::HandleNULL, //461 + &AuraEffect::HandleNULL, //462 + &AuraEffect::HandleNULL, //463 + &AuraEffect::HandleNULL, //464 + &AuraEffect::HandleNULL, //465 + &AuraEffect::HandleNULL, //466 + &AuraEffect::HandleNULL, //467 + &AuraEffect::HandleNULL, //468 + &AuraEffect::HandleNULL, //469 + &AuraEffect::HandleNULL, //471 + &AuraEffect::HandleNULL, //472 + &AuraEffect::HandleNULL, //473 + &AuraEffect::HandleNULL, //474 + &AuraEffect::HandleNULL, //475 + &AuraEffect::HandleNULL, //476 + &AuraEffect::HandleNULL, //477 + &AuraEffect::HandleNULL, //478 }; -AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster): +AuraEffect::AuraEffect(Aura* base, uint32 effIndex, int32 *baseAmount, Unit* caster) : m_base(base), m_spellInfo(base->GetSpellInfo()), -m_baseAmount(baseAmount ? *baseAmount : m_spellInfo->Effects[effIndex].BasePoints), +_effectInfo(base->GetSpellEffectInfo(effIndex)), +m_baseAmount(baseAmount ? *baseAmount : base->GetSpellEffectInfo(effIndex)->BasePoints), m_damage(0), m_critChance(0.0f), m_donePct(1.0f), m_spellmod(NULL), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex), m_canBeRecalculated(true), m_isPeriodic(false) @@ -476,10 +584,10 @@ int32 AuraEffect::CalculateAmount(Unit* caster) // default amount calculation int32 amount = 0; - if (!(m_spellInfo->AttributesEx8 & SPELL_ATTR8_MASTERY_SPECIALIZATION) || G3D::fuzzyEq(m_spellInfo->Effects[m_effIndex].BonusCoefficient, 0.0f)) - amount = m_spellInfo->Effects[m_effIndex].CalcValue(caster, &m_baseAmount, GetBase()->GetOwner()->ToUnit()); + if (!(m_spellInfo->AttributesEx8 & SPELL_ATTR8_MASTERY_SPECIALIZATION) || G3D::fuzzyEq(GetSpellEffectInfo()->BonusCoefficient, 0.0f)) + amount = GetSpellEffectInfo()->CalcValue(caster, &m_baseAmount, GetBase()->GetOwner()->ToUnit()); else if (caster && caster->GetTypeId() == TYPEID_PLAYER) - amount = int32(caster->GetFloatValue(PLAYER_MASTERY) * m_spellInfo->Effects[m_effIndex].BonusCoefficient); + amount = int32(caster->GetFloatValue(PLAYER_MASTERY) * GetSpellEffectInfo()->BonusCoefficient); // check item enchant aura cast if (!amount && caster) @@ -604,7 +712,7 @@ int32 AuraEffect::CalculateAmount(Unit* caster) void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= true*/, bool load /*= false*/) { - m_period = m_spellInfo->Effects[m_effIndex].ApplyAuraPeriod; + m_period = GetSpellEffectInfo()->ApplyAuraPeriod; // prepare periodics switch (GetAuraType()) @@ -694,7 +802,7 @@ void AuraEffect::CalculateSpellMod() m_spellmod->type = SpellModType(uint32(GetAuraType())); // SpellModType value == spell aura types m_spellmod->spellId = GetId(); - m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask; + m_spellmod->mask = GetSpellEffectInfo()->SpellClassMask; m_spellmod->charges = GetBase()->GetCharges(); } m_spellmod->value = GetAmount(); @@ -1021,7 +1129,7 @@ bool AuraEffect::IsAffectingSpell(SpellInfo const* spell) const return false; // Check EffectClassMask - if (m_spellInfo->Effects[m_effIndex].SpellClassMask & spell->SpellFamilyFlags) + if (GetSpellEffectInfo()->SpellClassMask & spell->SpellFamilyFlags) return true; return false; } @@ -1091,6 +1199,7 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) switch (GetAuraType()) { case SPELL_AURA_PROC_TRIGGER_SPELL: + case SPELL_AURA_PROC_TRIGGER_SPELL_2: HandleProcTriggerSpellAuraProc(aurApp, eventInfo); break; case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: @@ -1105,6 +1214,9 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE: HandleRaidProcFromChargeWithValueAuraProc(aurApp, eventInfo); break; + case SPELL_AURA_PROC_ON_POWER_AMOUNT: + HandleProcTriggerSpellOnPowerAmountAuraProc(aurApp, eventInfo); + break; default: break; } @@ -1114,7 +1226,7 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) void AuraEffect::CleanupTriggeredSpells(Unit* target) { - uint32 tSpellId = m_spellInfo->Effects[GetEffIndex()].TriggerSpell; + uint32 tSpellId = GetSpellEffectInfo()->TriggerSpell; if (!tSpellId) return; @@ -1127,8 +1239,8 @@ void AuraEffect::CleanupTriggeredSpells(Unit* target) // needed for spell 43680, maybe others /// @todo is there a spell flag, which can solve this in a more sophisticated way? - if (m_spellInfo->Effects[GetEffIndex()].ApplyAuraName == SPELL_AURA_PERIODIC_TRIGGER_SPELL && - uint32(m_spellInfo->GetDuration()) == m_spellInfo->Effects[GetEffIndex()].ApplyAuraPeriod) + if (GetSpellEffectInfo()->ApplyAuraName == SPELL_AURA_PERIODIC_TRIGGER_SPELL && + uint32(m_spellInfo->GetDuration()) == GetSpellEffectInfo()->ApplyAuraPeriod) return; target->RemoveAurasDueToSpell(tSpellId, GetCasterGUID()); @@ -1268,30 +1380,6 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const target->CastSpell(target, 24932, true, NULL, this); } - // Heart of the Wild - if (AuraEffect const* heartOfTheWild = target->GetAuraEffectOfRankedSpell(17003, EFFECT_0)) - { - uint32 heartOfTheWildSpellId = 0; - int32 heartOfTheWildAmount = 0; - - switch (GetMiscValue()) - { - case FORM_CAT: - heartOfTheWildSpellId = 24900; - heartOfTheWildAmount = heartOfTheWild->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); - break; - case FORM_BEAR: - heartOfTheWildSpellId = 24899; - heartOfTheWildAmount = heartOfTheWild->GetSpellInfo()->Effects[EFFECT_2].CalcValue(); - break; - default: - break; - } - - if (heartOfTheWildSpellId) - target->CastCustomSpell(target, heartOfTheWildSpellId, &heartOfTheWildAmount, NULL, NULL, true, NULL, this); - } - switch (GetMiscValue()) { case FORM_CAT: @@ -1327,12 +1415,6 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const int32 bp = aurEff->GetAmount(); target->CastCustomSpell(target, 48418, &bp, NULL, NULL, true); } - // Survival of the Fittest - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DRUID, 961, EFFECT_0)) - { - int32 bp = aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue(GetCaster()); - target->CastCustomSpell(target, 62069, &bp, NULL, NULL, true, 0, this); - } break; case FORM_MOONKIN: // Master Shapeshifter - Moonkin @@ -2594,9 +2676,8 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo vehicleId = creatureInfo->VehicleId; //some spell has one aura of mount and one of vehicle - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (GetSpellInfo()->Effects[i].Effect == SPELL_EFFECT_SUMMON - && GetSpellInfo()->Effects[i].MiscValue == GetMiscValue()) + for (SpellEffectInfo const* effect : GetBase()->GetSpellEffectInfos()) + if (effect && effect->Effect == SPELL_EFFECT_SUMMON && effect->MiscValue == GetMiscValue()) displayId = 0; } @@ -4598,8 +4679,9 @@ void AuraEffect::HandleNoReagentUseAura(AuraApplication const* aurApp, uint8 mod flag128 mask; Unit::AuraEffectList const& noReagent = target->GetAuraEffectsByType(SPELL_AURA_NO_REAGENT_USE); - for (Unit::AuraEffectList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i) - mask |= (*i)->m_spellInfo->Effects[(*i)->m_effIndex].SpellClassMask; + for (Unit::AuraEffectList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i) + if (SpellEffectInfo const* effect = (*i)->GetSpellEffectInfo()) + mask |= effect->SpellClassMask; target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1 , mask[0]); target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+1, mask[1]); @@ -5021,11 +5103,11 @@ void AuraEffect::HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mod if (GetAmount() <= 0) return; - if (GetSpellInfo()->Effects[m_effIndex].ItemType == 0) + if (GetSpellEffectInfo()->ItemType == 0) return; // Soul Shard - if (GetSpellInfo()->Effects[m_effIndex].ItemType == 6265) + if (GetSpellEffectInfo()->ItemType == 6265) { // Soul Shard only from units that grant XP or honor if (!plCaster->isHonorOrXPTarget(target) || @@ -5038,16 +5120,16 @@ void AuraEffect::HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mod uint32 count = m_amount; ItemPosCountVec dest; - InventoryResult msg = plCaster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, GetSpellInfo()->Effects[m_effIndex].ItemType, count, &noSpaceForCount); + InventoryResult msg = plCaster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, GetSpellEffectInfo()->ItemType, count, &noSpaceForCount); if (msg != EQUIP_ERR_OK) { count-=noSpaceForCount; - plCaster->SendEquipError(msg, NULL, NULL, GetSpellInfo()->Effects[m_effIndex].ItemType); + plCaster->SendEquipError(msg, NULL, NULL, GetSpellEffectInfo()->ItemType); if (count == 0) return; } - Item* newitem = plCaster->StoreNewItem(dest, GetSpellInfo()->Effects[m_effIndex].ItemType, true); + Item* newitem = plCaster->StoreNewItem(dest, GetSpellEffectInfo()->ItemType, true); if (!newitem) { plCaster->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); @@ -5186,19 +5268,19 @@ void AuraEffect::HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, boo { Unit* target = aurApp->GetTarget(); - uint32 triggeredSpellId = sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->Effects[m_effIndex].TriggerSpell, target); + uint32 triggeredSpellId = GetSpellEffectInfo()->TriggerSpell; SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggeredSpellId); if (!triggeredSpellInfo) return; + Unit* caster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, target->GetMap()->GetDifficulty()) ? GetCaster() : target; + if (!caster) + return; + if (mode & AURA_EFFECT_HANDLE_REAL) { if (apply) { - Unit* caster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCaster() : target; - - if (!caster) - return; // If amount avalible cast with basepoints (Crypt Fever for example) if (GetAmount()) caster->CastCustomSpell(target, triggeredSpellId, &m_amount, NULL, NULL, true, NULL, this); @@ -5207,13 +5289,13 @@ void AuraEffect::HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, boo } else { - ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target->GetGUID(); + ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, caster->GetMap()->GetDifficulty()) ? GetCasterGUID() : target->GetGUID(); target->RemoveAura(triggeredSpellId, casterGUID, 0, aurApp->GetRemoveMode()); } } else if (mode & AURA_EFFECT_HANDLE_REAPPLY && apply) { - ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target->GetGUID(); + ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, caster->GetMap()->GetDifficulty()) ? GetCasterGUID() : target->GetGUID(); // change the stack amount to be equal to stack amount of our aura if (Aura* triggeredAura = target->GetAura(triggeredSpellId, casterGUID)) triggeredAura->ModStackAmount(GetBase()->GetStackAmount() - triggeredAura->GetStackAmount()); @@ -5384,7 +5466,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const } case 62292: // Blaze (Pool of Tar) // should we use custom damage? - target->CastSpell((Unit*)NULL, m_spellInfo->Effects[m_effIndex].TriggerSpell, true); + target->CastSpell((Unit*)NULL, GetSpellEffectInfo()->TriggerSpell, true); break; case 62399: // Overload Circuit if (target->GetMap()->IsDungeon() && int(target->GetAppliedAuras().count(62399)) >= (target->GetMap()->IsHeroic() ? 4 : 2)) @@ -5408,7 +5490,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const // Mirror Image if (GetId() == 55342) // Set name of summons to name of caster - target->CastSpell((Unit*)NULL, m_spellInfo->Effects[m_effIndex].TriggerSpell, true); + target->CastSpell((Unit*)NULL, GetSpellEffectInfo()->TriggerSpell, true); break; } case SPELLFAMILY_DRUID: @@ -5501,7 +5583,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) const { // generic casting code with custom spells and target/caster customs - uint32 triggerSpellId = GetSpellInfo()->Effects[GetEffIndex()].TriggerSpell; + uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId); SpellInfo const* auraSpellInfo = GetSpellInfo(); @@ -5765,7 +5847,7 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) if (triggeredSpellInfo) { - if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target) + if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, target->GetMap()->GetDifficulty()) ? caster : target) { triggerCaster->CastSpell(target, triggeredSpellInfo, true, NULL, this); TC_LOG_DEBUG("spells", "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell %u Trigger %u", GetId(), triggeredSpellInfo->Id); @@ -5782,10 +5864,10 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) void AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick(Unit* target, Unit* caster) const { - uint32 triggerSpellId = GetSpellInfo()->Effects[m_effIndex].TriggerSpell; + uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) { - if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target) + if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, target->GetMap()->GetDifficulty()) ? caster : target) { int32 basepoints = GetAmount(); triggerCaster->CastCustomSpell(target, triggerSpellId, &basepoints, &basepoints, &basepoints, true, nullptr, this); @@ -5808,7 +5890,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const } // Consecrate ticks can miss and will not show up in the combat log - if (GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA && + if (GetSpellEffectInfo()->Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA && caster->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE) return; @@ -5827,11 +5909,14 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const break; case 38772: // Grievous Wound { - uint32 percent = GetSpellInfo()->Effects[EFFECT_1].CalcValue(caster); - if (!target->HealthBelowPct(percent)) + if (SpellEffectInfo const* effect = GetSpellInfo()->GetEffect(DIFFICULTY_NONE, EFFECT_1)) { - target->RemoveAurasDueToSpell(GetSpellInfo()->Id); - return; + uint32 percent = effect->CalcValue(caster); + if (!target->HealthBelowPct(percent)) + { + target->RemoveAurasDueToSpell(GetSpellInfo()->Id); + return; + } } break; } @@ -5843,7 +5928,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); // AOE spells are not affected by the new periodic system. - bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); + bool isAreaAura = GetSpellEffectInfo()->IsAreaAuraEffect() || GetSpellEffectInfo()->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); // ignore negative values (can be result apply spellmods to aura damage uint32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; @@ -5854,11 +5939,11 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) { if (isAreaAura) - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); - damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); + damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()); // Calculate armor mitigation - if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) + if (caster->IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) { uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo()); cleanDamage.mitigated_damage += damage - damageReductedArmor; @@ -5902,7 +5987,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const damage = uint32(target->CountPctFromMaxHealth(damage)); if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) - if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) + if (GetSpellEffectInfo()->IsTargetingArea() || isAreaAura) { damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); if (caster->GetTypeId() != TYPEID_PLAYER) @@ -5950,6 +6035,18 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); } +bool AuraEffect::IsAreaAuraEffect() const +{ + if (_effectInfo->Effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || + _effectInfo->Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID || + _effectInfo->Effect == SPELL_EFFECT_APPLY_AREA_AURA_FRIEND || + _effectInfo->Effect == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY || + _effectInfo->Effect == SPELL_EFFECT_APPLY_AREA_AURA_PET || + _effectInfo->Effect == SPELL_EFFECT_APPLY_AREA_AURA_OWNER) + return true; + return false; +} + void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const { if (!caster || !target->IsAlive()) @@ -5961,7 +6058,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c return; } - if (GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA && + if (GetSpellEffectInfo()->Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA && caster->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE) return; @@ -5969,7 +6066,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); + bool isAreaAura = GetSpellEffectInfo()->IsAreaAuraEffect() || GetSpellEffectInfo()->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); // ignore negative values (can be result apply spellmods to aura damage uint32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; @@ -5977,12 +6074,12 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c { // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); + damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); } - damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()); // Calculate armor mitigation - if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) + if (caster->IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) { uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo()); cleanDamage.mitigated_damage += damage - damageReductedArmor; @@ -5990,7 +6087,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c } if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) - if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) + if (GetSpellEffectInfo()->IsTargetingArea() || isAreaAura) { damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); if (caster->GetTypeId() != TYPEID_PLAYER) @@ -6032,10 +6129,10 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); if (caster->IsAlive()) { - float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); + float gainMultiplier = GetSpellEffectInfo()->CalcValueMultiplier(caster); - uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetBase()->GetStackAmount())); - heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount())); + uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount())); + heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount())); int32 gain = caster->HealBySpell(caster, GetSpellInfo(), heal); caster->getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellInfo()); @@ -6063,7 +6160,7 @@ void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) caster->ModifyHealth(-(int32)damage); TC_LOG_DEBUG("spells", "PeriodicTick: donator %u target %u damage %u.", caster->GetEntry(), target->GetEntry(), damage); - float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); + float gainMultiplier = GetSpellEffectInfo()->CalcValueMultiplier(caster); damage = int32(damage * gainMultiplier); @@ -6089,7 +6186,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const if (GetBase()->IsPermanent() && target->IsFullHealth()) return; - bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); + bool isAreaAura = GetSpellEffectInfo()->IsAreaAuraEffect() || GetSpellEffectInfo()->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); // ignore negative values (can be result apply spellmods to aura damage int32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; @@ -6131,8 +6228,8 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const damage += addition; } if (isAreaAura) - damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellHealingPctDone(target, m_spellInfo); - damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()) * caster->SpellHealingPctDone(target, m_spellInfo); + damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()); } bool crit = false; @@ -6196,7 +6293,7 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con return; } - if (GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA && + if (GetSpellEffectInfo()->Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA && caster->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE) return; @@ -6219,7 +6316,7 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con int32 drainedAmount = -target->ModifyPower(powerType, -drainAmount); - float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); + float gainMultiplier = GetSpellEffectInfo()->CalcValueMultiplier(caster); SpellPeriodicAuraLogInfo pInfo(this, drainedAmount, 0, 0, 0, gainMultiplier, false); target->SendPeriodicAuraLog(&pInfo); @@ -6336,7 +6433,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con uint32 gain = uint32(-target->ModifyPower(powerType, -damage)); - float dmgMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); + float dmgMultiplier = GetSpellEffectInfo()->CalcValueMultiplier(caster); SpellInfo const* spellProto = GetSpellInfo(); // maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG @@ -6365,7 +6462,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve Unit* triggerCaster = aurApp->GetTarget(); Unit* triggerTarget = eventInfo.GetProcTarget(); - uint32 triggerSpellId = GetSpellInfo()->Effects[GetEffIndex()].TriggerSpell; + uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) { TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerSpellAuraProc: Triggering spell %u from aura %u proc", triggeredSpellInfo->Id, GetId()); @@ -6380,7 +6477,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp Unit* triggerCaster = aurApp->GetTarget(); Unit* triggerTarget = eventInfo.GetProcTarget(); - uint32 triggerSpellId = GetSpellInfo()->Effects[m_effIndex].TriggerSpell; + uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) { int32 basepoints0 = GetAmount(); @@ -6396,8 +6493,8 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv Unit* target = aurApp->GetTarget(); Unit* triggerTarget = eventInfo.GetProcTarget(); SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetSpellInfo()->SchoolMask); - uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE); - damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); + uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, GetSpellEffectInfo()); + damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE, GetSpellEffectInfo()); target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellInfo()); target->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); target->SendSpellNonMeleeDamageLog(&damageInfo); @@ -6438,7 +6535,7 @@ void AuraEffect::HandleRaidProcFromChargeAuraProc(AuraApplication* aurApp, ProcE { if (Unit* caster = GetCaster()) { - float radius = GetSpellInfo()->Effects[GetEffIndex()].CalcRadius(caster); + float radius = GetSpellEffectInfo()->CalcRadius(caster); if (Unit* triggerTarget = target->GetNextRandomRaidMemberOrPet(radius)) { @@ -6479,7 +6576,7 @@ void AuraEffect::HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurA { if (Unit* caster = GetCaster()) { - float radius = GetSpellInfo()->Effects[GetEffIndex()].CalcRadius(caster); + float radius = GetSpellEffectInfo()->CalcRadius(caster); if (Unit* triggerTarget = target->GetNextRandomRaidMemberOrPet(radius)) { @@ -6494,6 +6591,35 @@ void AuraEffect::HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurA target->CastCustomSpell(target, triggerSpellId, &value, NULL, NULL, true, NULL, this, GetCasterGUID()); } +void AuraEffect::HandleProcTriggerSpellOnPowerAmountAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) +{ + // Power amount required to proc the spell + int32 powerAmountRequired = GetAmount(); + // Power type required to proc + Powers powerRequired = Powers(_effectInfo->MiscValue); + + if (!powerRequired || !powerAmountRequired) + { + TC_LOG_ERROR("spells", "AuraEffect::HandleProcTriggerSpellOnPowerAmountAuraProc: Spell %u have 0 PowerAmountRequired in EffectAmount[%d] or 0 PowerRequired in EffectMiscValue", GetId(), GetEffIndex()); + return /*false*/; + } + + Unit* triggerCaster = aurApp->GetTarget(); + Unit* triggerTarget = eventInfo.GetProcTarget(); + + if (triggerCaster->GetPower(powerRequired) != powerAmountRequired) + return /*false*/; + + uint32 triggerSpellId = _effectInfo->TriggerSpell; + if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) + { + TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerSpellOnPowerAmountAuraProc: Triggering spell %u from aura %u proc", triggeredSpellInfo->Id, GetId()); + triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, nullptr, this); + } + else + TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerSpellOnPowerAmountAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); +} + void AuraEffect::HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 22571f4851e..ebfeece4c7c 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -29,13 +29,13 @@ typedef void(AuraEffect::*pAuraEffectHandler)(AuraApplication const* aurApp, uin class AuraEffect { - friend void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount); - friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID); + friend void Aura::_InitEffects(uint32 effMask, Unit* caster, int32 *baseAmount); + friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint32 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); friend Aura::~Aura(); - private: - ~AuraEffect(); - explicit AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster); + public: + ~AuraEffect(); + AuraEffect(Aura* base, uint32 effIndex, int32 *baseAmount, Unit* caster); Unit* GetCaster() const { return GetBase()->GetCaster(); } ObjectGuid GetCasterGUID() const { return GetBase()->GetCasterGUID(); } Aura* GetBase() const { return m_base; } @@ -49,9 +49,9 @@ class AuraEffect int32 GetBaseAmount() const { return m_baseAmount; } int32 GetPeriod() const { return m_period; } - int32 GetMiscValueB() const { return m_spellInfo->Effects[m_effIndex].MiscValueB; } - int32 GetMiscValue() const { return m_spellInfo->Effects[m_effIndex].MiscValue; } - AuraType GetAuraType() const { return (AuraType)m_spellInfo->Effects[m_effIndex].ApplyAuraName; } + int32 GetMiscValueB() const { return GetSpellEffectInfo()->MiscValueB; } + int32 GetMiscValue() const { return GetSpellEffectInfo()->MiscValue; } + AuraType GetAuraType() const { return (AuraType)GetSpellEffectInfo()->ApplyAuraName; } int32 GetAmount() const { return m_amount; } void SetAmount(int32 amount) { m_amount = amount; m_canBeRecalculated = false;} @@ -87,7 +87,7 @@ class AuraEffect bool IsPeriodic() const { return m_isPeriodic; } void SetPeriodic(bool isPeriodic) { m_isPeriodic = isPeriodic; } bool IsAffectingSpell(SpellInfo const* spell) const; - bool HasSpellClassMask() const { return m_spellInfo->Effects[m_effIndex].SpellClassMask; } + bool HasSpellClassMask() const { return GetSpellEffectInfo()->SpellClassMask; } void SendTickImmune(Unit* target, Unit* caster) const; void PeriodicTick(AuraApplication * aurApp, Unit* caster) const; @@ -98,10 +98,18 @@ class AuraEffect // add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras void HandleShapeshiftBoosts(Unit* target, bool apply) const; + + SpellEffectInfo const* GetSpellEffectInfo() const { return _effectInfo; } + + bool IsEffect() const { return _effectInfo->Effect != 0; } + bool IsEffect(SpellEffectName effectName) const { return _effectInfo->Effect == uint32(effectName); } + bool IsAreaAuraEffect() const; + private: Aura* const m_base; SpellInfo const* const m_spellInfo; + SpellEffectInfo const* _effectInfo; int32 const m_baseAmount; int32 m_amount; @@ -312,6 +320,7 @@ class AuraEffect void HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void HandleRaidProcFromChargeAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); + void HandleProcTriggerSpellOnPowerAmountAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); }; namespace Trinity diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 67df56d892e..9037715152a 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -26,6 +26,7 @@ #include "Unit.h" #include "Spell.h" #include "SpellAuraEffects.h" +#include "SpellPackets.h" #include "DynamicObject.h" #include "ObjectAccessor.h" #include "Util.h" @@ -37,9 +38,9 @@ #include "Vehicle.h" #include "Config.h" -AuraApplication::AuraApplication(Unit* target, Unit* caster, Aura* aura, uint8 effMask): +AuraApplication::AuraApplication(Unit* target, Unit* caster, Aura* aura, uint32 effMask): _target(target), _base(aura), _removeMode(AURA_REMOVE_NONE), _slot(MAX_AURAS), -_flags(AFLAG_NONE), _effectsToApply(effMask), _needClientUpdate(false) +_flags(AFLAG_NONE), _effectsToApply(effMask), _needClientUpdate(false), _effectMask(0) { ASSERT(GetTarget() && GetBase()); @@ -113,19 +114,19 @@ void AuraApplication::_Remove() } } -void AuraApplication::_InitFlags(Unit* caster, uint8 effMask) +void AuraApplication::_InitFlags(Unit* caster, uint32 effMask) { // mark as selfcast if needed - _flags |= (GetBase()->GetCasterGUID() == GetTarget()->GetGUID()) ? AFLAG_CASTER : AFLAG_NONE; + _flags |= (GetBase()->GetCasterGUID() == GetTarget()->GetGUID()) ? AFLAG_NONE : AFLAG_NOCASTER; // aura is cast by self or an enemy // one negative effect and we know aura is negative if (IsSelfcast() || !caster || !caster->IsFriendlyTo(GetTarget())) { bool negativeFound = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetBase()->GetSpellEffectInfos()) { - if (((1<<i) & effMask) && !GetBase()->GetSpellInfo()->IsPositiveEffect(i)) + if (effect && ((1 << effect->EffectIndex) & effMask) && !GetBase()->GetSpellInfo()->IsPositiveEffect(effect->EffectIndex)) { negativeFound = true; break; @@ -138,9 +139,9 @@ void AuraApplication::_InitFlags(Unit* caster, uint8 effMask) else { bool positiveFound = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetBase()->GetSpellEffectInfos()) { - if (((1<<i) & effMask) && GetBase()->GetSpellInfo()->IsPositiveEffect(i)) + if (effect && ((1 << effect->EffectIndex) & effMask) && GetBase()->GetSpellInfo()->IsPositiveEffect(effect->EffectIndex)) { positiveFound = true; break; @@ -150,12 +151,17 @@ void AuraApplication::_InitFlags(Unit* caster, uint8 effMask) } if (GetBase()->GetSpellInfo()->AttributesEx8 & SPELL_ATTR8_AURA_SEND_AMOUNT) - _flags |= AFLAG_ANY_EFFECT_AMOUNT_SENT; + _flags |= AFLAG_SCALABLE; } void AuraApplication::_HandleEffect(uint8 effIndex, bool apply) { AuraEffect* aurEff = GetBase()->GetEffect(effIndex); + if (!aurEff) + { + TC_LOG_ERROR("spells", "Aura %u has no effect at effectIndex %u but _HandleEffect was called", GetBase()->GetSpellInfo()->Id, uint32(effIndex)); + return; + } ASSERT(aurEff); ASSERT(HasEffect(effIndex) == (!apply)); ASSERT((1<<effIndex) & _effectsToApply); @@ -163,14 +169,14 @@ void AuraApplication::_HandleEffect(uint8 effIndex, bool apply) if (apply) { - ASSERT(!(_flags & (1<<effIndex))); - _flags |= 1<<effIndex; + ASSERT(!(_effectMask & (1<<effIndex))); + _effectMask |= 1<<effIndex; aurEff->HandleEffect(this, AURA_EFFECT_HANDLE_REAL, true); } else { - ASSERT(_flags & (1<<effIndex)); - _flags &= ~(1<<effIndex); + ASSERT(_effectMask & (1<<effIndex)); + _effectMask &= ~(1<<effIndex); aurEff->HandleEffect(this, AURA_EFFECT_HANDLE_REAL, false); // Remove all triggered by aura spells vs unlimited duration @@ -193,7 +199,7 @@ void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const Aura const* aura = GetBase(); data << uint32(aura->GetId()); - uint32 flags = _flags; + uint8 flags = _flags; if (aura->GetMaxDuration() > 0 && !(aura->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_HIDE_DURATION)) flags |= AFLAG_DURATION; data << uint16(flags); @@ -202,7 +208,7 @@ void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const // stack amount has priority over charges (checked on retail with spell 50262) data << uint8(aura->GetSpellInfo()->StackAmount ? aura->GetStackAmount() : aura->GetCharges()); - if (!(flags & AFLAG_CASTER)) + if (!(flags & AFLAG_NOCASTER)) data << aura->GetCasterGUID().WriteAsPacked(); if (flags & AFLAG_DURATION) @@ -211,44 +217,43 @@ void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const data << uint32(aura->GetDuration()); } - if (flags & AFLAG_ANY_EFFECT_AMOUNT_SENT) - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (AuraEffect const* eff = aura->GetEffect(i)) - if (HasEffect(i)) // Not all of aura's effects have to be applied on every target - data << int32(eff->GetAmount()); + if (flags & AFLAG_SCALABLE) + for (AuraEffect const* effect : GetBase()->GetAuraEffects()) + if (effect && HasEffect(effect->GetEffIndex())) // Not all of aura's effects have to be applied on every target + data << int32(effect->GetAmount()); } void AuraApplication::ClientUpdate(bool remove) { _needClientUpdate = false; - WorldPacket data(SMSG_AURA_UPDATE); - data << GetTarget()->GetPackGUID(); - BuildUpdatePacket(data, remove); + WorldPackets::Spells::SendAuraUpdate update; + update.Init(false, GetTarget()->GetGUID(), 1); + update.BuildUpdatePacket(this, remove, GetTarget()->getLevel()); // TODO 6.x should be caster's level - _target->SendMessageToSet(&data, true); + _target->SendMessageToSet(const_cast<WorldPacket*>(update.Write()), true); } -uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleEffectMask, WorldObject* owner) +uint32 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint32 avalibleEffectMask, WorldObject* owner) { ASSERT(spellProto); ASSERT(owner); - uint8 effMask = 0; + uint32 effMask = 0; switch (owner->GetTypeId()) { case TYPEID_UNIT: case TYPEID_PLAYER: - for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(owner->GetMap()->GetDifficulty())) { - if (spellProto->Effects[i].IsUnitOwnedAuraEffect()) - effMask |= 1 << i; + if (effect && effect->IsUnitOwnedAuraEffect()) + effMask |= 1 << effect->EffectIndex; } break; case TYPEID_DYNAMICOBJECT: - for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(owner->GetMap()->GetDifficulty())) { - if (spellProto->Effects[i].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) - effMask |= 1 << i; + if (effect && effect->Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) + effMask |= 1 << effect->EffectIndex; } break; default: @@ -257,7 +262,7 @@ uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleE return effMask & avalibleEffectMask; } -Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= NULL*/) +Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint32 tryEffMask, WorldObject* owner, Unit* caster, int32 *baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= NULL*/) { ASSERT(spellproto); ASSERT(owner); @@ -265,9 +270,10 @@ Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMas ASSERT(tryEffMask <= MAX_EFFECT_MASK); if (refresh) *refresh = false; - uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner); + uint32 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner); if (!effMask) return NULL; + if (Aura* foundAura = owner->ToUnit()->_TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID)) { // we've here aura, which script triggered removal after modding stack amount @@ -283,7 +289,7 @@ Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMas return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); } -Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/) +Aura* Aura::TryCreate(SpellInfo const* spellproto, uint32 tryEffMask, WorldObject* owner, Unit* caster, int32 *baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/) { ASSERT(spellproto); ASSERT(owner); @@ -295,7 +301,7 @@ Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); } -Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID) +Aura* Aura::Create(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID) { ASSERT(effMask); ASSERT(spellproto); @@ -354,7 +360,6 @@ m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEven m_duration = m_maxDuration; m_procCharges = CalcMaxCharges(caster); m_isUsingCharges = m_procCharges != 0; - memset(m_effects, 0, sizeof(m_effects)); // m_casterLevel = cast item level/caster level, caster level should be saved to db, confirmed with sniffs } @@ -366,15 +371,27 @@ AuraScript* Aura::GetScriptByName(std::string const& scriptName) const return NULL; } -void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount) +SpellEffectInfo const* Aura::GetSpellEffectInfo(uint32 index) const +{ + if (index >= _spelEffectInfos.size()) + return nullptr; + + return _spelEffectInfos[index]; +} + +void Aura::_InitEffects(uint32 effMask, Unit* caster, int32 *baseAmount) { // shouldn't be in constructor - functions in AuraEffect::AuraEffect use polymorphism - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + _spelEffectInfos = m_spellInfo->GetEffectsForDifficulty(GetOwner()->GetMap()->GetDifficulty()); + + ASSERT(!_spelEffectInfos.empty()); + + _effects.resize(GetSpellEffectInfos().size()); + + for (SpellEffectInfo const* effect : GetSpellEffectInfos()) { - if (effMask & (uint8(1) << i)) - m_effects[i] = new AuraEffect(this, i, baseAmount ? baseAmount + i : NULL, caster); - else - m_effects[i] = NULL; + if (effect && effMask & (uint8(1) << effect->EffectIndex)) + _effects[effect->EffectIndex] = new AuraEffect(this, effect->EffectIndex, baseAmount ? baseAmount + effect->EffectIndex : NULL, caster); } } @@ -389,9 +406,9 @@ Aura::~Aura() m_loadedScripts.erase(itr); } - // free effects memory - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - delete m_effects[i]; + // free effects memory todo 6.x + //for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + // delete m_effects[i]; ASSERT(m_applications.empty()); _DeleteRemovedApplications(); @@ -407,6 +424,14 @@ Unit* Aura::GetCaster() const return ObjectAccessor::GetUnit(*GetOwner(), GetCasterGUID()); } +AuraEffect* Aura::GetEffect(uint32 index) const +{ + if (index >= _effects.size()) + return nullptr; + + return _effects[index]; +} + AuraObjectType Aura::GetType() const { return (m_owner->GetTypeId() == TYPEID_DYNAMICOBJECT) ? DYNOBJ_AURA_TYPE : UNIT_AURA_TYPE; @@ -494,7 +519,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) // fill up to date target list // target, effMask - std::map<Unit*, uint8> targets; + std::map<Unit*, uint32> targets; FillTargetMap(targets, caster); @@ -503,7 +528,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) // mark all auras as ready to remove for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end();++appIter) { - std::map<Unit*, uint8>::iterator existing = targets.find(appIter->second->GetTarget()); + std::map<Unit*, uint32>::iterator existing = targets.find(appIter->second->GetTarget()); // not found in current area - remove the aura if (existing == targets.end()) targetsToRemove.push_back(appIter->second->GetTarget()); @@ -520,7 +545,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) } // register auras for units - for (std::map<Unit*, uint8>::iterator itr = targets.begin(); itr!= targets.end();) + for (std::map<Unit*, uint32>::iterator itr = targets.begin(); itr!= targets.end();) { // aura mustn't be already applied on target if (AuraApplication * aurApp = GetApplicationOfTarget(itr->first->GetGUID())) @@ -613,7 +638,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) return; // apply aura effects for units - for (std::map<Unit*, uint8>::iterator itr = targets.begin(); itr!= targets.end();++itr) + for (std::map<Unit*, uint32>::iterator itr = targets.begin(); itr!= targets.end();++itr) { if (AuraApplication * aurApp = GetApplicationOfTarget(itr->first->GetGUID())) { @@ -674,9 +699,9 @@ void Aura::UpdateOwner(uint32 diff, WorldObject* owner) m_updateTargetMapInterval -= diff; // update aura effects - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_effects[i]) - m_effects[i]->Update(diff, caster); + for (AuraEffect* effect : GetAuraEffects()) + if (effect) + effect->Update(diff, caster); // remove spellmods after effects update if (modSpell) @@ -880,9 +905,9 @@ void Aura::SetStackAmount(uint8 stackAmount) if (!(*apptItr)->GetRemoveMode()) HandleAuraSpecificMods(*apptItr, caster, false, true); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (HasEffect(i)) - m_effects[i]->ChangeAmount(m_effects[i]->CalculateAmount(caster), false, true); + for (AuraEffect* effect : GetAuraEffects()) + if (effect) + effect->ChangeAmount(effect->CalculateAmount(caster), false, true); for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr) if (!(*apptItr)->GetRemoveMode()) @@ -945,11 +970,11 @@ void Aura::RefreshSpellMods() player->RestoreAllSpellMods(0, this); } -bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const +bool Aura::HasMoreThanOneEffectForType(AuraType auraType, uint32 difficulty) const { uint32 count = 0; - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (HasEffect(i) && AuraType(GetSpellInfo()->Effects[i].ApplyAuraName) == auraType) + for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + if (effect && HasEffect(effect->EffectIndex) && AuraType(effect->ApplyAuraName) == auraType) ++count; return count > 1; @@ -957,8 +982,8 @@ bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const bool Aura::IsArea() const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (HasEffect(i) && GetSpellInfo()->Effects[i].IsAreaAuraEffect()) + for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + if (effect && HasEffect(effect->EffectIndex) && effect->IsAreaAuraEffect()) return true; return false; @@ -1020,7 +1045,7 @@ bool Aura::CanBeSaved() const bool Aura::CanBeSentToClient() const { - return !IsPassive() || GetSpellInfo()->HasAreaAuraEffect() || HasEffectType(SPELL_AURA_ABILITY_IGNORE_AURASTATE) || HasEffectType(SPELL_AURA_CAST_WHILE_WALKING); + return !IsPassive() || GetSpellInfo()->HasAreaAuraEffect(GetOwner() ? GetOwner()->GetMap()->GetDifficulty() : DIFFICULTY_NONE) || HasEffectType(SPELL_AURA_ABILITY_IGNORE_AURASTATE) || HasEffectType(SPELL_AURA_CAST_WHILE_WALKING); } bool Aura::IsSingleTargetWith(Aura const* aura) const @@ -1080,7 +1105,7 @@ int32 Aura::CalcDispelChance(Unit* auraTarget, bool offensive) const return 100 - resistChance; } -void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount) +void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 *amount) { m_maxDuration = maxduration; m_duration = duration; @@ -1088,22 +1113,23 @@ void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint m_isUsingCharges = m_procCharges != 0; m_stackAmount = stackamount; Unit* caster = GetCaster(); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_effects[i]) - { - m_effects[i]->SetAmount(amount[i]); - m_effects[i]->SetCanBeRecalculated((recalculateMask & (1 << i)) != 0); - m_effects[i]->CalculatePeriodic(caster, false, true); - m_effects[i]->CalculateSpellMod(); - m_effects[i]->RecalculateAmount(caster); - } + for (AuraEffect* effect : GetAuraEffects()) + { + if (!effect) + continue; + effect->SetAmount(amount[effect->GetEffIndex()]); + effect->SetCanBeRecalculated((recalculateMask & (1 << effect->GetEffIndex())) != 0); + effect->CalculatePeriodic(caster, false, true); + effect->CalculateSpellMod(); + effect->RecalculateAmount(caster); + } } bool Aura::HasEffectType(AuraType type) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (AuraEffect* effect : GetAuraEffects()) { - if (HasEffect(i) && m_effects[i]->GetAuraType() == type) + if (effect && effect->GetAuraType() == type) return true; } return false; @@ -1113,17 +1139,26 @@ void Aura::RecalculateAmountOfEffects() { ASSERT (!IsRemoved()); Unit* caster = GetCaster(); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (HasEffect(i)) - m_effects[i]->RecalculateAmount(caster); + for (AuraEffect* effect : GetAuraEffects()) + if (effect && !IsRemoved()) + effect->RecalculateAmount(caster); } void Aura::HandleAllEffects(AuraApplication * aurApp, uint8 mode, bool apply) { ASSERT (!IsRemoved()); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_effects[i] && !IsRemoved()) - m_effects[i]->HandleEffect(aurApp, mode, apply); + for (AuraEffect* effect : GetAuraEffects()) + if (effect && !IsRemoved()) + effect->HandleEffect(aurApp, mode, apply); +} + +uint32 Aura::GetEffectMask() const +{ + uint32 effMask = 0; + for (AuraEffect* effect : GetAuraEffects()) + if (effect) + effMask |= 1 << effect->GetEffIndex(); + return effMask; } void Aura::GetApplicationList(std::list<AuraApplication*> & applicationList) const @@ -1310,8 +1345,8 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b // Improved Devouring Plague if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 0)) { - uint32 damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), GetEffect(0)->GetAmount(), DOT); - damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT); + uint32 damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), GetEffect(0)->GetAmount(), DOT, GetEffect(0)->GetSpellEffectInfo()); + damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetEffect(0)->GetSpellEffectInfo()); int32 basepoints0 = aurEff->GetAmount() * GetEffect(0)->GetTotalTicks() * int32(damage) / 100; int32 heal = int32(CalculatePct(basepoints0, 15)); @@ -1517,47 +1552,40 @@ void Aura::HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* cast if (!caster || aurApp->GetRemoveMode()) return; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (AuraEffect* effect : GetAuraEffects()) { - if (!HasEffect(i)) + if (!effect || effect->IsAreaAuraEffect() || effect->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) continue; - if (m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) - continue; - - switch (m_spellInfo->Effects[i].ApplyAuraName) + switch (effect->GetSpellEffectInfo()->ApplyAuraName) { case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: case SPELL_AURA_PERIODIC_LEECH: { - AuraEffect* aurEff = GetEffect(i); - // ignore non positive values (can be result apply spellmods to aura damage - uint32 damage = std::max(aurEff->GetAmount(), 0); + uint32 damage = std::max(effect->GetAmount(), 0); // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); - aurEff->SetDonePct(caster->SpellDamagePctDone(target, m_spellInfo, DOT)); // Calculate done percentage first! - aurEff->SetDamage(caster->SpellDamageBonusDone(target, m_spellInfo, damage, DOT, GetStackAmount()) * aurEff->GetDonePct()); - aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); + effect->SetDonePct(caster->SpellDamagePctDone(target, m_spellInfo, DOT)); // Calculate done percentage first! + effect->SetDamage(caster->SpellDamageBonusDone(target, m_spellInfo, damage, DOT, effect->GetSpellEffectInfo(), GetStackAmount()) * effect->GetDonePct()); + effect->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); break; } case SPELL_AURA_PERIODIC_HEAL: case SPELL_AURA_OBS_MOD_HEALTH: { - AuraEffect* aurEff = GetEffect(i); - // ignore non positive values (can be result apply spellmods to aura damage - uint32 damage = std::max(aurEff->GetAmount(), 0); + uint32 damage = std::max(effect->GetAmount(), 0); // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); - aurEff->SetDonePct(caster->SpellHealingPctDone(target, m_spellInfo)); // Calculate done percentage first! - aurEff->SetDamage(caster->SpellHealingBonusDone(target, m_spellInfo, damage, DOT, GetStackAmount()) * aurEff->GetDonePct()); - aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); + effect->SetDonePct(caster->SpellHealingPctDone(target, m_spellInfo)); // Calculate done percentage first! + effect->SetDamage(caster->SpellHealingBonusDone(target, m_spellInfo, damage, DOT, effect->GetSpellEffectInfo(), GetStackAmount()) * effect->GetDonePct()); + effect->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); break; } default: @@ -1605,12 +1633,17 @@ bool Aura::CanStackWith(Aura const* existingAura) const if (IsPassive() && sameCaster && m_spellInfo->IsDifferentRankOf(existingSpellInfo)) return false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : existingAura->GetSpellEffectInfos()) { // prevent remove triggering aura by triggered aura - if (existingSpellInfo->Effects[i].TriggerSpell == GetId() - // prevent remove triggered aura by triggering aura refresh - || m_spellInfo->Effects[i].TriggerSpell == existingAura->GetId()) + if (effect && effect->TriggerSpell == GetId()) + return true; + } + + for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + { + // prevent remove triggered aura by triggering aura refresh + if (effect && effect->TriggerSpell == existingAura->GetId()) return true; } @@ -1620,7 +1653,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const // * The minimap tracking list will only show a check mark next to the last skill activated // Sometimes this bugs out and doesn't switch the check mark. It has no effect on the actual tracking though. // * The minimap dots are yellow for both resources - if (m_spellInfo->HasAura(SPELL_AURA_TRACK_RESOURCES) && existingSpellInfo->HasAura(SPELL_AURA_TRACK_RESOURCES)) + if (m_spellInfo->HasAura(GetOwner()->GetMap()->GetDifficulty(), SPELL_AURA_TRACK_RESOURCES) && existingSpellInfo->HasAura(GetOwner()->GetMap()->GetDifficulty(), SPELL_AURA_TRACK_RESOURCES)) return sWorld->getBoolConfig(CONFIG_ALLOW_TRACK_BOTH_RESOURCES); // check spell specific stack rules @@ -1659,7 +1692,10 @@ bool Aura::CanStackWith(Aura const* existingAura) const // check same periodic auras for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - switch (m_spellInfo->Effects[i].ApplyAuraName) + SpellEffectInfo const* effect = GetSpellEffectInfo(i); + if (!effect) + continue; + switch (effect->ApplyAuraName) { // DOT or HOT from different casters will stack case SPELL_AURA_PERIODIC_DAMAGE: @@ -1673,9 +1709,12 @@ bool Aura::CanStackWith(Aura const* existingAura) const case SPELL_AURA_OBS_MOD_POWER: case SPELL_AURA_OBS_MOD_HEALTH: case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: - // periodic auras which target areas are not allowed to stack this way (replenishment for example) - if (m_spellInfo->Effects[i].IsTargetingArea() || existingSpellInfo->Effects[i].IsTargetingArea()) - break; + { + SpellEffectInfo const* existingEffect = GetSpellEffectInfo(i); + // periodic auras which target areas are not allowed to stack this way (replenishment for example) + if (effect->IsTargetingArea() || (existingEffect && existingEffect->IsTargetingArea())) + break; + } return true; default: break; @@ -2246,7 +2285,7 @@ void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraAppli } } -UnitAura::UnitAura(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID) +UnitAura::UnitAura(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID) : Aura(spellproto, owner, caster, castItem, casterGUID) { m_AuraDRGroup = DIMINISHING_NONE; @@ -2280,31 +2319,31 @@ void UnitAura::Remove(AuraRemoveMode removeMode) GetUnitOwner()->RemoveOwnedAura(this, removeMode); } -void UnitAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) +void UnitAura::FillTargetMap(std::map<Unit*, uint32> & targets, Unit* caster) { - for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + for (SpellEffectInfo const* effect : GetSpellEffectInfos()) { - if (!HasEffect(effIndex)) + if (!effect || !HasEffect(effect->EffectIndex)) continue; UnitList targetList; // non-area aura - if (GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AURA) + if (effect->Effect == SPELL_EFFECT_APPLY_AURA) { targetList.push_back(GetUnitOwner()); } else { - float radius = GetSpellInfo()->Effects[effIndex].CalcRadius(caster); + float radius = effect->CalcRadius(caster); if (!GetUnitOwner()->HasUnitState(UNIT_STATE_ISOLATED)) { - switch (GetSpellInfo()->Effects[effIndex].Effect) + switch (effect->Effect) { case SPELL_EFFECT_APPLY_AREA_AURA_PARTY: case SPELL_EFFECT_APPLY_AREA_AURA_RAID: { targetList.push_back(GetUnitOwner()); - Trinity::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID); + Trinity::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, effect->Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID); Trinity::UnitListSearcher<Trinity::AnyGroupedUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check); GetUnitOwner()->VisitNearbyObject(radius, searcher); break; @@ -2340,16 +2379,16 @@ void UnitAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) for (UnitList::iterator itr = targetList.begin(); itr!= targetList.end();++itr) { - std::map<Unit*, uint8>::iterator existing = targets.find(*itr); + std::map<Unit*, uint32>::iterator existing = targets.find(*itr); if (existing != targets.end()) - existing->second |= 1<<effIndex; + existing->second |= 1 << effect->EffectIndex; else - targets[*itr] = 1<<effIndex; + targets[*itr] = 1 << effect->EffectIndex; } } } -DynObjAura::DynObjAura(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID) +DynObjAura::DynObjAura(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID) : Aura(spellproto, owner, caster, castItem, casterGUID) { LoadScripts(); @@ -2374,18 +2413,18 @@ void DynObjAura::Remove(AuraRemoveMode removeMode) _Remove(removeMode); } -void DynObjAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* /*caster*/) +void DynObjAura::FillTargetMap(std::map<Unit*, uint32> & targets, Unit* /*caster*/) { Unit* dynObjOwnerCaster = GetDynobjOwner()->GetCaster(); float radius = GetDynobjOwner()->GetRadius(); - for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + for (SpellEffectInfo const* effect : GetSpellEffectInfos()) { - if (!HasEffect(effIndex)) + if (!effect || !HasEffect(effect->EffectIndex)) continue; UnitList targetList; - if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY - || GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY) + if (effect->TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY + || effect->TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY) { Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius); Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check); @@ -2400,11 +2439,11 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* /*caster* for (UnitList::iterator itr = targetList.begin(); itr!= targetList.end();++itr) { - std::map<Unit*, uint8>::iterator existing = targets.find(*itr); + std::map<Unit*, uint32>::iterator existing = targets.find(*itr); if (existing != targets.end()) - existing->second |= 1<<effIndex; + existing->second |= 1 << effect->EffectIndex; else - targets[*itr] = 1<<effIndex; + targets[*itr] = 1 << effect->EffectIndex; } } } diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index f69d9baafe0..c2c356efa4b 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -41,24 +41,25 @@ class ChargeDropEvent; class AuraApplication { - friend void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask); + friend void Unit::_ApplyAura(AuraApplication * aurApp, uint32 effMask); friend void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode); friend void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex); friend void Unit::RemoveAura(AuraApplication * aurApp, AuraRemoveMode mode); - friend AuraApplication * Unit::_CreateAuraApplication(Aura* aura, uint8 effMask); + friend AuraApplication * Unit::_CreateAuraApplication(Aura* aura, uint32 effMask); private: Unit* const _target; Aura* const _base; AuraRemoveMode _removeMode:8; // Store info for know remove aura reason uint8 _slot; // Aura slot on unit uint8 _flags; // Aura info flag - uint8 _effectsToApply; // Used only at spell hit to determine which effect should be applied + uint32 _effectsToApply; // Used only at spell hit to determine which effect should be applied bool _needClientUpdate:1; + uint32 _effectMask; - explicit AuraApplication(Unit* target, Unit* caster, Aura* base, uint8 effMask); + explicit AuraApplication(Unit* target, Unit* caster, Aura* base, uint32 effMask); void _Remove(); private: - void _InitFlags(Unit* caster, uint8 effMask); + void _InitFlags(Unit* caster, uint32 effMask); void _HandleEffect(uint8 effIndex, bool apply); public: @@ -67,10 +68,10 @@ class AuraApplication uint8 GetSlot() const { return _slot; } uint8 GetFlags() const { return _flags; } - uint8 GetEffectMask() const { return _flags & (AFLAG_EFF_INDEX_0 | AFLAG_EFF_INDEX_1 | AFLAG_EFF_INDEX_2); } - bool HasEffect(uint8 effect) const { ASSERT(effect < MAX_SPELL_EFFECTS); return (_flags & (1 << effect)) != 0; } + uint32 GetEffectMask() const { return _effectMask; } + bool HasEffect(uint8 effect) const { ASSERT(effect < MAX_SPELL_EFFECTS); return (_effectMask & (1 << effect)) != 0; } bool IsPositive() const { return (_flags & AFLAG_POSITIVE) != 0; } - bool IsSelfcast() const { return (_flags & AFLAG_CASTER) != 0; } + bool IsSelfcast() const { return (_flags & AFLAG_NOCASTER) == 0; } uint8 GetEffectsToApply() const { return _effectsToApply; } void SetRemoveMode(AuraRemoveMode mode) { _removeMode = mode; } @@ -84,16 +85,16 @@ class AuraApplication class Aura { - friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint32 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); public: typedef std::map<ObjectGuid, AuraApplication*> ApplicationMap; - static uint8 BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleEffectMask, WorldObject* owner); - static Aura* TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty, bool* refresh = NULL); - static Aura* TryCreate(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty); - static Aura* Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID); + static uint32 BuildEffectMaskForOwner(SpellInfo const* spellProto, uint32 avalibleEffectMask, WorldObject* owner); + static Aura* TryRefreshStackOrCreate(SpellInfo const* spellproto, uint32 tryEffMask, WorldObject* owner, Unit* caster, int32 *baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty, bool* refresh = NULL); + static Aura* TryCreate(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty); + static Aura* Create(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); explicit Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID); - void _InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount); + void _InitEffects(uint32 effMask, Unit* caster, int32 *baseAmount); virtual ~Aura(); SpellInfo const* GetSpellInfo() const { return m_spellInfo; } @@ -113,7 +114,7 @@ class Aura void _Remove(AuraRemoveMode removeMode); virtual void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) = 0; - virtual void FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) = 0; + virtual void FillTargetMap(std::map<Unit*, uint32> & targets, Unit* caster) = 0; void UpdateTargetMap(Unit* caster, bool apply = true); void _RegisterForTargets() {Unit* caster = GetCaster(); UpdateTargetMap(caster, false);} @@ -152,7 +153,7 @@ class Aura uint8 GetCasterLevel() const { return m_casterLevel; } - bool HasMoreThanOneEffectForType(AuraType auraType) const; + bool HasMoreThanOneEffectForType(AuraType auraType, uint32 difficulty) const; bool IsArea() const; bool IsPassive() const; bool IsDeathPersistent() const; @@ -175,13 +176,14 @@ class Aura void UnregisterSingleTarget(); int32 CalcDispelChance(Unit* auraTarget, bool offensive) const; - void SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount); + void SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 *baseAmount); // helpers for aura effects bool HasEffect(uint8 effIndex) const { return GetEffect(effIndex) != NULL; } bool HasEffectType(AuraType type) const; - AuraEffect* GetEffect(uint8 effIndex) const { ASSERT (effIndex < MAX_SPELL_EFFECTS); return m_effects[effIndex]; } - uint8 GetEffectMask() const { uint8 effMask = 0; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (m_effects[i]) effMask |= 1<<i; return effMask; } + //AuraEffect* GetEffect(uint8 effIndex) const { ASSERT (effIndex < MAX_SPELL_EFFECTS); return Effects[effIndex]; } + AuraEffect* GetEffect(uint32 index) const; + uint32 GetEffectMask() const; void RecalculateAmountOfEffects(); void HandleAllEffects(AuraApplication * aurApp, uint8 mode, bool apply); @@ -242,6 +244,12 @@ class Aura AuraScript* GetScriptByName(std::string const& scriptName) const; std::list<AuraScript*> m_loadedScripts; + + AuraEffectVector GetAuraEffects() const { return _effects; } + + SpellEffectInfoVector GetSpellEffectInfos() const { return _spelEffectInfos; } + SpellEffectInfo const* GetSpellEffectInfo(uint32 index) const; + private: void _DeleteRemovedApplications(); protected: @@ -260,7 +268,7 @@ class Aura uint8 m_procCharges; // Aura charges (0 for infinite) uint8 m_stackAmount; // Aura stack amount - AuraEffect* m_effects[3]; + //AuraEffect* m_effects[3]; ApplicationMap m_applications; bool m_isRemoved:1; @@ -271,20 +279,23 @@ class Aura private: Unit::AuraApplicationList m_removedApplications; + + AuraEffectVector _effects; + SpellEffectInfoVector _spelEffectInfos; }; class UnitAura : public Aura { - friend Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); - protected: - explicit UnitAura(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + friend Aura* Aura::Create(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); public: + explicit UnitAura(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + void _ApplyForTarget(Unit* target, Unit* caster, AuraApplication * aurApp) override; void _UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * aurApp) override; void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override; - void FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) override; + void FillTargetMap(std::map<Unit*, uint32> & targets, Unit* caster) override; // Allow Apply Aura Handler to modify and access m_AuraDRGroup void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; } @@ -296,13 +307,13 @@ class UnitAura : public Aura class DynObjAura : public Aura { - friend Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); - protected: - explicit DynObjAura(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + friend Aura* Aura::Create(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); public: + explicit DynObjAura(SpellInfo const* spellproto, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override; - void FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) override; + void FillTargetMap(std::map<Unit*, uint32> & targets, Unit* caster) override; }; class ChargeDropEvent : public BasicEvent diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 8583d055123..f376e0979b2 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -57,6 +57,7 @@ #include "DB2Stores.h" #include "Battlefield.h" #include "BattlefieldMgr.h" +#include "SpellPackets.h" extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; @@ -118,6 +119,28 @@ SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0), m_strTarget() m_targetMask = 0; } +SpellCastTargets::SpellCastTargets(Unit* caster, uint32 targetMask, ObjectGuid targetGuid, ObjectGuid itemTargetGuid, ObjectGuid srcTransportGuid, ObjectGuid destTransportGuid, Position srcPos, Position destPos, float elevation, float missileSpeed, std::string targetString) : + m_targetMask(targetMask), m_objectTargetGUID(targetGuid), m_itemTargetGUID(itemTargetGuid), m_elevation(elevation), m_speed(missileSpeed), m_strTarget(targetString) +{ + m_objectTarget = NULL; + m_itemTarget = NULL; + m_itemTargetEntry = 0; + + m_src._transportGUID = srcTransportGuid; + if (m_src._transportGUID != ObjectGuid::Empty) + m_src._transportOffset.Relocate(srcPos); + else + m_src._position.Relocate(srcPos); + + m_dst._transportGUID = destTransportGuid; + if (m_dst._transportGUID != ObjectGuid::Empty) + m_dst._transportOffset.Relocate(destPos); + else + m_dst._position.Relocate(destPos); + + Update(caster); +} + SpellCastTargets::~SpellCastTargets() { } void SpellCastTargets::Read(ByteBuffer& data, Unit* caster) @@ -173,9 +196,41 @@ void SpellCastTargets::Read(ByteBuffer& data, Unit* caster) Update(caster); } -void SpellCastTargets::Write(ByteBuffer& data) +void SpellCastTargets::Write(WorldPackets::Spells::SpellTargetData& data) { - data << uint32(m_targetMask); + data.Flags = m_targetMask; + + if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET)) + data.Unit = m_objectTargetGUID; + + if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM) && m_itemTarget) + data.Item = m_itemTarget->GetGUID(); + + if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION) + { + WorldPackets::Spells::TargetLocation& target = data.SrcLocation.Value; + target.Transport = m_src._transportGUID; // relative position guid here - transport for example + if (!m_src._transportGUID.IsEmpty()) + target.Location = m_src._transportOffset; + else + target.Location = m_src._position; + data.SrcLocation.HasValue = true; + } + + if (m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + WorldPackets::Spells::TargetLocation& target = data.DstLocation.Value; + target.Transport = m_dst._transportGUID; // relative position guid here - transport for example + if (!m_dst._transportGUID.IsEmpty()) + target.Location = m_dst._transportOffset; + else + target.Location = m_dst._position; + data.DstLocation.HasValue = true; + } + + if (m_targetMask & TARGET_FLAG_STRING) + data.Name = m_strTarget; + /*data << uint32(m_targetMask); if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET)) data << m_objectTargetGUID.WriteAsPacked(); @@ -207,7 +262,7 @@ void SpellCastTargets::Write(ByteBuffer& data) } if (m_targetMask & TARGET_FLAG_STRING) - data << m_strTarget; + data << m_strTarget;*/ } ObjectGuid SpellCastTargets::GetOrigUnitTargetGUID() const @@ -507,20 +562,26 @@ void SpellCastTargets::OutDebug() const TC_LOG_INFO("spells", "elevation: %f", m_elevation); } -SpellValue::SpellValue(SpellInfo const* proto) +SpellValue::SpellValue(Difficulty diff, SpellInfo const* proto) { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - EffectBasePoints[i] = proto->Effects[i].BasePoints; + // todo 6.x + SpellEffectInfoVector effects = proto->GetEffectsForDifficulty(diff); + ASSERT(effects.size() <= MAX_SPELL_EFFECTS); + for (SpellEffectInfo const* effect : effects) + if (effect) + EffectBasePoints[effect->EffectIndex] = effect->BasePoints; + MaxAffectedTargets = proto->MaxAffectedTargets; RadiusMod = 1.0f; AuraStackAmount = 1; } Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) : -m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)), -m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster) -, m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster)) +m_spellInfo(info), m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster), +m_spellValue(new SpellValue(caster->GetMap()->GetDifficulty(), m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster)) { + _effects = info->GetEffectsForDifficulty(caster->GetMap()->GetDifficulty()); + m_customError = SPELL_CUSTOM_ERROR_NONE; m_skipCheck = skipCheck; m_selfContainer = NULL; @@ -592,7 +653,9 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme gameObjTarget = NULL; destTarget = NULL; damage = 0; + variance = 0.0f; effectHandleMode = SPELL_EFFECT_HANDLE_LAUNCH; + effectInfo = nullptr; m_diminishLevel = DIMINISHING_LEVEL_1; m_diminishGroup = DIMINISHING_NONE; m_damage = 0; @@ -764,36 +827,40 @@ void Spell::SelectSpellTargets() SelectExplicitTargets(); uint32 processedAreaEffectsMask = 0; - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + + for (SpellEffectInfo const* effect : GetEffects()) { + if (!effect) + continue; + // not call for empty effect. // Also some spells use not used effect targets for store targets for dummy effect in triggered spells - if (!m_spellInfo->Effects[i].IsEffect()) + if (!effect->IsEffect()) continue; // set expected type of implicit targets to be sent to client - uint32 implicitTargetMask = GetTargetFlagMask(m_spellInfo->Effects[i].TargetA.GetObjectType()) | GetTargetFlagMask(m_spellInfo->Effects[i].TargetB.GetObjectType()); + uint32 implicitTargetMask = GetTargetFlagMask(effect->TargetA.GetObjectType()) | GetTargetFlagMask(effect->TargetB.GetObjectType()); if (implicitTargetMask & TARGET_FLAG_UNIT) m_targets.SetTargetFlag(TARGET_FLAG_UNIT); if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM)) m_targets.SetTargetFlag(TARGET_FLAG_GAMEOBJECT); - SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetA, processedAreaEffectsMask); - SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetB, processedAreaEffectsMask); + SelectEffectImplicitTargets(SpellEffIndex(effect->EffectIndex), effect->TargetA, processedAreaEffectsMask); + SelectEffectImplicitTargets(SpellEffIndex(effect->EffectIndex), effect->TargetB, processedAreaEffectsMask); // Select targets of effect based on effect type // those are used when no valid target could be added for spell effect based on spell target type // some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL) // some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON) // some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS) - SelectEffectTypeImplicitTargets(i); + SelectEffectTypeImplicitTargets(effect->EffectIndex); if (m_targets.HasDst()) - AddDestTarget(*m_targets.GetDst(), i); + AddDestTarget(*m_targets.GetDst(), effect->EffectIndex); if (m_spellInfo->IsChanneled()) { - uint8 mask = (1 << i); + uint32 mask = (1 << effect->EffectIndex); for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { if (ihit->effectMask & mask) @@ -863,18 +930,23 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar // targets for effect already selected if (effectMask & processedEffectMask) return; - // choose which targets we can select at once - for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j) + if (SpellEffectInfo const* _effect = GetEffect(effIndex)) { - SpellEffectInfo const* effects = GetSpellInfo()->Effects; - if (effects[j].IsEffect() && - effects[effIndex].TargetA.GetTarget() == effects[j].TargetA.GetTarget() && - effects[effIndex].TargetB.GetTarget() == effects[j].TargetB.GetTarget() && - effects[effIndex].ImplicitTargetConditions == effects[j].ImplicitTargetConditions && - effects[effIndex].CalcRadius(m_caster) == effects[j].CalcRadius(m_caster) && - CheckScriptEffectImplicitTargets(effIndex, j)) + // choose which targets we can select at once + for (SpellEffectInfo const* effect : GetEffects()) { - effectMask |= 1 << j; + //for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j) + if (!effect || effect->EffectIndex <= uint32(effIndex)) + continue; + if (effect->IsEffect() && + _effect->TargetA.GetTarget() == effect->TargetA.GetTarget() && + _effect->TargetB.GetTarget() == effect->TargetB.GetTarget() && + _effect->ImplicitTargetConditions == effect->ImplicitTargetConditions && + _effect->CalcRadius(m_caster) == effect->CalcRadius(m_caster) && + CheckScriptEffectImplicitTargets(effIndex, effect->EffectIndex)) + { + effectMask |= 1 << effect->EffectIndex; + } } } processedEffectMask |= effectMask; @@ -1009,6 +1081,10 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar return; } + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + float range = 0.0f; switch (targetType.GetCheckType()) { @@ -1030,7 +1106,7 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar break; } - ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; + ConditionList* condList = effect->ImplicitTargetConditions; // handle emergency case - try to use other provided targets if no conditions provided if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty())) @@ -1116,9 +1192,12 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge std::list<WorldObject*> targets; SpellTargetObjectTypes objectType = targetType.GetObjectType(); SpellTargetCheckTypes selectionType = targetType.GetCheckType(); - ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + ConditionList* condList = effect->ImplicitTargetConditions; float coneAngle = float(M_PI) / 2; - float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod; + float radius = effect->CalcRadius(m_caster) * m_spellValue->RadiusMod; if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList)) { @@ -1199,8 +1278,11 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge } std::list<WorldObject*> targets; - float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod; - SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions); + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + float radius = effect->CalcRadius(m_caster) * m_spellValue->RadiusMod; + SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), effect->ImplicitTargetConditions); CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType); @@ -1236,7 +1318,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, effIndex)) { /// @todo fix this check - if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || m_spellInfo->HasEffect(SPELL_EFFECT_BIND)) + if (HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || HasEffect(SPELL_EFFECT_BIND)) dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId); else if (st->target_mapId == m_caster->GetMapId()) dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation); @@ -1284,23 +1366,26 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici } default: { - float dist; - float angle = targetType.CalcDirectionAngle(); - float objSize = m_caster->GetObjectSize(); - if (targetType.GetTarget() == TARGET_DEST_CASTER_SUMMON) - dist = PET_FOLLOW_DIST; - else - dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); + if (SpellEffectInfo const* effect = GetEffect(effIndex)) + { + float dist; + float angle = targetType.CalcDirectionAngle(); + float objSize = m_caster->GetObjectSize(); + if (targetType.GetTarget() == TARGET_DEST_CASTER_SUMMON) + dist = PET_FOLLOW_DIST; + else + dist = effect->CalcRadius(m_caster); - if (dist < objSize) - dist = objSize; - else if (targetType.GetTarget() == TARGET_DEST_CASTER_RANDOM) - dist = objSize + (dist - objSize) * float(rand_norm()); + if (dist < objSize) + dist = objSize; + else if (targetType.GetTarget() == TARGET_DEST_CASTER_RANDOM) + dist = objSize + (dist - objSize) * float(rand_norm()); - Position pos = dest._position; - m_caster->MovePositionToFirstCollision(pos, dist, angle); + Position pos = dest._position; + m_caster->MovePositionToFirstCollision(pos, dist, angle); - dest.Relocate(pos); + dest.Relocate(pos); + } break; } } @@ -1323,18 +1408,21 @@ void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplici break; default: { - float angle = targetType.CalcDirectionAngle(); - float objSize = target->GetObjectSize(); - float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); - if (dist < objSize) - dist = objSize; - else if (targetType.GetTarget() == TARGET_DEST_TARGET_RANDOM) - dist = objSize + (dist - objSize) * float(rand_norm()); - - Position pos = dest._position; - target->MovePositionToFirstCollision(pos, dist, angle); - - dest.Relocate(pos); + if (SpellEffectInfo const* effect = GetEffect(effIndex)) + { + float angle = targetType.CalcDirectionAngle(); + float objSize = target->GetObjectSize(); + float dist = effect->CalcRadius(m_caster); + if (dist < objSize) + dist = objSize; + else if (targetType.GetTarget() == TARGET_DEST_TARGET_RANDOM) + dist = objSize + (dist - objSize) * float(rand_norm()); + + Position pos = dest._position; + target->MovePositionToFirstCollision(pos, dist, angle); + + dest.Relocate(pos); + } break; } } @@ -1365,15 +1453,18 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT return; default: { - float angle = targetType.CalcDirectionAngle(); - float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); - if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM) - dist *= float(rand_norm()); + if (SpellEffectInfo const* effect = GetEffect(effIndex)) + { + float angle = targetType.CalcDirectionAngle(); + float dist = effect->CalcRadius(m_caster); + if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM) + dist *= float(rand_norm()); - Position pos = dest._position; - m_caster->MovePositionToFirstCollision(pos, dist, angle); + Position pos = dest._position; + m_caster->MovePositionToFirstCollision(pos, dist, angle); - dest.Relocate(pos); + dest.Relocate(pos); + } break; } } @@ -1451,21 +1542,25 @@ void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImpli void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask) { - uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTargets; + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + + uint32 maxTargets = effect->ChainTargets; if (Player* modOwner = m_caster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this); if (maxTargets > 1) { // mark damage multipliers as used - for (uint32 k = effIndex; k < MAX_SPELL_EFFECTS; ++k) - if (effMask & (1 << k)) - m_damageMultipliers[k] = 1.0f; + for (SpellEffectInfo const* eff : GetEffects()) + if (eff && (effMask & (1 << eff->EffectIndex))) + m_damageMultipliers[eff->EffectIndex] = 1.0f; m_applyMultiplierMask |= effMask; std::list<WorldObject*> targets; SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType() - , m_spellInfo->Effects[effIndex].ImplicitTargetConditions, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY); + , effect->ImplicitTargetConditions, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY); // Chain primary target is added earlier CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType); @@ -1644,11 +1739,14 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex) veh->SetLastShootPos(*m_targets.GetDstPos()); } -void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) +void Spell::SelectEffectTypeImplicitTargets(uint32 effIndex) { // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER /// @todo this is a workaround - target shouldn't be stored in target map for those spells - switch (m_spellInfo->Effects[effIndex].Effect) + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + switch (effect->Effect) { case SPELL_EFFECT_SUMMON_RAF_FRIEND: case SPELL_EFFECT_SUMMON_PLAYER: @@ -1667,17 +1765,17 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) } // select spell implicit targets based on effect type - if (!m_spellInfo->Effects[effIndex].GetImplicitTargetType()) + if (!effect->GetImplicitTargetType()) return; - uint32 targetMask = m_spellInfo->Effects[effIndex].GetMissingTargetMask(); + uint32 targetMask = effect->GetMissingTargetMask(); if (!targetMask) return; WorldObject* target = NULL; - switch (m_spellInfo->Effects[effIndex].GetImplicitTargetType()) + switch (effect->GetImplicitTargetType()) { // add explicit object target or self to the target map case EFFECT_IMPLICIT_TARGET_EXPLICIT: @@ -2012,9 +2110,9 @@ void Spell::CleanupTargetList() void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/) { - for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - if (!m_spellInfo->Effects[effIndex].IsEffect() || !CheckEffectTarget(target, effIndex, losPosition)) - effectMask &= ~(1 << effIndex); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && (!effect->IsEffect() || !CheckEffectTarget(target, effect->EffectIndex, losPosition))) + effectMask &= ~(1 << effect->EffectIndex); // no effects left if (!effectMask) @@ -2025,9 +2123,9 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= return; // Check for effect immune skip if immuned - for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - if (target->IsImmunedToSpellEffect(m_spellInfo, effIndex)) - effectMask &= ~(1 << effIndex); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && target->IsImmunedToSpellEffect(m_spellInfo, effect->EffectIndex)) + effectMask &= ~(1 << effect->EffectIndex); ObjectGuid targetGUID = target->GetGUID(); @@ -2120,19 +2218,22 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= void Spell::AddGOTarget(GameObject* go, uint32 effectMask) { - for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + for (SpellEffectInfo const* effect : GetEffects()) { - if (!m_spellInfo->Effects[effIndex].IsEffect()) - effectMask &= ~(1 << effIndex); + if (!effect) + continue; + + if (!effect->IsEffect()) + effectMask &= ~(1 << effect->EffectIndex); else { - switch (m_spellInfo->Effects[effIndex].Effect) + switch (effect->Effect) { case SPELL_EFFECT_GAMEOBJECT_DAMAGE: case SPELL_EFFECT_GAMEOBJECT_REPAIR: case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE: if (go->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) - effectMask &= ~(1 << effIndex); + effectMask &= ~(1 << effect->EffectIndex); break; default: break; @@ -2187,9 +2288,9 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask) void Spell::AddItemTarget(Item* item, uint32 effectMask) { - for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - if (!m_spellInfo->Effects[effIndex].IsEffect()) - effectMask &= ~(1 << effIndex); + for (SpellEffectInfo const* effect : GetEffects()) + if (!effect || !effect->IsEffect()) + effectMask &= ~(1 << effect->EffectIndex); // no effects left if (!effectMask) @@ -2234,10 +2335,10 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { uint8 farMask = 0; // create far target mask - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_spellInfo->Effects[i].IsFarUnitTargetEffect()) - if ((1 << i) & mask) - farMask |= (1 << i); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && effect->IsFarUnitTargetEffect()) + if ((1 << effect->EffectIndex) & mask) + farMask |= (1 << effect->EffectIndex); if (!farMask) return; @@ -2248,9 +2349,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // do far effects on the unit // can't use default call because of threading, do stuff as fast as possible - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (farMask & (1 << i)) - HandleEffects(unit, NULL, NULL, i, SPELL_EFFECT_HANDLE_HIT_TARGET); + for(SpellEffectInfo const* effect : GetEffects()) + if (effect && (farMask & (1 << effect->EffectIndex))) + HandleEffects(unit, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); return; } @@ -2433,7 +2534,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) } } - if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL))) + if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || HasEffect(SPELL_EFFECT_DISPEL))) { m_caster->CombatStart(unit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO)); @@ -2474,10 +2575,10 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA // disable effects to which unit is immune SpellMissInfo returnVal = SPELL_MISS_IMMUNE; - for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) - if (unit->IsImmunedToSpellEffect(m_spellInfo, effectNumber)) - effectMask &= ~(1 << effectNumber); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && (effectMask & (1 << effect->EffectIndex))) + if (unit->IsImmunedToSpellEffect(m_spellInfo, effect->EffectIndex)) + effectMask &= ~(1 << effect->EffectIndex); if (!effectMask) return returnVal; @@ -2535,9 +2636,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA } uint8 aura_effmask = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (effectMask & (1 << i) && m_spellInfo->Effects[i].IsUnitOwnedAuraEffect()) - aura_effmask |= 1 << i; + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && (effectMask & (1 << effect->EffectIndex) && effect->IsUnitOwnedAuraEffect())) + aura_effmask |= 1 << effect->EffectIndex; // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo, m_triggeredByAuraSpell != nullptr); @@ -2557,18 +2658,21 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA // Select rank for aura with level requirements only in specific cases // Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target SpellInfo const* aurSpellInfo = m_spellInfo; - int32 basePoints[3]; + int32 basePoints[MAX_SPELL_EFFECTS]; if (scaleAura) { aurSpellInfo = m_spellInfo->GetAuraRankForLevel(unitTarget->getLevel()); ASSERT(aurSpellInfo); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : aurSpellInfo->GetEffectsForDifficulty(0)) { - basePoints[i] = aurSpellInfo->Effects[i].BasePoints; - if (m_spellInfo->Effects[i].Effect != aurSpellInfo->Effects[i].Effect) + basePoints[effect->EffectIndex] = effect->BasePoints; + if (SpellEffectInfo const* myEffect = GetEffect(effect->EffectIndex)) { - aurSpellInfo = m_spellInfo; - break; + if (myEffect->Effect != effect->Effect) + { + aurSpellInfo = m_spellInfo; + break; + } } } } @@ -2577,7 +2681,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA { bool refresh = false; m_spellAura = Aura::TryRefreshStackOrCreate(aurSpellInfo, effectMask, unit, - m_originalCaster, (aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh); + m_originalCaster, (aurSpellInfo == m_spellInfo) ? m_spellValue->EffectBasePoints : basePoints, m_CastItem, ObjectGuid::Empty, &refresh); if (m_spellAura) { // Set aura stack amount to desired value @@ -2599,8 +2703,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA { m_spellAura->Remove(); bool found = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (effectMask & (1 << i) && m_spellInfo->Effects[i].Effect != SPELL_EFFECT_APPLY_AURA) + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && (effectMask & (1 << effect->EffectIndex) && effect->Effect != SPELL_EFFECT_APPLY_AURA)) found = true; if (!found) return SPELL_MISS_IMMUNE; @@ -2624,10 +2728,11 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA { int32 origDuration = duration; duration = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (AuraEffect const* eff = m_spellAura->GetEffect(i)) - if (int32 period = eff->GetPeriod()) // period is hastened by UNIT_MOD_CAST_SPEED - duration = std::max(std::max(origDuration / period, 1) * period, duration); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect) + if (AuraEffect const* eff = m_spellAura->GetEffect(effect->EffectIndex)) + if (int32 period = eff->GetPeriod()) // period is hastened by UNIT_MOD_CAST_SPEED + duration = std::max(std::max(origDuration / period, 1) * period, duration); // if there is no periodic effect if (!duration) @@ -2646,9 +2751,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA } } - for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) - HandleEffects(unit, NULL, NULL, effectNumber, SPELL_EFFECT_HANDLE_HIT_TARGET); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && (effectMask & (1 << effect->EffectIndex))) + HandleEffects(unit, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); return SPELL_MISS_NONE; } @@ -2742,9 +2847,9 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo* target) PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(); - for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) - HandleEffects(NULL, NULL, go, effectNumber, SPELL_EFFECT_HANDLE_HIT_TARGET); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && (effectMask & (1 << effect->EffectIndex))) + HandleEffects(NULL, NULL, go, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); CallScriptOnHitHandlers(); CallScriptAfterHitHandlers(); @@ -2759,9 +2864,9 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo* target) PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(); - for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) - HandleEffects(NULL, target->item, NULL, effectNumber, SPELL_EFFECT_HANDLE_HIT_TARGET); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && (effectMask & (1 << effect->EffectIndex))) + HandleEffects(NULL, target->item, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); CallScriptOnHitHandlers(); @@ -2776,9 +2881,9 @@ bool Spell::UpdateChanneledTargetList() uint8 channelTargetEffectMask = m_channelTargetEffectMask; uint8 channelAuraMask = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) - channelAuraMask |= 1<<i; + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) + channelAuraMask |= 1 << effect->EffectIndex; channelAuraMask &= channelTargetEffectMask; @@ -2843,15 +2948,15 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered // Fill aura scaling information if (m_caster->IsControlledByPlayer() && !m_spellInfo->IsPassive() && m_spellInfo->SpellLevel && !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING)) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) + if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) { // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive - if (m_spellInfo->IsPositiveEffect(i)) + if (m_spellInfo->IsPositiveEffect(effect->EffectIndex)) { - m_auraScaleMask |= (1 << i); - if (m_spellValue->EffectBasePoints[i] != m_spellInfo->Effects[i].BasePoints) + m_auraScaleMask |= (1 << effect->EffectIndex); + if (m_spellValue->EffectBasePoints[effect->EffectIndex] != effect->BasePoints) { m_auraScaleMask = 0; break; @@ -2966,8 +3071,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && m_spellInfo->IsBreakingStealth()) { m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST); - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_spellInfo->Effects[i].GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT) + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && effect->GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT) { m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_SPELL_ATTACK); break; @@ -3296,10 +3401,6 @@ void Spell::handle_immediate() // Remove used for cast item if need (it can be already NULL after TakeReagents call TakeCastItem(); - // handle ammo consumption for thrown weapons - if (m_spellInfo->IsRangedWeaponSpell() && m_spellInfo->IsChanneled()) - TakeAmmo(); - if (m_spellState != SPELL_STATE_CASTING) finish(true); // successfully finish spell cast (not last in case autorepeat or channel spell) } @@ -3391,14 +3492,14 @@ void Spell::_handle_immediate_phase() PrepareScriptHitHandlers(); // handle effects with SPELL_EFFECT_HANDLE_HIT mode - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { // don't do anything for empty effect - if (!m_spellInfo->Effects[j].IsEffect()) + if (!effect || !effect->IsEffect()) continue; // call effect handlers to handle destination hit - HandleEffects(NULL, NULL, NULL, j, SPELL_EFFECT_HANDLE_HIT); + HandleEffects(NULL, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT); } // process items @@ -3436,7 +3537,7 @@ void Spell::_handle_finish_phase() HandleHolyPower(m_caster->m_movedPlayer); } - if (m_caster->m_extraAttacks && m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + if (m_caster->m_extraAttacks && HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) { if (Unit* victim = ObjectAccessor::FindUnit(m_targets.GetOrigUnitTargetGUID())) m_caster->HandleProcExtraAttackFor(victim); @@ -3494,9 +3595,10 @@ void Spell::update(uint32 difftime) // check if the player caster has moved before the spell finished // with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect + SpellEffectInfo const* effect = GetEffect(EFFECT_0); if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) && m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) && - (m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) && + ((effect && effect->Effect != SPELL_EFFECT_STUCK) || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo)) { // don't cancel for melee, autorepeat, triggered and instant spells @@ -3671,17 +3773,18 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas if (result == SPELL_CAST_OK) return; - WorldPacket data(opcode, (4+1+1)); - data << uint8(cast_count); - data << uint32(spellInfo->Id); - data << uint8(result); // problem + WorldPackets::Spells::CastFailed packet(opcode); + packet.CastID = cast_count; + packet.SpellID = spellInfo->Id; + packet.Reason = result; + switch (result) { case SPELL_FAILED_NOT_READY: - data << uint32(0); // unknown (value 1 update cooldowns on client flag) + packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag) break; case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id + packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id break; case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id // hardcode areas limitation case @@ -3689,71 +3792,71 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas { case 41617: // Cenarion Mana Salve case 41619: // Cenarion Healing Salve - data << uint32(3905); + packet.FailedArg1 = 3905; break; case 41618: // Bottled Nethergon Energy case 41620: // Bottled Nethergon Vapor - data << uint32(3842); + packet.FailedArg1 = 3842; break; case 45373: // Bloodberry Elixir - data << uint32(4075); + packet.FailedArg1 = 4075; break; default: // default case (don't must be) - data << uint32(0); + packet.FailedArg1 = 0; break; } break; case SPELL_FAILED_TOTEMS: if (spellInfo->Totem[0]) - data << uint32(spellInfo->Totem[0]); + packet.FailedArg1 = spellInfo->Totem[0]; if (spellInfo->Totem[1]) - data << uint32(spellInfo->Totem[1]); + packet.FailedArg2 = spellInfo->Totem[1]; break; case SPELL_FAILED_TOTEM_CATEGORY: if (spellInfo->TotemCategory[0]) - data << uint32(spellInfo->TotemCategory[0]); + packet.FailedArg1 = spellInfo->TotemCategory[0]; if (spellInfo->TotemCategory[1]) - data << uint32(spellInfo->TotemCategory[1]); + packet.FailedArg2 = spellInfo->TotemCategory[1]; break; case SPELL_FAILED_EQUIPPED_ITEM_CLASS: case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND: case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND: - data << uint32(spellInfo->EquippedItemClass); - data << uint32(spellInfo->EquippedItemSubClassMask); + packet.FailedArg1 = spellInfo->EquippedItemClass; + packet.FailedArg2 = spellInfo->EquippedItemSubClassMask; break; case SPELL_FAILED_TOO_MANY_OF_ITEM: { - uint32 item = 0; - for (int8 eff = 0; eff < MAX_SPELL_EFFECTS; eff++) - if (spellInfo->Effects[eff].ItemType) - item = spellInfo->Effects[eff].ItemType; - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item); - if (proto && proto->ItemLimitCategory) - data << uint32(proto->ItemLimitCategory); - break; + uint32 item = 0; + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(caster->GetMap()->GetDifficulty())) + if (effect->ItemType) + item = effect->ItemType; + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item); + if (proto && proto->ItemLimitCategory) + packet.FailedArg1 = proto->ItemLimitCategory; + break; } case SPELL_FAILED_PREVENTED_BY_MECHANIC: - data << uint32(spellInfo->GetAllEffectsMechanicMask()); // SpellMechanic.dbc id + packet.FailedArg1 = spellInfo->GetAllEffectsMechanicMask(); // SpellMechanic.dbc id break; case SPELL_FAILED_NEED_EXOTIC_AMMO: - data << uint32(spellInfo->EquippedItemSubClassMask); // seems correct... + packet.FailedArg1 = spellInfo->EquippedItemSubClassMask; // seems correct... break; case SPELL_FAILED_NEED_MORE_ITEMS: - data << uint32(0); // Item id - data << uint32(0); // Item count? + packet.FailedArg1 = 0; // Item id + packet.FailedArg2 = 0; // Item count? break; case SPELL_FAILED_MIN_SKILL: - data << uint32(0); // SkillLine.dbc id - data << uint32(0); // required skill value + packet.FailedArg1 = 0; // SkillLine.dbc id + packet.FailedArg2 = 0; // required skill value break; case SPELL_FAILED_FISHING_TOO_LOW: - data << uint32(0); // required fishing skill + packet.FailedArg1 = 0; // required fishing skill break; case SPELL_FAILED_CUSTOM_ERROR: - data << uint32(customError); + packet.FailedArg1 = customError; break; case SPELL_FAILED_SILENCED: - data << uint32(0); // Unknown + packet.FailedArg1 = 0; // Unknown break; case SPELL_FAILED_REAGENTS: { @@ -3773,14 +3876,15 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas } } - data << uint32(missingItem); // first missing item + packet.FailedArg1 = missingItem; // first missing item break; } // TODO: SPELL_FAILED_NOT_STANDING default: break; } - caster->GetSession()->SendPacket(&data); + + caster->GetSession()->SendPacket(packet.Write()); } void Spell::SendSpellStart() @@ -3788,7 +3892,7 @@ void Spell::SendSpellStart() if (!IsNeedSendToClient()) return; - //TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id); + TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id); uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY; @@ -3803,7 +3907,81 @@ void Spell::SendSpellStart() if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNES) castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it - WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); + WorldPackets::Spells::SpellStart packet; + WorldPackets::Spells::SpellCastData& castData = packet.Cast; + + if (m_CastItem) + castData.CasterGUID = m_CastItem->GetGUID(); + else + castData.CasterGUID = m_caster->GetGUID(); + + castData.CasterUnit = m_caster->GetGUID(); + castData.CastID = m_cast_count; // pending spell cast? + castData.SpellID = m_spellInfo->Id; + castData.CastFlags = castFlags; + castData.CastTime = m_casttime; + + m_targets.Write(castData.Target); + + if (castFlags & CAST_FLAG_POWER_LEFT_SELF) + { + /// @todo Implement multiple power types + WorldPackets::Spells::SpellPowerData powerData; + powerData.Type = m_spellInfo->PowerType; + powerData.Cost = m_caster->GetPower((Powers)m_spellInfo->PowerType); + castData.RemainingPower.push_back(powerData); + } + + if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list + { + WorldPackets::Spells::RuneData& runeData = castData.RemainingRunes.Value; + //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature + //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster + if (Player* player = m_caster->ToPlayer()) + { + runeData.Start = m_runesState; // runes state before + runeData.Count = player->GetRunesState(); // runes state after + for (uint8 i = 0; i < MAX_RUNES; ++i) + { + // float casts ensure the division is performed on floats as we need float result + float baseCd = float(player->GetRuneBaseCooldown(i)); + runeData.Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed + } + } + else + { + runeData.Start = 0; + runeData.Count = 0; + for (uint8 i = 0; i < MAX_RUNES; ++i) + runeData.Cooldowns.push_back(0); + } + + castData.RemainingRunes.HasValue = true; + } + + /** @todo implement spell ammo packet data + if (castFlags & CAST_FLAG_PROJECTILE) + { + castData.Ammo.DisplayID = 0; + castData.Ammo.InventoryType = 0; + }**/ + + /** @todo implement spell immunity packet data + if (castFlags & CAST_FLAG_IMMUNITY) + { + castData.Immunities.School = 0; + castData.Immunities.Value = 0; + }**/ + + /** @todo implement heal prediction packet data + if (castFlags & CAST_FLAG_HEAL_PREDICTION) + { + castData.Predict.BeconGUID = ?? + castData.Predict.Points = 0; + castData.Predict.Type = 0; + }**/ + + /*WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); if (m_CastItem) data << m_CastItem->GetPackGUID(); else @@ -3863,9 +4041,9 @@ void Spell::SendSpellStart() data << uint8(0); // unkByte // if (unkByte == 2) // data.append(0); - } + }*/ - m_caster->SendMessageToSet(&data, true); + m_caster->SendMessageToSet(packet.Write(), true); } void Spell::SendSpellGo() @@ -3874,7 +4052,7 @@ void Spell::SendSpellGo() if (!IsNeedSendToClient()) return; - //TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id); + TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id); uint32 castFlags = CAST_FLAG_UNKNOWN_9; @@ -3897,7 +4075,7 @@ void Spell::SendSpellGo() castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list } - if (m_spellInfo->HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) + if (HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list if (m_targets.HasTraj()) @@ -3906,7 +4084,68 @@ void Spell::SendSpellGo() if (!m_spellInfo->StartRecoveryTime) castFlags |= CAST_FLAG_NO_GCD; - WorldPacket data(SMSG_SPELL_GO, 50); // guess size + WorldPackets::Spells::SpellGo packet; + WorldPackets::Spells::SpellCastData& castData = packet.Cast; + + if (m_CastItem) + castData.CasterGUID = m_CastItem->GetGUID(); + else + castData.CasterGUID = m_caster->GetGUID(); + + castData.CasterUnit = m_caster->GetGUID(); + castData.CastID = m_cast_count; // pending spell cast? + castData.SpellID = m_spellInfo->Id; + castData.CastFlags = castFlags; + castData.CastTime = getMSTime(); + + /// @todo implement multiple targets + if (m_targets.GetUnitTarget()) + castData.HitTargets.push_back(m_targets.GetUnitTargetGUID()); + + m_targets.Write(castData.Target); + + if (castFlags & CAST_FLAG_POWER_LEFT_SELF) + { + /// @todo Implement multiple power types + WorldPackets::Spells::SpellPowerData powerData; + powerData.Type = m_spellInfo->PowerType; + powerData.Cost = m_caster->GetPower((Powers)m_spellInfo->PowerType); + castData.RemainingPower.push_back(powerData); + } + + if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list + { + WorldPackets::Spells::RuneData& runeData = castData.RemainingRunes.Value; + //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature + //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster + if (Player* player = m_caster->ToPlayer()) + { + runeData.Start = m_runesState; // runes state before + runeData.Count = player->GetRunesState(); // runes state after + for (uint8 i = 0; i < MAX_RUNES; ++i) + { + // float casts ensure the division is performed on floats as we need float result + float baseCd = float(player->GetRuneBaseCooldown(i)); + runeData.Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed + } + } + else + { + runeData.Start = 0; + runeData.Count = 0; + for (uint8 i = 0; i < MAX_RUNES; ++i) + runeData.Cooldowns.push_back(0); + } + + castData.RemainingRunes.HasValue = true; + } + + if (castFlags & CAST_FLAG_ADJUST_MISSILE) + { + castData.MissileTrajectory.TravelTime = m_delayMoment; + castData.MissileTrajectory.Pitch = m_targets.GetElevation(); + } + /*WorldPacket data(SMSG_SPELL_GO, 50); // guess size if (m_CastItem) data << m_CastItem->GetPackGUID(); @@ -3922,7 +4161,7 @@ void Spell::SendSpellGo() WriteSpellGoTargets(&data); - m_targets.Write(data); + //m_targets.Write(data); if (castFlags & CAST_FLAG_POWER_LEFT_SELF) data << uint32(m_caster->GetPower((Powers)m_spellInfo->PowerType)); @@ -3970,7 +4209,7 @@ void Spell::SendSpellGo() if (m_targets.GetTargetMask() & TARGET_FLAG_EXTRA_TARGETS) { data << uint32(0); // Extra targets count - /* + for (uint8 i = 0; i < count; ++i) { data << float(0); // Target Position X @@ -3978,10 +4217,10 @@ void Spell::SendSpellGo() data << float(0); // Target Position Z data << uint64(0); // Target Guid } - */ - } - m_caster->SendMessageToSet(&data, true); + }*/ + + m_caster->SendMessageToSet(packet.Write(), true); } /// Writes miss and hit targets for a SMSG_SPELL_GO packet @@ -4052,9 +4291,9 @@ void Spell::SendLogExecute() data << uint32(m_spellInfo->Id); uint8 effCount = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_effectExecuteData[i]) + if (effect && m_effectExecuteData[effect->EffectIndex]) ++effCount; } @@ -4062,17 +4301,17 @@ void Spell::SendLogExecute() return; data << uint32(effCount); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (!m_effectExecuteData[i]) + if (!effect || !m_effectExecuteData[effect->EffectIndex]) continue; - data << uint32(m_spellInfo->Effects[i].Effect); // spell effect + data << uint32(effect->Effect); // spell effect - data.append(*m_effectExecuteData[i]); + data.append(*m_effectExecuteData[effect->EffectIndex]); - delete m_effectExecuteData[i]; - m_effectExecuteData[i] = NULL; + delete m_effectExecuteData[effect->EffectIndex]; + m_effectExecuteData[effect->EffectIndex] = NULL; } m_caster->SendMessageToSet(&data, true); } @@ -4184,19 +4423,19 @@ void Spell::ExecuteLogEffectResurrect(uint8 effIndex, Unit* target) void Spell::SendInterrupted(uint8 result) { - WorldPacket data(SMSG_SPELL_FAILURE, (8+4+1)); - data << m_caster->GetPackGUID(); - data << uint8(m_cast_count); - data << uint32(m_spellInfo->Id); - data << uint8(result); - m_caster->SendMessageToSet(&data, true); + WorldPackets::Spells::SpellFailure failurePacket; + failurePacket.CasterUnit = m_caster->GetGUID(); + failurePacket.CastID = m_cast_count; + failurePacket.SpellID = m_spellInfo->Id; + failurePacket.Reason = result; + m_caster->SendMessageToSet(failurePacket.Write(), true); - data.Initialize(SMSG_SPELL_FAILED_OTHER, (8+4)); - data << m_caster->GetPackGUID(); - data << uint8(m_cast_count); - data << uint32(m_spellInfo->Id); - data << uint8(result); - m_caster->SendMessageToSet(&data, true); + WorldPackets::Spells::SpellFailedOther failedPacket; + failedPacket.CasterUnit = m_caster->GetGUID(); + failedPacket.CastID = m_cast_count; + failedPacket.SpellID = m_spellInfo->Id; + failedPacket.Reason = result; + m_caster->SendMessageToSet(failedPacket.Write(), true); } void Spell::SendChannelUpdate(uint32 time) @@ -4407,36 +4646,6 @@ void Spell::TakePower() m_caster->ModifyPower(powerType, -irand(0, m_powerCost/4)); } -void Spell::TakeAmmo() -{ - if (m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER) - { - Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK); - - // wands don't have ammo - if (!pItem || pItem->IsBroken() || pItem->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_WAND) - return; - - if ((pItem->GetTemplate()->InventoryType == INVTYPE_THROWN || - pItem->GetTemplate()->InventoryType == INVTYPE_RANGED || - pItem->GetTemplate()->InventoryType == INVTYPE_RANGEDRIGHT) - && roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE))) - { - if (pItem->GetMaxStackCount() == 1) - { - // decrease durability for non-stackable throw weapon - m_caster->ToPlayer()->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED); - } - else - { - // decrease items amount for stackable throw weapon - uint32 count = 1; - m_caster->ToPlayer()->DestroyItemCount(pItem, count, true); - } - } - } -} - SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) { if (m_spellInfo->PowerType != POWER_RUNES || !runeCostID) @@ -4693,11 +4902,17 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT gameObjTarget = pGOTarget; destTarget = &m_destTargets[i]._position; - uint8 eff = m_spellInfo->Effects[i].Effect; + effectInfo = GetEffect(i); + if (!effectInfo) + { + TC_LOG_ERROR("spells", "Spell: %u HandleEffects at EffectIndex: %u missing effect", m_spellInfo->Id, i); + return; + } + uint32 eff = effectInfo->Effect; - TC_LOG_DEBUG("spells", "Spell: %u Effect : %u", m_spellInfo->Id, eff); + TC_LOG_DEBUG("spells", "Spell: %u Effect: %u", m_spellInfo->Id, eff); - damage = CalculateDamage(i, unitTarget); + damage = CalculateDamage(i, unitTarget, &variance); bool preventDefault = CallScriptEffectHandlers((SpellEffIndex)i, mode); @@ -4816,9 +5031,9 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_CASTER_AURASTATE; // Note: spell 62473 requres casterAuraSpell = triggering spell - if (m_spellInfo->CasterAuraSpell && !m_caster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->CasterAuraSpell, m_caster))) + if (m_spellInfo->CasterAuraSpell && !m_caster->HasAura(m_spellInfo->CasterAuraSpell)) return SPELL_FAILED_CASTER_AURASTATE; - if (m_spellInfo->ExcludeCasterAuraSpell && m_caster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->ExcludeCasterAuraSpell, m_caster))) + if (m_spellInfo->ExcludeCasterAuraSpell && m_caster->HasAura(m_spellInfo->ExcludeCasterAuraSpell)) return SPELL_FAILED_CASTER_AURASTATE; if (reqCombat && m_caster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat()) @@ -4831,7 +5046,8 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->isMoving() && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo)) { // skip stuck spell to allow use it in falling case and apply spell limitations at movement - if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK) && + SpellEffectInfo const* effect = GetEffect(EFFECT_0); + if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || (effect && effect->Effect != SPELL_EFFECT_STUCK)) && (IsAutoRepeat() || (m_spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0)) return SPELL_FAILED_MOVING; } @@ -4916,9 +5132,9 @@ SpellCastResult Spell::CheckCast(bool strict) } // check pet presence - for (int j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_spellInfo->Effects[j].TargetA.GetTarget() == TARGET_UNIT_PET) + if (effect && effect->TargetA.GetTarget() == TARGET_UNIT_PET) { if (!m_caster->GetGuardianPet()) { @@ -5009,10 +5225,12 @@ SpellCastResult Spell::CheckCast(bool strict) if (castResult != SPELL_CAST_OK) return castResult; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { + if (!effect) + continue; // for effects of spells that have only one target - switch (m_spellInfo->Effects[i].Effect) + switch (effect->Effect) { case SPELL_EFFECT_DUMMY: { @@ -5039,7 +5257,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_BAD_TARGETS; - if (m_spellInfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_PET) + if (effect->TargetA.GetTarget() != TARGET_UNIT_PET) break; Pet* pet = m_caster->ToPlayer()->GetPet(); @@ -5047,7 +5265,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (!pet) return SPELL_FAILED_NO_PET; - SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[i].TriggerSpell); + SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell); if (!learn_spellproto) return SPELL_FAILED_NOT_KNOWN; @@ -5078,7 +5296,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (!pet || pet->GetOwner() != m_caster) return SPELL_FAILED_BAD_TARGETS; - SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[i].TriggerSpell); + SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell); if (!learn_spellproto) return SPELL_FAILED_NOT_KNOWN; @@ -5090,7 +5308,7 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_EFFECT_APPLY_GLYPH: { - uint32 glyphId = m_spellInfo->Effects[i].MiscValue; + uint32 glyphId = effect->MiscValue; if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyphId)) if (m_caster->HasAura(gp->SpellID)) return SPELL_FAILED_UNIQUE_GLYPH; @@ -5127,7 +5345,7 @@ SpellCastResult Spell::CheckCast(bool strict) // Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects) if (m_caster->GetTypeId() == TYPEID_PLAYER) if (Unit* target = m_targets.GetUnitTarget()) - if (target != m_caster && target->getPowerType() != Powers(m_spellInfo->Effects[i].MiscValue)) + if (target != m_caster && target->getPowerType() != Powers(effect->MiscValue)) return SPELL_FAILED_BAD_TARGETS; break; } @@ -5200,13 +5418,13 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_EFFECT_OPEN_LOCK: { - if (m_spellInfo->Effects[i].TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET && - m_spellInfo->Effects[i].TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET) + if (effect->TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET && + effect->TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET) break; if (m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc. // we need a go target in case of TARGET_GAMEOBJECT_TARGET - || (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget())) + || (effect->TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget())) return SPELL_FAILED_BAD_TARGETS; Item* pTempItem = NULL; @@ -5219,7 +5437,7 @@ SpellCastResult Spell::CheckCast(bool strict) pTempItem = m_caster->ToPlayer()->GetItemByGuid(m_targets.GetItemTargetGUID()); // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET - if (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET && + if (effect->TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET && !m_targets.GetGOTarget() && (!pTempItem || !pTempItem->GetTemplate()->LockID || !pTempItem->IsLocked())) return SPELL_FAILED_BAD_TARGETS; @@ -5246,7 +5464,7 @@ SpellCastResult Spell::CheckCast(bool strict) int32 skillValue = 0; // check lock compatibility - SpellCastResult res = CanOpenLock(i, lockId, skillId, reqSkillValue, skillValue); + SpellCastResult res = CanOpenLock(effect->EffectIndex, lockId, skillId, reqSkillValue, skillValue); if (res != SPELL_CAST_OK) return res; @@ -5274,7 +5492,7 @@ SpellCastResult Spell::CheckCast(bool strict) // This is generic summon effect case SPELL_EFFECT_SUMMON: { - SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(m_spellInfo->Effects[i].MiscValueB); + SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(effect->MiscValueB); if (!SummonProperties) break; switch (SummonProperties->Category) @@ -5408,9 +5626,11 @@ SpellCastResult Spell::CheckCast(bool strict) } } - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - switch (m_spellInfo->Effects[i].ApplyAuraName) + if (!effect) + continue; + switch (effect->ApplyAuraName) { case SPELL_AURA_MOD_POSSESS_PET: { @@ -5432,8 +5652,8 @@ SpellCastResult Spell::CheckCast(bool strict) if (!m_caster->GetCharmerGUID().IsEmpty()) return SPELL_FAILED_CHARMED; - if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_CHARM - || m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_POSSESS) + if (effect->ApplyAuraName == SPELL_AURA_MOD_CHARM + || effect->ApplyAuraName == SPELL_AURA_MOD_POSSESS) { if (!m_caster->GetPetGUID().IsEmpty()) return SPELL_FAILED_ALREADY_HAVE_SUMMON; @@ -5456,7 +5676,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (target->GetOwner() && target->GetOwner()->GetTypeId() == TYPEID_PLAYER) return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED; - int32 damage = CalculateDamage(i, target); + int32 damage = CalculateDamage(effect->EffectIndex, target); if (damage && int32(target->getLevel()) > damage) return SPELL_FAILED_HIGHLEVEL; } @@ -5508,7 +5728,7 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_AURA_PERIODIC_MANA_LEECH: { - if (m_spellInfo->Effects[i].IsTargetingArea()) + if (effect->IsTargetingArea()) break; if (!m_targets.GetUnitTarget()) @@ -5608,14 +5828,17 @@ SpellCastResult Spell::CheckCasterAuras() const // We use bitmasks so the loop is done only once and not on every aura check below. if (m_spellInfo->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY) - school_immune |= uint32(m_spellInfo->Effects[i].MiscValue); - else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY) - mechanic_immune |= 1 << uint32(m_spellInfo->Effects[i].MiscValue); - else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY) - dispel_immune |= SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[i].MiscValue)); + if (!effect) + continue; + + if (effect->ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY) + school_immune |= uint32(effect->MiscValue); + else if (effect->ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY) + mechanic_immune |= 1 << uint32(effect->MiscValue); + else if (effect->ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY) + dispel_immune |= SpellInfo::GetDispelMask(DispelType(effect->MiscValue)); } // immune movement impairment and loss of control if (m_spellInfo->Id == 42292 || m_spellInfo->Id == 59752 || m_spellInfo->Id == 19574) @@ -5684,9 +5907,12 @@ SpellCastResult Spell::CheckCasterAuras() const //Make a second check for spell failed so the right SPELL_FAILED message is returned. //That is needed when your casting is prevented by multiple states and you are only immune to some of them. - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (AuraEffect* part = aura->GetEffect(i)) + if (!effect) + continue; + + if (AuraEffect* part = aura->GetEffect(effect->EffectIndex)) { switch (part->GetAuraType()) { @@ -5758,25 +5984,28 @@ bool Spell::CanAutoCast(Unit* target) { ObjectGuid targetguid = target->GetGUID(); - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA) + if (!effect) + continue; + + if (effect->Effect == SPELL_EFFECT_APPLY_AURA) { if (m_spellInfo->StackAmount <= 1) { - if (target->HasAuraEffect(m_spellInfo->Id, j)) + if (target->HasAuraEffect(m_spellInfo->Id, effect->EffectIndex)) return false; } else { - if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, j)) + if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, effect->EffectIndex)) if (aureff->GetBase()->GetStackAmount() >= m_spellInfo->StackAmount) return false; } } - else if (m_spellInfo->Effects[j].IsAreaAuraEffect()) + else if (effect->IsAreaAuraEffect()) { - if (target->HasAuraEffect(m_spellInfo->Id, j)) + if (target->HasAuraEffect(m_spellInfo->Id, effect->EffectIndex)) return false; } } @@ -5921,13 +6150,13 @@ SpellCastResult Spell::CheckItems() { // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example SpellCastResult failReason = SPELL_CAST_OK; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster - if (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_PET) + if (!effect || effect->TargetA.GetTarget() == TARGET_UNIT_PET) continue; - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL) + if (effect->Effect == SPELL_EFFECT_HEAL) { if (m_targets.GetUnitTarget()->IsFullHealth()) { @@ -5942,15 +6171,15 @@ SpellCastResult Spell::CheckItems() } // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_ENERGIZE) + if (effect->Effect == SPELL_EFFECT_ENERGIZE) { - if (m_spellInfo->Effects[i].MiscValue < 0 || m_spellInfo->Effects[i].MiscValue >= int8(MAX_POWERS)) + if (effect->MiscValue < 0 || effect->MiscValue >= int8(MAX_POWERS)) { failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; continue; } - Powers power = Powers(m_spellInfo->Effects[i].MiscValue); + Powers power = Powers(effect->MiscValue); if (m_targets.GetUnitTarget()->GetPower(power) == m_targets.GetUnitTarget()->GetMaxPower(power)) { failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; @@ -6048,34 +6277,37 @@ SpellCastResult Spell::CheckItems() } // special checks for spell effects - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - switch (m_spellInfo->Effects[i].Effect) + if (!effect) + continue; + + switch (effect->Effect) { case SPELL_EFFECT_CREATE_ITEM: case SPELL_EFFECT_CREATE_ITEM_2: { - if (!IsTriggered() && m_spellInfo->Effects[i].ItemType) + if (!IsTriggered() && effect->ItemType) { ItemPosCountVec dest; - InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->Effects[i].ItemType, 1); + InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, effect->ItemType, 1); if (msg != EQUIP_ERR_OK) { - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(m_spellInfo->Effects[i].ItemType); + ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(effect->ItemType); /// @todo Needs review if (pProto && !(pProto->ItemLimitCategory)) { - player->SendEquipError(msg, NULL, NULL, m_spellInfo->Effects[i].ItemType); + player->SendEquipError(msg, NULL, NULL, effect->ItemType); return SPELL_FAILED_DONT_REPORT; } else { if (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (m_spellInfo->SpellFamilyFlags[0] & 0x40000000))) return SPELL_FAILED_TOO_MANY_OF_ITEM; - else if (!(player->HasItemCount(m_spellInfo->Effects[i].ItemType))) + else if (!(player->HasItemCount(effect->ItemType))) return SPELL_FAILED_TOO_MANY_OF_ITEM; - else - player->CastSpell(m_caster, m_spellInfo->Effects[EFFECT_1].CalcValue(), false); // move this to anywhere + else if (SpellEffectInfo const* efi = GetEffect(EFFECT_1)) + player->CastSpell(m_caster, efi->CalcValue(), false); // move this to anywhere return SPELL_FAILED_DONT_REPORT; } } @@ -6083,7 +6315,7 @@ SpellCastResult Spell::CheckItems() break; } case SPELL_EFFECT_ENCHANT_ITEM: - if (m_spellInfo->Effects[i].ItemType && m_targets.GetItemTarget() + if (effect->ItemType && m_targets.GetItemTarget() && (m_targets.GetItemTarget()->IsVellum())) { // cannot enchant vellum for other player @@ -6093,10 +6325,10 @@ SpellCastResult Spell::CheckItems() if (m_CastItem && m_CastItem->GetTemplate()->Flags[0] & ITEM_PROTO_FLAG_TRIGGERED_CAST) return SPELL_FAILED_TOTEM_CATEGORY; ItemPosCountVec dest; - InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->Effects[i].ItemType, 1); + InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, effect->ItemType, 1); if (msg != EQUIP_ERR_OK) { - player->SendEquipError(msg, NULL, NULL, m_spellInfo->Effects[i].ItemType); + player->SendEquipError(msg, NULL, NULL, effect->ItemType); return SPELL_FAILED_DONT_REPORT; } } @@ -6123,7 +6355,7 @@ SpellCastResult Spell::CheckItems() } } - SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(m_spellInfo->Effects[i].MiscValue); + SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(effect->MiscValue); // do not allow adding usable enchantments to items that have use effect already if (enchantEntry) { @@ -6168,7 +6400,7 @@ SpellCastResult Spell::CheckItems() // Not allow enchant in trade slot for some enchant type if (item->GetOwner() != m_caster) { - uint32 enchant_id = m_spellInfo->Effects[i].MiscValue; + uint32 enchant_id = effect->MiscValue; SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!pEnchant) return SPELL_FAILED_ERROR; @@ -6285,7 +6517,7 @@ SpellCastResult Spell::CheckItems() } case SPELL_EFFECT_CREATE_MANA_GEM: { - uint32 item_id = m_spellInfo->Effects[i].ItemType; + uint32 item_id = effect->ItemType; ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item_id); if (!pProto) @@ -6457,9 +6689,12 @@ bool Spell::UpdatePointers() WorldObject* transport = NULL; // update effect destinations (in case of moved transport dest target) - for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + for (SpellEffectInfo const* effect : GetEffects()) { - SpellDestination& dest = m_destTargets[effIndex]; + if (!effect) + continue; + + SpellDestination& dest = m_destTargets[effect->EffectIndex]; if (!dest._transportGUID) continue; @@ -6490,7 +6725,11 @@ CurrentSpellTypes Spell::GetCurrentContainer() const bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* losPosition) const { - switch (m_spellInfo->Effects[eff].ApplyAuraName) + SpellEffectInfo const* effect = GetEffect(eff); + if (!effect) + return false; + + switch (effect->ApplyAuraName) { case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_MOD_CHARM: @@ -6520,7 +6759,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo /// @todo shit below shouldn't be here, but it's temporary //Check targets for LOS visibility (except spells without range limitations) - switch (m_spellInfo->Effects[eff].Effect) + switch (effect->Effect) { case SPELL_EFFECT_RESURRECT_NEW: // player far away, maybe his corpse near? @@ -6731,21 +6970,19 @@ bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const void Spell::HandleLaunchPhase() { // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { // don't do anything for empty effect - if (!m_spellInfo->Effects[i].IsEffect()) + if (!effect || !effect->IsEffect()) continue; - HandleEffects(NULL, NULL, NULL, i, SPELL_EFFECT_HANDLE_LAUNCH); + HandleEffects(NULL, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_LAUNCH); } float multiplier[MAX_SPELL_EFFECTS]; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_applyMultiplierMask & (1 << i)) - multiplier[i] = m_spellInfo->Effects[i].CalcDamageMultiplier(m_originalCaster, this); - - bool usesAmmo = (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_DIRECT_DAMAGE) != 0; + for (SpellEffectInfo const* effect : GetEffects()) + if (effect && (m_applyMultiplierMask & (1 << effect->EffectIndex))) + multiplier[effect->EffectIndex] = effect->CalcDamageMultiplier(m_originalCaster, this); for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { @@ -6755,31 +6992,6 @@ void Spell::HandleLaunchPhase() if (!mask) continue; - // do not consume ammo anymore for Hunter's volley spell - if (IsTriggered() && m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->IsTargetingArea()) - usesAmmo = false; - - if (usesAmmo) - { - bool ammoTaken = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) - { - if (!(mask & 1<<i)) - continue; - switch (m_spellInfo->Effects[i].Effect) - { - case SPELL_EFFECT_SCHOOL_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - ammoTaken=true; - TakeAmmo(); - } - if (ammoTaken) - break; - } - } DoAllEffectOnLaunchTarget(target, multiplier); } } @@ -6796,18 +7008,18 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) if (!unit) return; - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (targetInfo.effectMask & (1<<i)) + if (effect && (targetInfo.effectMask & (1<<effect->EffectIndex))) { m_damage = 0; m_healing = 0; - HandleEffects(unit, NULL, NULL, i, SPELL_EFFECT_HANDLE_LAUNCH_TARGET); + HandleEffects(unit, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_LAUNCH_TARGET); if (m_damage > 0) { - if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) + if (effect->IsTargetingArea() || effect->IsAreaAuraEffect() || effect->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) { m_damage = int32(float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); if (m_caster->GetTypeId() != TYPEID_PLAYER) @@ -6822,10 +7034,10 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) } } - if (m_applyMultiplierMask & (1 << i)) + if (m_applyMultiplierMask & (1 << effect->EffectIndex)) { - m_damage = int32(m_damage * m_damageMultipliers[i]); - m_damageMultipliers[i] *= multiplier[i]; + m_damage = int32(m_damage * m_damageMultipliers[effect->EffectIndex]); + m_damageMultipliers[effect->EffectIndex] *= multiplier[effect->EffectIndex]; } targetInfo.damage += m_damage; } @@ -6845,6 +7057,10 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk if (!lockInfo) return SPELL_FAILED_BAD_TARGETS; + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return SPELL_FAILED_BAD_TARGETS; // no idea about correct error + bool reqKey = false; // some locks not have reqs for (int j = 0; j < MAX_LOCK_CASE; ++j) @@ -6863,7 +7079,7 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk reqKey = true; // wrong locktype, skip - if (uint32(m_spellInfo->Effects[effIndex].MiscValue) != lockInfo->Index[j]) + if (uint32(effect->MiscValue) != lockInfo->Index[j]) continue; skillId = SkillByLockType(LockType(lockInfo->Index[j])); @@ -6878,8 +7094,8 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk // skill bonus provided by casting spell (mostly item spells) // add the effect base points modifier from the spell cast (cheat lock / skeleton key etc.) - if (m_spellInfo->Effects[effIndex].TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET || m_spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET) - skillValue += m_spellInfo->Effects[effIndex].CalcValue(); + if (effect->TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET || effect->TargetB.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET) + skillValue += effect->CalcValue(); if (skillValue < reqSkillValue) return SPELL_FAILED_LOW_CASTLEVEL; @@ -6898,17 +7114,15 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk void Spell::SetSpellValue(SpellValueMod mod, int32 value) { + if (mod < SPELLVALUE_BASE_POINT_END) + { + if (SpellEffectInfo const* effect = GetEffect(mod)) + m_spellValue->EffectBasePoints[mod] = effect->CalcBaseValue(value); + return; + } + switch (mod) { - case SPELLVALUE_BASE_POINT0: - m_spellValue->EffectBasePoints[0] = m_spellInfo->Effects[EFFECT_0].CalcBaseValue(value); - break; - case SPELLVALUE_BASE_POINT1: - m_spellValue->EffectBasePoints[1] = m_spellInfo->Effects[EFFECT_1].CalcBaseValue(value); - break; - case SPELLVALUE_BASE_POINT2: - m_spellValue->EffectBasePoints[2] = m_spellInfo->Effects[EFFECT_2].CalcBaseValue(value); - break; case SPELLVALUE_RADIUS_MOD: m_spellValue->RadiusMod = (float)value / 10000; break; @@ -6931,7 +7145,7 @@ void Spell::FinishTargetProcessing() SendLogExecute(); } -void Spell::InitEffectExecuteData(uint8 effIndex) +void Spell::InitEffectExecuteData(uint32 effIndex) { ASSERT(effIndex < MAX_SPELL_EFFECTS); if (!m_effectExecuteData[effIndex]) @@ -7193,9 +7407,9 @@ bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByA { bool only_on_caster = (triggeredByAura && (triggeredByAura->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER)); // If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a cast spell with TARGET_UNIT_CASTER - for (uint8 i = 0;i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if ((effMask & (1 << i)) && (!only_on_caster || (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_CASTER))) + if (effect && ((effMask & (1 << effect->EffectIndex)) && (!only_on_caster || (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER)))) return true; } return false; @@ -7236,19 +7450,23 @@ void Spell::PrepareTriggersExecutedOnHit() continue; SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo(); uint32 auraSpellIdx = (*i)->GetEffIndex(); - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraSpellInfo->Effects[auraSpellIdx].TriggerSpell)) + // todo 6.x + if (SpellEffectInfo const* auraEffect = auraSpellInfo->GetEffect(m_caster->GetMap()->GetDifficulty(), auraSpellIdx)) { - // calculate the chance using spell base amount, because aura amount is not updated on combo-points change - // this possibly needs fixing - int32 auraBaseAmount = (*i)->GetBaseAmount(); - // proc chance is stored in effect amount - int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount); - // build trigger and add to the list - HitTriggerSpell spellTriggerInfo; - spellTriggerInfo.triggeredSpell = spellInfo; - spellTriggerInfo.triggeredByAura = auraSpellInfo; - spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount(); - m_hitTriggerSpells.push_back(spellTriggerInfo); + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraEffect->TriggerSpell)) + { + // calculate the chance using spell base amount, because aura amount is not updated on combo-points change + // this possibly needs fixing + int32 auraBaseAmount = (*i)->GetBaseAmount(); + // proc chance is stored in effect amount + int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount); + // build trigger and add to the list + HitTriggerSpell spellTriggerInfo; + spellTriggerInfo.triggeredSpell = spellInfo; + spellTriggerInfo.triggeredByAura = auraSpellInfo; + spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount(); + m_hitTriggerSpells.push_back(spellTriggerInfo); + } } } } @@ -7321,6 +7539,16 @@ void Spell::CancelGlobalCooldown() m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); } +bool Spell::HasEffect(SpellEffectName effect) const +{ + for (SpellEffectInfo const* eff : GetEffects()) + { + if (eff && eff->IsEffect(effect)) + return true; + } + return false; +} + namespace Trinity { diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index dc07449c41f..57302c4f32e 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -25,6 +25,14 @@ #include "SpellInfo.h" #include "PathGenerator.h" +namespace WorldPackets +{ + namespace Spells + { + struct SpellTargetData; + } +} + class Unit; class Player; class GameObject; @@ -99,10 +107,11 @@ class SpellCastTargets { public: SpellCastTargets(); + SpellCastTargets(Unit* caster, uint32 targetMask, ObjectGuid targetGuid, ObjectGuid itemTargetGuid, ObjectGuid srcTransportGuid, ObjectGuid destTransportGuid, Position srcPos, Position destPos, float elevation, float missileSpeed, std::string targetString); ~SpellCastTargets(); void Read(ByteBuffer& data, Unit* caster); - void Write(ByteBuffer& data); + void Write(WorldPackets::Spells::SpellTargetData& data); uint32 GetTargetMask() const { return m_targetMask; } void SetTargetMask(uint32 newMask) { m_targetMask = newMask; } @@ -168,6 +177,7 @@ class SpellCastTargets void Update(Unit* caster); void OutDebug() const; + std::string GetTargetString() const { return m_strTarget; } private: uint32 m_targetMask; @@ -191,7 +201,7 @@ class SpellCastTargets struct SpellValue { - explicit SpellValue(SpellInfo const* proto); + explicit SpellValue(Difficulty diff, SpellInfo const* proto); int32 EffectBasePoints[MAX_SPELL_EFFECTS]; uint32 MaxAffectedTargets; float RadiusMod; @@ -377,7 +387,7 @@ class Spell void SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask); void SelectImplicitTrajTargets(SpellEffIndex effIndex); - void SelectEffectTypeImplicitTargets(uint8 effIndex); + void SelectEffectTypeImplicitTargets(uint32 effIndex); uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList); template<class SEARCHER> void SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius); @@ -394,7 +404,6 @@ class Spell void cast(bool skipCheck = false); void finish(bool ok = true); void TakePower(); - void TakeAmmo(); void TakeRunePower(bool didHit); void TakeReagents(); @@ -417,7 +426,7 @@ class Spell SpellCastResult CheckCasterAuras() const; SpellCastResult CheckArenaAndRatedBattlegroundCastRules(); - int32 CalculateDamage(uint8 i, Unit const* target) const { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_spellValue->EffectBasePoints[i]); } + int32 CalculateDamage(uint8 i, Unit const* target, float* var = nullptr) const { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_spellValue->EffectBasePoints[i], var); } bool HaveTargetsForEffect(uint8 effect) const; void Delayed(); @@ -503,6 +512,24 @@ class Spell void CleanupTargetList(); void SetSpellValue(SpellValueMod mod, int32 value); + + SpellEffectInfoVector GetEffects() const { return _effects; } + SpellEffectInfo const* GetEffect(uint32 index) const + { + if (index >= _effects.size()) + return nullptr; + + return _effects[index]; + } + + bool HasEffect(SpellEffectName effect) const; + + Spell** m_selfContainer; // pointer to our spell container (if applicable) + + SpellInfo const* GetTriggeredByAuraSpell() const { return m_triggeredByAuraSpell; } + + int32 GetTimer() const { return m_timer; } + protected: bool HasGlobalCooldown() const; void TriggerGlobalCooldown(); @@ -518,8 +545,6 @@ class Spell // e.g. damage around area spell trigered by victim aura and damage enemies of aura caster Unit* m_originalCaster; // cached pointer for m_originalCaster, updated at Spell::UpdatePointers() - Spell** m_selfContainer; // pointer to our spell container (if applicable) - //Spell data SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example) WeaponAttackType m_attackType; // For weapon based attack @@ -558,7 +583,9 @@ class Spell GameObject* gameObjTarget; WorldLocation* destTarget; int32 damage; + float variance; SpellEffectHandleMode effectHandleMode; + SpellEffectInfo const* effectInfo; // used in effects handlers Aura* m_spellAura; @@ -591,7 +618,7 @@ class Spell uint64 timeDelay; SpellMissInfo missCondition:8; SpellMissInfo reflectResult:8; - uint8 effectMask:8; + uint32 effectMask:32; bool processed:1; bool alive:1; bool crit:1; @@ -599,13 +626,13 @@ class Spell int32 damage; }; std::list<TargetInfo> m_UniqueTargetInfo; - uint8 m_channelTargetEffectMask; // Mask req. alive targets + uint32 m_channelTargetEffectMask; // Mask req. alive targets struct GOTargetInfo { ObjectGuid targetGUID; uint64 timeDelay; - uint8 effectMask:8; + uint32 effectMask:32; bool processed:1; }; std::list<GOTargetInfo> m_UniqueGOTargetInfo; @@ -613,7 +640,7 @@ class Spell struct ItemTargetInfo { Item *item; - uint8 effectMask; + uint32 effectMask; }; std::list<ItemTargetInfo> m_UniqueItemInfo; @@ -638,7 +665,7 @@ class Spell void FinishTargetProcessing(); // spell execution log - void InitEffectExecuteData(uint8 effIndex); + void InitEffectExecuteData(uint32 effIndex); void CheckEffectExecuteData(); // Scripting system @@ -689,7 +716,7 @@ class Spell SpellInfo const* m_triggeredByAuraSpell; bool m_skipCheck; - uint8 m_auraScaleMask; + uint32 m_auraScaleMask; PathGenerator m_preGeneratedPath; ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS]; @@ -704,6 +731,8 @@ class Spell Spell(Spell const& right) = delete; Spell& operator=(Spell const& right) = delete; + + SpellEffectInfoVector _effects; }; namespace Trinity diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9c12abbe6e2..e3d2b9d3d1f 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -252,6 +252,68 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectUnused, //180 SPELL_EFFECT_180 unused &Spell::EffectUnused, //181 SPELL_EFFECT_181 unused &Spell::EffectNULL, //182 SPELL_EFFECT_182 + &Spell::EffectNULL, //183 SPELL_EFFECT_183 + &Spell::EffectNULL, //184 SPELL_EFFECT_184 + &Spell::EffectNULL, //185 SPELL_EFFECT_185 + &Spell::EffectNULL, //186 SPELL_EFFECT_186 + &Spell::EffectNULL, //187 SPELL_EFFECT_187 + &Spell::EffectNULL, //188 SPELL_EFFECT_188 + &Spell::EffectNULL, //189 SPELL_EFFECT_189 + &Spell::EffectNULL, //190 SPELL_EFFECT_190 + &Spell::EffectNULL, //191 SPELL_EFFECT_191 + &Spell::EffectNULL, //192 SPELL_EFFECT_192 + &Spell::EffectNULL, //193 SPELL_EFFECT_193 + &Spell::EffectNULL, //194 SPELL_EFFECT_194 + &Spell::EffectNULL, //195 SPELL_EFFECT_195 + &Spell::EffectNULL, //196 SPELL_EFFECT_196 + &Spell::EffectNULL, //197 SPELL_EFFECT_197 + &Spell::EffectNULL, //198 SPELL_EFFECT_198 + &Spell::EffectNULL, //199 SPELL_EFFECT_199 + &Spell::EffectNULL, //200 SPELL_EFFECT_200 + &Spell::EffectNULL, //201 SPELL_EFFECT_201 + &Spell::EffectNULL, //202 SPELL_EFFECT_202 + &Spell::EffectNULL, //203 SPELL_EFFECT_203 + &Spell::EffectNULL, //204 SPELL_EFFECT_204 + &Spell::EffectNULL, //205 SPELL_EFFECT_205 + &Spell::EffectNULL, //206 SPELL_EFFECT_206 + &Spell::EffectNULL, //207 SPELL_EFFECT_207 + &Spell::EffectNULL, //208 SPELL_EFFECT_208 + &Spell::EffectNULL, //209 SPELL_EFFECT_209 + &Spell::EffectNULL, //210 SPELL_EFFECT_210 + &Spell::EffectNULL, //211 SPELL_EFFECT_211 + &Spell::EffectNULL, //212 SPELL_EFFECT_212 + &Spell::EffectNULL, //213 SPELL_EFFECT_213 + &Spell::EffectNULL, //214 SPELL_EFFECT_214 + &Spell::EffectNULL, //215 SPELL_EFFECT_215 + &Spell::EffectNULL, //216 SPELL_EFFECT_216 + &Spell::EffectNULL, //217 SPELL_EFFECT_217 + &Spell::EffectNULL, //218 SPELL_EFFECT_218 + &Spell::EffectNULL, //219 SPELL_EFFECT_219 + &Spell::EffectNULL, //220 SPELL_EFFECT_220 + &Spell::EffectNULL, //221 SPELL_EFFECT_221 + &Spell::EffectNULL, //222 SPELL_EFFECT_222 + &Spell::EffectNULL, //223 SPELL_EFFECT_223 + &Spell::EffectNULL, //224 SPELL_EFFECT_224 + &Spell::EffectNULL, //225 SPELL_EFFECT_225 + &Spell::EffectNULL, //226 SPELL_EFFECT_226 + &Spell::EffectNULL, //227 SPELL_EFFECT_227 + &Spell::EffectNULL, //228 SPELL_EFFECT_228 + &Spell::EffectNULL, //229 SPELL_EFFECT_229 + &Spell::EffectNULL, //230 SPELL_EFFECT_230 + &Spell::EffectNULL, //231 SPELL_EFFECT_231 + &Spell::EffectNULL, //232 SPELL_EFFECT_232 + &Spell::EffectNULL, //233 SPELL_EFFECT_233 + &Spell::EffectNULL, //234 SPELL_EFFECT_234 + &Spell::EffectNULL, //235 SPELL_EFFECT_235 + &Spell::EffectNULL, //236 SPELL_EFFECT_236 + &Spell::EffectNULL, //237 SPELL_EFFECT_237 + &Spell::EffectNULL, //238 SPELL_EFFECT_238 + &Spell::EffectNULL, //239 SPELL_EFFECT_239 + &Spell::EffectNULL, //240 SPELL_EFFECT_240 + &Spell::EffectNULL, //241 SPELL_EFFECT_241 + &Spell::EffectNULL, //242 SPELL_EFFECT_242 + &Spell::EffectNULL, //243 SPELL_EFFECT_243 + &Spell::EffectNULL, //244 SPELL_EFFECT_244 }; void Spell::EffectNULL(SpellEffIndex /*effIndex*/) @@ -284,7 +346,7 @@ void Spell::EffectResurrectNew(SpellEffIndex effIndex) return; uint32 health = damage; - uint32 mana = m_spellInfo->Effects[effIndex].MiscValue; + uint32 mana = effectInfo->MiscValue; ExecuteLogEffectResurrect(effIndex, target); target->SetResurrectRequestData(m_caster, health, mana, 0); SendResurrectRequest(target); @@ -359,7 +421,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) { // Consumption case 28865: - damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250); + damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == DIFFICULTY_NONE ? 2750 : 4250); break; // percent from health with min case 25599: // Thundercrash @@ -419,23 +481,6 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) } case SPELLFAMILY_PRIEST: { - // Improved Mind Blast (Mind Blast in shadow form bonus) - if (m_caster->GetShapeshiftForm() == FORM_SHADOW && (m_spellInfo->SpellFamilyFlags[0] & 0x00002000)) - { - Unit::AuraEffectList const& ImprMindBlast = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_FLAT_MODIFIER); - for (Unit::AuraEffectList::const_iterator i = ImprMindBlast.begin(); i != ImprMindBlast.end(); ++i) - { - if ((*i)->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_PRIEST && - ((*i)->GetSpellInfo()->SpellIconID == 95)) - { - int chance = (*i)->GetSpellInfo()->Effects[EFFECT_1].CalcValue(m_caster); - if (roll_chance_i(chance)) - // Mind Trauma - m_caster->CastSpell(unitTarget, 48301, true, nullptr); - break; - } - } - } break; } case SPELLFAMILY_DRUID: @@ -464,31 +509,14 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) if (AuraEffect const* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x00010000, 0, 0, m_caster->GetGUID())) { // count consumed deadly poison doses at target - bool needConsume = true; uint32 spellId = aurEff->GetId(); uint32 doses = aurEff->GetBase()->GetStackAmount(); if (doses > combo) doses = combo; - // Master Poisoner - Unit::AuraEffectList const& auraList = player->GetAuraEffectsByType(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK); - for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter) - { - if ((*iter)->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_ROGUE && (*iter)->GetSpellInfo()->SpellIconID == 1960) - { - uint32 chance = (*iter)->GetSpellInfo()->Effects[EFFECT_2].CalcValue(m_caster); - - if (chance && roll_chance_i(chance)) - needConsume = false; - - break; - } - } - - if (needConsume) - for (uint32 i = 0; i < doses; ++i) - unitTarget->RemoveAuraFromStack(spellId, m_caster->GetGUID()); + for (uint32 i = 0; i < doses; ++i) + unitTarget->RemoveAuraFromStack(spellId, m_caster->GetGUID()); damage *= doses; damage += int32(player->GetTotalAttackPowerValue(BASE_ATTACK) * 0.09f * combo); @@ -533,10 +561,11 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) } } - if (m_originalCaster && damage > 0 && apply_direct_bonus) + if (m_originalCaster && apply_direct_bonus) { - damage = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); - damage = unitTarget->SpellDamageBonusTaken(m_originalCaster, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); + uint32 bonus = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effectInfo); + damage = bonus + uint32(bonus * variance); + damage = unitTarget->SpellDamageBonusTaken(m_originalCaster, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effectInfo); } m_damage += damage; @@ -612,16 +641,16 @@ void Spell::EffectDummy(SpellEffIndex effIndex) sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, itemTarget); } -void Spell::EffectTriggerSpell(SpellEffIndex effIndex) +void Spell::EffectTriggerSpell(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET && effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH) return; - uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell; + uint32 triggered_spell_id = effectInfo->TriggerSpell; /// @todo move those to spell scripts - if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_TRIGGER_SPELL + if (effectInfo->Effect == SPELL_EFFECT_TRIGGER_SPELL && effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET) { // special cases @@ -718,13 +747,13 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) SpellCastTargets targets; if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET) { - if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo)) + if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficulty())) return; targets.SetUnitTarget(unitTarget); } else //if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH) { - if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) && (m_spellInfo->Effects[effIndex].GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK)) + if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficulty()) && (effectInfo->GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK)) return; if (spellInfo->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION) @@ -738,7 +767,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) CustomSpellValues values; // set basepoints for trigger with value effect - if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE) + if (effectInfo->Effect == SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE) { values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); values.AddSpellMod(SPELLVALUE_BASE_POINT1, damage); @@ -754,13 +783,13 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID); } -void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex) +void Spell::EffectTriggerMissileSpell(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET && effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell; + uint32 triggered_spell_id = effectInfo->TriggerSpell; // normal case SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); @@ -773,13 +802,13 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex) SpellCastTargets targets; if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET) { - if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo)) + if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficulty())) return; targets.SetUnitTarget(unitTarget); } else //if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT) { - if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) && (m_spellInfo->Effects[effIndex].GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK)) + if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficulty()) && (effectInfo->GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK)) return; if (spellInfo->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION) @@ -790,7 +819,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex) CustomSpellValues values; // set basepoints for trigger with value effect - if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE) + if (effectInfo->Effect == SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE) { // maybe need to set value only when basepoints == 0? values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); @@ -807,7 +836,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex) m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID); } -void Spell::EffectForceCast(SpellEffIndex effIndex) +void Spell::EffectForceCast(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -815,7 +844,7 @@ void Spell::EffectForceCast(SpellEffIndex effIndex) if (!unitTarget) return; - uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell; + uint32 triggered_spell_id = effectInfo->TriggerSpell; // normal case SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); @@ -826,7 +855,7 @@ void Spell::EffectForceCast(SpellEffIndex effIndex) return; } - if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_FORCE_CAST && damage) + if (effectInfo->Effect == SPELL_EFFECT_FORCE_CAST && damage) { switch (m_spellInfo->Id) { @@ -850,7 +879,7 @@ void Spell::EffectForceCast(SpellEffIndex effIndex) CustomSpellValues values; // set basepoints for trigger with value effect - if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_FORCE_CAST_WITH_VALUE) + if (effectInfo->Effect == SPELL_EFFECT_FORCE_CAST_WITH_VALUE) { // maybe need to set value only when basepoints == 0? values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); @@ -864,12 +893,12 @@ void Spell::EffectForceCast(SpellEffIndex effIndex) unitTarget->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK); } -void Spell::EffectTriggerRitualOfSummoning(SpellEffIndex effIndex) +void Spell::EffectTriggerRitualOfSummoning(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell; + uint32 triggered_spell_id = effectInfo->TriggerSpell; SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); if (!spellInfo) @@ -924,12 +953,15 @@ void Spell::EffectJumpDest(SpellEffIndex effIndex) void Spell::CalculateJumpSpeeds(uint8 i, float dist, float & speedXY, float & speedZ) { - if (m_spellInfo->Effects[i].MiscValue) - speedZ = float(m_spellInfo->Effects[i].MiscValue)/10; - else if (m_spellInfo->Effects[i].MiscValueB) - speedZ = float(m_spellInfo->Effects[i].MiscValueB)/10; - else - speedZ = 10.0f; + if (SpellEffectInfo const* effect = GetEffect(i)) + { + if (effect->MiscValue) + speedZ = float(effect->MiscValue) / 10; + else if (effect->MiscValueB) + speedZ = float(effect->MiscValueB) / 10; + else + speedZ = 10.0f; + } speedXY = dist * 10.0f / speedZ; } @@ -1087,7 +1119,7 @@ void Spell::EffectApplyAreaAura(SpellEffIndex effIndex) m_spellAura->_ApplyEffectForTargets(effIndex); } -void Spell::EffectUnlearnSpecialization(SpellEffIndex effIndex) +void Spell::EffectUnlearnSpecialization(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -1096,7 +1128,7 @@ void Spell::EffectUnlearnSpecialization(SpellEffIndex effIndex) return; Player* player = unitTarget->ToPlayer(); - uint32 spellToUnlearn = m_spellInfo->Effects[effIndex].TriggerSpell; + uint32 spellToUnlearn = effectInfo->TriggerSpell; player->RemoveSpell(spellToUnlearn); @@ -1108,17 +1140,18 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS)) + if (effectInfo->MiscValue < 0 || effectInfo->MiscValue >= int8(MAX_POWERS)) return; - Powers powerType = Powers(m_spellInfo->Effects[effIndex].MiscValue); + Powers powerType = Powers(effectInfo->MiscValue); if (!unitTarget || !unitTarget->IsAlive() || unitTarget->getPowerType() != powerType || damage < 0) return; // add spell damage bonus - damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); - damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); + uint32 bonus = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effectInfo); + damage = bonus + uint32(bonus * variance); + damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, effectInfo); int32 newDamage = -(unitTarget->ModifyPower(powerType, -damage)); @@ -1127,7 +1160,7 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex) // Don't restore from self drain if (m_caster != unitTarget) { - gainMultiplier = m_spellInfo->Effects[effIndex].CalcValueMultiplier(m_originalCaster, this); + gainMultiplier = effectInfo->CalcValueMultiplier(m_originalCaster, this); int32 gain = int32(newDamage* gainMultiplier); @@ -1136,7 +1169,7 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex) ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, newDamage, gainMultiplier); } -void Spell::EffectSendEvent(SpellEffIndex effIndex) +void Spell::EffectSendEvent(SpellEffIndex /*effIndex*/) { // we do not handle a flag dropping or clicking on flag in battleground by sendevent system if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET @@ -1159,7 +1192,7 @@ void Spell::EffectSendEvent(SpellEffIndex effIndex) // this check was requested by scripters, but it has some downsides: // now it's impossible to script (using sEventScripts) a cast which misses all targets // or to have an ability to script the moment spell hits dest (in a case when there are object targets present) - if (m_spellInfo->Effects[effIndex].GetProvidedTargetMask() & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT_MASK)) + if (effectInfo->GetProvidedTargetMask() & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT_MASK)) return; // some spells have no target entries in dbc and they use focus target if (focusObject) @@ -1167,14 +1200,14 @@ void Spell::EffectSendEvent(SpellEffIndex effIndex) /// @todo there should be a possibility to pass dest target to event script } - TC_LOG_DEBUG("spells", "Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->Effects[effIndex].MiscValue, m_spellInfo->Id); + TC_LOG_DEBUG("spells", "Spell ScriptStart %u for spellid %u in EffectSendEvent ", effectInfo->MiscValue, m_spellInfo->Id); if (ZoneScript* zoneScript = m_caster->GetZoneScript()) - zoneScript->ProcessEvent(target, m_spellInfo->Effects[effIndex].MiscValue); + zoneScript->ProcessEvent(target, effectInfo->MiscValue); else if (InstanceScript* instanceScript = m_caster->GetInstanceScript()) // needed in case Player is the caster - instanceScript->ProcessEvent(target, m_spellInfo->Effects[effIndex].MiscValue); + instanceScript->ProcessEvent(target, effectInfo->MiscValue); - m_caster->GetMap()->ScriptsStart(sEventScripts, m_spellInfo->Effects[effIndex].MiscValue, m_caster, target); + m_caster->GetMap()->ScriptsStart(sEventScripts, effectInfo->MiscValue, m_caster, target); } void Spell::EffectPowerBurn(SpellEffIndex effIndex) @@ -1182,10 +1215,10 @@ void Spell::EffectPowerBurn(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS)) + if (effectInfo->MiscValue < 0 || effectInfo->MiscValue >= int8(MAX_POWERS)) return; - Powers powerType = Powers(m_spellInfo->Effects[effIndex].MiscValue); + Powers powerType = Powers(effectInfo->MiscValue); if (!unitTarget || !unitTarget->IsAlive() || unitTarget->getPowerType() != powerType || damage < 0) return; @@ -1201,7 +1234,7 @@ void Spell::EffectPowerBurn(SpellEffIndex effIndex) int32 newDamage = -(unitTarget->ModifyPower(powerType, -damage)); // NO - Not a typo - EffectPowerBurn uses effect value multiplier - not effect damage multiplier - float dmgMultiplier = m_spellInfo->Effects[effIndex].CalcValueMultiplier(m_originalCaster, this); + float dmgMultiplier = effectInfo->CalcValueMultiplier(m_originalCaster, this); // add log data before multiplication (need power amount, not damage) ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, newDamage, 0.0f); @@ -1271,7 +1304,7 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/) int32 tickheal = targetAura->GetAmount(); if (Unit* auraCaster = targetAura->GetCaster()) - tickheal = auraCaster->SpellHealingBonusDone(unitTarget, targetAura->GetSpellInfo(), tickheal, DOT); + tickheal = auraCaster->SpellHealingBonusDone(unitTarget, targetAura->GetSpellInfo(), tickheal, DOT, effectInfo); //int32 tickheal = targetAura->GetSpellInfo()->EffectBasePoints[idx] + 1; //It is said that talent bonus should not be included @@ -1294,11 +1327,15 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/) } // Death Pact - return pct of max health to caster else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) - addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL); + addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL, effectInfo); else - addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL); + { + addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, effectInfo); + uint32 bonus = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, effectInfo); + damage = bonus + uint32(bonus * variance); + } - addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL); + addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL, effectInfo); // Remove Grievious bite if fully healed if (unitTarget->HasAura(48920) && (unitTarget->GetHealth() + addhealth >= unitTarget->GetMaxHealth())) @@ -1320,8 +1357,8 @@ void Spell::EffectHealPct(SpellEffIndex /*effIndex*/) if (!m_originalCaster) return; - uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL); - heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL); + uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL, effectInfo); + heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL, effectInfo); m_healing += heal; } @@ -1338,12 +1375,13 @@ void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/) if (!m_originalCaster) return; - uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL); + uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL, effectInfo); + heal += uint32(heal * variance); - m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL); + m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL, effectInfo); } -void Spell::EffectHealthLeech(SpellEffIndex effIndex) +void Spell::EffectHealthLeech(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -1351,12 +1389,13 @@ void Spell::EffectHealthLeech(SpellEffIndex effIndex) if (!unitTarget || !unitTarget->IsAlive() || damage < 0) return; - damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); - damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); + uint32 bonus = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effectInfo); + damage = bonus + uint32(bonus * variance); + damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, effectInfo); TC_LOG_DEBUG("spells", "HealthLeech :%i", damage); - float healMultiplier = m_spellInfo->Effects[effIndex].CalcValueMultiplier(m_originalCaster, this); + float healMultiplier = effectInfo->CalcValueMultiplier(m_originalCaster, this); m_damage += damage; // get max possible damage, don't count overkill for heal @@ -1364,8 +1403,8 @@ void Spell::EffectHealthLeech(SpellEffIndex effIndex) if (m_caster->IsAlive()) { - healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL); - healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL); + healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL, effectInfo); + healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL, effectInfo); m_caster->HealBySpell(m_caster, m_spellInfo, uint32(healthGain)); } @@ -1491,8 +1530,8 @@ void Spell::EffectCreateItem(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - DoCreateItem(effIndex, m_spellInfo->Effects[effIndex].ItemType); - ExecuteLogEffectCreateItem(effIndex, m_spellInfo->Effects[effIndex].ItemType); + DoCreateItem(effIndex, effectInfo->ItemType); + ExecuteLogEffectCreateItem(effIndex, effectInfo->ItemType); } void Spell::EffectCreateItem2(SpellEffIndex effIndex) @@ -1505,7 +1544,7 @@ void Spell::EffectCreateItem2(SpellEffIndex effIndex) Player* player = unitTarget->ToPlayer(); - uint32 item_id = m_spellInfo->Effects[effIndex].ItemType; + uint32 item_id = effectInfo->ItemType; if (item_id) DoCreateItem(effIndex, item_id); @@ -1553,7 +1592,7 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex) if (!m_spellAura) { Unit* caster = m_caster->GetEntry() == WORLD_TRIGGER ? m_originalCaster : m_caster; - float radius = m_spellInfo->Effects[effIndex].CalcRadius(caster); + float radius = effectInfo->CalcRadius(caster); // Caster not in world, might be spell triggered from aura removal if (!caster->IsInWorld()) @@ -1578,7 +1617,7 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex) m_spellAura->_ApplyEffectForTargets(effIndex); } -void Spell::EffectEnergize(SpellEffIndex effIndex) +void Spell::EffectEnergize(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -1588,10 +1627,10 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) if (!unitTarget->IsAlive()) return; - if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS)) + if (effectInfo->MiscValue < 0 || effectInfo->MiscValue >= int8(MAX_POWERS)) return; - Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); + Powers power = Powers(effectInfo->MiscValue); if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) return; @@ -1687,7 +1726,7 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) } } -void Spell::EffectEnergizePct(SpellEffIndex effIndex) +void Spell::EffectEnergizePct(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -1697,10 +1736,10 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex) if (!unitTarget->IsAlive()) return; - if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS)) + if (effectInfo->MiscValue < 0 || effectInfo->MiscValue >= int8(MAX_POWERS)) return; - Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); + Powers power = Powers(effectInfo->MiscValue); if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) return; @@ -1887,7 +1926,7 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex) ExecuteLogEffectOpenLock(effIndex, gameObjTarget ? (Object*)gameObjTarget : (Object*)itemTarget); } -void Spell::EffectSummonChangeItem(SpellEffIndex effIndex) +void Spell::EffectSummonChangeItem(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; @@ -1905,7 +1944,7 @@ void Spell::EffectSummonChangeItem(SpellEffIndex effIndex) if (m_CastItem->GetOwnerGUID() != player->GetGUID()) return; - uint32 newitemid = m_spellInfo->Effects[effIndex].ItemType; + uint32 newitemid = effectInfo->ItemType; if (!newitemid) return; @@ -2022,14 +2061,14 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - uint32 entry = m_spellInfo->Effects[effIndex].MiscValue; + uint32 entry = effectInfo->MiscValue; if (!entry) return; - SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(m_spellInfo->Effects[effIndex].MiscValueB); + SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(effectInfo->MiscValueB); if (!properties) { - TC_LOG_ERROR("spells", "EffectSummonType: Unhandled summon type %u", m_spellInfo->Effects[effIndex].MiscValueB); + TC_LOG_ERROR("spells", "EffectSummonType: Unhandled summon type %u", effectInfo->MiscValueB); return; } @@ -2130,7 +2169,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) } default: { - float radius = m_spellInfo->Effects[effIndex].CalcRadius(); + float radius = effectInfo->CalcRadius(); TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; @@ -2175,8 +2214,8 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) // The spell that this effect will trigger. It has SPELL_AURA_CONTROL_VEHICLE uint32 spellId = VEHICLE_SPELL_RIDE_HARDCODED; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[effIndex].CalcValue()); - if (spellInfo && spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectInfo->CalcValue()); + if (spellInfo && spellInfo->HasAura(m_originalCaster->GetMap()->GetDifficulty(), SPELL_AURA_CONTROL_VEHICLE)) spellId = spellInfo->Id; // Hard coded enter vehicle spell @@ -2214,13 +2253,13 @@ void Spell::EffectLearnSpell(SpellEffIndex effIndex) Player* player = unitTarget->ToPlayer(); - uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : m_spellInfo->Effects[effIndex].TriggerSpell; + uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : effectInfo->TriggerSpell; player->LearnSpell(spellToLearn, false); TC_LOG_DEBUG("spells", "Spell: %s has learned spell %u from %s", player->GetGUID().ToString().c_str(), spellToLearn, m_caster->GetGUID().ToString().c_str()); } -void Spell::EffectDispel(SpellEffIndex effIndex) +void Spell::EffectDispel(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -2229,7 +2268,7 @@ void Spell::EffectDispel(SpellEffIndex effIndex) return; // Create dispel mask by dispel type - uint32 dispel_type = m_spellInfo->Effects[effIndex].MiscValue; + uint32 dispel_type = effectInfo->MiscValue; uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(dispel_type)); DispelChargesList dispel_list; @@ -2316,12 +2355,15 @@ void Spell::EffectDispel(SpellEffIndex effIndex) // Devour Magic if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->GetCategory() == SPELLCATEGORY_DEVOUR_MAGIC) { - int32 heal_amount = m_spellInfo->Effects[EFFECT_1].CalcValue(m_caster); - m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true); - // Glyph of Felhunter - if (Unit* owner = m_caster->GetOwner()) + if (SpellEffectInfo const* effect = GetEffect(EFFECT_1)) + { + int32 heal_amount = effect->CalcValue(m_caster); + m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true); + // Glyph of Felhunter + if (Unit* owner = m_caster->GetOwner()) if (owner->GetAura(56249)) owner->CastCustomSpell(owner, 19658, &heal_amount, NULL, NULL, true); + } } } @@ -2376,7 +2418,7 @@ void Spell::EffectPickPocket(SpellEffIndex /*effIndex*/) m_caster->ToPlayer()->SendLoot(unitTarget->GetGUID(), LOOT_PICKPOCKETING); } -void Spell::EffectAddFarsight(SpellEffIndex effIndex) +void Spell::EffectAddFarsight(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; @@ -2384,7 +2426,7 @@ void Spell::EffectAddFarsight(SpellEffIndex effIndex) if (m_caster->GetTypeId() != TYPEID_PLAYER) return; - float radius = m_spellInfo->Effects[effIndex].CalcRadius(); + float radius = effectInfo->CalcRadius(); int32 duration = m_spellInfo->GetDuration(); // Caster not in world, might be spell triggered from aura removal if (!m_caster->IsInWorld()) @@ -2412,7 +2454,7 @@ void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/) unitTarget->ToPlayer()->SendTalentWipeConfirm(m_caster->GetGUID()); } -void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex effIndex) +void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -2423,7 +2465,7 @@ void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex effIndex) if (unitTarget->IsInFlight()) return; - float dis = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); + float dis = effectInfo->CalcRadius(m_caster); float fx, fy, fz; m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetObjectSize(), dis); @@ -2431,7 +2473,7 @@ void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex effIndex) unitTarget->NearTeleportTo(fx, fy, fz, -m_caster->GetOrientation(), unitTarget == m_caster); } -void Spell::EffectLearnSkill(SpellEffIndex effIndex) +void Spell::EffectLearnSkill(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -2442,7 +2484,7 @@ void Spell::EffectLearnSkill(SpellEffIndex effIndex) if (damage < 0) return; - uint32 skillid = m_spellInfo->Effects[effIndex].MiscValue; + uint32 skillid = effectInfo->MiscValue; SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skillid, unitTarget->getRace(), unitTarget->getClass()); if (!rcEntry) return; @@ -2452,10 +2494,10 @@ void Spell::EffectLearnSkill(SpellEffIndex effIndex) return; uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid); - unitTarget->ToPlayer()->SetSkill(skillid, m_spellInfo->Effects[effIndex].CalcValue(), std::max<uint16>(skillval, 1), tier->Value[damage - 1]); + unitTarget->ToPlayer()->SetSkill(skillid, effectInfo->CalcValue(), std::max<uint16>(skillval, 1), tier->Value[damage - 1]); } -void Spell::EffectPlayMovie(SpellEffIndex effIndex) +void Spell::EffectPlayMovie(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -2463,7 +2505,7 @@ void Spell::EffectPlayMovie(SpellEffIndex effIndex) if (unitTarget->GetTypeId() != TYPEID_PLAYER) return; - uint32 movieId = GetSpellInfo()->Effects[effIndex].MiscValue; + uint32 movieId = effectInfo->MiscValue; if (!sMovieStore.LookupEntry(movieId)) return; @@ -2502,7 +2544,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex) player->DestroyItemCount(itemTarget, count, true); unitTarget = player; // and add a scroll - DoCreateItem(effIndex, m_spellInfo->Effects[effIndex].ItemType); + DoCreateItem(effIndex, effectInfo->ItemType); itemTarget = NULL; m_targets.SetItemTarget(NULL); } @@ -2512,7 +2554,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex) if (!(m_CastItem && m_CastItem->GetTemplate()->Flags[0] & ITEM_PROTO_FLAG_TRIGGERED_CAST)) player->UpdateCraftSkill(m_spellInfo->Id); - uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue; + uint32 enchant_id = effectInfo->MiscValue; if (!enchant_id) return; @@ -2546,7 +2588,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex) } } -void Spell::EffectEnchantItemPrismatic(SpellEffIndex effIndex) +void Spell::EffectEnchantItemPrismatic(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -2558,7 +2600,7 @@ void Spell::EffectEnchantItemPrismatic(SpellEffIndex effIndex) if (!player) return; - uint32 enchantId = m_spellInfo->Effects[effIndex].MiscValue; + uint32 enchantId = effectInfo->MiscValue; if (!enchantId) return; @@ -2622,7 +2664,7 @@ void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex) if (!itemTarget) return; - uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue; + uint32 enchant_id = effectInfo->MiscValue; if (!enchant_id) { @@ -2757,7 +2799,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex) owner = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself(); } - uint32 petentry = m_spellInfo->Effects[effIndex].MiscValue; + uint32 petentry = effectInfo->MiscValue; if (!owner) { @@ -2843,7 +2885,7 @@ void Spell::EffectLearnPetSpell(SpellEffIndex effIndex) if (!pet) return; - SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[effIndex].TriggerSpell); + SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effectInfo->TriggerSpell); if (!learn_spellproto) return; @@ -2887,7 +2929,7 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/) unitTarget->ToCreature()->AI()->AttackStart(m_caster); } -void Spell::EffectWeaponDmg(SpellEffIndex effIndex) +void Spell::EffectWeaponDmg(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET) return; @@ -2898,9 +2940,11 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) // multiple weapon dmg effect workaround // execute only the last weapon damage // and handle all effects at once - for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { - switch (m_spellInfo->Effects[j].Effect) + if (!effect) + continue; + switch (effect->Effect) { case SPELL_EFFECT_WEAPON_DAMAGE: case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: @@ -2988,48 +3032,14 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) // Blood Strike if (m_spellInfo->SpellFamilyFlags[0] & 0x400000) { - float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) / 2.0f; - // Death Knight T8 Melee 4P Bonus - if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0)) - AddPct(bonusPct, aurEff->GetAmount()); - AddPct(totalDamagePercentMod, bonusPct); - break; - } - // Death Strike - if (m_spellInfo->SpellFamilyFlags[0] & 0x10) - { - // Glyph of Death Strike - // 2% more damage per 5 runic power, up to a maximum of 40% - if (AuraEffect const* aurEff = m_caster->GetAuraEffect(59336, EFFECT_0)) - if (uint32 runic = std::min<uint32>(uint32(m_caster->GetPower(POWER_RUNIC_POWER) / 2.5f), aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(m_caster))) - AddPct(totalDamagePercentMod, runic); - break; - } - // Obliterate (12.5% more damage per disease) - if (m_spellInfo->SpellFamilyFlags[1] & 0x20000) - { - float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), false) / 2.0f; - // Death Knight T8 Melee 4P Bonus - if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0)) - AddPct(bonusPct, aurEff->GetAmount()); - AddPct(totalDamagePercentMod, bonusPct); - break; - } - // Blood-Caked Strike - Blood-Caked Blade - if (m_spellInfo->SpellIconID == 1736) - { - AddPct(totalDamagePercentMod, unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) * 50.0f); - break; - } - // Heart Strike - if (m_spellInfo->SpellFamilyFlags[0] & 0x1000000) - { - float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()); - // Death Knight T8 Melee 4P Bonus - if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0)) - AddPct(bonusPct, aurEff->GetAmount()); - - AddPct(totalDamagePercentMod, bonusPct); + if (SpellEffectInfo const* effect = GetEffect(EFFECT_2)) + { + float bonusPct = effect->CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) / 2.0f; + // Death Knight T8 Melee 4P Bonus + if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0)) + AddPct(bonusPct, aurEff->GetAmount()); + AddPct(totalDamagePercentMod, bonusPct); + } break; } break; @@ -3038,20 +3048,22 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) bool normalized = false; float weaponDamagePercentMod = 1.0f; - for (int j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { - switch (m_spellInfo->Effects[j].Effect) + if (!effect) + continue; + switch (effect->Effect) { case SPELL_EFFECT_WEAPON_DAMAGE: case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - fixed_bonus += CalculateDamage(j, unitTarget); + fixed_bonus += CalculateDamage(effect->EffectIndex, unitTarget); break; case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - fixed_bonus += CalculateDamage(j, unitTarget); + fixed_bonus += CalculateDamage(effect->EffectIndex, unitTarget); normalized = true; break; case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - ApplyPct(weaponDamagePercentMod, CalculateDamage(j, unitTarget)); + ApplyPct(weaponDamagePercentMod, CalculateDamage(effect->EffectIndex, unitTarget)); break; default: break; // not weapon damage effect, just skip @@ -3083,11 +3095,13 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, true); // Sequence is important - for (int j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { + if (!effect) + continue; // We assume that a spell have at most one fixed_bonus // and at most one weaponDamagePercentMod - switch (m_spellInfo->Effects[j].Effect) + switch (effect->Effect) { case SPELL_EFFECT_WEAPON_DAMAGE: case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: @@ -3189,7 +3203,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - uint32 gameobject_id = m_spellInfo->Effects[effIndex].MiscValue; + uint32 gameobject_id = effectInfo->MiscValue; GameObject* pGameObj = new GameObject; @@ -3321,7 +3335,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) case 55693: // Remove Collapsing Cave Aura if (!unitTarget) return; - unitTarget->RemoveAurasDueToSpell(m_spellInfo->Effects[effIndex].CalcValue()); + unitTarget->RemoveAurasDueToSpell(effectInfo->CalcValue()); break; // Bending Shinbone case 8856: @@ -3455,7 +3469,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) case 45151: { //Workaround for Range ... should be global for every ScriptEffect - float radius = m_spellInfo->Effects[effIndex].CalcRadius(); + float radius = effectInfo->CalcRadius(); if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->GetDistance(m_caster) >= radius && !unitTarget->HasAura(46394) && unitTarget != m_caster) unitTarget->CastSpell(unitTarget, 46394, true); @@ -3567,7 +3581,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) return; float x, y, z; - float radius = m_spellInfo->Effects[effIndex].CalcRadius(); + float radius = effectInfo->CalcRadius(); for (uint8 i = 0; i < 15; ++i) { m_caster->GetRandomPoint(*destTarget, radius, x, y, z); @@ -3613,8 +3627,9 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex != 0) return; - uint32 spellID = m_spellInfo->Effects[EFFECT_0].CalcValue(); - uint32 questID = m_spellInfo->Effects[EFFECT_1].CalcValue(); + // Effects for 58418 and 58420 are all DIFFICULTY_NONE so always valid + uint32 spellID = GetEffect(EFFECT_0)->CalcValue(); + uint32 questID = GetEffect(EFFECT_1)->CalcValue(); if (unitTarget->ToPlayer()->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE) unitTarget->CastSpell(unitTarget, spellID, true); @@ -3664,7 +3679,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) { /// @todo a hack, range = 11, should after some time cast, otherwise too far m_caster->CastSpell(parent, 62496, true); - unitTarget->CastSpell(parent, m_spellInfo->Effects[EFFECT_0].CalcValue()); + unitTarget->CastSpell(parent, GetEffect(EFFECT_0)->CalcValue()); // DIFFICULTY_NONE, so effect always valid } } } @@ -3856,7 +3871,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) //CREATE DUEL FLAG OBJECT GameObject* pGameObj = new GameObject; - uint32 gameobject_id = m_spellInfo->Effects[effIndex].MiscValue; + uint32 gameobject_id = effectInfo->MiscValue; Map* map = m_caster->GetMap(); if (!pGameObj->Create(sObjectMgr->GetGenerator<HighGuid::GameObject>()->Generate(), gameobject_id, @@ -3981,12 +3996,12 @@ void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/) ScriptInfo activateCommand; activateCommand.command = SCRIPT_COMMAND_ACTIVATE_OBJECT; - // int32 unk = m_spellInfo->Effects[effIndex].MiscValue; // This is set for EffectActivateObject spells; needs research + // int32 unk = effectInfo->MiscValue; // This is set for EffectActivateObject spells; needs research gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, 0, m_caster, gameObjTarget); } -void Spell::EffectApplyGlyph(SpellEffIndex effIndex) +void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; @@ -4020,7 +4035,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex) } // apply new one - if (uint32 newGlyph = m_spellInfo->Effects[effIndex].MiscValue) + if (uint32 newGlyph = effectInfo->MiscValue) { if (GlyphPropertiesEntry const* newGlyphProperties = sGlyphPropertiesStore.LookupEntry(newGlyph)) { @@ -4059,7 +4074,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex) } } -void Spell::EffectEnchantHeldItem(SpellEffIndex effIndex) +void Spell::EffectEnchantHeldItem(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4078,9 +4093,9 @@ void Spell::EffectEnchantHeldItem(SpellEffIndex effIndex) if (!item->IsEquipped()) return; - if (m_spellInfo->Effects[effIndex].MiscValue) + if (effectInfo->MiscValue) { - uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue; + uint32 enchant_id = effectInfo->MiscValue; int32 duration = m_spellInfo->GetDuration(); //Try duration index first .. if (!duration) duration = damage;//+1; //Base points after .. @@ -4174,7 +4189,7 @@ void Spell::EffectFeedPet(SpellEffIndex effIndex) player->DestroyItemCount(foodItem, count, true); /// @todo fix crash when a spell has two effects, both pointed at the same item target - m_caster->CastCustomSpell(pet, m_spellInfo->Effects[effIndex].TriggerSpell, &benefit, NULL, NULL, true); + m_caster->CastCustomSpell(pet, effectInfo->TriggerSpell, &benefit, NULL, NULL, true); } void Spell::EffectDismissPet(SpellEffIndex effIndex) @@ -4196,8 +4211,8 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - uint32 go_id = m_spellInfo->Effects[effIndex].MiscValue; - uint8 slot = m_spellInfo->Effects[effIndex].Effect - SPELL_EFFECT_SUMMON_OBJECT_SLOT1; + uint32 go_id = effectInfo->MiscValue; + uint8 slot = effectInfo->Effect - SPELL_EFFECT_SUMMON_OBJECT_SLOT1; ObjectGuid guid = m_caster->m_ObjectSlot[slot]; if (!guid.IsEmpty()) { @@ -4320,7 +4335,7 @@ void Spell::EffectLeap(SpellEffIndex /*effIndex*/) unitTarget->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), unitTarget == m_caster); } -void Spell::EffectReputation(SpellEffIndex effIndex) +void Spell::EffectReputation(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4332,7 +4347,7 @@ void Spell::EffectReputation(SpellEffIndex effIndex) int32 repChange = damage; - uint32 factionId = m_spellInfo->Effects[effIndex].MiscValue; + uint32 factionId = effectInfo->MiscValue; FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId); if (!factionEntry) @@ -4343,7 +4358,7 @@ void Spell::EffectReputation(SpellEffIndex effIndex) player->GetReputationMgr().ModifyReputation(factionEntry, repChange); } -void Spell::EffectQuestComplete(SpellEffIndex effIndex) +void Spell::EffectQuestComplete(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4352,7 +4367,7 @@ void Spell::EffectQuestComplete(SpellEffIndex effIndex) return; Player* player = unitTarget->ToPlayer(); - uint32 questId = m_spellInfo->Effects[effIndex].MiscValue; + uint32 questId = effectInfo->MiscValue; if (questId) { Quest const* quest = sObjectMgr->GetQuestTemplate(questId); @@ -4377,7 +4392,7 @@ void Spell::EffectForceDeselect(SpellEffIndex /*effIndex*/) m_caster->SendMessageToSet(&data, true); } -void Spell::EffectSelfResurrect(SpellEffIndex effIndex) +void Spell::EffectSelfResurrect(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; @@ -4396,7 +4411,7 @@ void Spell::EffectSelfResurrect(SpellEffIndex effIndex) if (damage < 0) { health = uint32(-damage); - mana = m_spellInfo->Effects[effIndex].MiscValue; + mana = effectInfo->MiscValue; } // percent case else @@ -4488,7 +4503,7 @@ void Spell::EffectChargeDest(SpellEffIndex /*effIndex*/) } } -void Spell::EffectKnockBack(SpellEffIndex effIndex) +void Spell::EffectKnockBack(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4509,13 +4524,13 @@ void Spell::EffectKnockBack(SpellEffIndex effIndex) unitTarget->InterruptNonMeleeSpells(true); float ratio = 0.1f; - float speedxy = float(m_spellInfo->Effects[effIndex].MiscValue) * ratio; + float speedxy = float(effectInfo->MiscValue) * ratio; float speedz = float(damage) * ratio; if (speedxy < 0.1f && speedz < 0.1f) return; float x, y; - if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_KNOCK_BACK_DEST) + if (effectInfo->Effect == SPELL_EFFECT_KNOCK_BACK_DEST) { if (m_targets.HasDst()) destTarget->GetPosition(x, y); @@ -4530,7 +4545,7 @@ void Spell::EffectKnockBack(SpellEffIndex effIndex) unitTarget->KnockbackFrom(x, y, speedxy, speedz); } -void Spell::EffectLeapBack(SpellEffIndex effIndex) +void Spell::EffectLeapBack(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET) return; @@ -4538,13 +4553,13 @@ void Spell::EffectLeapBack(SpellEffIndex effIndex) if (!unitTarget) return; - float speedxy = float(m_spellInfo->Effects[effIndex].MiscValue)/10; - float speedz = float(damage/10); + float speedxy = float(effectInfo->MiscValue) / 10; + float speedz = float(damage / 10); //1891: Disengage m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891); } -void Spell::EffectQuestClear(SpellEffIndex effIndex) +void Spell::EffectQuestClear(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4553,7 +4568,7 @@ void Spell::EffectQuestClear(SpellEffIndex effIndex) return; Player* player = unitTarget->ToPlayer(); - uint32 quest_id = m_spellInfo->Effects[effIndex].MiscValue; + uint32 quest_id = effectInfo->MiscValue; Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id); @@ -4587,7 +4602,7 @@ void Spell::EffectQuestClear(SpellEffIndex effIndex) player->RemoveRewardedQuest(quest_id); } -void Spell::EffectSendTaxi(SpellEffIndex effIndex) +void Spell::EffectSendTaxi(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4595,10 +4610,10 @@ void Spell::EffectSendTaxi(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - unitTarget->ToPlayer()->ActivateTaxiPathTo(m_spellInfo->Effects[effIndex].MiscValue, m_spellInfo->Id); + unitTarget->ToPlayer()->ActivateTaxiPathTo(effectInfo->MiscValue, m_spellInfo->Id); } -void Spell::EffectPullTowards(SpellEffIndex effIndex) +void Spell::EffectPullTowards(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4607,7 +4622,7 @@ void Spell::EffectPullTowards(SpellEffIndex effIndex) return; Position pos; - if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_PULL_TOWARDS_DEST) + if (effectInfo->Effect == SPELL_EFFECT_PULL_TOWARDS_DEST) { if (m_targets.HasDst()) pos.Relocate(*destTarget); @@ -4619,13 +4634,13 @@ void Spell::EffectPullTowards(SpellEffIndex effIndex) pos.Relocate(m_caster); } - float speedXY = float(m_spellInfo->Effects[effIndex].MiscValue) * 0.1f; + float speedXY = float(effectInfo->MiscValue) * 0.1f; float speedZ = unitTarget->GetDistance(pos) / speedXY * 0.5f * Movement::gravity; unitTarget->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ); } -void Spell::EffectDispelMechanic(SpellEffIndex effIndex) +void Spell::EffectDispelMechanic(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4633,7 +4648,7 @@ void Spell::EffectDispelMechanic(SpellEffIndex effIndex) if (!unitTarget) return; - uint32 mechanic = m_spellInfo->Effects[effIndex].MiscValue; + uint32 mechanic = effectInfo->MiscValue; DispelList dispel_list; Unit::AuraMap const& auras = unitTarget->GetOwnedAuras(); for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) @@ -4752,7 +4767,7 @@ void Spell::EffectDurabilityDamage(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - int32 slot = m_spellInfo->Effects[effIndex].MiscValue; + int32 slot = effectInfo->MiscValue; // -1 means all player equipped items and -2 all items if (slot < 0) @@ -4773,7 +4788,7 @@ void Spell::EffectDurabilityDamage(SpellEffIndex effIndex) } } -void Spell::EffectDurabilityDamagePCT(SpellEffIndex effIndex) +void Spell::EffectDurabilityDamagePCT(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4781,7 +4796,7 @@ void Spell::EffectDurabilityDamagePCT(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - int32 slot = m_spellInfo->Effects[effIndex].MiscValue; + int32 slot = effectInfo->MiscValue; // FIXME: some spells effects have value -1/-2 // Possibly its mean -1 all player equipped items and -2 all items @@ -4818,7 +4833,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - uint32 name_id = m_spellInfo->Effects[effIndex].MiscValue; + uint32 name_id = effectInfo->MiscValue; GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(name_id); @@ -4833,9 +4848,9 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (m_targets.HasDst()) destTarget->GetPosition(fx, fy, fz); //FIXME: this can be better check for most objects but still hack - else if (m_spellInfo->Effects[effIndex].HasRadius() && m_spellInfo->Speed == 0) + else if (effectInfo->HasRadius() && m_spellInfo->Speed == 0) { - float dis = m_spellInfo->Effects[effIndex].CalcRadius(m_originalCaster); + float dis = effectInfo->CalcRadius(m_originalCaster); m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis); } else @@ -5044,7 +5059,7 @@ void Spell::EffectSkinPlayerCorpse(SpellEffIndex /*effIndex*/) target->RemovedInsignia(player); } -void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex) +void Spell::EffectStealBeneficialBuff(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5057,7 +5072,7 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex) DispelChargesList steal_list; // Create dispel mask by dispel type - uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[effIndex].MiscValue)); + uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(effectInfo->MiscValue)); Unit::AuraMap const& auras = unitTarget->GetOwnedAuras(); for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) { @@ -5149,7 +5164,7 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex) m_caster->SendMessageToSet(&dataSuccess, true); } -void Spell::EffectKillCreditPersonal(SpellEffIndex effIndex) +void Spell::EffectKillCreditPersonal(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5157,10 +5172,10 @@ void Spell::EffectKillCreditPersonal(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - unitTarget->ToPlayer()->KilledMonsterCredit(m_spellInfo->Effects[effIndex].MiscValue); + unitTarget->ToPlayer()->KilledMonsterCredit(effectInfo->MiscValue); } -void Spell::EffectKillCredit(SpellEffIndex effIndex) +void Spell::EffectKillCredit(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5168,7 +5183,7 @@ void Spell::EffectKillCredit(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - int32 creatureEntry = m_spellInfo->Effects[effIndex].MiscValue; + int32 creatureEntry = effectInfo->MiscValue; if (!creatureEntry) { if (m_spellInfo->Id == 42793) // Burn Body @@ -5179,7 +5194,7 @@ void Spell::EffectKillCredit(SpellEffIndex effIndex) unitTarget->ToPlayer()->RewardPlayerAndGroupAtEvent(creatureEntry, unitTarget); } -void Spell::EffectQuestFail(SpellEffIndex effIndex) +void Spell::EffectQuestFail(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5187,10 +5202,10 @@ void Spell::EffectQuestFail(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - unitTarget->ToPlayer()->FailQuest(m_spellInfo->Effects[effIndex].MiscValue); + unitTarget->ToPlayer()->FailQuest(effectInfo->MiscValue); } -void Spell::EffectQuestStart(SpellEffIndex effIndex) +void Spell::EffectQuestStart(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5202,7 +5217,7 @@ void Spell::EffectQuestStart(SpellEffIndex effIndex) if (!player) return; - if (Quest const* quest = sObjectMgr->GetQuestTemplate(m_spellInfo->Effects[effIndex].MiscValue)) + if (Quest const* quest = sObjectMgr->GetQuestTemplate(effectInfo->MiscValue)) { if (!player->CanTakeQuest(quest, false)) return; @@ -5234,10 +5249,10 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) if (count == 0) count = 1; for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j) { - if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue)) + if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(effectInfo->MiscValue)) { if (m_spellInfo->Id == 45529) - if (player->GetBaseRune(j) != RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) + if (player->GetBaseRune(j) != RuneType(effectInfo->MiscValueB)) continue; player->SetRuneCooldown(j, 0); --count; @@ -5250,7 +5265,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) for (uint32 l = 0; l + 1 < MAX_RUNES && count > 0; ++l) { // Check if both runes are on cd as that is the only time when this needs to come into effect - if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l+1) && player->GetCurrentRune(l+1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB))) + if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RuneType(effectInfo->MiscValueB)) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RuneType(effectInfo->MiscValueB))) { // Should always update the rune with the lowest cd if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l+1)) @@ -5280,7 +5295,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) } } -void Spell::EffectCreateTamedPet(SpellEffIndex effIndex) +void Spell::EffectCreateTamedPet(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5288,7 +5303,7 @@ void Spell::EffectCreateTamedPet(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || !unitTarget->GetPetGUID().IsEmpty() || unitTarget->getClass() != CLASS_HUNTER) return; - uint32 creatureEntry = m_spellInfo->Effects[effIndex].MiscValue; + uint32 creatureEntry = effectInfo->MiscValue; Pet* pet = unitTarget->CreateTamedPetFrom(creatureEntry, m_spellInfo->Id); if (!pet) return; @@ -5313,14 +5328,14 @@ void Spell::EffectCreateTamedPet(SpellEffIndex effIndex) } } -void Spell::EffectDiscoverTaxi(SpellEffIndex effIndex) +void Spell::EffectDiscoverTaxi(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - uint32 nodeid = m_spellInfo->Effects[effIndex].MiscValue; + uint32 nodeid = effectInfo->MiscValue; if (sTaxiNodesStore.LookupEntry(nodeid)) unitTarget->ToPlayer()->GetSession()->SendDiscoverNewTaxiNode(nodeid); } @@ -5373,7 +5388,7 @@ void Spell::EffectGameObjectRepair(SpellEffIndex /*effIndex*/) gameObjTarget->ModifyHealth(damage, m_caster); } -void Spell::EffectGameObjectSetDestructionState(SpellEffIndex effIndex) +void Spell::EffectGameObjectSetDestructionState(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5382,7 +5397,7 @@ void Spell::EffectGameObjectSetDestructionState(SpellEffIndex effIndex) return; Player* player = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself(); - gameObjTarget->SetDestructibleState(GameObjectDestructibleState(m_spellInfo->Effects[effIndex].MiscValue), player, true); + gameObjTarget->SetDestructibleState(GameObjectDestructibleState(effectInfo->MiscValue), player, true); } void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* properties, uint32 numGuardians) @@ -5464,7 +5479,7 @@ void Spell::EffectRenamePet(SpellEffIndex /*effIndex*/) unitTarget->SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); } -void Spell::EffectPlayMusic(SpellEffIndex effIndex) +void Spell::EffectPlayMusic(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5472,7 +5487,7 @@ void Spell::EffectPlayMusic(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - uint32 soundid = m_spellInfo->Effects[effIndex].MiscValue; + uint32 soundid = effectInfo->MiscValue; if (!sSoundEntriesStore.LookupEntry(soundid)) { @@ -5508,7 +5523,7 @@ void Spell::EffectActivateSpec(SpellEffIndex /*effIndex*/) unitTarget->ToPlayer()->ActivateTalentGroup(damage-1); // damage is 1 or 2, spec is 0 or 1 } -void Spell::EffectPlaySound(SpellEffIndex effIndex) +void Spell::EffectPlaySound(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5529,7 +5544,7 @@ void Spell::EffectPlaySound(SpellEffIndex effIndex) break; } - uint32 soundId = m_spellInfo->Effects[effIndex].MiscValue; + uint32 soundId = effectInfo->MiscValue; if (!sSoundEntriesStore.LookupEntry(soundId)) { @@ -5540,7 +5555,7 @@ void Spell::EffectPlaySound(SpellEffIndex effIndex) player->PlayDirectSound(soundId, player); } -void Spell::EffectRemoveAura(SpellEffIndex effIndex) +void Spell::EffectRemoveAura(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5548,7 +5563,7 @@ void Spell::EffectRemoveAura(SpellEffIndex effIndex) if (!unitTarget) return; // there may be need of specifying casterguid of removed auras - unitTarget->RemoveAurasDueToSpell(m_spellInfo->Effects[effIndex].TriggerSpell); + unitTarget->RemoveAurasDueToSpell(effectInfo->TriggerSpell); } void Spell::EffectDamageFromMaxHealthPCT(SpellEffIndex /*effIndex*/) @@ -5562,7 +5577,7 @@ void Spell::EffectDamageFromMaxHealthPCT(SpellEffIndex /*effIndex*/) m_damage += unitTarget->CountPctFromMaxHealth(damage); } -void Spell::EffectGiveCurrency(SpellEffIndex effIndex) +void Spell::EffectGiveCurrency(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5570,10 +5585,10 @@ void Spell::EffectGiveCurrency(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - unitTarget->ToPlayer()->ModifyCurrency(m_spellInfo->Effects[effIndex].MiscValue, damage); + unitTarget->ToPlayer()->ModifyCurrency(effectInfo->MiscValue, damage); } -void Spell::EffectCastButtons(SpellEffIndex effIndex) +void Spell::EffectCastButtons(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; @@ -5582,8 +5597,8 @@ void Spell::EffectCastButtons(SpellEffIndex effIndex) return; Player* p_caster = m_caster->ToPlayer(); - uint32 button_id = m_spellInfo->Effects[effIndex].MiscValue + 132; - uint32 n_buttons = m_spellInfo->Effects[effIndex].MiscValueB; + uint32 button_id = effectInfo->MiscValue + 132; + uint32 n_buttons = effectInfo->MiscValueB; for (; n_buttons; --n_buttons, ++button_id) { @@ -5628,25 +5643,27 @@ void Spell::EffectRechargeManaGem(SpellEffIndex /*effIndex*/) if (!player) return; - - uint32 item_id = m_spellInfo->Effects[EFFECT_0].ItemType; - - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item_id); - if (!pProto) + if (SpellEffectInfo const* effect = GetEffect(EFFECT_0)) { - player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } + uint32 item_id = effect->ItemType; - if (Item* pItem = player->GetItemByEntry(item_id)) - { - for (int x = 0; x < pProto->Effects.size(); ++x) - pItem->SetSpellCharges(x, pProto->Effects[x].Charges); - pItem->SetState(ITEM_CHANGED, player); + ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item_id); + if (!pProto) + { + player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (Item* pItem = player->GetItemByEntry(item_id)) + { + for (int x = 0; x < pProto->Effects.size(); ++x) + pItem->SetSpellCharges(x, pProto->Effects[x].Charges); + pItem->SetState(ITEM_CHANGED, player); + } } } -void Spell::EffectBind(SpellEffIndex effIndex) +void Spell::EffectBind(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5659,8 +5676,8 @@ void Spell::EffectBind(SpellEffIndex effIndex) WorldLocation homeLoc; uint32 areaId = player->GetAreaId(); - if (m_spellInfo->Effects[effIndex].MiscValue) - areaId = m_spellInfo->Effects[effIndex].MiscValue; + if (effectInfo->MiscValue) + areaId = effectInfo->MiscValue; if (m_targets.HasDst()) homeLoc.WorldRelocate(*destTarget); @@ -5668,27 +5685,19 @@ void Spell::EffectBind(SpellEffIndex effIndex) homeLoc = player->GetWorldLocation(); player->SetHomebind(homeLoc, areaId); - - // binding - WorldPacket data(SMSG_BINDPOINTUPDATE, 4 + 4 + 4 + 4 + 4); - data << float(homeLoc.GetPositionX()); - data << float(homeLoc.GetPositionY()); - data << float(homeLoc.GetPositionZ()); - data << uint32(homeLoc.GetMapId()); - data << uint32(areaId); - player->SendDirectMessage(&data); + player->SendBindPointUpdate(); TC_LOG_DEBUG("spells", "EffectBind: New homebind X: %f, Y: %f, Z: %f, MapId: %u, AreaId: %u", homeLoc.GetPositionX(), homeLoc.GetPositionY(), homeLoc.GetPositionZ(), homeLoc.GetMapId(), areaId); // zone update - data.Initialize(SMSG_PLAYERBOUND, 8 + 4); + WorldPacket data(SMSG_PLAYERBOUND, 8 + 4); data << m_caster->GetGUID(); data << uint32(areaId); player->SendDirectMessage(&data); } -void Spell::EffectSummonRaFFriend(SpellEffIndex effIndex) +void Spell::EffectSummonRaFFriend(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5696,10 +5705,10 @@ void Spell::EffectSummonRaFFriend(SpellEffIndex effIndex) if (m_caster->GetTypeId() != TYPEID_PLAYER || !unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - m_caster->CastSpell(unitTarget, m_spellInfo->Effects[effIndex].TriggerSpell, true); + m_caster->CastSpell(unitTarget, effectInfo->TriggerSpell, true); } -void Spell::EffectUnlockGuildVaultTab(SpellEffIndex effIndex) +void Spell::EffectUnlockGuildVaultTab(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; @@ -5707,7 +5716,7 @@ void Spell::EffectUnlockGuildVaultTab(SpellEffIndex effIndex) // Safety checks done in Spell::CheckCast Player* caster = m_caster->ToPlayer(); if (Guild* guild = caster->GetGuild()) - guild->HandleBuyBankTab(caster->GetSession(), m_spellInfo->Effects[effIndex].BasePoints - 1); // Bank tabs start at zero internally + guild->HandleBuyBankTab(caster->GetSession(), effectInfo->BasePoints - 1); // Bank tabs start at zero internally } void Spell::EffectResurrectWithAura(SpellEffIndex effIndex) @@ -5731,8 +5740,8 @@ void Spell::EffectResurrectWithAura(SpellEffIndex effIndex) uint32 health = target->CountPctFromMaxHealth(damage); uint32 mana = CalculatePct(target->GetMaxPower(POWER_MANA), damage); uint32 resurrectAura = 0; - if (sSpellMgr->GetSpellInfo(GetSpellInfo()->Effects[effIndex].TriggerSpell)) - resurrectAura = GetSpellInfo()->Effects[effIndex].TriggerSpell; + if (sSpellMgr->GetSpellInfo(effectInfo->TriggerSpell)) + resurrectAura = effectInfo->TriggerSpell; if (resurrectAura && target->HasAura(resurrectAura)) return; @@ -5742,7 +5751,7 @@ void Spell::EffectResurrectWithAura(SpellEffIndex effIndex) SendResurrectRequest(target); } -void Spell::EffectCreateAreaTrigger(SpellEffIndex effIndex) +void Spell::EffectCreateAreaTrigger(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; @@ -5754,7 +5763,7 @@ void Spell::EffectCreateAreaTrigger(SpellEffIndex effIndex) pos = destTarget->GetPosition(); // trigger entry/miscvalue relation is currently unknown, for now use MiscValue as trigger entry - uint32 triggerEntry = GetSpellInfo()->Effects[effIndex].MiscValue; + uint32 triggerEntry = effectInfo->MiscValue; AreaTrigger * areaTrigger = new AreaTrigger; if (!areaTrigger->CreateAreaTrigger(sObjectMgr->GetGenerator<HighGuid::AreaTrigger>()->Generate(), triggerEntry, GetCaster(), GetSpellInfo(), pos)) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index cc88cc41e5a..da3135f6001 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -341,10 +341,8 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_ SpellEffectInfo::SpellEffectInfo(SpellEntry const* /*spellEntry*/, SpellInfo const* spellInfo, uint8 effIndex, SpellEffectEntry const* _effect) { - SpellScalingEntry const* scaling = spellInfo->GetSpellScaling(); - _spellInfo = spellInfo; - _effIndex = _effect ? _effect->EffectIndex : effIndex; + EffectIndex = _effect ? _effect->EffectIndex : effIndex; Effect = _effect ? _effect->Effect : 0; ApplyAuraName = _effect ? _effect->EffectAura : 0; ApplyAuraPeriod = _effect ? _effect->EffectAuraPeriod : 0; @@ -358,6 +356,7 @@ SpellEffectInfo::SpellEffectInfo(SpellEntry const* /*spellEntry*/, SpellInfo con MiscValue = _effect ? _effect->EffectMiscValue : 0; MiscValueB = _effect ? _effect->EffectMiscValueB : 0; Mechanic = Mechanics(_effect ? _effect->EffectMechanic : 0); + PositionFacing = _effect ? _effect->EffectPosFacing : 0.0f; TargetA = SpellImplicitTargetInfo(_effect ? _effect->ImplicitTarget[0] : 0); TargetB = SpellImplicitTargetInfo(_effect ? _effect->ImplicitTarget[1] : 0); RadiusEntry = _effect && _effect->EffectRadiusIndex ? sSpellRadiusStore.LookupEntry(_effect->EffectRadiusIndex) : NULL; @@ -366,11 +365,15 @@ SpellEffectInfo::SpellEffectInfo(SpellEntry const* /*spellEntry*/, SpellInfo con ItemType = _effect ? _effect->EffectItemType : 0; TriggerSpell = _effect ? _effect->EffectTriggerSpell : 0; SpellClassMask = _effect ? _effect->EffectSpellClassMask : flag128(); + BonusCoefficientFromAP = _effect ? _effect->BonusCoefficientFromAP : 0.0f; ImplicitTargetConditions = NULL; - // TODO: 6.x these values are no longer in dbc - ScalingMultiplier = /*scaling ? scaling->Multiplier[_effIndex] :*/ 0.0f; - DeltaScalingMultiplier = /*scaling ? scaling->RandomMultiplier[_effIndex] :*/ 0.0f; - ComboScalingMultiplier = /*scaling ? scaling->OtherMultiplier[_effIndex] :*/ 0.0f; + + uint32 _effectScalingId = _effect ? sSpellEffectScallingByEffectId.find(_effect->ID) != sSpellEffectScallingByEffectId.end() ? sSpellEffectScallingByEffectId[_effect->ID] : 0 : 0; + SpellEffectScalingEntry const* _effectScalingEntry = sSpellEffectScalingStore.LookupEntry(_effectScalingId); + + Scaling.Coefficient = _effectScalingEntry ? _effectScalingEntry->Coefficient : 0.0f; + Scaling.Variance = _effectScalingEntry ? _effectScalingEntry->Variance : 0.0f; + Scaling.ResourceCoefficient = _effectScalingEntry ? _effectScalingEntry->ResourceCoefficient : 0.0f; } bool SpellEffectInfo::IsEffect() const @@ -378,7 +381,7 @@ bool SpellEffectInfo::IsEffect() const return Effect != 0; } -bool SpellEffectInfo::IsEffect(SpellEffects effectName) const +bool SpellEffectInfo::IsEffect(SpellEffectName effectName) const { return Effect == uint32(effectName); } @@ -429,42 +432,71 @@ bool SpellEffectInfo::IsUnitOwnedAuraEffect() const return IsAreaAuraEffect() || Effect == SPELL_EFFECT_APPLY_AURA; } -int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const* target) const +int32 SpellEffectInfo::CalcValue(Unit const* caster /*= nullptr*/, int32 const* bp /*= nullptr*/, Unit const* target /*= nullptr*/, float* variance /*= nullptr*/) const { float basePointsPerLevel = RealPointsPerLevel; int32 basePoints = bp ? *bp : BasePoints; float comboDamage = PointsPerResource; // base amount modification based on spell lvl vs caster lvl - if (ScalingMultiplier != 0.0f) + if (Scaling.Coefficient != 0.0f) { - if (caster) + int32 level = _spellInfo->SpellLevel; + if (target && _spellInfo->IsPositiveEffect(EffectIndex) && (Effect == SPELL_EFFECT_APPLY_AURA)) + level = target->getLevel(); + else if (caster) + level = caster->getLevel(); + + if (!(_spellInfo->AttributesEx11 & SPELL_ATTR11_UNK2) && _spellInfo->AttributesEx10 & SPELL_ATTR10_UNK12) + level = _spellInfo->BaseLevel; + + if (_spellInfo->Scaling.MaxScalingLevel && _spellInfo->Scaling.MaxScalingLevel > level) + level = _spellInfo->Scaling.MaxScalingLevel; + + float value = 0.0f; + if (level > 0) { - int32 level = caster->getLevel(); - if (target && _spellInfo->IsPositiveEffect(_effIndex) && (Effect == SPELL_EFFECT_APPLY_AURA)) - level = target->getLevel(); + if (!_spellInfo->Scaling.Class) + return 0; - if (GtSpellScalingEntry const* gtScaling = sGtSpellScalingStore.LookupEntry((_spellInfo->ScalingClass != -1 ? _spellInfo->ScalingClass - 1 : MAX_CLASSES - 1) * 100 + level - 1)) + if (!_spellInfo->Scaling.ScalesFromItemLevel) { - float multiplier = gtScaling->value; - if (_spellInfo->CastTimeMax > 0 && _spellInfo->CastTimeMaxLevel > level) - multiplier *= float(_spellInfo->CastTimeMin + (level - 1) * (_spellInfo->CastTimeMax - _spellInfo->CastTimeMin) / (_spellInfo->CastTimeMaxLevel - 1)) / float(_spellInfo->CastTimeMax); - if (_spellInfo->CoefLevelBase > level) - multiplier *= (1.0f - _spellInfo->CoefBase) * (float)(level - 1) / (float)(_spellInfo->CoefLevelBase - 1) + _spellInfo->CoefBase; - - float preciseBasePoints = ScalingMultiplier * multiplier; - if (DeltaScalingMultiplier) + if (!(_spellInfo->AttributesEx11 & SPELL_ATTR11_UNK2)) { - float delta = fabs(DeltaScalingMultiplier * ScalingMultiplier * multiplier * 0.5f); - preciseBasePoints += frand(-delta, delta); + if (GtSpellScalingEntry const* gtScaling = sGtSpellScalingStore.EvaluateTable(level - 1, (_spellInfo->Scaling.Class > 0 ? _spellInfo->Scaling.Class - 1 : MAX_CLASSES - 1))) + value = gtScaling->value; } + else + value = GetRandomPropertyPoints(level, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0); + } + else + value = GetRandomPropertyPoints(_spellInfo->Scaling.ScalesFromItemLevel, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0); - basePoints = int32(preciseBasePoints); + if (level < _spellInfo->Scaling.CastTimeMaxLevel && _spellInfo->Scaling.CastTimeMax) + value *= float(_spellInfo->Scaling.CastTimeMin + (level - 1) * (_spellInfo->Scaling.CastTimeMax - _spellInfo->Scaling.CastTimeMin) / (_spellInfo->Scaling.CastTimeMaxLevel - 1)) / float(_spellInfo->Scaling.CastTimeMax); - if (ComboScalingMultiplier) - comboDamage = ComboScalingMultiplier * multiplier; - } + if (level < _spellInfo->Scaling.NerfMaxLevel) + value *= ((((1.0 - _spellInfo->Scaling.NerfFactor) * (level - 1)) / (_spellInfo->Scaling.NerfMaxLevel - 1)) + _spellInfo->Scaling.NerfFactor); + } + + value *= Scaling.Coefficient; + if (value != 0.0f && value < 1.0f) + value = 1.0f; + + if (Scaling.Variance) + { + float delta = fabs(Scaling.Variance * 0.5f); + float valueVariance = frand(-delta, delta); + value += value * valueVariance; + + if (variance) + *variance = valueVariance; } + + basePoints = int32(value); + + if (Scaling.ResourceCoefficient) + comboDamage = Scaling.ResourceCoefficient * value; } else { @@ -508,22 +540,9 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const if (uint8 comboPoints = caster->m_movedPlayer->GetComboPoints()) value += comboDamage * comboPoints; - value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value); + value = caster->ApplyEffectModifiers(_spellInfo, EffectIndex, value); // amount multiplication based on caster's level -/* REVIEW - MERGE <<<<<<< HEAD - if (!_spellInfo->GetSpellScaling() && !basePointsPerLevel && (_spellInfo->Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION && _spellInfo->SpellLevel) && - Effect != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && - Effect != SPELL_EFFECT_KNOCK_BACK && - Effect != SPELL_EFFECT_ADD_EXTRA_ATTACKS && - ApplyAuraName != SPELL_AURA_MOD_SPEED_ALWAYS && - ApplyAuraName != SPELL_AURA_MOD_SPEED_NOT_STACK && - ApplyAuraName != SPELL_AURA_MOD_INCREASE_SPEED && - ApplyAuraName != SPELL_AURA_MOD_DECREASE_SPEED) - //there are many more: slow speed, -healing pct - value *= 0.25f * exp(caster->getLevel() * (70 - _spellInfo->SpellLevel) / 1000.0f); - //value = int32(value * (int32)getLevel() / (int32)(_spellInfo->spellLevel ? _spellInfo->spellLevel : 1)); -======= */ if (!caster->IsControlledByPlayer() && _spellInfo->SpellLevel && _spellInfo->SpellLevel != caster->getLevel() && !basePointsPerLevel && (_spellInfo->Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)) @@ -568,13 +587,12 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const if (canEffectScale) { - GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.LookupEntry(_spellInfo->SpellLevel - 1); - GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(caster->getLevel() - 1); + GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.EvaluateTable(_spellInfo->SpellLevel - 1, 0); + GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.EvaluateTable(caster->getLevel() - 1, 0); if (spellScaler && casterScaler) value *= casterScaler->ratio / spellScaler->ratio; } } -// REVIEW - MERGE >>>>>>> master } return int32(value); @@ -862,14 +880,30 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_UNIT}, // 182 SPELL_EFFECT_182 }; -SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effects) +SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap effects) { Id = spellEntry->ID; + // SpellDifficultyEntry + for (SpellEffectEntryMap::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) + { + SpellEffectEntryVector effects = itr->second; + _effects[itr->first].resize(effects.size()); + + for (uint32 i = effects.size(); i > 0; --i) + { + SpellEffectEntry const* effect = effects[i - 1]; + if (!effect) + continue; + + _effects[itr->first][effect->EffectIndex] = new SpellEffectInfo(spellEntry, this, effect->EffectIndex, effect); + } + } + SpellName = spellEntry->Name_lang; - //Rank = spellEntry->Rank; + Rank = nullptr; RuneCostID = spellEntry->RuneCostID; - //SpellDifficultyId = spellEntry->DifficultyID; + SpellDifficultyId = 0; SpellScalingId = spellEntry->ScalingID; SpellAuraOptionsId = spellEntry->AuraOptionsID; SpellAuraRestrictionsId = spellEntry->AuraRestrictionsID; @@ -880,7 +914,6 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effe SpellEquippedItemsId = spellEntry->EquippedItemsID; SpellInterruptsId = spellEntry->InterruptsID; SpellLevelsId = spellEntry->LevelsID; - //SpellPowerId = spellEntry->PowerID; SpellReagentsId = spellEntry->ReagentsID; SpellShapeshiftId = spellEntry->ShapeshiftID; SpellTargetRestrictionsId = spellEntry->TargetRestrictionsID; @@ -916,18 +949,16 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effe SpellIconID = _misc ? _misc->SpellIconID : 0; ActiveIconID = _misc ? _misc->ActiveIconID : 0; - // SpellDifficultyEntry - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - Effects[i] = SpellEffectInfo(spellEntry, this, i, effects[i]); - // SpellScalingEntry SpellScalingEntry const* _scaling = GetSpellScaling(); - CastTimeMin = _scaling ? _scaling->CastTimeMin : 0; - CastTimeMax = _scaling ?_scaling->CastTimeMax : 0; - CastTimeMaxLevel = _scaling ? _scaling->CastTimeMaxLevel : 0; - ScalingClass = _scaling ? _scaling->ScalingClass : 0; - CoefBase = _scaling ? _scaling->NerfFactor : 0; - CoefLevelBase = _scaling ? _scaling->NerfMaxLevel : 0; + Scaling.CastTimeMin = _scaling ? _scaling->CastTimeMin : 0; + Scaling.CastTimeMax = _scaling ?_scaling->CastTimeMax : 0; + Scaling.CastTimeMaxLevel = _scaling ? _scaling->CastTimeMaxLevel : 0; + Scaling.Class = _scaling ? _scaling->ScalingClass : 0; + Scaling.NerfFactor = _scaling ? _scaling->NerfFactor : 0; + Scaling.NerfMaxLevel = _scaling ? _scaling->NerfMaxLevel : 0; + Scaling.MaxScalingLevel = _scaling ? _scaling->MaxScalingLevel : 0; + Scaling.ScalesFromItemLevel = _scaling ? _scaling->ScalesFromItemLevel : 0; // SpellAuraOptionsEntry SpellAuraOptionsEntry const* _options = GetSpellAuraOptions(); @@ -1040,58 +1071,99 @@ uint32 SpellInfo::GetCategory() const return CategoryEntry ? CategoryEntry->ID : 0; } -bool SpellInfo::HasEffect(SpellEffects effect) const +bool SpellInfo::HasEffect(uint32 difficulty, SpellEffectName effect) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsEffect(effect)) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfo const* eff : effects) + { + if (eff && eff->IsEffect(effect)) return true; + } return false; } -bool SpellInfo::HasAura(AuraType aura) const +bool SpellInfo::HasEffect(SpellEffectName effect) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsAura(aura)) + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + { + for (SpellEffectInfo const* eff : itr->second) + { + if (eff && eff->IsEffect(effect)) + return true; + } + } + return false; +} + +bool SpellInfo::HasAura(uint32 difficulty, AuraType aura) const +{ + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfo const* effect : effects) + { + if (effect && effect->IsAura(aura)) return true; + } return false; } -bool SpellInfo::HasAreaAuraEffect() const +bool SpellInfo::HasAreaAuraEffect(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsAreaAuraEffect()) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfo const* effect : effects) + { + if (effect && effect->IsAreaAuraEffect()) return true; + } + return false; +} + +bool SpellInfo::HasAreaAuraEffect() const +{ + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + { + for (SpellEffectInfo const* effect : itr->second) + { + if (effect && effect->IsAreaAuraEffect()) + return true; + } + } return false; } bool SpellInfo::IsExplicitDiscovery() const { - return ((Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM - || Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2) - && Effects[1].Effect == SPELL_EFFECT_SCRIPT_EFFECT) + SpellEffectInfo const* effect0 = GetEffect(DIFFICULTY_NONE, EFFECT_0); + SpellEffectInfo const* effect1 = GetEffect(DIFFICULTY_NONE, EFFECT_1); + + return ((effect0 && (effect0->Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM || effect0->Effect == SPELL_EFFECT_CREATE_ITEM_2)) + && effect1 && effect1->Effect == SPELL_EFFECT_SCRIPT_EFFECT) || Id == 64323; } bool SpellInfo::IsLootCrafting() const { - return (Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM || + SpellEffectInfo const* effect0 = GetEffect(DIFFICULTY_NONE, EFFECT_0); + return effect0 && (effect0->Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM || // different random cards from Inscription (121==Virtuoso Inking Set category) r without explicit item - (Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2 && - ((TotemCategory[0] != 0 || (Totem[0] != 0 && SpellIconID == 1)) || Effects[0].ItemType == 0))); + (effect0->Effect == SPELL_EFFECT_CREATE_ITEM_2 && + ((TotemCategory[0] != 0 || (Totem[0] != 0 && SpellIconID == 1)) || effect0->ItemType == 0))); } bool SpellInfo::IsQuestTame() const { - return Effects[0].Effect == SPELL_EFFECT_THREAT && Effects[1].Effect == SPELL_EFFECT_APPLY_AURA && Effects[1].ApplyAuraName == SPELL_AURA_DUMMY; + SpellEffectInfo const* effect0 = GetEffect(DIFFICULTY_NONE, EFFECT_0); + SpellEffectInfo const* effect1 = GetEffect(DIFFICULTY_NONE, EFFECT_1); + return effect0 && effect1 && effect0->Effect == SPELL_EFFECT_THREAT && effect1->Effect == SPELL_EFFECT_APPLY_AURA && effect1->ApplyAuraName == SPELL_AURA_DUMMY; } -bool SpellInfo::IsProfessionOrRiding() const +bool SpellInfo::IsProfessionOrRiding(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfo const* effect : effects) { - if (Effects[i].Effect == SPELL_EFFECT_SKILL) + if ((effect && effect->Effect == SPELL_EFFECT_SKILL)) { - uint32 skill = Effects[i].MiscValue; + uint32 skill = effect->MiscValue; if (IsProfessionOrRidingSkill(skill)) return true; @@ -1100,13 +1172,14 @@ bool SpellInfo::IsProfessionOrRiding() const return false; } -bool SpellInfo::IsProfession() const +bool SpellInfo::IsProfession(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfo const* effect : effects) { - if (Effects[i].Effect == SPELL_EFFECT_SKILL) + if (effect && effect->Effect == SPELL_EFFECT_SKILL) { - uint32 skill = Effects[i].MiscValue; + uint32 skill = effect->MiscValue; if (IsProfessionSkill(skill)) return true; @@ -1115,13 +1188,14 @@ bool SpellInfo::IsProfession() const return false; } -bool SpellInfo::IsPrimaryProfession() const +bool SpellInfo::IsPrimaryProfession(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for(SpellEffectInfo const* effect : effects) { - if (Effects[i].Effect == SPELL_EFFECT_SKILL) + if (effect && effect->Effect == SPELL_EFFECT_SKILL) { - uint32 skill = Effects[i].MiscValue; + uint32 skill = effect->MiscValue; if (IsPrimaryProfessionSkill(skill)) return true; @@ -1130,9 +1204,9 @@ bool SpellInfo::IsPrimaryProfession() const return false; } -bool SpellInfo::IsPrimaryProfessionFirstRank() const +bool SpellInfo::IsPrimaryProfessionFirstRank(uint32 difficulty) const { - return IsPrimaryProfession() && GetRank() == 1; + return IsPrimaryProfession(difficulty) && GetRank() == 1; } bool SpellInfo::IsAbilityLearnedWithProfession() const @@ -1163,20 +1237,26 @@ bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const return false; } -bool SpellInfo::IsAffectingArea() const +bool SpellInfo::IsAffectingArea(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsEffect() && (Effects[i].IsTargetingArea() || Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) || Effects[i].IsAreaAuraEffect())) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfo const* effect : effects) + { + if (effect && effect->IsEffect() && (effect->IsTargetingArea() || effect->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) || effect->IsAreaAuraEffect())) return true; + } return false; } // checks if spell targets are selected from area, doesn't include spell effects in check (like area wide auras for example) -bool SpellInfo::IsTargetingArea() const +bool SpellInfo::IsTargetingArea(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsEffect() && Effects[i].IsTargetingArea()) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfo const* effect : effects) + { + if (effect && effect->IsEffect() && effect->IsTargetingArea()) return true; + } return false; } @@ -1185,7 +1265,7 @@ bool SpellInfo::NeedsExplicitUnitTarget() const return (GetExplicitTargetMask() & TARGET_FLAG_UNIT_MASK) != 0; } -bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const +bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell, uint32 difficulty) const { if (NeedsExplicitUnitTarget()) return true; @@ -1205,12 +1285,16 @@ bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) con if (triggeringSpell->IsChanneled()) { uint32 mask = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfo const* effect : effects) { - if (Effects[i].TargetA.GetTarget() != TARGET_UNIT_CASTER && Effects[i].TargetA.GetTarget() != TARGET_DEST_CASTER - && Effects[i].TargetB.GetTarget() != TARGET_UNIT_CASTER && Effects[i].TargetB.GetTarget() != TARGET_DEST_CASTER) + if (!effect) + continue; + + if (effect->TargetA.GetTarget() != TARGET_UNIT_CASTER && effect->TargetA.GetTarget() != TARGET_DEST_CASTER + && effect->TargetB.GetTarget() != TARGET_UNIT_CASTER && effect->TargetB.GetTarget() != TARGET_DEST_CASTER) { - mask |= Effects[i].GetProvidedTargetMask(); + mask |= effect->GetProvidedTargetMask(); } } @@ -1248,19 +1332,23 @@ bool SpellInfo::IsStackableWithRanks() const return false; // All stance spells. if any better way, change it. - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + SpellEffectInfoVector effects = GetEffectsForDifficulty(DIFFICULTY_NONE); + for (SpellEffectInfo const* effect : effects) { + if (!effect) + continue; + switch (SpellFamilyName) { case SPELLFAMILY_PALADIN: // Paladin aura Spell - if (Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID) + if (effect->Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID) return false; break; case SPELLFAMILY_DRUID: // Druid form Spell - if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA && - Effects[i].ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) + if (effect->Effect == SPELL_EFFECT_APPLY_AURA && + effect->ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) return false; break; } @@ -1268,9 +1356,9 @@ bool SpellInfo::IsStackableWithRanks() const return true; } -bool SpellInfo::IsPassiveStackableWithRanks() const +bool SpellInfo::IsPassiveStackableWithRanks(uint32 difficulty) const { - return IsPassive() && !HasEffect(SPELL_EFFECT_APPLY_AURA); + return IsPassive() && !HasEffect(difficulty, SPELL_EFFECT_APPLY_AURA); } bool SpellInfo::IsMultiSlotAura() const @@ -1650,12 +1738,12 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a // aura limitations if (player) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffectsForDifficulty(player->GetMap()->GetDifficulty())) { - if (!Effects[i].IsAura()) + if (!effect || !effect->IsAura()) continue; - switch (Effects[i].ApplyAuraName) + switch (effect->ApplyAuraName) { case SPELL_AURA_FLY: { @@ -1665,7 +1753,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a } case SPELL_AURA_MOUNTED: { - if (Effects[i].MiscValueB && !player->GetMountCapability(Effects[i].MiscValueB)) + if (effect->MiscValueB && !player->GetMountCapability(effect->MiscValueB)) return SPELL_FAILED_NOT_HERE; break; } @@ -1814,14 +1902,14 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta return SPELL_FAILED_TARGET_AURASTATE; } - if (TargetAuraSpell && !unitTarget->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster))) + if (TargetAuraSpell && !unitTarget->HasAura(TargetAuraSpell)) return SPELL_FAILED_TARGET_AURASTATE; - if (ExcludeTargetAuraSpell && unitTarget->HasAura(sSpellMgr->GetSpellIdForDifficulty(ExcludeTargetAuraSpell, caster))) + if (ExcludeTargetAuraSpell && unitTarget->HasAura(ExcludeTargetAuraSpell)) return SPELL_FAILED_TARGET_AURASTATE; if (unitTarget->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) - if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT_NEW)) + if (HasEffect(caster->GetMap()->GetDifficulty(), SPELL_EFFECT_SELF_RESURRECT) || HasEffect(caster->GetMap()->GetDifficulty(), SPELL_EFFECT_RESURRECT) || HasEffect(caster->GetMap()->GetDifficulty(), SPELL_EFFECT_RESURRECT_NEW)) return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED; return SPELL_CAST_OK; @@ -1872,18 +1960,18 @@ SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const if (vehicle) { uint16 checkMask = 0; - for (uint8 effIndex = EFFECT_0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + for (SpellEffectInfo const* effect : GetEffectsForDifficulty(caster->GetMap()->GetDifficulty())) { - if (Effects[effIndex].ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) + if (effect && effect->ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) { - SpellShapeshiftFormEntry const* shapeShiftFromEntry = sSpellShapeshiftFormStore.LookupEntry(Effects[effIndex].MiscValue); + SpellShapeshiftFormEntry const* shapeShiftFromEntry = sSpellShapeshiftFormStore.LookupEntry(effect->MiscValue); if (shapeShiftFromEntry && (shapeShiftFromEntry->Flags & 1) == 0) // unk flag checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED; break; } } - if (HasAura(SPELL_AURA_MOUNTED)) + if (HasAura(caster->GetMap()->GetDifficulty(), SPELL_AURA_MOUNTED)) checkMask |= VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL; if (!checkMask) @@ -1897,12 +1985,12 @@ SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const // Can only summon uncontrolled minions/guardians when on controlled vehicle if (vehicleSeat->Flags & (VEHICLE_SEAT_FLAG_CAN_CONTROL | VEHICLE_SEAT_FLAG_UNK2)) { - for (uint32 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffectsForDifficulty(caster->GetMap()->GetDifficulty())) { - if (Effects[i].Effect != SPELL_EFFECT_SUMMON) + if (!effect || effect->Effect != SPELL_EFFECT_SUMMON) continue; - SummonPropertiesEntry const* props = sSummonPropertiesStore.LookupEntry(Effects[i].MiscValueB); + SummonPropertiesEntry const* props = sSummonPropertiesStore.LookupEntry(effect->MiscValueB); if (props && props->Category != SUMMON_CATEGORY_WILD) return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; } @@ -1942,19 +2030,30 @@ uint32 SpellInfo::GetAllEffectsMechanicMask() const uint32 mask = 0; if (Mechanic) mask |= 1 << Mechanic; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsEffect() && Effects[i].Mechanic) - mask |= 1 << Effects[i].Mechanic; + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + { + for (SpellEffectInfo const* effect : itr->second) + { + if (effect && effect->IsEffect() && effect->Mechanic) + mask |= 1 << effect->Mechanic; + } + } return mask; } -uint32 SpellInfo::GetEffectMechanicMask(uint8 effIndex) const +uint32 SpellInfo::GetEffectMechanicMask(uint32 effIndex) const { uint32 mask = 0; if (Mechanic) mask |= 1 << Mechanic; - if (Effects[effIndex].IsEffect() && Effects[effIndex].Mechanic) - mask |= 1 << Effects[effIndex].Mechanic; + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + { + for (SpellEffectInfo const* effect : itr->second) + { + if (effect && effect->EffectIndex == effIndex && effect->IsEffect() && effect->Mechanic) + mask |= 1 << effect->Mechanic; + } + } return mask; } @@ -1963,28 +2062,34 @@ uint32 SpellInfo::GetSpellMechanicMaskByEffectMask(uint32 effectMask) const uint32 mask = 0; if (Mechanic) mask |= 1 << Mechanic; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if ((effectMask & (1 << i)) && Effects[i].Mechanic) - mask |= 1 << Effects[i].Mechanic; + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + { + for (SpellEffectInfo const* effect : itr->second) + { + if (effect && (effectMask & (1 << effect->EffectIndex)) && effect->Mechanic) + mask |= 1 << effect->Mechanic; + } + } return mask; } -Mechanics SpellInfo::GetEffectMechanic(uint8 effIndex) const +Mechanics SpellInfo::GetEffectMechanic(uint32 effIndex, uint32 difficulty) const { - if (Effects[effIndex].IsEffect() && Effects[effIndex].Mechanic) - return Mechanics(Effects[effIndex].Mechanic); + SpellEffectInfo const* effect = GetEffect(difficulty, effIndex); + if (effect && effect->IsEffect() && effect->Mechanic) + return Mechanics(effect->Mechanic); if (Mechanic) return Mechanics(Mechanic); return MECHANIC_NONE; } -bool SpellInfo::HasAnyEffectMechanic() const +/*bool SpellInfo::HasAnyEffectMechanic() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (Effects[i].Mechanic) return true; return false; -} +}*/ uint32 SpellInfo::GetDispelMask() const { @@ -2005,7 +2110,7 @@ uint32 SpellInfo::GetExplicitTargetMask() const return ExplicitTargetMask; } -AuraStateType SpellInfo::GetAuraState() const +AuraStateType SpellInfo::GetAuraState(uint32 difficulty) const { // Seals if (GetSpellSpecific() == SPELL_SPECIFIC_SEAL) @@ -2048,10 +2153,10 @@ AuraStateType SpellInfo::GetAuraState() const return AURA_STATE_BLEEDING; if (GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsAura() && (Effects[i].ApplyAuraName == SPELL_AURA_MOD_STUN - || Effects[i].ApplyAuraName == SPELL_AURA_MOD_ROOT)) - return AURA_STATE_FROZEN; + for (SpellEffectInfo const* effect : GetEffectsForDifficulty(difficulty)) + if (effect && effect->IsAura() && (effect->ApplyAuraName == SPELL_AURA_MOD_STUN + || effect->ApplyAuraName == SPELL_AURA_MOD_ROOT)) + return AURA_STATE_FROZEN; switch (Id) { @@ -2076,24 +2181,27 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const { bool food = false; bool drink = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) { - if (!Effects[i].IsAura()) - continue; - switch (Effects[i].ApplyAuraName) + for (SpellEffectInfo const* effect : itr->second) { - // Food + if (!effect || !effect->IsAura()) + continue; + switch (effect->ApplyAuraName) + { + // Food case SPELL_AURA_MOD_REGEN: case SPELL_AURA_OBS_MOD_HEALTH: food = true; break; - // Drink + // Drink case SPELL_AURA_MOD_POWER_REGEN: case SPELL_AURA_OBS_MOD_POWER: drink = true; break; default: break; + } } } @@ -2133,8 +2241,8 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const // Arcane brillance and Arcane intelect (normal check fails because of flags difference) if (SpellFamilyFlags[0] & 0x400) return SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE; - - if ((SpellFamilyFlags[0] & 0x1000000) && Effects[0].ApplyAuraName == SPELL_AURA_MOD_CONFUSE) + SpellEffectInfo const* effect = GetEffect(DIFFICULTY_NONE, EFFECT_0); + if (effect && (SpellFamilyFlags[0] & 0x1000000) && effect->ApplyAuraName == SPELL_AURA_MOD_CONFUSE) return SPELL_SPECIFIC_MAGE_POLYMORPH; break; @@ -2220,12 +2328,14 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const break; } - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) { - if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) + for (SpellEffectInfo const* effect : itr->second) { - switch (Effects[i].ApplyAuraName) + if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) { + switch (effect->ApplyAuraName) + { case SPELL_AURA_MOD_CHARM: case SPELL_AURA_MOD_POSSESS_PET: case SPELL_AURA_MOD_POSSESS: @@ -2238,10 +2348,10 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const case SPELL_AURA_TRACK_RESOURCES: case SPELL_AURA_TRACK_STEALTHED: return SPELL_SPECIFIC_TRACKER; + } } } } - return SPELL_SPECIFIC_NORMAL; } @@ -2290,11 +2400,11 @@ uint32 SpellInfo::CalcCastTime(uint8 level, Spell* spell /*= NULL*/) const level = spell->GetCaster()->getLevel(); // not all spells have cast time index and this is all is pasiive abilities - if (level && CastTimeMax > 0) + if (level && Scaling.CastTimeMax > 0) { - castTime = CastTimeMax; - if (CastTimeMaxLevel > level) - castTime = CastTimeMin + int32(level - 1) * (CastTimeMax - CastTimeMin) / (CastTimeMaxLevel - 1); + castTime = Scaling.CastTimeMax; + if (Scaling.CastTimeMaxLevel > level) + castTime = Scaling.CastTimeMin + int32(level - 1) * (Scaling.CastTimeMax - Scaling.CastTimeMin) / (Scaling.CastTimeMaxLevel - 1); } else if (CastTimeEntry) castTime = CastTimeEntry->CastTime; @@ -2311,7 +2421,7 @@ uint32 SpellInfo::CalcCastTime(uint8 level, Spell* spell /*= NULL*/) const return (castTime > 0) ? uint32(castTime) : 0; } -uint32 SpellInfo::GetMaxTicks() const +uint32 SpellInfo::GetMaxTicks(uint32 difficulty) const { int32 DotDuration = GetDuration(); if (DotDuration == 0) @@ -2321,16 +2431,16 @@ uint32 SpellInfo::GetMaxTicks() const if (DotDuration > 30000) DotDuration = 30000; - for (uint8 x = 0; x < MAX_SPELL_EFFECTS; x++) + for (SpellEffectInfo const* effect : GetEffectsForDifficulty(difficulty)) { - if (Effects[x].Effect == SPELL_EFFECT_APPLY_AURA) - switch (Effects[x].ApplyAuraName) + if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) + switch (effect->ApplyAuraName) { case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_HEAL: case SPELL_AURA_PERIODIC_LEECH: - if (Effects[x].ApplyAuraPeriod != 0) - return DotDuration / Effects[x].ApplyAuraPeriod; + if (effect->ApplyAuraPeriod != 0) + return DotDuration / effect->ApplyAuraPeriod; break; } } @@ -2426,8 +2536,8 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c { if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION) { - GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.LookupEntry(SpellLevel - 1); - GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(caster->getLevel() - 1); + GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.EvaluateTable(SpellLevel - 1, 0); + GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.EvaluateTable(caster->getLevel() - 1, 0); if (spellScaler && casterScaler) powerCost *= casterScaler->ratio / spellScaler->ratio; } @@ -2492,13 +2602,13 @@ SpellInfo const* SpellInfo::GetAuraRankForLevel(uint8 level) const return this; bool needRankSelection = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (IsPositiveEffect(i) && - (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA || - Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || - Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID) && - !Effects[i].ScalingMultiplier) + if (effect && IsPositiveEffect(effect->Effect) && + (effect->Effect == SPELL_EFFECT_APPLY_AURA || + effect->Effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || + effect->Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID) && + !effect->Scaling.Coefficient) { needRankSelection = true; break; @@ -2550,32 +2660,35 @@ void SpellInfo::_InitializeExplicitTargetMask() bool dstSet = false; uint32 targetMask = Targets; // prepare target mask using effect target entries - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) { - if (!Effects[i].IsEffect()) - continue; + for (SpellEffectInfo const* effect : itr->second) + { + if (!effect || !effect->IsEffect()) + continue; - targetMask |= Effects[i].TargetA.GetExplicitTargetMask(srcSet, dstSet); - targetMask |= Effects[i].TargetB.GetExplicitTargetMask(srcSet, dstSet); + targetMask |= effect->TargetA.GetExplicitTargetMask(srcSet, dstSet); + targetMask |= effect->TargetB.GetExplicitTargetMask(srcSet, dstSet); - // add explicit target flags based on spell effects which have EFFECT_IMPLICIT_TARGET_EXPLICIT and no valid target provided - if (Effects[i].GetImplicitTargetType() != EFFECT_IMPLICIT_TARGET_EXPLICIT) - continue; + // add explicit target flags based on spell effects which have EFFECT_IMPLICIT_TARGET_EXPLICIT and no valid target provided + if (effect->GetImplicitTargetType() != EFFECT_IMPLICIT_TARGET_EXPLICIT) + continue; - // extend explicit target mask only if valid targets for effect could not be provided by target types - uint32 effectTargetMask = Effects[i].GetMissingTargetMask(srcSet, dstSet, targetMask); + // extend explicit target mask only if valid targets for effect could not be provided by target types + uint32 effectTargetMask = effect->GetMissingTargetMask(srcSet, dstSet, targetMask); - // don't add explicit object/dest flags when spell has no max range - if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f) - effectTargetMask &= ~(TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_DEST_LOCATION); + // don't add explicit object/dest flags when spell has no max range + if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f) + effectTargetMask &= ~(TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_DEST_LOCATION); - targetMask |= effectTargetMask; + targetMask |= effectTargetMask; + } } ExplicitTargetMask = targetMask; } -bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const +bool SpellInfo::_IsPositiveEffect(uint32 effIndex, bool deep) const { // not found a single positive spell with this attribute if (Attributes & SPELL_ATTR0_NEGATIVE_1) @@ -2640,40 +2753,50 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const } // Special case: effects which determine positivity of whole spell - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) { - if (Effects[i].IsAura() && Effects[i].ApplyAuraName == SPELL_AURA_MOD_STEALTH) - return true; + for (SpellEffectInfo const* effect : itr->second) + { + if (effect && effect->IsAura() && effect->ApplyAuraName == SPELL_AURA_MOD_STEALTH) + return true; + } } - switch (Effects[effIndex].Effect) + for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) { - case SPELL_EFFECT_DUMMY: - // some explicitly required dummy effect sets - switch (Id) + for (SpellEffectInfo const* effect : itr->second) + { + if (!effect || effect->EffectIndex != effIndex) + continue; + + switch (effect->Effect) { + case SPELL_EFFECT_DUMMY: + // some explicitly required dummy effect sets + switch (Id) + { case 28441: return false; // AB Effect 000 default: break; - } - break; - // always positive effects (check before target checks that provided non-positive result in some case for positive effects) - case SPELL_EFFECT_HEAL: - case SPELL_EFFECT_LEARN_SPELL: - case SPELL_EFFECT_SKILL_STEP: - case SPELL_EFFECT_HEAL_PCT: - case SPELL_EFFECT_ENERGIZE_PCT: - return true; - case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: - return false; + } + break; + // always positive effects (check before target checks that provided non-positive result in some case for positive effects) + case SPELL_EFFECT_HEAL: + case SPELL_EFFECT_LEARN_SPELL: + case SPELL_EFFECT_SKILL_STEP: + case SPELL_EFFECT_HEAL_PCT: + case SPELL_EFFECT_ENERGIZE_PCT: + return true; + case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: + return false; - // non-positive aura use - case SPELL_EFFECT_APPLY_AURA: - case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: - { - switch (Effects[effIndex].ApplyAuraName) + // non-positive aura use + case SPELL_EFFECT_APPLY_AURA: + case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: { + switch (effect->ApplyAuraName) + { case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from bas point sign (negative -> negative) case SPELL_AURA_MOD_STAT: case SPELL_AURA_MOD_SKILL: @@ -2681,16 +2804,16 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const case SPELL_AURA_MOD_HEALING_PCT: case SPELL_AURA_MOD_HEALING_DONE: case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: - if (Effects[effIndex].CalcValue() < 0) + if (effect->CalcValue() < 0) return false; break; case SPELL_AURA_MOD_DAMAGE_TAKEN: // dependent from bas point sign (positive -> negative) - if (Effects[effIndex].CalcValue() > 0) + if (effect->CalcValue() > 0) return false; break; case SPELL_AURA_MOD_CRIT_PCT: case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: - if (Effects[effIndex].CalcValue() > 0) + if (effect->CalcValue() > 0) return true; // some expected positive spells have SPELL_ATTR1_NEGATIVE break; case SPELL_AURA_ADD_TARGET_TRIGGER: @@ -2699,17 +2822,20 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const case SPELL_AURA_PERIODIC_TRIGGER_SPELL: if (!deep) { - if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(Effects[effIndex].TriggerSpell)) + if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(effect->TriggerSpell)) { // negative targets of main spell return early - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfoMap::const_iterator it = spellTriggeredProto->_effects.begin(); it != spellTriggeredProto->_effects.end(); ++it) { - if (!spellTriggeredProto->Effects[i].Effect) - continue; - // if non-positive trigger cast targeted to positive target this main cast is non-positive - // this will place this spell auras as debuffs - if (_IsPositiveTarget(spellTriggeredProto->Effects[i].TargetA.GetTarget(), spellTriggeredProto->Effects[i].TargetB.GetTarget()) && !spellTriggeredProto->_IsPositiveEffect(i, true)) - return false; + for (SpellEffectInfo const* eff : itr->second) + { + if (!eff || !eff->Effect) + continue; + // if non-positive trigger cast targeted to positive target this main cast is non-positive + // this will place this spell auras as debuffs + if (_IsPositiveTarget(eff->TargetA.GetTarget(), eff->TargetB.GetTarget()) && !spellTriggeredProto->_IsPositiveEffect(eff->EffectIndex, true)) + return false; + } } } } @@ -2717,9 +2843,23 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example) break; case SPELL_AURA_MOD_STUN: //have positive and negative spells, we can't sort its correctly at this moment. - if (effIndex == 0 && Effects[1].Effect == 0 && Effects[2].Effect == 0) + { + bool more = false; + for (SpellEffectInfoMap::const_iterator i = _effects.begin(); i != _effects.end(); ++i) + { + for (SpellEffectInfo const* eff : i->second) + { + if (eff && eff->EffectIndex != 0) + { + more = true; + break; + } + } + } + if (effIndex == 0 && !more) return false; // but all single stun aura spells is negative break; + } case SPELL_AURA_MOD_PACIFY_SILENCE: if (Id == 24740) // Wisp Costume return true; @@ -2734,12 +2874,12 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const return false; case SPELL_AURA_PERIODIC_DAMAGE: // used in positive spells also. // part of negative spell if cast at self (prevent cancel) - if (Effects[effIndex].TargetA.GetTarget() == TARGET_UNIT_CASTER) + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER) return false; break; case SPELL_AURA_MOD_DECREASE_SPEED: // used in positive spells also // part of positive spell if cast at self - if (Effects[effIndex].TargetA.GetTarget() != TARGET_UNIT_CASTER) + if (effect->TargetA.GetTarget() != TARGET_UNIT_CASTER) return false; // but not this if this first effect (didn't find better check) if (Attributes & SPELL_ATTR0_NEGATIVE_1 && effIndex == 0) @@ -2748,7 +2888,7 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const case SPELL_AURA_MECHANIC_IMMUNITY: { // non-positive immunities - switch (Effects[effIndex].MiscValue) + switch (effect->MiscValue) { case MECHANIC_BANDAGE: case MECHANIC_SHIELD: @@ -2764,10 +2904,10 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const case SPELL_AURA_ADD_PCT_MODIFIER: { // non-positive mods - switch (Effects[effIndex].MiscValue) + switch (effect->MiscValue) { case SPELLMOD_COST: // dependent from bas point sign (negative -> positive) - if (Effects[effIndex].CalcValue() > 0) + if (effect->CalcValue() > 0) { if (!deep) { @@ -2793,25 +2933,26 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const } default: break; + } + break; + } + default: + break; } - break; - } - default: - break; - } - - // non-positive targets - if (!_IsPositiveTarget(Effects[effIndex].TargetA.GetTarget(), Effects[effIndex].TargetB.GetTarget())) - return false; - // negative spell if triggered spell is negative - if (!deep && !Effects[effIndex].ApplyAuraName && Effects[effIndex].TriggerSpell) - { - if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(Effects[effIndex].TriggerSpell)) - if (!spellTriggeredProto->_IsPositiveSpell()) + // non-positive targets + if (!_IsPositiveTarget(effect->TargetA.GetTarget(), effect->TargetB.GetTarget())) return false; - } + // negative spell if triggered spell is negative + if (!deep && !effect->ApplyAuraName && effect->TriggerSpell) + { + if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(effect->TriggerSpell)) + if (!spellTriggeredProto->_IsPositiveSpell()) + return false; + } + } + } // ok, positive return true; } @@ -2870,7 +3011,10 @@ SpellLevelsEntry const* SpellInfo::GetSpellLevels() const SpellPowerEntry const* SpellInfo::GetSpellPower() const { - return SpellPowerId ? sSpellPowerStore.LookupEntry(SpellPowerId) : NULL; + auto itr = sSpellPowerBySpellIDStore.find(Id); + if (itr != sSpellPowerBySpellIDStore.end()) + return itr->second; + return NULL; } SpellReagentsEntry const* SpellInfo::GetSpellReagents() const @@ -2931,16 +3075,72 @@ SpellCooldownsEntry const* SpellInfo::GetSpellCooldowns() const void SpellInfo::_UnloadImplicitTargetConditionLists() { // find the same instances of ConditionList and delete them. - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint32 d = 0; d < DIFFICULTY_MAX; ++d) { - ConditionList* cur = Effects[i].ImplicitTargetConditions; - if (!cur) - continue; - for (uint8 j = i; j < MAX_SPELL_EFFECTS; ++j) + for (uint32 i = 0; i < _effects.size(); ++i) + { + if (SpellEffectInfo const* effect = GetEffect(d, i)) + { + ConditionList* cur = effect->ImplicitTargetConditions; + if (!cur) + continue; + for (uint8 j = i; j < _effects.size(); ++j) + { + if (SpellEffectInfo const* eff = GetEffect(d, j)) + { + if (eff->ImplicitTargetConditions == cur) + const_cast<SpellEffectInfo*>(eff)->ImplicitTargetConditions = NULL; + } + } + delete cur; + } + } + } +} + +SpellEffectInfoVector SpellInfo::GetEffectsForDifficulty(uint32 difficulty) const +{ + // 6.x todo: add first highest difficulty effect, resize list to max element, add lower diff effects without overwriting any higher diffed ones + + SpellEffectInfoVector effList; + + // DIFFICULTY_NONE effects are the default effects, always active if current difficulty's effects don't overwrite + SpellEffectInfoMap::const_iterator itr = _effects.find(DIFFICULTY_NONE); + if (itr != _effects.end()) + effList = itr->second; + + // downscale difficulty if original was not found + // DIFFICULTY_NONE is already in our list + for (; difficulty > DIFFICULTY_NONE; --difficulty) + { + SpellEffectInfoMap::const_iterator itr = _effects.find(difficulty); + if (itr != _effects.end()) { - if (Effects[j].ImplicitTargetConditions == cur) - Effects[j].ImplicitTargetConditions = NULL; + for (SpellEffectInfo const* effect : itr->second) + { + // overwrite any existing effect from DIFFICULTY_NONE + if (effect) + { + if (effect->EffectIndex >= effList.size()) + effList.resize(effect->EffectIndex + 1); + + effList[effect->EffectIndex] = effect; + } + } + // if we found any effect in our difficulty then stop searching + break; } - delete cur; } + if (effList.empty()) + TC_LOG_ERROR("spells", "GetEffectsForDifficulty did not find any effects for spell %u in difficulty %u", Id, difficulty); + return effList; +} + +SpellEffectInfo const* SpellInfo::GetEffect(uint32 difficulty, uint32 index) const +{ + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + if (index >= effects.size()) + return nullptr; + + return effects[index]; } diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 1fad30dd23b..0f655580b6d 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -65,6 +65,11 @@ enum SpellCastTargetFlags TARGET_FLAG_DEST_TARGET = 0x00040000, // sometimes appears with DEST_TARGET spells (may appear or not for a given spell) TARGET_FLAG_EXTRA_TARGETS = 0x00080000, // uint32 counter, loop { vec3 - screen position (?), guid }, not used so far TARGET_FLAG_UNIT_PASSENGER = 0x00100000, // guessed, used to validate target (if vehicle passenger) + TARGET_FLAG_UNK400000 = 0X00400000, + TARGET_FLAG_UNK1000000 = 0X01000000, + TARGET_FLAG_UNK4000000 = 0X04000000, + TARGET_FLAG_UNK10000000 = 0X10000000, + TARGET_FLAG_UNK40000000 = 0X40000000, TARGET_FLAG_UNIT_MASK = TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT_ALLY | TARGET_FLAG_UNIT_DEAD | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_UNIT_PASSENGER, @@ -230,8 +235,8 @@ private: class SpellEffectInfo { SpellInfo const* _spellInfo; - uint8 _effIndex; public: + uint32 EffectIndex; uint32 Effect; uint32 ApplyAuraName; uint32 ApplyAuraPeriod; @@ -245,6 +250,7 @@ public: int32 MiscValue; int32 MiscValueB; Mechanics Mechanic; + float PositionFacing; SpellImplicitTargetInfo TargetA; SpellImplicitTargetInfo TargetB; SpellRadiusEntry const* RadiusEntry; @@ -253,20 +259,24 @@ public: uint32 ItemType; uint32 TriggerSpell; flag128 SpellClassMask; + float BonusCoefficientFromAP; std::list<Condition*>* ImplicitTargetConditions; // SpellScalingEntry - float ScalingMultiplier; - float DeltaScalingMultiplier; - float ComboScalingMultiplier; + struct ScalingInfo + { + float Coefficient; + float Variance; + float ResourceCoefficient; + } Scaling; - SpellEffectInfo() : _spellInfo(NULL), _effIndex(0), Effect(0), ApplyAuraName(0), ApplyAuraPeriod(0), DieSides(0), + SpellEffectInfo() : _spellInfo(NULL), EffectIndex(0), Effect(0), ApplyAuraName(0), ApplyAuraPeriod(0), DieSides(0), RealPointsPerLevel(0), BasePoints(0), PointsPerResource(0), Amplitude(0), ChainAmplitude(0), - BonusCoefficient(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), RadiusEntry(NULL), ChainTargets(0), - ItemType(0), TriggerSpell(0), ImplicitTargetConditions(NULL) {} + BonusCoefficient(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), PositionFacing(0), + RadiusEntry(NULL), ChainTargets(0), ItemType(0), TriggerSpell(0), BonusCoefficientFromAP(0.0f), ImplicitTargetConditions(NULL) { } SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex, SpellEffectEntry const* effect); bool IsEffect() const; - bool IsEffect(SpellEffects effectName) const; + bool IsEffect(SpellEffectName effectName) const; bool IsAura() const; bool IsAura(AuraType aura) const; bool IsTargetingArea() const; @@ -275,7 +285,7 @@ public: bool IsFarDestTargetEffect() const; bool IsUnitOwnedAuraEffect() const; - int32 CalcValue(Unit const* caster = NULL, int32 const* basePoints = NULL, Unit const* target = NULL) const; + int32 CalcValue(Unit const* caster = nullptr, int32 const* basePoints = nullptr, Unit const* target = nullptr, float* variance = nullptr) const; int32 CalcBaseValue(int32 value) const; float CalcValueMultiplier(Unit* caster, Spell* spell = NULL) const; float CalcDamageMultiplier(Unit* caster, Spell* spell = NULL) const; @@ -299,6 +309,14 @@ private: static StaticData _data[TOTAL_SPELL_EFFECTS]; }; +typedef std::vector<SpellEffectInfo const*> SpellEffectInfoVector; +typedef std::unordered_map<uint32, SpellEffectInfoVector> SpellEffectInfoMap; + +typedef std::vector<SpellEffectEntry const*> SpellEffectEntryVector; +typedef std::unordered_map<uint32, SpellEffectEntryVector> SpellEffectEntryMap; + +typedef std::vector<AuraEffect*> AuraEffectVector; + class SpellInfo { public: @@ -390,20 +408,24 @@ public: uint32 SpellEquippedItemsId; uint32 SpellInterruptsId; uint32 SpellLevelsId; - uint32 SpellPowerId; uint32 SpellReagentsId; uint32 SpellShapeshiftId; uint32 SpellTargetRestrictionsId; uint32 SpellTotemsId; uint32 SpellMiscId; // SpellScalingEntry - int32 CastTimeMin; - int32 CastTimeMax; - int32 CastTimeMaxLevel; - int32 ScalingClass; - float CoefBase; - int32 CoefLevelBase; - SpellEffectInfo Effects[MAX_SPELL_EFFECTS]; + struct ScalingInfo + { + int32 CastTimeMin; + int32 CastTimeMax; + uint32 CastTimeMaxLevel; + int32 Class; + float NerfFactor; + uint32 NerfMaxLevel; + uint32 MaxScalingLevel; + uint32 ScalesFromItemLevel; + } Scaling; + uint32 ExplicitTargetMask; SpellChainNode const* ChainEntry; @@ -425,33 +447,35 @@ public: SpellTotemsEntry const* GetSpellTotems() const; SpellMiscEntry const* GetSpellMisc() const; - SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effects); + SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap effects); ~SpellInfo(); uint32 GetCategory() const; - bool HasEffect(SpellEffects effect) const; - bool HasAura(AuraType aura) const; + bool HasEffect(uint32 difficulty, SpellEffectName effect) const; + bool HasEffect(SpellEffectName effect) const; + bool HasAura(uint32 difficulty, AuraType aura) const; + bool HasAreaAuraEffect(uint32 difficulty) const; bool HasAreaAuraEffect() const; bool IsExplicitDiscovery() const; bool IsLootCrafting() const; bool IsQuestTame() const; - bool IsProfessionOrRiding() const; - bool IsProfession() const; - bool IsPrimaryProfession() const; - bool IsPrimaryProfessionFirstRank() const; + bool IsProfessionOrRiding(uint32 difficulty = DIFFICULTY_NONE) const; + bool IsProfession(uint32 difficulty = DIFFICULTY_NONE) const; + bool IsPrimaryProfession(uint32 difficulty = DIFFICULTY_NONE) const; + bool IsPrimaryProfessionFirstRank(uint32 difficulty = DIFFICULTY_NONE) const; bool IsAbilityLearnedWithProfession() const; bool IsAbilityOfSkillType(uint32 skillType) const; - bool IsAffectingArea() const; - bool IsTargetingArea() const; + bool IsAffectingArea(uint32 difficulty) const; + bool IsTargetingArea(uint32 difficulty) const; bool NeedsExplicitUnitTarget() const; - bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const; + bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell, uint32 difficulty) const; bool IsPassive() const; bool IsAutocastable() const; bool IsStackableWithRanks() const; - bool IsPassiveStackableWithRanks() const; + bool IsPassiveStackableWithRanks(uint32 difficulty) const; bool IsMultiSlotAura() const; bool IsStackableOnOneSlotWithDifferentCasters() const; bool IsCooldownStartedOnEvent() const; @@ -486,15 +510,15 @@ public: SpellSchoolMask GetSchoolMask() const; uint32 GetAllEffectsMechanicMask() const; - uint32 GetEffectMechanicMask(uint8 effIndex) const; + uint32 GetEffectMechanicMask(uint32 effIndex) const; uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const; - Mechanics GetEffectMechanic(uint8 effIndex) const; - bool HasAnyEffectMechanic() const; + Mechanics GetEffectMechanic(uint32 effIndex, uint32 difficulty) const; + //bool HasAnyEffectMechanic() const; uint32 GetDispelMask() const; static uint32 GetDispelMask(DispelType type); uint32 GetExplicitTargetMask() const; - AuraStateType GetAuraState() const; + AuraStateType GetAuraState(uint32 difficulty) const; SpellSpecificType GetSpellSpecific() const; float GetMinRange(bool positive = false) const; @@ -503,7 +527,7 @@ public: int32 GetDuration() const; int32 GetMaxDuration() const; - uint32 GetMaxTicks() const; + uint32 GetMaxTicks(uint32 difficulty) const; uint32 CalcCastTime(uint8 level = 0, Spell* spell = NULL) const; uint32 GetRecoveryTime() const; @@ -523,12 +547,19 @@ public: // loading helpers void _InitializeExplicitTargetMask(); - bool _IsPositiveEffect(uint8 effIndex, bool deep) const; + bool _IsPositiveEffect(uint32 effIndex, bool deep) const; bool _IsPositiveSpell() const; static bool _IsPositiveTarget(uint32 targetA, uint32 targetB); // unloading helpers void _UnloadImplicitTargetConditionLists(); + + SpellEffectInfoVector GetEffectsForDifficulty(uint32 difficulty) const; + SpellEffectInfo const* GetEffect(uint32 difficulty, uint32 index) const; + SpellEffectInfo const* GetEffect(uint32 index) const { return GetEffect(DIFFICULTY_NONE, index); } + SpellEffectInfo const* GetEffect(WorldObject* obj, uint32 index) const { return GetEffect(obj->GetMap()->GetDifficulty(), index); } + + SpellEffectInfoMap _effects; }; #endif // _SPELLINFO_H diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 3b7ab7abe30..544abc9ca87 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -59,9 +59,9 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, if (spellproto->IsPositive()) return DIMINISHING_NONE; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect: spellproto->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellproto->Effects[i].ApplyAuraName == SPELL_AURA_MOD_TAUNT) + if (effect && effect->ApplyAuraName == SPELL_AURA_MOD_TAUNT) return DIMINISHING_TAUNT; } @@ -370,9 +370,12 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg bool needCheckReagents = false; // check effects - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - switch (spellInfo->Effects[i].Effect) + if (!effect) + continue; + + switch (effect->Effect) { case 0: continue; @@ -381,7 +384,7 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg case SPELL_EFFECT_CREATE_ITEM: case SPELL_EFFECT_CREATE_ITEM_2: { - if (spellInfo->Effects[i].ItemType == 0) + if (effect->ItemType == 0) { // skip auto-loot crafting spells, its not need explicit item info (but have special fake items sometime) if (!spellInfo->IsLootCrafting()) @@ -398,14 +401,14 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg } // also possible IsLootCrafting case but fake item must exist anyway - else if (!sObjectMgr->GetItemTemplate(spellInfo->Effects[i].ItemType)) + else if (!sObjectMgr->GetItemTemplate(effect->ItemType)) { if (msg) { if (player) - ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType); + ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, effect->ItemType); else - TC_LOG_ERROR("sql.sql", "Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType); + TC_LOG_ERROR("sql.sql", "Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, effect->ItemType); } return false; } @@ -415,15 +418,15 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg } case SPELL_EFFECT_LEARN_SPELL: { - SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell); + SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(effect->TriggerSpell); if (!IsSpellValid(spellInfo2, player, msg)) { if (msg) { if (player) - ChatHandler(player->GetSession()).PSendSysMessage("Spell %u learn to broken spell %u, and then...", spellInfo->Id, spellInfo->Effects[i].TriggerSpell); + ChatHandler(player->GetSession()).PSendSysMessage("Spell %u learn to broken spell %u, and then...", spellInfo->Id, effect->TriggerSpell); else - TC_LOG_ERROR("sql.sql", "Spell %u learn to invalid spell %u, and then...", spellInfo->Id, spellInfo->Effects[i].TriggerSpell); + TC_LOG_ERROR("sql.sql", "Spell %u learn to invalid spell %u, and then...", spellInfo->Id, effect->TriggerSpell); } return false; } @@ -453,81 +456,6 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg return true; } -uint32 SpellMgr::GetSpellDifficultyId(uint32 spellId) const -{ - SpellDifficultySearcherMap::const_iterator i = mSpellDifficultySearcherMap.find(spellId); - return i == mSpellDifficultySearcherMap.end() ? 0 : i->second; -} - -void SpellMgr::SetSpellDifficultyId(uint32 spellId, uint32 id) -{ - if (uint32 i = GetSpellDifficultyId(spellId)) - TC_LOG_ERROR("spells", "SpellMgr::SetSpellDifficultyId: Spell %u has already spellDifficultyId %u. Will override with spellDifficultyId %u.", spellId, i, id); - mSpellDifficultySearcherMap[spellId] = id; -} - -// TODO: 6.x adapt to new spell diff system -uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const -{ - /*if (!GetSpellInfo(spellId)) - return spellId; - - if (!caster || !caster->GetMap() || !caster->GetMap()->IsDungeon()) - return spellId; - - uint32 mode = uint32(caster->GetMap()->GetSpawnMode()); - if (mode >= MAX_DIFFICULTY) - { - TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: Incorrect Difficulty for spell %u.", spellId); - return spellId; //return source spell - } - - uint32 difficultyId = GetSpellDifficultyId(spellId); - if (!difficultyId) - return spellId; //return source spell, it has only REGULAR_DIFFICULTY - - SpellDifficultyEntry const* difficultyEntry = sSpellDifficultyStore.LookupEntry(difficultyId); - if (!difficultyEntry) - { - TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: SpellDifficultyEntry not found for spell %u. This should never happen.", spellId); - return spellId; //return source spell - } - - if (difficultyEntry->SpellID[mode] <= 0 && mode > DUNGEON_DIFFICULTY_HEROIC) - { - TC_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is NULL, using mode %u", spellId, mode, mode - 2); - mode -= 2; - } - - if (difficultyEntry->SpellID[mode] <= 0) - { - TC_LOG_ERROR("sql.sql", "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is 0. Check spelldifficulty_dbc!", spellId, mode); - return spellId; - } - - TC_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: spellid for spell %u in mode %u is %d", spellId, mode, difficultyEntry->SpellID[mode]); - return uint32(difficultyEntry->SpellID[mode]); - */ - return 0; -} - -SpellInfo const* SpellMgr::GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const -{ - if (!spell) - return NULL; - - uint32 newSpellId = GetSpellIdForDifficulty(spell->Id, caster); - SpellInfo const* newSpell = GetSpellInfo(newSpellId); - if (!newSpell) - { - TC_LOG_DEBUG("spells", "SpellMgr::GetSpellForDifficultyFromSpell: spell %u not found. Check spelldifficulty_dbc!", newSpellId); - return spell; - } - - TC_LOG_DEBUG("spells", "SpellMgr::GetSpellForDifficultyFromSpell: Spell id for instance mode is %u (original %u)", newSpell->Id, spell->Id); - return newSpell; -} - SpellChainNode const* SpellMgr::GetSpellChainNode(uint32 spell_id) const { SpellChainMap::const_iterator itr = mSpellChains.find(spell_id); @@ -1021,22 +949,6 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE return true; } -SpellBonusEntry const* SpellMgr::GetSpellBonusData(uint32 spellId) const -{ - // Lookup data - SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId); - if (itr != mSpellBonusMap.end()) - return &itr->second; - // Not found, try lookup for 1 spell rank if exist - if (uint32 rank_1 = GetFirstSpellInChain(spellId)) - { - SpellBonusMap::const_iterator itr2 = mSpellBonusMap.find(rank_1); - if (itr2 != mSpellBonusMap.end()) - return &itr2->second; - } - return NULL; -} - SpellThreatEntry const* SpellMgr::GetSpellThreatEntry(uint32 spellID) const { SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellID); @@ -1479,13 +1391,13 @@ void SpellMgr::LoadSpellLearnSkills() if (!entry) continue; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : entry->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (entry->Effects[i].Effect == SPELL_EFFECT_SKILL) + if (effect && effect->Effect == SPELL_EFFECT_SKILL) { SpellLearnSkillNode dbc_node; - dbc_node.skill = entry->Effects[i].MiscValue; - dbc_node.step = entry->Effects[i].CalcValue(); + dbc_node.skill = effect->MiscValue; + dbc_node.step = effect->CalcValue(); if (dbc_node.skill != SKILL_RIDING) dbc_node.value = 1; else @@ -1562,12 +1474,12 @@ void SpellMgr::LoadSpellLearnSpells() if (!entry) continue; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : entry->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (entry->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL) + if (effect && effect->Effect == SPELL_EFFECT_LEARN_SPELL) { SpellLearnSpellNode dbc_node; - dbc_node.spell = entry->Effects[i].TriggerSpell; + dbc_node.spell = effect->TriggerSpell; dbc_node.active = true; // all dbc based learned spells is active (show in spell book or hide by client itself) // ignore learning not existed spells (broken/outdated/or generic learnig spell 483 @@ -1577,7 +1489,7 @@ void SpellMgr::LoadSpellLearnSpells() // talent or passive spells or skill-step spells auto-cast and not need dependent learning, // pet teaching spells must not be dependent learning (cast) // other required explicit dependent learning - dbc_node.autoLearned = entry->Effects[i].TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentBySpellID(spell) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP); + dbc_node.autoLearned = effect->TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentBySpellID(spell) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP); SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spell); @@ -1672,8 +1584,8 @@ void SpellMgr::LoadSpellTargetPositions() mSpellTargetPositions.clear(); // need for reload case - // 0 1 2 3 4 5 6 - QueryResult result = WorldDatabase.Query("SELECT id, effIndex, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM spell_target_position"); + // 0 1 2 3 4 5 + QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, MapID, PositionX, PositionY, PositionZ FROM spell_target_position"); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty."); @@ -1694,29 +1606,47 @@ void SpellMgr::LoadSpellTargetPositions() st.target_X = fields[3].GetFloat(); st.target_Y = fields[4].GetFloat(); st.target_Z = fields[5].GetFloat(); - st.target_Orientation = fields[6].GetFloat(); MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId); if (!mapEntry) { - TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) target map (ID: %u) does not exist in `Map.dbc`.", Spell_ID, effIndex, st.target_mapId); + TC_LOG_ERROR("sql.sql", "Spell (ID: %u, EffectIndex: %u) is using a non-existant MapID (ID: %u).", Spell_ID, effIndex, st.target_mapId); continue; } - if (st.target_X==0 && st.target_Y==0 && st.target_Z==0) + if (st.target_X == 0 && st.target_Y == 0 && st.target_Z == 0) { - TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) target coordinates not provided.", Spell_ID, effIndex); + TC_LOG_ERROR("sql.sql", "Spell (ID: %u, EffectIndex: %u): target coordinates not provided.", Spell_ID, effIndex); continue; } SpellInfo const* spellInfo = GetSpellInfo(Spell_ID); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Spell (Id: %u) listed in `spell_target_position` does not exist.", Spell_ID); + TC_LOG_ERROR("sql.sql", "Spell (ID: %u) listed in `spell_target_position` does not exist.", Spell_ID); continue; } - if (spellInfo->Effects[effIndex].TargetA.GetTarget() == TARGET_DEST_DB || spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DB) + SpellEffectInfo const* effect = spellInfo->GetEffect(effIndex); + if (!effect) + { + TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have an effect at index %u.", Spell_ID, effIndex, effIndex); + continue; + } + + // target facing is in degrees for 6484 & 9268... (blizz sucks) + if (effect->PositionFacing > 2 * M_PI) + st.target_Orientation = effect->PositionFacing * M_PI / 180; + else + st.target_Orientation = effect->PositionFacing; + + if (effect->TargetA.GetTarget() == TARGET_DEST_DB || effect->TargetB.GetTarget() == TARGET_DEST_DB) + { + TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have TARGET_DEST_DB as target at index %u.", Spell_ID, effIndex, effIndex); + continue; + } + + if (effect->TargetA.GetTarget() == TARGET_DEST_DB || effect->TargetB.GetTarget() == TARGET_DEST_DB) { std::pair<uint32, SpellEffIndex> key = std::make_pair(Spell_ID, effIndex); mSpellTargetPositions[key] = st; @@ -2121,45 +2051,6 @@ void SpellMgr::LoadSpellProcs() TC_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void SpellMgr::LoadSpellBonusess() -{ - uint32 oldMSTime = getMSTime(); - - mSpellBonusMap.clear(); // need for reload case - - // 0 1 2 3 4 - QueryResult result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data"); - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 spell bonus data. DB table `spell_bonus_data` is empty."); - return; - } - - uint32 count = 0; - do - { - Field* fields = result->Fetch(); - uint32 entry = fields[0].GetUInt32(); - - SpellInfo const* spell = GetSpellInfo(entry); - if (!spell) - { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_bonus_data` does not exist", entry); - continue; - } - - SpellBonusEntry& sbe = mSpellBonusMap[entry]; - sbe.direct_damage = fields[1].GetFloat(); - sbe.dot_damage = fields[2].GetFloat(); - sbe.ap_bonus = fields[3].GetFloat(); - sbe.ap_dot_bonus = fields[4].GetFloat(); - - ++count; - } while (result->NextRow()); - - TC_LOG_INFO("server.loading", ">> Loaded %u extra spell bonus data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); -} - void SpellMgr::LoadSpellThreats() { uint32 oldMSTime = getMSTime(); @@ -2255,9 +2146,16 @@ void SpellMgr::LoadSpellPetAuras() TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_pet_auras` does not exist", spell); continue; } - if (spellInfo->Effects[eff].Effect != SPELL_EFFECT_DUMMY && - (spellInfo->Effects[eff].Effect != SPELL_EFFECT_APPLY_AURA || - spellInfo->Effects[eff].ApplyAuraName != SPELL_AURA_DUMMY)) + SpellEffectInfo const* effect = spellInfo->GetEffect(eff); + if (!effect) + { + TC_LOG_ERROR("spells", "Spell %u listed in `spell_pet_auras` does not have effect at index %u", spell, uint32(eff)); + continue; + } + + if (effect->Effect != SPELL_EFFECT_DUMMY && + (effect->Effect != SPELL_EFFECT_APPLY_AURA || + effect->ApplyAuraName != SPELL_AURA_DUMMY)) { TC_LOG_ERROR("spells", "Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell); continue; @@ -2270,7 +2168,7 @@ void SpellMgr::LoadSpellPetAuras() continue; } - PetAura pa(pet, aura, spellInfo->Effects[eff].TargetA.GetTarget() == TARGET_UNIT_PET, spellInfo->Effects[eff].CalcValue()); + PetAura pa(pet, aura, effect->TargetA.GetTarget() == TARGET_UNIT_PET, effect->CalcValue()); mSpellPetAuraMap[(spell<<8) + eff] = pa; } @@ -2302,11 +2200,11 @@ void SpellMgr::LoadEnchantCustomAttr() if (!(spellInfo->AttributesEx2 & SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT)) continue; - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellInfo->Effects[j].Effect == SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) + if (effect && effect->Effect == SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) { - uint32 enchId = spellInfo->Effects[j].MiscValue; + uint32 enchId = effect->MiscValue; SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchId); if (!ench) continue; @@ -2393,10 +2291,10 @@ void SpellMgr::LoadSpellLinked() } if (effect >= 0) - for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* eff : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellInfo->Effects[j].CalcValue() == abs(effect)) - TC_LOG_ERROR("sql.sql", "Spell %u Effect: %u listed in `spell_linked_spell` has same bp%u like effect (possible hack)", abs(trigger), abs(effect), j); + if (eff && eff->CalcValue() == abs(effect)) + TC_LOG_ERROR("sql.sql", "Spell %u Effect: %u listed in `spell_linked_spell` has same bp%u like effect (possible hack)", abs(trigger), abs(effect), eff->EffectIndex); } spellInfo = GetSpellInfo(abs(effect)); @@ -2570,11 +2468,11 @@ void SpellMgr::LoadPetDefaultSpells() if (!spellEntry) continue; - for (uint8 k = 0; k < MAX_SPELL_EFFECTS; ++k) + for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - if (spellEntry->Effects[k].Effect == SPELL_EFFECT_SUMMON || spellEntry->Effects[k].Effect == SPELL_EFFECT_SUMMON_PET) + if (effect && (effect->Effect == SPELL_EFFECT_SUMMON || effect->Effect == SPELL_EFFECT_SUMMON_PET)) { - uint32 creature_id = spellEntry->Effects[k].MiscValue; + uint32 creature_id = effect->MiscValue; CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature_id); if (!cInfo) continue; @@ -2791,18 +2689,7 @@ void SpellMgr::LoadSpellAreas() TC_LOG_INFO("server.loading", ">> Loaded %u spell area requirements in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -// Temporary structure to hold spell effect entries for faster loading -struct SpellEffectArray -{ - SpellEffectArray() - { - effects[0] = NULL; - effects[1] = NULL; - effects[2] = NULL; - } - - SpellEffectEntry const* effects[MAX_SPELL_EFFECTS]; -}; +typedef std::vector<SpellEffectEntry const*> SpellEffectVector; void SpellMgr::LoadSpellInfoStore() { @@ -2811,25 +2698,30 @@ void SpellMgr::LoadSpellInfoStore() UnloadSpellInfoStore(); mSpellInfoMap.resize(sSpellStore.GetNumRows(), NULL); - std::map<uint32, SpellEffectArray> effectsBySpell; + std::unordered_map<uint32, SpellEffectEntryMap> effectsBySpell; for (uint32 i = 0; i < sSpellEffectStore.GetNumRows(); ++i) { SpellEffectEntry const* effect = sSpellEffectStore.LookupEntry(i); if (!effect) continue; - - // TODO: 6.x implement dynamic spell effect storage and remove MAX_SPELL_EFFECTS - // This is a temporary fix to avoid crash when loading spells + if (effect->EffectIndex >= MAX_SPELL_EFFECTS) + { + TC_LOG_ERROR("server.loading", "Spell %u has invalid EffectIndex %u, max is %u, skipped", i, effect->EffectIndex, uint32(MAX_SPELL_EFFECTS)); continue; + } - effectsBySpell[effect->SpellID].effects[effect->EffectIndex] = effect; + SpellEffectEntryVector& effectsForDifficulty = effectsBySpell[effect->SpellID][effect->DifficultyID]; + if (effectsForDifficulty.size() <= effect->EffectIndex) + effectsForDifficulty.resize(effect->EffectIndex + 1); + + effectsForDifficulty[effect->EffectIndex] = effect; } for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(i)) - mSpellInfoMap[i] = new SpellInfo(spellEntry, effectsBySpell[i].effects); + mSpellInfoMap[i] = new SpellInfo(spellEntry, effectsBySpell[i]); TC_LOG_INFO("server.loading", ">> Loaded SpellInfo store in %u ms", GetMSTimeDiffToNow(oldMSTime)); } @@ -2891,9 +2783,12 @@ void SpellMgr::LoadSpellInfoCustomAttributes() if (!spellInfo) continue; - for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - switch (spellInfo->Effects[j].ApplyAuraName) + if (!effect) + continue; + + switch (effect->ApplyAuraName) { case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_MOD_CONFUSE: @@ -2917,7 +2812,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes() break; } - switch (spellInfo->Effects[j].Effect) + switch (effect->Effect) { case SPELL_EFFECT_SCHOOL_DAMAGE: case SPELL_EFFECT_WEAPON_DAMAGE: @@ -2955,7 +2850,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes() // only enchanting profession enchantments procs can stack if (IsPartOfSkillLine(SKILL_ENCHANTING, i)) { - uint32 enchantId = spellInfo->Effects[j].MiscValue; + uint32 enchantId = effect->MiscValue; SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId); if (!enchant) break; @@ -2972,7 +2867,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes() // if proced directly from enchantment, not via proc aura // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly // however its not expected to stack so this check is good - if (procInfo->HasAura(SPELL_AURA_PROC_TRIGGER_SPELL)) + if (procInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_PROC_TRIGGER_SPELL)) continue; procInfo->AttributesCu |= SPELL_ATTR0_CU_ENCHANT_PROC; @@ -3028,9 +2923,11 @@ void SpellMgr::LoadSpellInfoCorrections() if (!spellInfo) continue; - for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) { - switch (spellInfo->Effects[j].Effect) + if (!effect) + continue; + switch (effect->Effect) { case SPELL_EFFECT_CHARGE: case SPELL_EFFECT_CHARGE_DEST: @@ -3049,43 +2946,43 @@ void SpellMgr::LoadSpellInfoCorrections() switch (spellInfo->Id) { case 42436: // Drink! (Brewfest) - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); break; case 52611: // Summon Skeletons case 52612: // Summon Skeletons - spellInfo->Effects[EFFECT_0].MiscValueB = 64; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->MiscValueB = 64; break; case 40244: // Simon Game Visual case 40245: // Simon Game Visual case 40246: // Simon Game Visual case 40247: // Simon Game Visual case 42835: // Spout, remove damage effect, only anim is needed - spellInfo->Effects[EFFECT_0].Effect = 0; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->Effect = 0; break; case 30657: // Quake - spellInfo->Effects[EFFECT_0].TriggerSpell = 30571; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TriggerSpell = 30571; break; case 30541: // Blaze (needs conditions entry) - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ENEMY); - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ENEMY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(); break; case 63665: // Charge (Argent Tournament emote on riders) case 31298: // Sleep (needs target selection script) case 51904: // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed) case 68933: // Wrath of Air Totem rank 2 (Aura) case 29200: // Purify Helboar Meat - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(); break; case 31344: // Howl of Azgalor - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yards instead of 50000?! + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yards instead of 50000?! break; case 42818: // Headless Horseman - Wisp Flight Port case 42821: // Headless Horseman - Wisp Flight Missile spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100 yards break; case 36350: // They Must Burn Bomb Aura (self) - spellInfo->Effects[EFFECT_0].TriggerSpell = 36325; // They Must Burn Bomb Drop (DND) + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TriggerSpell = 36325; // They Must Burn Bomb Drop (DND) break; case 49838: // Stop Time spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; @@ -3094,11 +2991,11 @@ void SpellMgr::LoadSpellInfoCorrections() case 62136: // Energize Cores case 54069: // Energize Cores case 56251: // Energize Cores - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENTRY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENTRY); break; case 50785: // Energize Cores case 59372: // Energize Cores - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENEMY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENEMY); break; case 63320: // Glyph of Life Tap case 53228: // Rapid Killing (Rank 1) @@ -3111,8 +3008,8 @@ void SpellMgr::LoadSpellInfoCorrections() break; case 59725: // Improved Spell Reflection - aoe aura // Target entry seems to be wrong for this spell :/ - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY); - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS_2); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS_2); break; case 31347: // Doom case 36327: // Shoot Arcane Explosion Arrow @@ -3184,7 +3081,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 33711: // Murmur's Touch case 38794: // Murmur's Touch spellInfo->MaxAffectedTargets = 1; - spellInfo->Effects[EFFECT_0].TriggerSpell = 33760; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TriggerSpell = 33760; break; case 17941: // Shadow Trance case 22008: // Netherwind Focus @@ -3199,7 +3096,7 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->ProcCharges = 1; break; case 44544: // Fingers of Frost - spellInfo->Effects[EFFECT_0].SpellClassMask = flag128(685904631, 1151048, 0, 0); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask = flag128(685904631, 1151048, 0, 0); break; case 74396: // Fingers of Frost visual buff spellInfo->ProcCharges = 2; @@ -3214,16 +3111,16 @@ void SpellMgr::LoadSpellInfoCorrections() case 47204: // Everlasting Affliction (4) case 47205: // Everlasting Affliction (5) // add corruption to affected spells - spellInfo->Effects[EFFECT_1].SpellClassMask[0] |= 2; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->SpellClassMask[0] |= 2; break; case 37408: // Oscillation Field spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; break; case 51852: // The Eye of Acherus (no spawn in phase 2 in db) - spellInfo->Effects[EFFECT_0].MiscValue |= 1; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->MiscValue |= 1; break; case 51912: // Crafty's Ultra-Advanced Proto-Typical Shortening Blaster - spellInfo->Effects[EFFECT_0].ApplyAuraPeriod = 3000; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->ApplyAuraPeriod = 3000; break; // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data // To prevent aura staying on target after talent unlearned @@ -3239,23 +3136,23 @@ void SpellMgr::LoadSpellInfoCorrections() break; case 51466: // Elemental Oath (Rank 1) case 51470: // Elemental Oath (Rank 2) - spellInfo->Effects[EFFECT_1].Effect = SPELL_EFFECT_APPLY_AURA; - spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; - spellInfo->Effects[EFFECT_1].MiscValue = SPELLMOD_EFFECT2; - spellInfo->Effects[EFFECT_1].SpellClassMask = flag128(0x00000000, 0x00004000, 0x00000000, 0x00000000); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->Effect = SPELL_EFFECT_APPLY_AURA; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->MiscValue = SPELLMOD_EFFECT2; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->SpellClassMask = flag128(0x00000000, 0x00004000, 0x00000000, 0x00000000); break; case 47569: // Improved Shadowform (Rank 1) // with this spell atrribute aura can be stacked several times spellInfo->Attributes &= ~SPELL_ATTR0_NOT_SHAPESHIFT; break; case 64904: // Hymn of Hope - spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->ApplyAuraName = SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT; break; case 30421: // Nether Portal - Perseverence - spellInfo->Effects[EFFECT_2].BasePoints += 30000; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_2))->BasePoints += 30000; break; case 41913: // Parasitic Shadowfiend Passive - spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_DUMMY; // proc debuff, and summon infinite fiends + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->ApplyAuraName = SPELL_AURA_DUMMY; // proc debuff, and summon infinite fiends break; case 27892: // To Anchor 1 case 27928: // To Anchor 1 @@ -3269,8 +3166,8 @@ void SpellMgr::LoadSpellInfoCorrections() // this is the only known exception, probably just wrong data case 29214: // Wrath of the Plaguebringer case 54836: // Wrath of the Plaguebringer - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY); - spellInfo->Effects[EFFECT_1].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY); break; case 63675: // Improved Devouring Plague spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; @@ -3284,47 +3181,47 @@ void SpellMgr::LoadSpellInfoCorrections() break; case 53241: // Marked for Death (Rank 1) case 53243: // Marked for Death (Rank 2) - spellInfo->Effects[EFFECT_0].SpellClassMask = flag128(0x00067801, 0x10820001, 0x00000801, 0x00000000); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask = flag128(0x00067801, 0x10820001, 0x00000801, 0x00000000); break; case 5176: // Wrath case 2912: // Starfire - case 78674: // Starsurge - spellInfo->Effects[EFFECT_1].Effect = SPELL_EFFECT_DUMMY; - spellInfo->Effects[EFFECT_1].TargetA = TARGET_UNIT_CASTER; + //case 78674: // Starsurge 6.x effect 1 is no more + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->Effect = SPELL_EFFECT_DUMMY; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->TargetA = TARGET_UNIT_CASTER; break; case 70728: // Exploit Weakness (needs target selection script) case 70840: // Devious Minds (needs target selection script) - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_PET); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(TARGET_UNIT_PET); break; case 70893: // Culling The Herd (needs target selection script) - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_MASTER); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(TARGET_UNIT_MASTER); break; case 54800: // Sigil of the Frozen Conscience - change class mask to custom extended flags of Icy Touch // this is done because another spell also uses the same SpellFamilyFlags as Icy Touch // SpellFamilyFlags[0] & 0x00000040 in SPELLFAMILY_DEATHKNIGHT is currently unused (3.3.5a) // this needs research on modifier applying rules, does not seem to be in Attributes fields - spellInfo->Effects[EFFECT_0].SpellClassMask = flag128(0x00000040, 0x00000000, 0x00000000, 0x00000000); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask = flag128(0x00000040, 0x00000000, 0x00000000, 0x00000000); break; case 64949: // Idol of the Flourishing Life - spellInfo->Effects[EFFECT_0].SpellClassMask = flag128(0x00000000, 0x02000000, 0x00000000, 0x00000000); - spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask = flag128(0x00000000, 0x02000000, 0x00000000, 0x00000000); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; break; case 34231: // Libram of the Lightbringer case 60792: // Libram of Tolerance case 64956: // Libram of the Resolute - spellInfo->Effects[EFFECT_0].SpellClassMask = flag128(0x80000000, 0x00000000, 0x00000000, 0x00000000); - spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask = flag128(0x80000000, 0x00000000, 0x00000000, 0x00000000); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; break; case 28851: // Libram of Light case 28853: // Libram of Divinity case 32403: // Blessed Book of Nagrand - spellInfo->Effects[EFFECT_0].SpellClassMask = flag128(0x40000000, 0x00000000, 0x00000000, 0x00000000); - spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask = flag128(0x40000000, 0x00000000, 0x00000000, 0x00000000); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; break; case 45602: // Ride Carpet - spellInfo->Effects[EFFECT_0].BasePoints = 0; // force seat 0, vehicle doesn't have the required seat flags for "no seat specified (-1)" + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->BasePoints = 0; // force seat 0, vehicle doesn't have the required seat flags for "no seat specified (-1)" break; case 61719: // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE; @@ -3339,7 +3236,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 56606: // Ride Jokkum case 61791: // Ride Vehicle (Yogg-Saron) /// @todo: remove this when basepoints of all Ride Vehicle auras are calculated correctly - spellInfo->Effects[EFFECT_0].BasePoints = 1; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->BasePoints = 1; break; case 59630: // Black Magic spellInfo->Attributes |= SPELL_ATTR0_PASSIVE; @@ -3350,12 +3247,12 @@ void SpellMgr::LoadSpellInfoCorrections() case 51798: // Brewfest - Relay Race - Intro - Quest Complete case 47134: // Quest Complete //! HACK: This spell break quest complete for alliance and on retail not used °_O - spellInfo->Effects[EFFECT_0].Effect = 0; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->Effect = 0; break; // ULDUAR SPELLS // case 62374: // Pursued (Flame Leviathan) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd break; case 63342: // Focused Eyebeam Summon Trigger (Kologarn) spellInfo->MaxAffectedTargets = 1; @@ -3377,7 +3274,7 @@ void SpellMgr::LoadSpellInfoCorrections() // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc. // The above situation causes the visual for this spell to be bugged, so we remove the instakill // effect and implement a script hack for that. - spellInfo->Effects[EFFECT_1].Effect = 0; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->Effect = 0; break; case 64386: // Terrifying Screech (Auriaya) case 64389: // Sentinel Blast (Auriaya) @@ -3391,7 +3288,7 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; break; case 63414: // Spinning Up (Mimiron) - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); spellInfo->ChannelInterruptFlags = 0; break; case 63036: // Rocket Strike (Mimiron) @@ -3411,7 +3308,7 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->MaxAffectedTargets = 3; break; case 62293: // Cosmic Smash (Algalon the Observer) - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_DEST_CASTER); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(TARGET_DEST_CASTER); break; case 62311: // Cosmic Smash (Algalon the Observer) case 64596: // Cosmic Smash (Algalon the Observer) @@ -3426,7 +3323,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 64031: // Scrapyard Teleport case 64032: // Formation Grounds Teleport case 65042: // Prison of Yogg-Saron Teleport - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); break; // ENDOF ULDUAR SPELLS // @@ -3444,14 +3341,14 @@ void SpellMgr::LoadSpellInfoCorrections() // case 72435: // Defiling Horror case 72452: // Defiling Horror - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd break; case 72830: // Achievement Check - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd break; case 72900: // Start Halls of Reflection Quest AE - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd break; // ENDOF HALLS OF REFLECTION SPELLS // @@ -3467,7 +3364,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 70859: // Upper Spire Teleport case 70860: // Frozen Throne Teleport case 70861: // Sindragosa's Lair Teleport - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); break; case 69075: // Bone Storm (Lord Marrowgar) case 70834: // Bone Storm (Lord Marrowgar) @@ -3477,7 +3374,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 71160: // Plague Stench (Stinky) case 71161: // Plague Stench (Stinky) case 71123: // Decimate (Stinky & Precious) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd break; case 71169: // Shadow's Fate spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; @@ -3489,59 +3386,59 @@ void SpellMgr::LoadSpellInfoCorrections() case 73844: // Award Reputation - Boss Kill case 73845: // Award Reputation - Boss Kill case 73846: // Award Reputation - Boss Kill - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd break; case 72378: // Blood Nova (Deathbringer Saurfang) case 73058: // Blood Nova (Deathbringer Saurfang) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); break; case 72769: // Scent of Blood (Deathbringer Saurfang) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // no break case 72771: // Scent of Blood (Deathbringer Saurfang) - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); break; case 72723: // Resistant Skin (Deathbringer Saurfang adds) // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client - spellInfo->Effects[EFFECT_2].Effect = 0; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_2))->Effect = 0; break; case 70460: // Coldflame Jets (Traps after Saurfang) spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(1); // 10 seconds break; case 71412: // Green Ooze Summon (Professor Putricide) case 71415: // Orange Ooze Summon (Professor Putricide) - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); break; case 71159: // Awaken Plagued Zombies spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21); break; case 70530: // Volatile Ooze Beam Protection (Professor Putricide) - spellInfo->Effects[EFFECT_0].Effect = SPELL_EFFECT_APPLY_AURA; // for an unknown reason this was SPELL_EFFECT_APPLY_AREA_AURA_RAID + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->Effect = SPELL_EFFECT_APPLY_AURA; // for an unknown reason this was SPELL_EFFECT_APPLY_AREA_AURA_RAID break; // THIS IS HERE BECAUSE COOLDOWN ON CREATURE PROCS IS NOT IMPLEMENTED case 71604: // Mutated Strength (Professor Putricide) case 72673: // Mutated Strength (Professor Putricide) case 72674: // Mutated Strength (Professor Putricide) case 72675: // Mutated Strength (Professor Putricide) - spellInfo->Effects[EFFECT_1].Effect = 0; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->Effect = 0; break; case 72454: // Mutated Plague (Professor Putricide) case 72464: // Mutated Plague (Professor Putricide) case 72506: // Mutated Plague (Professor Putricide) case 72507: // Mutated Plague (Professor Putricide) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd break; case 70911: // Unbound Plague (Professor Putricide) (needs target selection script) case 72854: // Unbound Plague (Professor Putricide) (needs target selection script) case 72855: // Unbound Plague (Professor Putricide) (needs target selection script) case 72856: // Unbound Plague (Professor Putricide) (needs target selection script) - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ENEMY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ENEMY); break; case 71518: // Unholy Infusion Quest Credit (Professor Putricide) case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel) case 72289: // Frost Infusion Quest Credit (Sindragosa) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // another missing radius + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // another missing radius break; case 71708: // Empowered Flare (Blood Prince Council) case 72785: // Empowered Flare (Blood Prince Council) @@ -3565,18 +3462,18 @@ void SpellMgr::LoadSpellInfoCorrections() break; case 72015: // Frostbolt Volley (only heroic) case 72016: // Frostbolt Volley (only heroic) - spellInfo->Effects[EFFECT_2].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_40_YARDS); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_2))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_40_YARDS); break; case 70936: // Summon Suppressor (needs target selection script) - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(); break; case 72706: // Achievement Check (Valithria Dreamwalker) case 71357: // Order Whelp - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd break; case 70598: // Sindragosa's Fury - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DEST); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_DEST_DEST); break; case 69846: // Frost Bomb spellInfo->Speed = 0.0f; // This spell's summon happens instantly @@ -3594,12 +3491,12 @@ void SpellMgr::LoadSpellInfoCorrections() case 73708: // Defile case 73709: // Defile case 73710: // Defile - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd break; case 69030: // Val'kyr Target Search - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd break; case 69198: // Raging Spirit Visual spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd @@ -3608,9 +3505,9 @@ void SpellMgr::LoadSpellInfoCorrections() case 74295: // Harvest Souls case 74296: // Harvest Souls case 74297: // Harvest Souls - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd - spellInfo->Effects[EFFECT_2].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_2))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd break; case 73655: // Harvest Soul spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; @@ -3622,34 +3519,34 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(28); // 5 seconds break; case 73529: // Shadow Trap - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd break; case 74282: // Shadow Trap (searcher) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_3_YARDS); // 3yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_3_YARDS); // 3yd break; case 72595: // Restore Soul case 73650: // Restore Soul - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd break; case 74086: // Destroy Soul - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd break; case 74302: // Summon Spirit Bomb case 74342: // Summon Spirit Bomb - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd spellInfo->MaxAffectedTargets = 1; break; case 74341: // Summon Spirit Bomb case 74343: // Summon Spirit Bomb - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd spellInfo->MaxAffectedTargets = 3; break; case 73579: // Summon Spirit Bomb - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd break; case 72350: // Fury of Frostmourne - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd break; case 75127: // Kill Frostmourne Players case 72351: // Fury of Frostmourne @@ -3657,31 +3554,31 @@ void SpellMgr::LoadSpellInfoCorrections() case 72429: // Mass Resurrection case 73159: // Play Movie case 73582: // Trigger Vile Spirit (Inside, Heroic) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd break; case 72376: // Raise Dead spellInfo->MaxAffectedTargets = 3; - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd break; case 71809: // Jump spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(3); // 20yd - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd break; case 72405: // Broken Frostmourne - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd break; // ENDOF ICECROWN CITADEL SPELLS // // RUBY SANCTUM SPELLS // case 74799: // Soul Consumption - spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_12_YARDS); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_12_YARDS); break; case 74769: // Twilight Cutter case 77844: // Twilight Cutter case 77845: // Twilight Cutter case 77846: // Twilight Cutter - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd break; case 75509: // Twilight Mending spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE; @@ -3726,7 +3623,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 76606: // Disable Beacon Beams L case 76608: // Disable Beacon Beams R // Little hack, Increase the radius so it can hit the Cave In Stalkers in the platform. - spellInfo->Effects[EFFECT_0].MaxRadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_45_YARDS); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->MaxRadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_45_YARDS); break; case 75323: // Reverberating Hymn // Aura is refreshed at 3 seconds, and the tick should happen at the fourth. @@ -3755,7 +3652,7 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->MaxAffectedTargets = 1; break; case 75697: // Evolution - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENTRY); + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENTRY); break; // ISLE OF CONQUEST SPELLS // @@ -3773,7 +3670,7 @@ void SpellMgr::LoadSpellInfoCorrections() case SPELLFAMILY_PALADIN: // Seals of the Pure should affect Seal of Righteousness if (spellInfo->SpellIconID == 25 && spellInfo->Attributes & SPELL_ATTR0_PASSIVE) - spellInfo->Effects[EFFECT_0].SpellClassMask[1] |= 0x20000000; + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask[1] |= 0x20000000; break; case SPELLFAMILY_DEATHKNIGHT: // Icy Touch - extend FamilyFlags (unused value) for Sigil of the Frozen Conscience to use @@ -3790,3 +3687,42 @@ void SpellMgr::LoadSpellInfoCorrections() TC_LOG_INFO("server.loading", ">> Loaded SpellInfo corrections in %u ms", GetMSTimeDiffToNow(oldMSTime)); } + +void SpellMgr::LoadPetFamilySpellsStore() +{ + for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) + { + SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j); + if (!skillLine) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->SpellID); + if (!spellInfo) + continue; + + SpellLevelsEntry const* levels = sSpellLevelsStore.LookupEntry(spellInfo->LevelsID); + if (spellInfo->LevelsID && (!levels || levels->SpellLevel)) + continue; + + if (SpellMiscEntry const* spellMisc = sSpellMiscStore.LookupEntry(spellInfo->MiscID)) + { + if (spellMisc->Attributes & SPELL_ATTR0_PASSIVE) + { + for (uint32 i = 1; i < sCreatureFamilyStore.GetNumRows(); ++i) + { + CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(i); + if (!cFamily) + continue; + + if (skillLine->SkillLine != cFamily->SkillLine[0] && skillLine->SkillLine != cFamily->SkillLine[1]) + continue; + + if (skillLine->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) + continue; + + sPetFamilySpellsStore[i].insert(spellInfo->ID); + } + } + } + } +} diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 053935a53cb..3acd13b3a0e 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -313,16 +313,6 @@ struct SpellEnchantProcEntry typedef std::unordered_map<uint32, SpellEnchantProcEntry> SpellEnchantProcEventMap; -struct SpellBonusEntry -{ - float direct_damage; - float dot_damage; - float ap_bonus; - float ap_dot_bonus; -}; - -typedef std::unordered_map<uint32, SpellBonusEntry> SpellBonusMap; - enum SpellGroup { SPELL_GROUP_NONE = 0, @@ -617,12 +607,6 @@ class SpellMgr // Spell correctness for client using static bool IsSpellValid(SpellInfo const* spellInfo, Player* player = NULL, bool msg = true); - // Spell difficulty - uint32 GetSpellDifficultyId(uint32 spellId) const; - void SetSpellDifficultyId(uint32 spellId, uint32 id); - uint32 GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const; - SpellInfo const* GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const; - // Spell Ranks table SpellChainNode const* GetSpellChainNode(uint32 spell_id) const; uint32 GetFirstSpellInChain(uint32 spell_id) const; @@ -668,9 +652,6 @@ class SpellMgr SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const; bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; - // Spell bonus data table - SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const; - // Spell threat table SpellThreatEntry const* GetSpellThreatEntry(uint32 spellID) const; @@ -705,6 +686,8 @@ class SpellMgr } uint32 GetSpellInfoStoreSize() const { return mSpellInfoMap.size(); } + void LoadPetFamilySpellsStore(); + private: SpellInfo* _GetSpellInfo(uint32 spellId) { return spellId < GetSpellInfoStoreSize() ? mSpellInfoMap[spellId] : NULL; } @@ -723,7 +706,6 @@ class SpellMgr void LoadSpellGroupStackRules(); void LoadSpellProcEvents(); void LoadSpellProcs(); - void LoadSpellBonusess(); void LoadSpellThreats(); void LoadSkillLineAbilityMap(); void LoadSpellPetAuras(); @@ -752,7 +734,6 @@ class SpellMgr SpellGroupStackMap mSpellGroupStack; SpellProcEventMap mSpellProcEventMap; SpellProcMap mSpellProcMap; - SpellBonusMap mSpellBonusMap; SpellThreatMap mSpellThreatMap; SpellPetAuraMap mSpellPetAuraMap; SpellLinkedMap mSpellLinkedMap; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 8ab3a72b47e..1d5eab259aa 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -110,11 +110,14 @@ std::string _SpellScript::EffectHook::EffIndexToString() bool _SpellScript::EffectNameCheck::Check(SpellInfo const* spellEntry, uint8 effIndex) { - if (!spellEntry->Effects[effIndex].Effect && !effName) + SpellEffectInfo const* effect = spellEntry->GetEffect(effIndex); + if (!effect) + return false; + if (!effect->Effect && !effName) return true; - if (!spellEntry->Effects[effIndex].Effect) + if (!effect->Effect) return false; - return (effName == SPELL_EFFECT_ANY) || (spellEntry->Effects[effIndex].Effect == effName); + return (effName == SPELL_EFFECT_ANY) || (effect->Effect == effName); } std::string _SpellScript::EffectNameCheck::ToString() @@ -132,11 +135,14 @@ std::string _SpellScript::EffectNameCheck::ToString() bool _SpellScript::EffectAuraNameCheck::Check(SpellInfo const* spellEntry, uint8 effIndex) { - if (!spellEntry->Effects[effIndex].ApplyAuraName && !effAurName) + SpellEffectInfo const* effect = spellEntry->GetEffect(effIndex); + if (!effect) + return false; + if (!effect->ApplyAuraName && !effAurName) return true; - if (!spellEntry->Effects[effIndex].ApplyAuraName) + if (!effect->ApplyAuraName) return false; - return (effAurName == SPELL_AURA_ANY) || (spellEntry->Effects[effIndex].ApplyAuraName == effAurName); + return (effAurName == SPELL_AURA_ANY) || (effect->ApplyAuraName == effAurName); } std::string _SpellScript::EffectAuraNameCheck::ToString() @@ -218,8 +224,12 @@ bool SpellScript::TargetHook::CheckEffect(SpellInfo const* spellEntry, uint8 eff if (!targetType) return false; - if (spellEntry->Effects[effIndex].TargetA.GetTarget() != targetType && - spellEntry->Effects[effIndex].TargetB.GetTarget() != targetType) + SpellEffectInfo const* effect = spellEntry->GetEffect(effIndex); + if (!effect) + return false; + + if (effect->TargetA.GetTarget() != targetType && + effect->TargetB.GetTarget() != targetType) return false; SpellImplicitTargetInfo targetInfo(targetType); @@ -635,6 +645,11 @@ SpellValue const* SpellScript::GetSpellValue() return m_spell->m_spellValue; } +SpellEffectInfo const* SpellScript::GetEffectInfo(SpellEffIndex effIndex) const +{ + return m_spell->GetEffect(effIndex); +} + bool AuraScript::_Validate(SpellInfo const* entry) { for (std::list<CheckAreaTargetHandler>::iterator itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr) diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 653ae9ab5e9..ba25a056ee8 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -342,6 +342,7 @@ class SpellScript : public _SpellScript Unit* GetOriginalCaster(); SpellInfo const* GetSpellInfo(); SpellValue const* GetSpellValue(); + SpellEffectInfo const* GetEffectInfo(SpellEffIndex) const; // methods useable after spell is prepared // accessors to the explicit targets of the spell diff --git a/src/server/game/Texts/ChatTextBuilder.h b/src/server/game/Texts/ChatTextBuilder.h index 72f80bb07a3..a4834d555d3 100644 --- a/src/server/game/Texts/ChatTextBuilder.h +++ b/src/server/game/Texts/ChatTextBuilder.h @@ -20,6 +20,7 @@ #include "Chat.h" #include "ObjectMgr.h" +#include "Packets/ChatPackets.h" namespace Trinity { @@ -32,13 +33,9 @@ namespace Trinity void operator()(WorldPacket& data, LocaleConstant locale) { BroadcastText const* bct = sObjectMgr->GetBroadcastText(_textId); - ChatHandler::BuildChatPacket(data, _msgType, bct ? Language(bct->Language) : LANG_UNIVERSAL, _source, _target, bct ? bct->GetText(locale, _source->getGender()) : "", _achievementId, "", locale); - } - - size_t operator()(WorldPacket* data, LocaleConstant locale) const - { - BroadcastText const* bct = sObjectMgr->GetBroadcastText(_textId); - return ChatHandler::BuildChatPacket(*data, _msgType, bct ? Language(bct->Language) : LANG_UNIVERSAL, _source, _target, bct ? bct->GetText(locale, _source->getGender()) : "", _achievementId, "", locale); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, _msgType, bct ? Language(bct->Language) : LANG_UNIVERSAL, _source, _target, bct ? bct->GetText(locale, _source->getGender()) : "", _achievementId, "", locale); + data = *packet.Write(); } private: @@ -57,7 +54,9 @@ namespace Trinity void operator()(WorldPacket& data, LocaleConstant locale) { - ChatHandler::BuildChatPacket(data, _msgType, _language, _source, _target, _text, 0, "", locale); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, _msgType, _language, _source, _target, _text, 0, "", locale); + data = *packet.Write(); } private: diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 77819b87ec0..992942cefeb 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -24,6 +24,7 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "CreatureTextMgr.h" +#include "ChatPackets.h" class CreatureTextBuilder { @@ -31,11 +32,12 @@ class CreatureTextBuilder CreatureTextBuilder(WorldObject const* obj, uint8 gender, ChatMsg msgtype, uint8 textGroup, uint32 id, uint32 language, WorldObject const* target) : _source(obj), _gender(gender), _msgType(msgtype), _textGroup(textGroup), _textId(id), _language(language), _target(target) { } - size_t operator()(WorldPacket* data, LocaleConstant locale) const + void operator()(WorldPacket& data, LocaleConstant locale) const { std::string const& text = sCreatureTextMgr->GetLocalizedChatString(_source->GetEntry(), _gender, _textGroup, _textId, locale); - - return ChatHandler::BuildChatPacket(*data, _msgType, Language(_language), _source, _target, text, 0, "", locale); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, _msgType, Language(_language), _source, _target, text, 0, "", locale); + data = *packet.Write(); } private: @@ -54,11 +56,12 @@ class PlayerTextBuilder PlayerTextBuilder(WorldObject const* obj, WorldObject const* speaker, uint8 gender, ChatMsg msgtype, uint8 textGroup, uint32 id, uint32 language, WorldObject const* target) : _source(obj), _talker(speaker), _gender(gender), _msgType(msgtype), _textGroup(textGroup), _textId(id), _language(language), _target(target) { } - size_t operator()(WorldPacket* data, LocaleConstant locale) const + void operator()(WorldPacket& data, LocaleConstant locale) const { std::string const& text = sCreatureTextMgr->GetLocalizedChatString(_source->GetEntry(), _gender, _textGroup, _textId, locale); - - return ChatHandler::BuildChatPacket(*data, _msgType, Language(_language), _talker, _target, text, 0, "", locale); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, _msgType, Language(_language), _talker, _target, text, 0, "", locale); + data = *packet.Write(); } private: diff --git a/src/server/game/Texts/CreatureTextMgr.h b/src/server/game/Texts/CreatureTextMgr.h index 06efadb1dc7..647d8249e68 100644 --- a/src/server/game/Texts/CreatureTextMgr.h +++ b/src/server/game/Texts/CreatureTextMgr.h @@ -24,6 +24,7 @@ #include "SharedDefines.h" #include "Opcodes.h" #include "Group.h" +#include "Packets/ChatPackets.h" enum CreatureTextRange { @@ -133,50 +134,38 @@ class CreatureTextLocalizer ~CreatureTextLocalizer() { for (size_t i = 0; i < _packetCache.size(); ++i) - { - if (_packetCache[i]) - delete _packetCache[i]->first; delete _packetCache[i]; - } } void operator()(Player* player) { LocaleConstant loc_idx = player->GetSession()->GetSessionDbLocaleIndex(); - WorldPacket* messageTemplate; - size_t whisperGUIDpos; + WorldPackets::Chat::Chat* messageTemplate; // create if not cached yet if (!_packetCache[loc_idx]) { - messageTemplate = new WorldPacket(); - whisperGUIDpos = _builder(messageTemplate, loc_idx); - ASSERT(messageTemplate->GetOpcode() != NULL_OPCODE); - _packetCache[loc_idx] = new std::pair<WorldPacket*, size_t>(messageTemplate, whisperGUIDpos); + messageTemplate = new WorldPackets::Chat::Chat(); + _packetCache[loc_idx] = messageTemplate; } else - { - messageTemplate = _packetCache[loc_idx]->first; - whisperGUIDpos = _packetCache[loc_idx]->second; - } + messageTemplate = _packetCache[loc_idx]; - WorldPacket data(*messageTemplate); switch (_msgType) { case CHAT_MSG_MONSTER_WHISPER: case CHAT_MSG_RAID_BOSS_WHISPER: - // TODO: Fix this. GUIDs are now always written packed and can have different packed lengths - //data.put<uint64>(whisperGUIDpos, player->GetGUID().GetRawValue()); + messageTemplate->TargetGUID = player->GetGUID(); break; default: break; } - player->SendDirectMessage(&data); + player->SendDirectMessage(messageTemplate->Write()); } private: - std::vector<std::pair<WorldPacket*, size_t>* > _packetCache; + std::vector<WorldPackets::Chat::Chat*> _packetCache; Builder const& _builder; ChatMsg _msgType; }; diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 6f42d41c694..43d4374c544 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -519,10 +519,10 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s if (!changenth(line, 2, chraccount)) // characters.account update ROLLBACK(DUMP_FILE_BROKEN); - race = uint8(atol(getnth(line, 4).c_str())); - playerClass = uint8(atol(getnth(line, 5).c_str())); - gender = uint8(atol(getnth(line, 6).c_str())); - level = uint8(atol(getnth(line, 7).c_str())); + race = uint8(atoul(getnth(line, 4).c_str())); + playerClass = uint8(atoul(getnth(line, 5).c_str())); + gender = uint8(atoul(getnth(line, 6).c_str())); + level = uint8(atoul(getnth(line, 7).c_str())); if (name.empty()) { // check if the original name already exists diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 098181c76a1..53a2ee814a7 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -46,6 +46,7 @@ #include "LFGMgr.h" #include "MapManager.h" #include "Memory.h" +#include "MiscPackets.h" #include "MMapFactory.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" @@ -64,6 +65,7 @@ #include "WaypointMovementGenerator.h" #include "WeatherMgr.h" #include "WorldSession.h" +#include "ChatPackets.h" #include <boost/algorithm/string.hpp> @@ -1411,6 +1413,8 @@ void World::SetInitialWorldSettings() LoadDBCStores(m_dataPath); LoadDB2Stores(m_dataPath); + sSpellMgr->LoadPetFamilySpellsStore(); + TC_LOG_INFO("server.loading", "Loading SpellInfo store..."); sSpellMgr->LoadSpellInfoStore(); @@ -1487,9 +1491,6 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Spell Proc conditions and data..."); sSpellMgr->LoadSpellProcs(); - TC_LOG_INFO("server.loading", "Loading Spell Bonus Data..."); - sSpellMgr->LoadSpellBonusess(); - TC_LOG_INFO("server.loading", "Loading Aggro Spells Definitions..."); sSpellMgr->LoadSpellThreats(); @@ -2287,7 +2288,9 @@ namespace Trinity while (char* line = lineFromMessage(pos)) { WorldPacket* data = new WorldPacket(); - ChatHandler::BuildChatPacket(*data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); + *data = *packet.Write(); data_list.push_back(data); } } @@ -2345,16 +2348,15 @@ void World::SendGMText(uint32 string_id, ...) /// DEPRECATED, only for debug purpose. Send a System Message to all players (except self if mentioned) void World::SendGlobalText(const char* text, WorldSession* self) { - WorldPacket data; - // need copy to prevent corruption by strtok call in LineFromMessage original string char* buf = strdup(text); char* pos = buf; while (char* line = ChatHandler::LineFromMessage(pos)) { - ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); - SendGlobalMessage(&data, self); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line); + SendGlobalMessage(packet.Write(), self); } free(buf); @@ -2386,9 +2388,9 @@ bool World::SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession /// Send a System Message to all players in the zone (except self if mentioned) void World::SendZoneText(uint32 zone, const char* text, WorldSession* self, uint32 team) { - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, text); - SendZoneMessage(zone, &data, self, team); + WorldPackets::Chat::Chat packet; + ChatHandler::BuildChatPacket(&packet, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, text); + SendZoneMessage(zone, packet.Write(), self, team); } /// Kick (and save) all players @@ -3305,9 +3307,9 @@ void World::UpdateCharacterInfo(ObjectGuid const& guid, std::string const& name, if (race != RACE_NONE) itr->second.Race = race; - WorldPacket data(SMSG_INVALIDATE_PLAYER, 8); - data << guid; - SendGlobalMessage(&data); + WorldPackets::Misc::InvalidatePlayer data; + data.Guid = guid; + SendGlobalMessage(data.Write()); } void World::UpdateCharacterInfoLevel(ObjectGuid const& guid, uint8 level) |