aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Battlefield/Battlefield.cpp24
-rw-r--r--src/server/game/Battlefield/Battlefield.h11
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp2
-rw-r--r--src/server/game/DataStores/DBCStores.cpp56
-rw-r--r--src/server/game/DataStores/DBCStores.h15
-rw-r--r--src/server/game/DataStores/DBCStructure.h1
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp8
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h4
-rw-r--r--src/server/game/Entities/Player/Player.cpp607
-rw-r--r--src/server/game/Entities/Player/Player.h55
-rw-r--r--src/server/game/Entities/Unit/StatSystem.cpp2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp53
-rw-r--r--src/server/game/Entities/Unit/Unit.h21
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp6
-rw-r--r--src/server/game/Globals/ObjectMgr.h4
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp4
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp10
-rw-r--r--src/server/game/Handlers/PetHandler.cpp2
-rw-r--r--src/server/game/Handlers/SkillHandler.cpp2
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp78
-rw-r--r--src/server/game/Maps/Map.cpp26
-rw-r--r--src/server/game/Maps/Map.h11
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h6
-rw-r--r--src/server/game/OutdoorPvP/OutdoorPvP.cpp49
-rw-r--r--src/server/game/OutdoorPvP/OutdoorPvP.h23
-rw-r--r--src/server/game/Server/Packets/CombatPackets.cpp7
-rw-r--r--src/server/game/Server/Packets/CombatPackets.h19
-rw-r--r--src/server/game/Server/Packets/MiscPackets.cpp30
-rw-r--r--src/server/game/Server/Packets/MiscPackets.h40
-rw-r--r--src/server/game/Server/Packets/QueryPackets.h2
-rw-r--r--src/server/game/Server/Packets/SpellPackets.cpp119
-rw-r--r--src/server/game/Server/Packets/SpellPackets.h104
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp18
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h8
-rw-r--r--src/server/game/Server/WorldSession.cpp2
-rw-r--r--src/server/game/Server/WorldSession.h10
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp7
-rw-r--r--src/server/game/Spells/Spell.cpp117
-rw-r--r--src/server/game/Spells/Spell.h14
-rw-r--r--src/server/game/Spells/SpellEffects.cpp45
-rw-r--r--src/server/game/Spells/SpellInfo.cpp68
-rw-r--r--src/server/game/Spells/SpellInfo.h1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp144
-rw-r--r--src/server/game/Spells/SpellMgr.h1
-rw-r--r--src/server/game/Tools/CharacterDatabaseCleaner.cpp4
-rw-r--r--src/server/game/Weather/Weather.cpp13
-rw-r--r--src/server/game/Weather/Weather.h2
-rw-r--r--src/server/game/Weather/WeatherMgr.cpp6
-rw-r--r--src/server/scripts/Commands/cs_learn.cpp2
-rw-r--r--src/server/scripts/Commands/cs_list.cpp2
-rw-r--r--src/server/scripts/Commands/cs_lookup.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp2
-rw-r--r--src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp6
-rw-r--r--src/server/scripts/Kalimdor/zone_the_barrens.cpp2
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp414
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h23
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp52
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp6
-rw-r--r--src/server/scripts/Northrend/zone_zuldrak.cpp2
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp8
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp39
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp2
-rw-r--r--src/server/scripts/Spells/spell_holiday.cpp4
-rw-r--r--src/server/shared/Debugging/Errors.h6
64 files changed, 1536 insertions, 899 deletions
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp
index 54c43673411..c9f2492617a 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -450,6 +450,25 @@ void Battlefield::SendUpdateWorldState(uint32 variable, uint32 value, bool hidde
BroadcastPacketToZone(worldstate.Write());
}
+void Battlefield::AddCapturePoint(BfCapturePoint* cp)
+{
+ Battlefield::BfCapturePointMap::iterator i = m_capturePoints.find(cp->GetCapturePointEntry());
+ if (i != m_capturePoints.end())
+ {
+ TC_LOG_ERROR("bg.battlefield", "Battlefield::AddCapturePoint: CapturePoint %s already exists!", cp->GetCapturePointEntry());
+ delete i->second;
+ }
+ m_capturePoints[cp->GetCapturePointEntry()] = cp;
+}
+
+BfCapturePoint* Battlefield::GetCapturePoint(uint32 entry) const
+{
+ Battlefield::BfCapturePointMap::const_iterator itr = m_capturePoints.find(entry);
+ if (itr != m_capturePoints.end())
+ return itr->second;
+ return nullptr;
+}
+
void Battlefield::RegisterZone(uint32 zoneId)
{
sBattlefieldMgr->AddZone(zoneId, this);
@@ -913,10 +932,11 @@ bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint)
TC_LOG_DEBUG("bg.battlefield", "Creating capture point %u", capturePoint->GetEntry());
m_capturePointGUID = capturePoint->GetGUID();
+ m_capturePointEntry = capturePoint->GetEntry();
// check info existence
GameObjectTemplate const* goinfo = capturePoint->GetGOInfo();
- if (goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT)
+ if (goinfo->type != GAMEOBJECT_TYPE_CONTROL_ZONE)
{
TC_LOG_ERROR("misc", "OutdoorPvP: GO %u is not capture point!", capturePoint->GetEntry());
return false;
@@ -927,7 +947,7 @@ bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint)
m_maxSpeed = m_maxValue / (goinfo->controlZone.minTime ? goinfo->controlZone.minTime : 60);
m_neutralValuePct = goinfo->controlZone.neutralPercent;
m_minValue = m_maxValue * goinfo->controlZone.neutralPercent / 100;
- m_capturePointEntry = capturePoint->GetEntry();
+
if (m_team == TEAM_ALLIANCE)
{
m_value = m_maxValue;
diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h
index 2ea1f100ee2..3fcfc22b941 100644
--- a/src/server/game/Battlefield/Battlefield.h
+++ b/src/server/game/Battlefield/Battlefield.h
@@ -402,15 +402,8 @@ class Battlefield : public ZoneScript
void BroadcastPacketToWar(WorldPacket const* data) const;
// CapturePoint system
- void AddCapturePoint(BfCapturePoint* cp) { m_capturePoints[cp->GetCapturePointEntry()] = cp; }
-
- BfCapturePoint* GetCapturePoint(uint32 lowguid) const
- {
- Battlefield::BfCapturePointMap::const_iterator itr = m_capturePoints.find(lowguid);
- if (itr != m_capturePoints.end())
- return itr->second;
- return NULL;
- }
+ void AddCapturePoint(BfCapturePoint* cp);
+ BfCapturePoint* GetCapturePoint(uint32 entry) const;
void RegisterZone(uint32 zoneid);
bool HasPlayer(Player* player) const;
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 0bba2c84827..e870eadec1e 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -1078,7 +1078,7 @@ void Battleground::AddPlayer(Player* player)
BattlegroundPlayer bp;
bp.OfflineRemoveTime = 0;
bp.Team = team;
- bp.ActiveSpec = player->GetActiveTalentSpec();
+ bp.ActiveSpec = player->GetSpecId(player->GetActiveTalentGroup());
// Add to list/maps
m_Players[player->GetGUID()] = bp;
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 7532a6f8c75..bd087be84dd 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -76,7 +76,6 @@ DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
DBCStorage <ChrPowerTypesEntry> sChrPowerTypesStore(ChrClassesXPowerTypesfmt);
DBCStorage <ChrSpecializationEntry> sChrSpecializationStore(ChrSpecializationEntryfmt);
ChrSpecializationByIndexArray sChrSpecializationByIndexStore;
-SpecializationSpellsBySpecStore sSpecializationSpellsBySpecStore;
DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt);
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt);
@@ -199,6 +198,7 @@ DBCStorage <SkillTiersEntry> sSkillTiersStore(SkillTiersfmt);
DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
DBCStorage <SpecializationSpellsEntry> sSpecializationSpellsStore(SpecializationSpellsEntryfmt);
+std::unordered_map<uint32, std::vector<SpecializationSpellsEntry const*>> sSpecializationSpellsBySpecStore;
DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt);
DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt);
DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
@@ -229,9 +229,7 @@ DBCStorage <SpellShapeshiftFormEntry> sSpellShapeshiftFormStore(SpellShapeshiftF
DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
-TalentBySpellIDMap sTalentBySpellIDMap;
-SpecializationSpellsMap sSpecializationSpellsMap;
-SpecializationOverrideSpellsMap sSpecializationOverrideSpellMap;
+TalentsByPosition sTalentByPos;
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
DBCStorage <TransportAnimationEntry> sTransportAnimationStore(TransportAnimationfmt);
@@ -546,16 +544,15 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sSkillTiersStore, dbcPath, "SkillTiers.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc");//15595
LoadDBC(availableDbcLocales, bad_dbc_files, sSpecializationSpellsStore, dbcPath, "SpecializationSpells.dbc");
- for (uint32 i = 1; i < sSpecializationSpellsStore.GetNumRows(); ++i)
+ for (uint32 i = 0; i < sSpecializationSpellsStore.GetNumRows(); ++i)
{
SpecializationSpellsEntry const* specSpells = sSpecializationSpellsStore.LookupEntry(i);
if (!specSpells)
continue;
- sSpecializationSpellsBySpecStore[specSpells->SpecID].push_back(specSpells);
- if (specSpells->OverridesSpellID)
- sSpecializationOverrideSpellMap[specSpells->SpecID][specSpells->OverridesSpellID] = specSpells->SpellID;
+ sSpecializationSpellsBySpecStore[specSpells->SpecID].push_back(specSpells);
}
+
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc"/*, &CustomSpellEntryfmt, &CustomSpellEntryIndex*/);
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoriesStore, dbcPath, "SpellCategories.dbc");//15595
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoryStore, dbcPath, "SpellCategory.dbc");
@@ -599,15 +596,17 @@ void LoadDBCStores(const std::string& dataPath)
sSpellEffectScallingByEffectId.insert(std::make_pair(spellEffectScaling->SpellEffectID, j));
}
- LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//15595
-
- for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
+ LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//19342
+ for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
- if (!talentInfo)
- continue;
-
- sTalentBySpellIDMap[talentInfo->SpellID] = talentInfo;
+ if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(i))
+ {
+ if (talentInfo->ClassID < MAX_CLASSES && talentInfo->TierID < MAX_TALENT_TIERS && talentInfo->ColumnIndex < MAX_TALENT_COLUMNS)
+ sTalentByPos[talentInfo->ClassID][talentInfo->TierID][talentInfo->ColumnIndex].push_back(talentInfo);
+ else
+ TC_LOG_ERROR("server.loading", "Value of class (found: %u, max allowed %u) or (found: %u, max allowed %u) tier or column (found: %u, max allowed %u) is invalid.",
+ talentInfo->ClassID, MAX_CLASSES, talentInfo->TierID, MAX_TALENT_TIERS, talentInfo->ColumnIndex, MAX_TALENT_COLUMNS);
+ }
}
//LoadDBC(availableDbcLocales, bad_dbc_files, sTeamContributionPointsStore, dbcPath, "TeamContributionPoints.dbc");
@@ -967,14 +966,6 @@ PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundB
return NULL;
}
-TalentEntry const* GetTalentBySpellID(uint32 spellID)
-{
- auto itr = sTalentBySpellIDMap.find(spellID);
- if (itr != sTalentBySpellIDMap.end())
- return itr->second;
- return nullptr;
-}
-
uint32 GetLiquidFlags(uint32 liquidType)
{
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquidType))
@@ -1044,14 +1035,6 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u
return NULL;
}
-uint32 GetTalentSpellCost(uint32 spellId)
-{
- TalentBySpellIDMap::const_iterator itr = sTalentBySpellIDMap.find(spellId);
- if (itr == sTalentBySpellIDMap.end())
- return 0;
- return 1;
-}
-
uint32 GetQuestUniqueBitFlag(uint32 questId)
{
QuestV2Entry const* v2 = sQuestV2Store.LookupEntry(questId);
@@ -1060,3 +1043,12 @@ uint32 GetQuestUniqueBitFlag(uint32 questId)
return v2->UniqueBitFlag;
}
+
+std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId)
+{
+ auto itr = sSpecializationSpellsBySpecStore.find(specId);
+ if (itr != sSpecializationSpellsBySpecStore.end())
+ return &itr->second;
+
+ return nullptr;
+}
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index 8a411300a79..edbb5aa55bf 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -30,8 +30,6 @@ 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
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
@@ -91,14 +89,10 @@ typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRac
typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds;
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
-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;
+std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId);
+typedef std::vector<TalentEntry const*> TalentsByPosition[MAX_CLASSES][MAX_TALENT_TIERS][MAX_TALENT_COLUMNS];
+extern TalentsByPosition sTalentByPos;
template<class T>
class GameTable
@@ -243,8 +237,6 @@ 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;
extern DBCStorage <SpellCategoryEntry> sSpellCategoryStore;
extern DBCStorage <SpellDurationEntry> sSpellDurationStore;
@@ -271,7 +263,6 @@ extern DBCStorage <SpellTargetRestrictionsEntry> sSpellTargetRestrictionsStore;
//extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore;
extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore;
extern DBCStorage <TalentEntry> sTalentStore;
-extern TalentBySpellIDMap sTalentBySpellIDMap;
extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
extern DBCStorage <UnitPowerBarEntry> sUnitPowerBarStore;
extern DBCStorage <VehicleEntry> sVehicleStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 69739a32854..0bad082801d 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1788,6 +1788,7 @@ struct SummonPropertiesEntry
};
#define MAX_TALENT_TIERS 7
+#define MAX_TALENT_COLUMNS 3
struct TalentEntry
{
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 78efc590566..bb4bed9f79a 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -1315,8 +1315,8 @@ void GameObject::Use(Unit* user)
{
if (Player* ChairUser = ObjectAccessor::FindPlayer(itr->second))
{
- if (ChairUser->IsSitState() && ChairUser->getStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f)
- continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->getStandState() != UNIT_STAND_STATE_SIT check is required.
+ if (ChairUser->IsSitState() && ChairUser->GetStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f)
+ continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->GetStandState() != UNIT_STAND_STATE_SIT check is required.
else
itr->second.Clear(); // This seat is unoccupied.
}
@@ -1345,7 +1345,7 @@ void GameObject::Use(Unit* user)
{
itr->second = player->GetGUID(); //this slot in now used by player
player->TeleportTo(GetMapId(), x_lowest, y_lowest, GetPositionZ(), GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET);
- player->SetStandState(UNIT_STAND_STATE_SIT_LOW_CHAIR + info->chair.chairheight);
+ player->SetStandState(UnitStandStateType(UNIT_STAND_STATE_SIT_LOW_CHAIR + info->chair.chairheight));
return;
}
}
@@ -1773,7 +1773,7 @@ void GameObject::Use(Unit* user)
WorldPacket data(SMSG_ENABLE_BARBER_SHOP, 0);
player->SendDirectMessage(&data);
- player->SetStandState(UNIT_STAND_STATE_SIT_LOW_CHAIR+info->barberChair.chairheight);
+ player->SetStandState(UnitStandStateType(UNIT_STAND_STATE_SIT_LOW_CHAIR + info->barberChair.chairheight));
return;
}
default:
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 239324c572d..ff89e3f7cc0 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -776,11 +776,11 @@ union GameObjectValue
{
uint32 MaxOpens;
} FishingHole;
- //29 GAMEOBJECT_TYPE_CAPTURE_POINT
+ //29 GAMEOBJECT_TYPE_CONTROL_ZONE
struct
{
OPvPCapturePoint *OPvPObj;
- } CapturePoint;
+ } ControlZone;
//33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
struct
{
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index bd084491dee..d373e46fc41 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -33,6 +33,7 @@
#include "CharacterPackets.h"
#include "TalentPackets.h"
#include "Chat.h"
+#include "CombatPackets.h"
#include "Common.h"
#include "ConditionMgr.h"
#include "CreatureAI.h"
@@ -2997,13 +2998,14 @@ void Player::InitTalentForLevel()
{
uint8 level = getLevel();
// talents base at level diff (talents = level - 9 but some can be used already)
+ if (level < MIN_SPECIALIZATION_LEVEL)
+ ResetTalentSpecialization();
+
+ uint32 talentTiers = CalculateTalentsTiers();
if (level < 15)
{
// Remove all talent points
- if (GetUsedTalentCount() > 0) // Free any used talents
- {
- ResetTalents(true);
- }
+ ResetTalents(true);
}
else
{
@@ -3012,9 +3014,15 @@ void Player::InitTalentForLevel()
SetTalentGroupsCount(1);
SetActiveTalentGroup(0);
}
+
+ if (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED))
+ for (uint32 t = talentTiers; t < MAX_TALENT_TIERS; ++t)
+ for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
+ for (TalentEntry const* talent : sTalentByPos[getClass()][t][c])
+ RemoveTalent(talent);
}
- SetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS, CalculateTalentsPoints());
+ SetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS, talentTiers);
if (!GetSession()->PlayerLoading())
SendTalentsInfoData(); // update at client
@@ -3293,29 +3301,20 @@ void DeleteSpellFromAllPlayers(uint32 spellId)
}
}
-bool Player::AddTalent(uint32 talentId, uint8 spec, bool learning)
+bool Player::AddTalent(TalentEntry const* talent, uint8 spec, bool learning)
{
- TalentEntry const* talentEntry = sTalentStore.LookupEntry(talentId);
-
- // Check if talent exists in Talent.dbc
- if (!talentEntry)
- {
- TC_LOG_ERROR("spells", "Player::addTalent: Talent %u not found", talentId);
- return false;
- }
-
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentEntry->SpellID);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID);
if (!spellInfo)
{
// do character spell book cleanup (all characters)
- if (!IsInWorld()) // spell load case
+ if (!IsInWorld() && !learning) // spell load case
{
- TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", talentEntry->SpellID);
+ TC_LOG_ERROR("spells", "Player::AddTalent: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", talent->SpellID);
- DeleteSpellFromAllPlayers(talentEntry->SpellID);
+ DeleteSpellFromAllPlayers(talent->SpellID);
}
else
- TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request.", talentEntry->SpellID);
+ TC_LOG_ERROR("spells", "Player::AddTalent: Non-existed in SpellStore spell #%u request.", talent->SpellID);
return false;
}
@@ -3323,40 +3322,58 @@ bool Player::AddTalent(uint32 talentId, uint8 spec, bool learning)
if (!SpellMgr::IsSpellValid(spellInfo, this, false))
{
// do character spell book cleanup (all characters)
- if (!IsInWorld()) // spell load case
+ if (!IsInWorld() && !learning) // spell load case
{
- TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", talentEntry->SpellID);
+ TC_LOG_ERROR("spells", "Player::AddTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", talent->SpellID);
- DeleteSpellFromAllPlayers(talentEntry->SpellID);
+ DeleteSpellFromAllPlayers(talent->SpellID);
}
else
- TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed.", talentEntry->SpellID);
+ TC_LOG_ERROR("spells", "Player::AddTalent: Broken spell #%u learning not allowed.", talent->SpellID);
return false;
}
- 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();
+ if (talent->OverridesSpellID)
+ AddOverrideSpell(talent->OverridesSpellID, talent->SpellID);
- newtalent->state = state;
- newtalent->spec = spec;
+ PlayerTalentMap::iterator itr = GetTalentMap(spec)->find(talent->ID);
+ if (itr != GetTalentMap(spec)->end())
+ itr->second->state = PLAYERSPELL_UNCHANGED;
+ else
+ {
+ PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
+ PlayerTalent* newtalent = new PlayerTalent();
- (*GetTalentMap(spec))[talentId] = newtalent;
+ newtalent->state = state;
+ newtalent->spec = spec;
- return true;
- }
- //else
- // TC_LOG_ERROR("spells", "Player::addTalent: Talent %u not found in talent store.", talentId);
+ (*GetTalentMap(spec))[talent->ID] = newtalent;
}
- else
- itr->second->state = PLAYERSPELL_UNCHANGED;
- return false;
+ return true;
+}
+
+void Player::RemoveTalent(TalentEntry const* talent)
+{
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID);
+ if (!spellInfo)
+ return;
+
+ RemoveSpell(talent->SpellID, true);
+
+ // search for spells that the talent teaches and unlearn them
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
+ RemoveSpell(effect->TriggerSpell, true);
+
+ if (talent->OverridesSpellID)
+ RemoveOverrideSpell(talent->OverridesSpellID, talent->SpellID);
+
+ // if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
+ PlayerTalentMap::iterator plrTalent = GetTalentMap(GetActiveTalentGroup())->find(talent->ID);
+ if (plrTalent != GetTalentMap(GetActiveTalentGroup())->end())
+ plrTalent->second->state = PLAYERSPELL_REMOVED;
}
bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, bool fromSkill /*= false*/)
@@ -3452,7 +3469,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
if (active)
{
if (spellInfo->IsPassive() && IsNeedCastPassiveSpellAtLearn(spellInfo))
- CastSpell (this, spellId, true);
+ CastSpell(this, spellId, true);
}
else if (IsInWorld())
{
@@ -3568,11 +3585,9 @@ 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 && talentCost > 0 && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
+ if (!loading && spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) && 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);
@@ -3589,72 +3604,45 @@ 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())
{
if (spellInfo->IsPrimaryProfessionFirstRank())
- SetFreePrimaryProfessions(freeProfs-1);
+ SetFreePrimaryProfessions(freeProfs - 1);
}
- // add dependent skills
- uint16 maxskill = GetMaxSkillValueForLevel();
-
- SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId);
-
SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
- if (spellLearnSkill)
+ // add dependent skills if this spell is not learned from adding skill already
+ if (!fromSkill)
{
- uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill);
- uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill);
+ if (SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId))
+ {
+ 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 ? maxskill : spellLearnSkill->maxvalue;
+ uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : 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
- {
- // not ranked skills
- for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
+ SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value);
+ }
+ else
{
- SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
- if (!pSkill)
- continue;
-
- if (HasSkill(pSkill->ID))
- continue;
-
- 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)))
+ // not ranked skills
+ for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
{
- 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;
- }
+ SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
+ if (!pSkill)
+ 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);
}
}
}
@@ -3733,8 +3721,7 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const
{
-
- if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
+ if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetSpecId(GetActiveTalentGroup())))
return spellInfo->Id == chrSpec->MasterySpellID[0] || spellInfo->Id == chrSpec->MasterySpellID[1];
return false;
@@ -3789,7 +3776,8 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
// unlearn non talent higher ranks (recursive)
if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id))
{
- if (HasSpell(nextSpell) && !GetTalentBySpellID(nextSpell))
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(nextSpell);
+ if (HasSpell(nextSpell) && !spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT))
RemoveSpell(nextSpell, disabled, false);
}
//unlearn spells dependent from recently removed spells
@@ -3915,6 +3903,8 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
}
}
+ m_overrideSpells.erase(spell_id);
+
if (spell_id == 46917 && m_canTitanGrip)
SetCanTitanGrip(false);
@@ -4117,11 +4107,8 @@ uint32 Player::GetNextResetTalentsCost() const
}
}
-bool Player::ResetTalents(bool noCost, bool resetTalents, bool resetSpecialization)
+bool Player::ResetTalents(bool noCost)
{
- if (!resetTalents && !resetSpecialization)
- return false;
-
sScriptMgr->OnPlayerTalentsReset(this, noCost);
// not need after this call
@@ -4143,41 +4130,30 @@ bool Player::ResetTalents(bool noCost, bool resetTalents, bool resetSpecializati
RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
- if (resetTalents)
+ for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
{
- for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
- {
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
- 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 (talentInfo->ClassID != getClass())
- continue;
-
- SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
- if (!spellEntry)
- continue;
+ TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
+ if (!talentInfo)
+ continue;
- RemoveSpell(spellEntry->Id, false);
+ // 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;
- // 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);
+ // skip non-existant talent ranks
+ if (talentInfo->SpellID == 0)
+ continue;
- GetTalentMap(GetActiveTalentGroup())->erase(talentId);
- }
+ RemoveTalent(talentInfo);
}
- if (resetSpecialization)
- {
- SetTalentSpec(GetActiveTalentGroup(), 0);
- SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0);
- }
+ // Remove spec specific spells
+ RemoveSpecializationSpells();
+
+ SetSpecId(GetActiveTalentGroup(), 0);
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0);
SQLTransaction trans = CharacterDatabase.BeginTransaction();
_SaveTalents(trans);
@@ -4205,35 +4181,6 @@ bool Player::ResetTalents(bool noCost, bool resetTalents, bool resetSpecializati
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)
@@ -4298,10 +4245,10 @@ bool Player::HasSpell(uint32 spell) const
!itr->second->disabled);
}
-bool Player::HasTalent(uint32 talentId, uint8 group)
+bool Player::HasTalent(uint32 talentId, uint8 group) const
{
PlayerTalentMap::const_iterator itr = GetTalentMap(group)->find(talentId);
- return (itr != GetTalentMap(group)->end());
+ return (itr != GetTalentMap(group)->end() && itr->second->state != PLAYERSPELL_REMOVED);
}
bool Player::HasActiveSpell(uint32 spell) const
@@ -5950,26 +5897,28 @@ void Player::UpdateSkillsForLevel()
if (!rcEntry)
continue;
- if (GetSkillRangeType(rcEntry) != SKILL_RANGE_LEVEL)
- continue;
-
- if (IsWeaponSkill(rcEntry->SkillID))
- continue;
-
uint16 field = itr->second.pos / 2;
uint8 offset = itr->second.pos & 1; // itr->second.pos % 2
- //uint16 val = GetUInt16Value(PLAYER_SKILL_LINEID + SKILL_RANK_OFFSET + field, offset);
- uint16 max = GetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset);
-
- /// update only level dependent max skill values
- if (max != 1)
+ if (GetSkillRangeType(rcEntry) == SKILL_RANGE_LEVEL)
{
- SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_RANK_OFFSET + field, offset, maxSkill);
- SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset, maxSkill);
- if (itr->second.uState != SKILL_NEW)
- itr->second.uState = SKILL_CHANGED;
+ if (!IsWeaponSkill(rcEntry->SkillID))
+ {
+ uint16 max = GetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset);
+
+ /// update only level dependent max skill values
+ if (max != 1)
+ {
+ SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_RANK_OFFSET + field, offset, maxSkill);
+ SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset, maxSkill);
+ if (itr->second.uState != SKILL_NEW)
+ itr->second.uState = SKILL_CHANGED;
+ }
+ }
}
+
+ // Update level dependent skillline spells
+ LearnSkillRewardedSpells(rcEntry->SkillID, GetUInt16Value(PLAYER_SKILL_LINEID + SKILL_RANK_OFFSET + field, offset));
}
}
@@ -8414,7 +8363,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
- spell->m_glyphIndex = glyphIndex; // glyph index
+ spell->m_misc.Data = glyphIndex; // glyph index
spell->prepare(&targets);
++count;
@@ -8442,7 +8391,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
- spell->m_glyphIndex = glyphIndex; // glyph index
+ spell->m_misc.Data = glyphIndex; // glyph index
spell->prepare(&targets);
++count;
@@ -17192,17 +17141,19 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
if (talentSpec)
{
if (sChrSpecializationStore.LookupEntry(talentSpec))
- SetTalentSpec(i, talentSpec);
+ SetSpecId(i, talentSpec);
else
SetAtLoginFlag(AT_LOGIN_RESET_TALENTS);
}
}
- SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, GetActiveTalentSpec());
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, GetSpecId(GetActiveTalentGroup()));
_LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS));
_LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS));
+ LearnSpecializationSpells();
+
_LoadGlyphs(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GLYPHS));
_LoadAuras(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURAS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS), time_diff);
_LoadGlyphAuras();
@@ -18724,7 +18675,7 @@ bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report
else if (mapDiff->HasMessage()) // if (missingAchievement) covered by this case
SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY, target_difficulty);
else if (missingItem)
- GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, sObjectMgr->GetItemTemplate(missingItem)->GetName(GetSession()->GetSessionDbcLocale()));
+ GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(missingItem))->GetName(GetSession()->GetSessionDbcLocale()));
else if (LevelMin)
GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED), LevelMin);
}
@@ -18911,7 +18862,7 @@ void Player::SaveToDB(bool create /*=false*/)
ss.str("");
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
- ss << GetTalentSpec(i) << " ";
+ ss << GetSpecId(i) << " ";
stmt->setString(index++, ss.str());
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
stmt->setUInt8(index++, m_stableSlots);
@@ -19048,7 +18999,7 @@ void Player::SaveToDB(bool create /*=false*/)
ss.str("");
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
- ss << GetTalentSpec(i) << " ";
+ ss << GetSpecId(i) << " ";
stmt->setString(index++, ss.str());
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
stmt->setUInt8(index++, m_stableSlots);
@@ -19937,12 +19888,6 @@ bool Player::CanSpeak() const
/*** LOW LEVEL FUNCTIONS:Notifiers ***/
/*********************************************************/
-void Player::SendAttackSwingNotInRange()
-{
- WorldPacket data(SMSG_ATTACKSWING_NOTINRANGE, 0);
- GetSession()->SendPacket(&data);
-}
-
void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, SQLTransaction& trans)
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_POSITION);
@@ -19971,26 +19916,32 @@ void Player::SetUInt32ValueInArray(Tokenizer& Tokenizer, uint16 index, uint32 va
void Player::SendAttackSwingDeadTarget()
{
- WorldPacket data(SMSG_ATTACKSWING_DEADTARGET, 0);
- GetSession()->SendPacket(&data);
+ WorldPackets::Combat::AttackSwingError packet(ATTACKSWINGERR_DEADTARGET);
+ GetSession()->SendPacket(packet.Write());
}
void Player::SendAttackSwingCantAttack()
{
- WorldPacket data(SMSG_ATTACKSWING_CANT_ATTACK, 0);
- GetSession()->SendPacket(&data);
+ WorldPackets::Combat::AttackSwingError packet(ATTACKSWINGERR_CANT_ATTACK);
+ GetSession()->SendPacket(packet.Write());
}
-void Player::SendAttackSwingCancelAttack()
+void Player::SendAttackSwingNotInRange()
{
- WorldPacket data(SMSG_CANCEL_COMBAT, 0);
- GetSession()->SendPacket(&data);
+ WorldPackets::Combat::AttackSwingError packet(ATTACKSWINGERR_NOTINRANGE);
+ GetSession()->SendPacket(packet.Write());
}
void Player::SendAttackSwingBadFacingAttack()
{
- WorldPacket data(SMSG_ATTACKSWING_BADFACING, 0);
- GetSession()->SendPacket(&data);
+ WorldPackets::Combat::AttackSwingError packet(ATTACKSWINGERR_BADFACING);
+ GetSession()->SendPacket(packet.Write());
+}
+
+void Player::SendAttackSwingCancelAttack()
+{
+ WorldPackets::Combat::CancelCombat packet;
+ GetSession()->SendPacket(packet.Write());
}
void Player::SendAutoRepeatCancel(Unit* target)
@@ -25403,43 +25354,60 @@ void Player::CompletedAchievement(AchievementEntry const* entry)
bool Player::LearnTalent(uint32 talentId)
{
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
if (!talentInfo)
return false;
- uint32 maxTalentTier = GetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS);
+ if (talentInfo->SpecID && talentInfo->SpecID != GetSpecId(GetActiveTalentGroup()))
+ return false;
// prevent learn talent for different class (cheating)
if (talentInfo->ClassID != getClass())
return false;
// check if we have enough talent points
- if (talentInfo->TierID > maxTalentTier)
+ if (talentInfo->TierID >= GetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS))
return false;
- // Check if player doesnt have any spell in selected collumn
- for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++)
+ // Check if there is a different talent for us to learn in selected slot
+ // Example situation:
+ // Warrior talent row 2 slot 0
+ // Talent.dbc has an entry for each specialization
+ // but only 2 out of 3 have SpecID != 0
+ // We need to make sure that if player is in one of these defined specs he will not learn the other choice
+ TalentEntry const* bestSlotMatch = nullptr;
+ for (TalentEntry const* talent : sTalentByPos[getClass()][talentInfo->TierID][talentInfo->ColumnIndex])
{
- if (TalentEntry const* talent = sTalentStore.LookupEntry(i))
+ if (!talent->SpecID)
+ bestSlotMatch = talent;
+ else if (talent->SpecID == GetSpecId(GetActiveTalentGroup()))
{
- if (talentInfo->TierID == talent->TierID && HasSpell(talent->SpellID))
- return false;
+ bestSlotMatch = talent;
+ break;
}
}
+ if (talentInfo != bestSlotMatch)
+ return false;
+
+ // Check if player doesnt have any talent in current tier
+ for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
+ for (TalentEntry const* talent : sTalentByPos[getClass()][talentInfo->TierID][c])
+ if (HasTalent(talent->ID, GetActiveTalentGroup()))
+ return false;
+
// spell not set in talent.dbc
uint32 spellid = talentInfo->SpellID;
- if (spellid == 0)
+ if (!spellid)
{
TC_LOG_ERROR("entities.player", "Talent.dbc has no spellInfo for talent: %u (spell id = 0)", talentId);
return false;
}
// already known
- if (HasSpell(spellid))
+ if (HasTalent(talentId, GetActiveTalentGroup()) || HasSpell(spellid))
return false;
- if (!AddTalent(talentId, GetActiveTalentGroup(), true))
+ if (!AddTalent(talentInfo, GetActiveTalentGroup(), true))
return false;
LearnSpell(spellid, false);
@@ -25451,49 +25419,42 @@ bool Player::LearnTalent(uint32 talentId)
void Player::LearnTalentSpecialization(uint32 talentSpec)
{
- if (GetActiveTalentSpec())
+ if (GetSpecId(GetActiveTalentGroup()))
return;
- SetTalentSpec(GetActiveTalentGroup(), talentSpec);
-
+ SetSpecId(GetActiveTalentGroup(), talentSpec);
SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, talentSpec);
- PlayerTalentMap* talents = GetTalentMap(GetActiveTalentGroup());
-
- for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
- {
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
- if (!talentInfo || talentInfo->ClassID != getClass() || talentInfo->SpecID != talentSpec)
- continue;
-
- 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);
- }
- }
+ // Reset only talents that have different spells for each spec
+ uint32 class_ = getClass();
+ for (uint32 t = 0; t < MAX_TALENT_TIERS; ++t)
+ for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
+ if (sTalentByPos[class_][t][c].size() > 1)
+ for (TalentEntry const* talent : sTalentByPos[class_][t][c])
+ RemoveTalent(talent);
+ LearnSpecializationSpells();
SendTalentsInfoData();
+}
- SaveToDB();
+void Player::ResetTalentSpecialization()
+{
+ if (!GetSpecId(GetActiveTalentGroup()))
+ return;
- SendTalentsInfoData();
-}
+ SetSpecId(GetActiveTalentGroup(), 0);
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0);
+ // Reset only talents that have different spells for each spec
+ uint32 class_ = getClass();
+ for (uint32 t = 0; t < MAX_TALENT_TIERS; ++t)
+ for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
+ if (sTalentByPos[class_][t][c].size() > 1)
+ for (TalentEntry const* talent : sTalentByPos[class_][t][c])
+ RemoveTalent(talent);
-void Player::AddKnownCurrency(uint32 itemId)
-{
- if (CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemId))
- SetFlag64(0, (1LL << (ctEntry->ID-1)));
+ RemoveSpecializationSpells();
+ SendTalentsInfoData();
}
void Player::UpdateFallInformationIfNeed(MovementInfo const& minfo, uint16 opcode)
@@ -25576,12 +25537,14 @@ void Player::SendTalentsInfoData()
{
WorldPackets::Talent::TalentGroupInfo groupInfoPkt;
- groupInfoPkt.SpecID = GetTalentSpec(i);
-
+ groupInfoPkt.SpecID = GetSpecId(i);
groupInfoPkt.TalentIDs.reserve(GetTalentMap(i)->size());
for (PlayerTalentMap::const_iterator itr = GetTalentMap(i)->begin(); itr != GetTalentMap(i)->end(); ++itr)
{
+ if (itr->second->state == PLAYERSPELL_REMOVED)
+ continue;
+
TalentEntry const* talentInfo = sTalentStore.LookupEntry(itr->first);
if (!talentInfo)
{
@@ -25599,9 +25562,6 @@ void Player::SendTalentsInfoData()
continue;
}
- if (!HasTalent(itr->first, i))
- continue;
-
groupInfoPkt.TalentIDs.push_back(uint16(itr->first));
}
@@ -25918,7 +25878,8 @@ void Player::_LoadTalents(PreparedQueryResult result)
if (result)
{
do
- AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8(), false);
+ if (TalentEntry const* talent = sTalentStore.LookupEntry((*result)[0].GetUInt32()))
+ AddTalent(talent, (*result)[1].GetUInt8(), false);
while (result->NextRow());
}
}
@@ -25929,15 +25890,25 @@ void Player::_SaveTalents(SQLTransaction& trans)
stmt->setUInt64(0, GetGUID().GetCounter());
trans->Append(stmt);
+ PlayerTalentMap* talents;
for (uint8 group = 0; group < MAX_TALENT_GROUPS; ++group)
{
- for (PlayerTalentMap::iterator itr = GetTalentMap(group)->begin(); itr != GetTalentMap(group)->end(); ++itr)
+ talents = GetTalentMap(group);
+ for (PlayerTalentMap::iterator itr = talents->begin(); itr != talents->end();)
{
+ if (itr->second->state == PLAYERSPELL_REMOVED)
+ {
+ delete itr->second;
+ itr = talents->erase(itr);
+ continue;
+ }
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT);
stmt->setUInt64(0, GetGUID().GetCounter());
stmt->setUInt32(1, itr->first);
stmt->setUInt8(2, itr->second->spec);
trans->Append(stmt);
+ ++itr;
}
}
}
@@ -25988,12 +25959,12 @@ void Player::UpdateTalentGroupCount(uint8 count)
SendTalentsInfoData();
}
-void Player::ActivateTalentGroup(uint8 group)
+void Player::ActivateTalentGroup(uint8 spec)
{
- if (GetActiveTalentGroup() == group)
+ if (GetActiveTalentGroup() == spec)
return;
- if (group > GetTalentGroupsCount())
+ if (spec > GetTalentGroupsCount())
return;
if (IsNonMeleeSpellCast(false))
@@ -26025,57 +25996,76 @@ void Player::ActivateTalentGroup(uint8 group)
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
{
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
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)
+ if (talentInfo->ClassID != getClass())
continue;
- SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
- if (!spellEntry)
+ if (talentInfo->SpellID == 0)
+ continue;
+
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
+ if (!spellInfo)
continue;
RemoveSpell(talentInfo->SpellID, true);
// search for spells that the talent teaches and unlearn them
- for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
RemoveSpell(effect->TriggerSpell, true);
+
+ if (talentInfo->OverridesSpellID)
+ RemoveOverrideSpell(talentInfo->OverridesSpellID, talentInfo->SpellID);
}
- // remove glyphs
+ // Remove spec specific spells
+ RemoveSpecializationSpells();
+
+ // set glyphs
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
// remove secondary glyph
if (uint32 oldglyph = GetGlyph(GetActiveTalentGroup(), slot))
if (GlyphPropertiesEntry const* old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
RemoveAurasDueToSpell(old_gp->SpellID);
- // Activate new group
- SetActiveTalentGroup(group);
-
- uint32 spentTalents = 0;
+ SetActiveTalentGroup(spec);
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, GetSpecId(spec));
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
{
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
if (!talentInfo)
continue;
// learn only talents for character class
- if (getClass() != talentInfo->ClassID)
+ if (talentInfo->ClassID != getClass())
continue;
- ++spentTalents;
+ if (!talentInfo->SpellID)
+ continue;
- if (HasTalent(talentInfo->SpellID, group))
- LearnSpell(talentInfo->SpellID, false);
+ // if the talent can be found in the newly activated PlayerTalentMap
+ if (HasTalent(talentInfo->ID, GetActiveTalentGroup()))
+ {
+ LearnSpell(talentInfo->SpellID, false); // add the talent to the PlayerSpellMap
+ if (talentInfo->OverridesSpellID)
+ AddOverrideSpell(talentInfo->OverridesSpellID, talentInfo->SpellID);
+ }
}
+ LearnSpecializationSpells();
+
+ if (CanUseMastery())
+ if (ChrSpecializationEntry const* specialization = sChrSpecializationStore.LookupEntry(GetSpecId(GetActiveTalentGroup())))
+ for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
+ if (uint32 mastery = specialization->MasterySpellID[i])
+ LearnSpell(mastery, false);
+
// set glyphs
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
{
@@ -26089,7 +26079,6 @@ void Player::ActivateTalentGroup(uint8 group)
SetGlyph(slot, glyph);
}
- SetUsedTalentCount(spentTalents);
InitTalentForLevel();
{
@@ -26108,10 +26097,8 @@ void Player::ActivateTalentGroup(uint8 group)
SetPower(pw, 0);
- if (!sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
- {
+ if (!sChrSpecializationStore.LookupEntry(GetSpecId(GetActiveTalentGroup())))
ResetTalents(true);
- }
}
void Player::ResetTimeSync()
@@ -27152,10 +27139,17 @@ void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell)
GetSession()->SendPacket(&data);
}
-uint32 Player::CalculateTalentsPoints() const
+uint32 Player::CalculateTalentsTiers() const
{
- // 1 talent point for every 15 levels
- return getLevel() >= 100 ? 7 : uint32(floor(getLevel() / 15.f));
+ static uint32 const DefaultTalentRowLevels[MAX_TALENT_TIERS] = { 15, 30, 45, 60, 75, 90, 100 };
+ static uint32 const DKTalentRowLevels[MAX_TALENT_TIERS] = { 57, 58, 59, 60, 75, 90, 100 };
+
+ uint32 const* rowLevels = (getClass() != CLASS_DEATH_KNIGHT) ? DefaultTalentRowLevels : DKTalentRowLevels;
+ for (uint32 i = MAX_TALENT_TIERS; i; --i)
+ if (getLevel() >= rowLevels[i - 1])
+ return i;
+
+ return 0;
}
Difficulty Player::GetDifficultyID(MapEntry const* mapEntry) const
@@ -27218,3 +27212,64 @@ Difficulty Player::CheckLoadedLegacyRaidDifficultyID(Difficulty difficulty)
return difficulty;
}
+
+SpellInfo const* Player::GetCastSpellInfo(SpellInfo const* spellInfo) const
+{
+ auto range = m_overrideSpells.equal_range(spellInfo->Id);
+ for (auto itr = range.first; itr != range.second; ++itr)
+ if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(itr->second))
+ return Unit::GetCastSpellInfo(newInfo);
+
+ return Unit::GetCastSpellInfo(spellInfo);
+}
+
+void Player::RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
+{
+ auto range = m_overrideSpells.equal_range(overridenSpellId);
+ for (auto itr = range.first; itr != range.second; ++itr)
+ {
+ if (itr->second == newSpellId)
+ {
+ m_overrideSpells.erase(itr);
+ break;
+ }
+ }
+}
+
+void Player::LearnSpecializationSpells()
+{
+ if (std::vector<SpecializationSpellsEntry const*> const* specSpells = GetSpecializationSpells(GetSpecId(GetActiveTalentGroup())))
+ {
+ for (size_t j = 0; j < specSpells->size(); ++j)
+ {
+ SpecializationSpellsEntry const* specSpell = specSpells->at(j);
+ LearnSpell(specSpell->SpellID, false);
+ if (specSpell->OverridesSpellID)
+ AddOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID);
+ }
+ }
+}
+
+void Player::RemoveSpecializationSpells()
+{
+ for (uint32 i = 0; i < MAX_SPECIALIZATIONS; ++i)
+ {
+ if (ChrSpecializationEntry const* specialization = sChrSpecializationByIndexStore[getClass()][i])
+ {
+ if (std::vector<SpecializationSpellsEntry const*> const* specSpells = GetSpecializationSpells(specialization->ID))
+ {
+ for (size_t j = 0; j < specSpells->size(); ++j)
+ {
+ SpecializationSpellsEntry const* specSpell = specSpells->at(j);
+ RemoveSpell(specSpell->SpellID, true);
+ if (specSpell->OverridesSpellID)
+ RemoveOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID);
+ }
+ }
+
+ for (uint32 j = 0; j < MAX_MASTERY_SPELLS; ++j)
+ if (uint32 mastery = specialization->MasterySpellID[j])
+ RemoveAurasDueToSpell(mastery);
+ }
+ }
+}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index e895e696bb4..a22cd007ee0 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -670,6 +670,14 @@ struct SkillStatusData
typedef std::unordered_map<uint32, SkillStatusData> SkillStatusMap;
+enum AttackSwingErr
+{
+ ATTACKSWINGERR_CANT_ATTACK = 0,
+ ATTACKSWINGERR_NOTINRANGE = 1,
+ ATTACKSWINGERR_BADFACING = 2,
+ ATTACKSWINGERR_DEADTARGET = 3
+};
+
class Quest;
class Spell;
class Item;
@@ -1239,13 +1247,15 @@ private:
struct PlayerTalentInfo
{
- PlayerTalentInfo() : UsedTalentCount(0), ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), GroupsCount(1)
+ PlayerTalentInfo() :
+ ResetTalentsCost(0), ResetTalentsTime(0),
+ ActiveGroup(0), GroupsCount(1)
{
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;
+ GroupInfo[i].SpecId = 0;
}
}
@@ -1263,10 +1273,9 @@ struct PlayerTalentInfo
{
PlayerTalentMap* Talents;
uint32 Glyphs[MAX_GLYPH_SLOT_INDEX];
- uint32 TalentTree;
+ uint32 SpecId;
} GroupInfo[MAX_TALENT_GROUPS];
- uint32 UsedTalentCount;
uint32 ResetTalentsCost;
time_t ResetTalentsTime;
uint8 ActiveGroup;
@@ -1276,6 +1285,7 @@ private:
PlayerTalentInfo(PlayerTalentInfo const&);
};
+
class Player : public Unit, public GridObject<Player>
{
friend class WorldSession;
@@ -1812,6 +1822,7 @@ class Player : public Unit, public GridObject<Player>
void SendRemoveControlBar();
bool HasSpell(uint32 spell) const override;
bool HasActiveSpell(uint32 spell) const; // show in spellbook
+ SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const override;
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;
bool IsSpellFitByClassAndRace(uint32 spell_id) const;
bool IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const;
@@ -1831,41 +1842,37 @@ class Player : public Unit, public GridObject<Player>
void LearnSpellHighestRank(uint32 spellid);
void AddTemporarySpell(uint32 spellId);
void RemoveTemporarySpell(uint32 spellId);
+ void AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId) { m_overrideSpells.emplace(overridenSpellId, newSpellId); }
+ void RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId);
+ void LearnSpecializationSpells();
+ void RemoveSpecializationSpells();
void SetReputation(uint32 factionentry, uint32 value);
uint32 GetReputation(uint32 factionentry) const;
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 GetTalentGroupsCount() const { return _talentMgr->GroupsCount; }
- void SetTalentGroupsCount(uint8 count) { _talentMgr->GroupsCount = count; }
+ uint32 GetSpecId(uint8 group) const { return _talentMgr->GroupInfo[group].SpecId; }
+ void SetSpecId(uint8 group, uint32 tree) { _talentMgr->GroupInfo[group].SpecId = tree; }
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].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 noCost = false);
uint32 GetNextResetTalentsCost() const;
void InitTalentForLevel();
void SendTalentsInfoData();
bool LearnTalent(uint32 talentId);
- bool AddTalent(uint32 talentId, uint8 spec, bool learning);
- bool HasTalent(uint32 talentId, uint8 spec);
- uint32 CalculateTalentsPoints() const;
-
-
+ bool AddTalent(TalentEntry const* talent, uint8 spec, bool learning);
+ bool HasTalent(uint32 spell_id, uint8 spec) const;
+ void RemoveTalent(TalentEntry const* talent);
+ uint32 CalculateTalentsTiers() const;
void LearnTalentSpecialization(uint32 talentSpec);
+ void ResetTalentSpecialization();
// Dual Spec
void UpdateTalentGroupCount(uint8 count);
@@ -2793,6 +2800,7 @@ class Player : public Unit, public GridObject<Player>
PlayerMails m_mail;
PlayerSpellMap m_spells;
+ std::unordered_multimap<uint32 /*overridenSpellId*/, uint32 /*newSpellId*/> m_overrideSpells;
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
GlobalCooldownMgr m_GlobalCooldownMgr;
@@ -2911,9 +2919,6 @@ class Player : public Unit, public GridObject<Player>
void RefundItem(Item* item);
void SendItemRefundResult(Item* item, ItemExtendedCostEntry const* iece, uint8 error);
- // know currencies are not removed at any point (0 displayed)
- void AddKnownCurrency(uint32 itemId);
-
void AdjustQuestReqItemCount(Quest const* quest);
bool IsCanDelayTeleport() const { return m_bCanDelayTeleport; }
diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp
index eea0040404e..d9d6cd9d2e5 100644
--- a/src/server/game/Entities/Unit/StatSystem.cpp
+++ b/src/server/game/Entities/Unit/StatSystem.cpp
@@ -526,7 +526,7 @@ void Player::UpdateMastery()
value += GetRatingBonusValue(CR_MASTERY);
SetFloatValue(PLAYER_MASTERY, value);
- ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec());
+ ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetSpecId(GetActiveTalentGroup()));
if (!chrSpec)
return;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index a2adb6a320c..59822acb7ad 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -63,6 +63,7 @@
#include "MovementStructures.h"
#include "WorldSession.h"
#include "ChatPackets.h"
+#include "MiscPackets.h"
#include "MovementPackets.h"
#include "CombatPackets.h"
#include "CombatLogPackets.h"
@@ -161,6 +162,30 @@ ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
_damageInfo(damageInfo), _healInfo(healInfo)
{ }
+SpellInfo const* ProcEventInfo::GetSpellInfo() const
+{
+ /// WORKAROUND: unfinished new proc system
+ if (_spell)
+ return _spell->GetSpellInfo();
+ if (_damageInfo)
+ return _damageInfo->GetSpellInfo();
+ /*if (_healInfo)
+ return _healInfo->GetSpellInfo();*/
+ return nullptr;
+}
+
+SpellSchoolMask ProcEventInfo::GetSchoolMask() const
+{
+ /// WORKAROUND: unfinished new proc system
+ if (_spell)
+ return _spell->GetSpellInfo()->GetSchoolMask();
+ if (_damageInfo)
+ return _damageInfo->GetSchoolMask();
+ /*if (_healInfo)
+ return _healInfo->GetSchoolMask();*/
+ return SPELL_SCHOOL_MASK_NONE;
+}
+
Unit::Unit(bool isWorldObject) :
WorldObject(isWorldObject), m_movedPlayer(NULL), m_lastSanctuaryTime(0),
IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(),
@@ -12575,7 +12600,7 @@ void Unit::StopMoving()
bool Unit::IsSitState() const
{
- uint8 s = getStandState();
+ UnitStandStateType s = GetStandState();
return
s == UNIT_STAND_STATE_SIT_CHAIR || s == UNIT_STAND_STATE_SIT_LOW_CHAIR ||
s == UNIT_STAND_STATE_SIT_MEDIUM_CHAIR || s == UNIT_STAND_STATE_SIT_HIGH_CHAIR ||
@@ -12584,22 +12609,21 @@ bool Unit::IsSitState() const
bool Unit::IsStandState() const
{
- uint8 s = getStandState();
+ UnitStandStateType s = GetStandState();
return !IsSitState() && s != UNIT_STAND_STATE_SLEEP && s != UNIT_STAND_STATE_KNEEL;
}
-void Unit::SetStandState(uint8 state)
+void Unit::SetStandState(UnitStandStateType state)
{
- SetByteValue(UNIT_FIELD_BYTES_1, 0, state);
+ SetByteValue(UNIT_FIELD_BYTES_1, 0, uint8(state));
if (IsStandState())
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED);
if (GetTypeId() == TYPEID_PLAYER)
{
- WorldPacket data(SMSG_STANDSTATE_UPDATE, 1);
- data << (uint8)state;
- ToPlayer()->GetSession()->SendPacket(&data);
+ WorldPackets::Misc::StandStateUpdate packet(state);
+ ToPlayer()->GetSession()->SendPacket(packet.Write());
}
}
@@ -16545,3 +16569,18 @@ void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/
packet.Initalize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, getGender()), 0, "", locale);
target->SendDirectMessage(packet.Write());
}
+
+SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const
+{
+ Unit::AuraEffectList swaps = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS);
+ Unit::AuraEffectList const& swaps2 = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2);
+ if (!swaps2.empty())
+ swaps.insert(swaps.end(), swaps2.begin(), swaps2.end());
+
+ for (AuraEffect const* auraEffect : swaps)
+ if (auraEffect->IsAffectingSpell(spellInfo))
+ if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount()))
+ return newInfo;
+
+ return spellInfo;
+}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 1b8c188afb4..0311b67befd 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -97,7 +97,7 @@ enum SpellModOp
SPELLMOD_COOLDOWN = 11,
SPELLMOD_EFFECT2 = 12,
SPELLMOD_IGNORE_ARMOR = 13,
- SPELLMOD_COST = 14,
+ SPELLMOD_COST = 14, // Used when SpellPowerEntry::PowerIndex == 0
SPELLMOD_CRIT_DAMAGE_BONUS = 15,
SPELLMOD_RESIST_MISS_CHANCE = 16,
SPELLMOD_JUMP_TARGETS = 17,
@@ -113,10 +113,16 @@ enum SpellModOp
SPELLMOD_VALUE_MULTIPLIER = 27,
SPELLMOD_RESIST_DISPEL_CHANCE = 28,
SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
- SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30
+ SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30,
+ SPELLMOD_STACK_AMOUNT = 31, // has no effect on tooltip parsing
+ SPELLMOD_EFFECT4 = 32,
+ SPELLMOD_EFFECT5 = 33,
+ SPELLMOD_SPELL_COST2 = 34, // Used when SpellPowerEntry::PowerIndex == 1
+ SPELLMOD_JUMP_DISTANCE = 35,
+ SPELLMOD_STACK_AMOUNT2 = 37 // same as SPELLMOD_STACK_AMOUNT but affects tooltips
};
-#define MAX_SPELLMOD 32
+#define MAX_SPELLMOD 38
enum SpellValueMod
{
@@ -978,8 +984,8 @@ public:
uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
uint32 GetHitMask() const { return _hitMask; }
- SpellInfo const* GetSpellInfo() const { return NULL; }
- SpellSchoolMask GetSchoolMask() const { return SPELL_SCHOOL_MASK_NONE; }
+ SpellInfo const* GetSpellInfo() const;
+ SpellSchoolMask GetSchoolMask() const;
DamageInfo* GetDamageInfo() const { return _damageInfo; }
HealInfo* GetHealInfo() const { return _healInfo; }
@@ -1500,10 +1506,10 @@ class Unit : public WorldObject
uint32 GetCreatureType() const;
uint32 GetCreatureTypeMask() const;
- uint8 getStandState() const { return GetByteValue(UNIT_FIELD_BYTES_1, 0); }
+ UnitStandStateType GetStandState() const { return UnitStandStateType(GetByteValue(UNIT_FIELD_BYTES_1, 0)); }
bool IsSitState() const;
bool IsStandState() const;
- void SetStandState(uint8 state);
+ void SetStandState(UnitStandStateType state);
void SetStandFlags(uint8 flags) { SetByteFlag(UNIT_FIELD_BYTES_1, 2, flags); }
void RemoveStandFlags(uint8 flags) { RemoveByteFlag(UNIT_FIELD_BYTES_1, 2, flags); }
@@ -1930,6 +1936,7 @@ class Unit : public WorldObject
Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; }
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
int32 GetCurrentSpellCastTime(uint32 spell_id) const;
+ virtual SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const;
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT];
ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT];
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index d588d048d3d..202165ffd57 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -156,11 +156,11 @@ bool normalizePlayerName(std::string& name)
}
// Extracts player and realm names delimited by -
-ExtendedPlayerName ExtractExtendedPlayerName(std::string& name)
+ExtendedPlayerName ExtractExtendedPlayerName(std::string const& name)
{
size_t pos = name.find('-');
if (pos != std::string::npos)
- return ExtendedPlayerName(name.substr(0, pos), name.substr(pos+1));
+ return ExtendedPlayerName(name.substr(0, pos), name.substr(pos + 1));
else
return ExtendedPlayerName(name, "");
}
@@ -1869,7 +1869,7 @@ ObjectGuid::LowType ObjectMgr::AddGOData(uint32 entry, uint32 mapId, float x, fl
data.spawnMask = 1;
data.go_state = GO_STATE_READY;
data.phaseMask = PHASEMASK_NORMAL;
- data.artKit = goinfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT ? 21 : 0;
+ data.artKit = goinfo->type == GAMEOBJECT_TYPE_CONTROL_ZONE ? 21 : 0;
data.dbData = false;
AddGameobjectToGrid(guid, &data);
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 579cc7a5d4e..428d234fdb6 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -636,12 +636,12 @@ bool normalizePlayerName(std::string& name);
struct ExtendedPlayerName
{
- ExtendedPlayerName(std::string const& name, std::string const& realm) : Name(name), Realm(realm) {}
+ ExtendedPlayerName(std::string const& name, std::string const& realm) : Name(name), Realm(realm) { }
std::string Name;
std::string Realm;
};
-ExtendedPlayerName ExtractExtendedPlayerName(std::string& name);
+ExtendedPlayerName ExtractExtendedPlayerName(std::string const& name);
struct LanguageDesc
{
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index c255d786ce3..c7a7bcbf62c 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -1369,7 +1369,7 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData)
return;
}
- if (_player->getStandState() != UNIT_STAND_STATE_SIT_LOW_CHAIR + go->GetGOInfo()->barberChair.chairheight)
+ if (_player->GetStandState() != UNIT_STAND_STATE_SIT_LOW_CHAIR + go->GetGOInfo()->barberChair.chairheight)
{
SendBarberShopResult(BARBER_SHOP_RESULT_NOT_ON_CHAIR);
return;
@@ -1399,7 +1399,7 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData)
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1);
- _player->SetStandState(0); // stand up
+ _player->SetStandState(UNIT_STAND_STATE_STAND);
}
void WorldSession::HandleRemoveGlyph(WorldPacket& recvData)
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index aed2da5c534..1860904d617 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -419,7 +419,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPackets::Character::LogoutRequ
// not set flags if player can't free move to prevent lost state at logout cancel
if (GetPlayer()->CanFreeMove())
{
- if (GetPlayer()->getStandState() == UNIT_STAND_STATE_STAND)
+ if (GetPlayer()->GetStandState() == UNIT_STAND_STATE_STAND)
GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT);
GetPlayer()->SetRooted(true);
GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
@@ -543,13 +543,9 @@ void WorldSession::HandleSetSelectionOpcode(WorldPackets::Misc::SetSelection& pa
_player->SetSelection(packet.Selection);
}
-void WorldSession::HandleStandStateChangeOpcode(WorldPacket& recvData)
+void WorldSession::HandleStandStateChangeOpcode(WorldPackets::Misc::StandStateChange& packet)
{
- // TC_LOG_DEBUG("network", "WORLD: Received CMSG_STANDSTATECHANGE"); -- too many spam in log at lags/debug stop
- uint32 animstate;
- recvData >> animstate;
-
- _player->SetStandState(animstate);
+ _player->SetStandState(packet.StandState);
}
void WorldSession::HandleContactListOpcode(WorldPacket& recvData)
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 9a132bb1ae2..c1ac3cb18b2 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -752,7 +752,7 @@ void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket)
charmInfo->SetSpellAutocast(spellInfo, state != 0);
}
-void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest)
+void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& castRequest)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL");
/*
diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index d7cf1226088..a83ce9f996d 100644
--- a/src/server/game/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
@@ -32,10 +32,8 @@ void WorldSession::HandleLearnTalentsOpcode(WorldPackets::Talent::LearnTalents&
{
bool anythingLearned = false;
for (uint32 talentId : packet.Talents)
- {
if (_player->LearnTalent(talentId))
anythingLearned = true;
- }
if (anythingLearned)
_player->SendTalentsInfoData();
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index e1459f696f9..55574585246 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -320,109 +320,53 @@ void WorldSession::HandleGameobjectReportUse(WorldPackets::GameObject::GameObjec
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry());
}
-void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest)
+void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast)
{
// ignore for remote control state (for player case)
Unit* mover = _player->m_mover;
if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER)
- {
return;
- }
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(castRequest.SpellID);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cast.Cast.SpellID);
if (!spellInfo)
{
- TC_LOG_ERROR("network", "WORLD: unknown spell id %u", castRequest.SpellID);
+ TC_LOG_ERROR("network", "WORLD: unknown spell id %u", cast.Cast.SpellID);
return;
}
if (spellInfo->IsPassive())
- {
return;
- }
Unit* caster = mover;
- if (caster->GetTypeId() == TYPEID_UNIT && !caster->ToCreature()->HasSpell(castRequest.SpellID))
+ if (caster->GetTypeId() == TYPEID_UNIT && !caster->ToCreature()->HasSpell(spellInfo->Id))
{
// 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)
- {
return;
- }
caster = _player;
}
- if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(castRequest.SpellID))
- {
- // not have spell in spellbook
+ // check known spell
+ if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id))
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);
- if (!swaps2.empty())
- swaps.insert(swaps.end(), swaps2.begin(), swaps2.end());
- if (!swaps.empty())
- {
- for (Unit::AuraEffectList::const_iterator itr = swaps.begin(); itr != swaps.end(); ++itr)
- {
- if ((*itr)->IsAffectingSpell(spellInfo))
- {
- if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo((*itr)->GetAmount()))
- {
- spellInfo = newInfo;
- castRequest.SpellID = newInfo->Id;
- }
- break;
- }
- }
- }
+ // Check possible spell cast overrides
+ spellInfo = caster->GetCastSpellInfo(spellInfo);
// Client is resending autoshot cast opcode when other spell is cast during shoot rotation
// Skip it to prevent "interrupt" message
if (spellInfo->IsAutoRepeatRangedSpell() && caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)
&& caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo)
- {
return;
- }
// can't use our own spells when we're in possession of another unit,
if (_player->isPossessing())
- {
return;
- }
// client provided 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);
+ SpellCastTargets targets(caster, cast.Cast.Target);
// auto-selection buff level base at target level (in spellInfo)
if (targets.GetUnitTarget())
@@ -435,8 +379,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest&
}
Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, ObjectGuid::Empty, false);
- spell->m_cast_count = castRequest.CastID; // set count of casts
- spell->m_glyphIndex = castRequest.Misc; // 6.x Misc is just a guess
+ spell->m_cast_count = cast.Cast.CastID; // set count of casts
+ spell->m_misc.Data = cast.Cast.Misc; // 6.x Misc is just a guess
spell->prepare(&targets);
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 41594ad7d94..724d2a7eed4 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -29,6 +29,7 @@
#include "InstanceScript.h"
#include "MapInstanced.h"
#include "MapManager.h"
+#include "MiscPackets.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Pet.h"
@@ -36,6 +37,7 @@
#include "Transport.h"
#include "Vehicle.h"
#include "VMapFactory.h"
+#include "Weather.h"
u_map_magic MapMagic = { {'M','A','P','S'} };
u_map_magic MapVersionMagic = { {'v','1','.','4'} };
@@ -49,6 +51,10 @@ u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
GridState* si_GridStates[MAX_GRID_STATE];
+
+ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), WeatherId(WEATHER_STATE_FINE),
+ WeatherGrade(0.0f), OverrideLightId(0), LightFadeInTime(0) { }
+
Map::~Map()
{
sScriptMgr->OnDestroyMap(this);
@@ -2706,7 +2712,7 @@ uint32 Map::GetPlayersCountExceptGMs() const
return count;
}
-void Map::SendToPlayers(WorldPacket* data) const
+void Map::SendToPlayers(WorldPacket const* data) const
{
for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
itr->GetSource()->GetSession()->SendPacket(data);
@@ -3491,13 +3497,10 @@ void Map::SendZoneDynamicInfo(Player* player)
player->SendDirectMessage(&data);
}
- if (uint32 weather = itr->second.WeatherId)
+ if (WeatherState weatherId = itr->second.WeatherId)
{
- WorldPacket data(SMSG_WEATHER, 4 + 4 + 1);
- data << uint32(weather);
- data << float(itr->second.WeatherGrade);
- data << uint8(0);
- player->SendDirectMessage(&data);
+ WorldPackets::Misc::Weather weather(weatherId, itr->second.WeatherGrade);
+ player->SendDirectMessage(weather.Write());
}
if (uint32 overrideLight = itr->second.OverrideLightId)
@@ -3532,7 +3535,7 @@ void Map::SetZoneMusic(uint32 zoneId, uint32 musicId)
}
}
-void Map::SetZoneWeather(uint32 zoneId, uint32 weatherId, float weatherGrade)
+void Map::SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade)
{
if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end())
_zoneDynamicInfo.insert(ZoneDynamicInfoMap::value_type(zoneId, ZoneDynamicInfo()));
@@ -3544,15 +3547,12 @@ void Map::SetZoneWeather(uint32 zoneId, uint32 weatherId, float weatherGrade)
if (!players.isEmpty())
{
- WorldPacket data(SMSG_WEATHER, 4 + 4 + 1);
- data << uint32(weatherId);
- data << float(weatherGrade);
- data << uint8(0);
+ WorldPackets::Misc::Weather weather(weatherId, weatherGrade);
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource())
if (player->GetZoneId() == zoneId)
- player->SendDirectMessage(&data);
+ player->SendDirectMessage(weather.Write());
}
}
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index d38852e50c9..752953091f8 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -53,6 +53,8 @@ class MapInstanced;
class BattlegroundMap;
class InstanceMap;
class Transport;
+enum WeatherState : uint32;
+
namespace Trinity { struct ObjectUpdater; }
struct ScriptAction
@@ -231,11 +233,10 @@ enum LevelRequirementVsMode
struct ZoneDynamicInfo
{
- ZoneDynamicInfo() : MusicId(0), WeatherId(0), WeatherGrade(0.0f),
- OverrideLightId(0), LightFadeInTime(0) { }
+ ZoneDynamicInfo();
uint32 MusicId;
- uint32 WeatherId;
+ WeatherState WeatherId;
float WeatherGrade;
uint32 OverrideLightId;
uint32 LightFadeInTime;
@@ -424,7 +425,7 @@ class Map : public GridRefManager<NGridType>
void AddWorldObject(WorldObject* obj) { i_worldObjects.insert(obj); }
void RemoveWorldObject(WorldObject* obj) { i_worldObjects.erase(obj); }
- void SendToPlayers(WorldPacket* data) const;
+ void SendToPlayers(WorldPacket const* data) const;
typedef MapRefManager PlayerList;
PlayerList const& GetPlayers() const { return m_mapRefManager; }
@@ -513,7 +514,7 @@ class Map : public GridRefManager<NGridType>
void SendZoneDynamicInfo(Player* player);
void SetZoneMusic(uint32 zoneId, uint32 musicId);
- void SetZoneWeather(uint32 zoneId, uint32 weatherId, float weatherGrade);
+ void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade);
void SetZoneOverrideLight(uint32 zoneId, uint32 lightId, uint32 fadeInTime);
void UpdateAreaDependentAuras();
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 122181fb313..7a6b20696fd 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -504,7 +504,7 @@ enum SpellAttr4
SPELL_ATTR4_UNK4 = 0x00000010, // 4 This will no longer cause guards to attack on use??
SPELL_ATTR4_UNK5 = 0x00000020, // 5
SPELL_ATTR4_NOT_STEALABLE = 0x00000040, // 6 although such auras might be dispellable, they cannot be stolen
- SPELL_ATTR4_TRIGGERED = 0x00000080, // 7 spells forced to be triggered
+ SPELL_ATTR4_CAN_CAST_WHILE_CASTING = 0x00000080, // 7 Can be cast while another cast is in progress - see CanCastWhileCasting(SpellRec const*,CGUnit_C *,int &)
SPELL_ATTR4_FIXED_DAMAGE = 0x00000100, // 8 Ignores resilience and any (except mechanic related) damage or % damage taken auras on target.
SPELL_ATTR4_TRIGGER_ACTIVATE = 0x00000200, // 9 initially disabled / trigger activate from event (Execute, Riposte, Deep Freeze end other)
SPELL_ATTR4_SPELL_VS_EXTEND_COST = 0x00000400, // 10 Rogue Shiv have this flag
@@ -1188,7 +1188,7 @@ enum SpellEffectName
SPELL_EFFECT_178 = 178, // Unused (4.3.4)
SPELL_EFFECT_CREATE_AREATRIGGER = 179,
SPELL_EFFECT_UPDATE_AREATRIGGER = 180, // NYI
- SPELL_EFFECT_REMOVE_TALENT = 181, // NYI
+ SPELL_EFFECT_REMOVE_TALENT = 181,
SPELL_EFFECT_182 = 182,
SPELL_EFFECT_183 = 183,
SPELL_EFFECT_REPUTATION_2 = 184, // NYI
@@ -1517,7 +1517,7 @@ enum SpellCastResult // 19116
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_FAILED_UNKNOWN = 260,
SPELL_CAST_OK = 0xFFFF // custom value, must not be sent to client
};
diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp
index a23d71e0fe8..089bba92c38 100644
--- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp
+++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp
@@ -141,7 +141,7 @@ bool OPvPCapturePoint::SetCapturePointData(uint32 entry, uint32 map, float x, fl
// check info existence
GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
- if (!goinfo || goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT)
+ if (!goinfo || goinfo->type != GAMEOBJECT_TYPE_CONTROL_ZONE)
{
TC_LOG_ERROR("outdoorpvp", "OutdoorPvP: GO %u is not capture point!", entry);
return false;
@@ -548,21 +548,6 @@ bool OutdoorPvP::HandleDropFlag(Player* player, uint32 id)
return false;
}
-bool OPvPCapturePoint::HandleGossipOption(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*id*/)
-{
- return false;
-}
-
-bool OPvPCapturePoint::CanTalkTo(Player* /*player*/, Creature* /*c*/, GossipMenuItems const& /*gso*/)
-{
- return false;
-}
-
-bool OPvPCapturePoint::HandleDropFlag(Player* /*player*/, uint32 /*id*/)
-{
- return false;
-}
-
int32 OPvPCapturePoint::HandleOpenGo(Player* /*player*/, ObjectGuid guid)
{
std::map<ObjectGuid, uint32>::iterator itr = m_ObjectTypes.find(guid);
@@ -573,18 +558,32 @@ int32 OPvPCapturePoint::HandleOpenGo(Player* /*player*/, ObjectGuid guid)
return -1;
}
-bool OutdoorPvP::HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/)
-{
- return false;
-}
-
-void OutdoorPvP::BroadcastPacket(WorldPacket &data) const
+void OutdoorPvP::BroadcastPacket(WorldPacket const* data) const
{
// This is faster than sWorld->SendZoneMessage
for (uint32 team = 0; team < 2; ++team)
for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
if (Player* const player = ObjectAccessor::FindPlayer(*itr))
- player->GetSession()->SendPacket(&data);
+ player->SendDirectMessage(data);
+}
+
+void OutdoorPvP::AddCapturePoint(OPvPCapturePoint* cp)
+{
+ OPvPCapturePointMap::iterator i = m_capturePoints.find(cp->m_capturePointGUID);
+ if (i != m_capturePoints.end())
+ {
+ TC_LOG_ERROR("outdoorpvp", "OutdoorPvP::AddCapturePoint: CapturePoint %s already exists!", cp->m_capturePointGUID);
+ delete i->second;
+ }
+ m_capturePoints[cp->m_capturePointGUID] = cp;
+}
+
+OPvPCapturePoint* OutdoorPvP::GetCapturePoint(ObjectGuid guid) const
+{
+ OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.find(guid);
+ if (itr != m_capturePoints.end())
+ return itr->second;
+ return nullptr;
}
void OutdoorPvP::RegisterZone(uint32 zoneId)
@@ -622,7 +621,7 @@ void OutdoorPvP::TeamApplyBuff(TeamId team, uint32 spellId, uint32 spellId2)
void OutdoorPvP::OnGameObjectCreate(GameObject* go)
{
- if (go->GetGoType() != GAMEOBJECT_TYPE_CAPTURE_POINT)
+ if (go->GetGoType() != GAMEOBJECT_TYPE_CONTROL_ZONE)
return;
if (OPvPCapturePoint *cp = GetCapturePoint(go->GetGUID()))
@@ -631,7 +630,7 @@ void OutdoorPvP::OnGameObjectCreate(GameObject* go)
void OutdoorPvP::OnGameObjectRemove(GameObject* go)
{
- if (go->GetGoType() != GAMEOBJECT_TYPE_CAPTURE_POINT)
+ if (go->GetGoType() != GAMEOBJECT_TYPE_CONTROL_ZONE)
return;
if (OPvPCapturePoint *cp = GetCapturePoint(go->GetGUID()))
diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.h b/src/server/game/OutdoorPvP/OutdoorPvP.h
index 8f4475bce13..f550a35aff0 100644
--- a/src/server/game/OutdoorPvP/OutdoorPvP.h
+++ b/src/server/game/OutdoorPvP/OutdoorPvP.h
@@ -119,11 +119,11 @@ class OPvPCapturePoint
virtual void SendChangePhase();
- virtual bool HandleGossipOption(Player* player, ObjectGuid guid, uint32 gossipid);
+ virtual bool HandleGossipOption(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*gossipId*/) { return false; }
- virtual bool CanTalkTo(Player* player, Creature* c, GossipMenuItems const& gso);
+ virtual bool CanTalkTo(Player* /*player*/, Creature* /*creature*/, GossipMenuItems const& /*gso*/) { return false; }
- virtual bool HandleDropFlag(Player* player, uint32 spellId);
+ virtual bool HandleDropFlag(Player* /*player*/, uint32 /*spellId*/) { return false; }
virtual void DeleteSpawns();
@@ -204,7 +204,7 @@ class OutdoorPvP : public ZoneScript
virtual void FillInitialWorldStates(WorldPacket & /*data*/) { }
// called when a player triggers an areatrigger
- virtual bool HandleAreaTrigger(Player* player, uint32 trigger);
+ virtual bool HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/) { return false; }
// called on custom spell
virtual bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go);
@@ -274,25 +274,16 @@ class OutdoorPvP : public ZoneScript
// world state stuff
virtual void SendRemoveWorldStates(Player* /*player*/) { }
- void BroadcastPacket(WorldPacket & data) const;
+ void BroadcastPacket(WorldPacket const* data) const;
virtual void HandlePlayerEnterZone(Player* player, uint32 zone);
virtual void HandlePlayerLeaveZone(Player* player, uint32 zone);
virtual void HandlePlayerResurrects(Player* player, uint32 zone);
- void AddCapturePoint(OPvPCapturePoint* cp)
- {
- m_capturePoints[cp->m_capturePointGUID] = cp;
- }
+ void AddCapturePoint(OPvPCapturePoint* cp);
- OPvPCapturePoint * GetCapturePoint(ObjectGuid guid) const
- {
- OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.find(guid);
- if (itr != m_capturePoints.end())
- return itr->second;
- return NULL;
- }
+ OPvPCapturePoint * GetCapturePoint(ObjectGuid guid) const;
void RegisterZone(uint32 zoneid);
diff --git a/src/server/game/Server/Packets/CombatPackets.cpp b/src/server/game/Server/Packets/CombatPackets.cpp
index a23cbc7515b..53a489ebc21 100644
--- a/src/server/game/Server/Packets/CombatPackets.cpp
+++ b/src/server/game/Server/Packets/CombatPackets.cpp
@@ -140,3 +140,10 @@ WorldPacket const* WorldPackets::Combat::AttackerStateUpdate::Write()
return &_worldPacket;
}
+
+WorldPacket const* WorldPackets::Combat::AttackSwingError::Write()
+{
+ _worldPacket.WriteBits(Reason, 2);
+ _worldPacket.FlushBits();
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/CombatPackets.h b/src/server/game/Server/Packets/CombatPackets.h
index 012859ffc65..54d97e5774c 100644
--- a/src/server/game/Server/Packets/CombatPackets.h
+++ b/src/server/game/Server/Packets/CombatPackets.h
@@ -36,6 +36,17 @@ namespace WorldPackets
ObjectGuid Victim;
};
+ class AttackSwingError final : public ServerPacket
+ {
+ public:
+ AttackSwingError() : ServerPacket(SMSG_ATTACKSWING_ERROR, 4) { }
+ AttackSwingError(AttackSwingErr reason) : ServerPacket(SMSG_ATTACKSWING_ERROR, 4), Reason(reason) { }
+
+ WorldPacket const* Write() override;
+
+ AttackSwingErr Reason = ATTACKSWINGERR_CANT_ATTACK;
+ };
+
class AttackStop final : public ClientPacket
{
public:
@@ -165,6 +176,14 @@ namespace WorldPackets
UnkAttackerState UnkState;
float Unk = 0.0f;
};
+
+ class CancelCombat final : public ServerPacket
+ {
+ public:
+ CancelCombat() : ServerPacket(SMSG_CANCEL_COMBAT, 0) { }
+
+ WorldPacket const* Write() override { return &_worldPacket; }
+ };
}
}
diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp
index da92f65020a..699d504554e 100644
--- a/src/server/game/Server/Packets/MiscPackets.cpp
+++ b/src/server/game/Server/Packets/MiscPackets.cpp
@@ -259,3 +259,33 @@ void WorldPackets::Misc::ResurrectResponse::Read()
_worldPacket >> Resurrecter;
_worldPacket >> Response;
}
+
+WorldPackets::Misc::Weather::Weather() : ServerPacket(SMSG_WEATHER, 4 + 4 + 1) { }
+
+WorldPackets::Misc::Weather::Weather(WeatherState weatherID, float intensity /*= 0.0f*/, bool abrupt /*= false*/)
+ : ServerPacket(SMSG_WEATHER, 4 + 4 + 1), WeatherID(weatherID), Intensity(intensity), Abrupt(abrupt) { }
+
+WorldPacket const* WorldPackets::Misc::Weather::Write()
+{
+ _worldPacket << uint32(WeatherID);
+ _worldPacket << float(Intensity);
+ _worldPacket.WriteBit(Abrupt);
+
+ _worldPacket.FlushBits();
+ return &_worldPacket;
+}
+
+void WorldPackets::Misc::StandStateChange::Read()
+{
+ uint32 state;
+ _worldPacket >> state;
+
+ StandState = UnitStandStateType(state);
+}
+
+WorldPacket const* WorldPackets::Misc::StandStateUpdate::Write()
+{
+ _worldPacket << uint8(State);
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h
index b46b0aed60a..4a0d0bfbd12 100644
--- a/src/server/game/Server/Packets/MiscPackets.h
+++ b/src/server/game/Server/Packets/MiscPackets.h
@@ -23,6 +23,8 @@
#include "WorldSession.h"
#include "G3D/Vector3.h"
#include "Object.h"
+#include "Unit.h"
+#include "Weather.h"
namespace WorldPackets
{
@@ -339,7 +341,7 @@ namespace WorldPackets
void Read() override { }
};
- class RequestCemeteryListResponse : public ServerPacket
+ class RequestCemeteryListResponse final : public ServerPacket
{
public:
RequestCemeteryListResponse() : ServerPacket(SMSG_REQUEST_CEMETERY_LIST_RESPONSE, 1) { }
@@ -361,13 +363,47 @@ namespace WorldPackets
uint32 Response = 0;
};
- class AreaTriggerNoCorpse : public ServerPacket
+ class AreaTriggerNoCorpse final : public ServerPacket
{
public:
AreaTriggerNoCorpse() : ServerPacket(SMSG_AREA_TRIGGER_NO_CORPSE, 0) { }
WorldPacket const* Write() override { return &_worldPacket; }
};
+
+ class Weather final : public ServerPacket
+ {
+ public:
+ Weather();
+ Weather(WeatherState weatherID, float intensity = 0.0f, bool abrupt = false);
+
+ WorldPacket const* Write() override;
+
+ bool Abrupt = false;
+ float Intensity = 0.0f;
+ WeatherState WeatherID = WEATHER_STATE_FINE;
+ };
+
+ class StandStateChange final : public ClientPacket
+ {
+ public:
+ StandStateChange(WorldPacket&& packet) : ClientPacket(CMSG_STAND_STATE_CHANGE, std::move(packet)) { }
+
+ void Read() override;
+
+ UnitStandStateType StandState = UNIT_STAND_STATE_STAND;
+ };
+
+ class StandStateUpdate final : public ServerPacket
+ {
+ public:
+ StandStateUpdate() : ServerPacket(SMSG_STAND_STATE_UPDATE, 1) { }
+ StandStateUpdate(UnitStandStateType state) : ServerPacket(SMSG_STAND_STATE_UPDATE, 1), State(state) { }
+
+ WorldPacket const* Write() override;
+
+ UnitStandStateType State = UNIT_STAND_STATE_STAND;
+ };
}
}
diff --git a/src/server/game/Server/Packets/QueryPackets.h b/src/server/game/Server/Packets/QueryPackets.h
index 9b131ae82be..5a48db610ca 100644
--- a/src/server/game/Server/Packets/QueryPackets.h
+++ b/src/server/game/Server/Packets/QueryPackets.h
@@ -314,7 +314,7 @@ namespace WorldPackets
WorldPacket const* Write() override;
time_t CurrentTime = time_t(0);
- int32 TimeOutRequest;
+ int32 TimeOutRequest = 0;
};
}
}
diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp
index 053bb6c504f..6f93fec73f2 100644
--- a/src/server/game/Server/Packets/SpellPackets.cpp
+++ b/src/server/game/Server/Packets/SpellPackets.cpp
@@ -141,78 +141,91 @@ WorldPacket const* WorldPackets::Spells::AuraUpdate::Write()
return &_worldPacket;
}
-void WorldPackets::Spells::SpellCastRequest::Read()
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::TargetLocation& location)
{
- 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;
+ buffer >> location.Transport;
+ buffer >> location.Location.m_positionX;
+ buffer >> location.Location.m_positionY;
+ buffer >> location.Location.m_positionZ;
+ return buffer;
+}
- if (HasSrcLocation)
- {
- _worldPacket >> SrcTransportGuid;
- _worldPacket >> SrcPos.m_positionX;
- _worldPacket >> SrcPos.m_positionY;
- _worldPacket >> SrcPos.m_positionZ;
- }
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::SpellTargetData& targetData)
+{
+ buffer.ResetBitPos();
- if (HasDstLocation)
- {
- _worldPacket >> DstTransportGuid;
- _worldPacket >> DstPos.m_positionX;
- _worldPacket >> DstPos.m_positionY;
- _worldPacket >> DstPos.m_positionZ;
- }
+ targetData.Flags = buffer.ReadBits(21);
+ targetData.SrcLocation.HasValue = buffer.ReadBit();
+ targetData.DstLocation.HasValue = buffer.ReadBit();
+ targetData.Orientation.HasValue = buffer.ReadBit();
+ uint32 nameLength = buffer.ReadBits(7);
- if (HasOrientation)
- _worldPacket >> Orientation;
+ buffer >> targetData.Unit;
+ buffer >> targetData.Item;
- Name = _worldPacket.ReadString(NameLen);
+ if (targetData.SrcLocation.HasValue)
+ buffer >> targetData.SrcLocation.Value;
- _worldPacket >> Pitch;
- _worldPacket >> Speed;
+ if (targetData.DstLocation.HasValue)
+ buffer >> targetData.DstLocation.Value;
- _worldPacket >> Guid;
+ if (targetData.Orientation.HasValue)
+ buffer >> targetData.Orientation.Value;
- _worldPacket.ResetBitPos();
+ targetData.Name = buffer.ReadString(nameLength);
- SendCastFlags = _worldPacket.ReadBits(5);
+ return buffer;
+}
- bool HasMoveUpdate = _worldPacket.ReadBit();
- uint32 SpellWeightCount = _worldPacket.ReadBits(2);
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::MissileTrajectoryRequest& trajectory)
+{
+ buffer >> trajectory.Pitch;
+ buffer >> trajectory.Speed;
+ return buffer;
+}
- if (HasMoveUpdate)
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::SpellCastRequest& request)
+{
+ buffer >> request.CastID;
+ buffer >> request.SpellID;
+ buffer >> request.Misc;
+ buffer >> request.Target;
+ buffer >> request.MissileTrajectory;
+ buffer >> request.Charmer;
+
+ buffer.ResetBitPos();
+ request.SendCastFlags = buffer.ReadBits(5);
+ request.MoveUpdate.HasValue = buffer.ReadBit();
+ request.Weight.resize(buffer.ReadBits(2));
+
+ if (request.MoveUpdate.HasValue)
+ buffer >> request.MoveUpdate.Value;
+
+ for (WorldPackets::Spells::SpellWeight& weight : request.Weight)
{
- _worldPacket >> movementInfo;
+ buffer.ResetBitPos();
+ weight.Type = buffer.ReadBits(2);
+ buffer >> weight.ID;
+ buffer >> weight.Quantity;
}
- for (uint32 i = 0; i < SpellWeightCount; ++i)
- {
- _worldPacket.ResetBitPos();
- SpellWeight unused;
- unused.Type = _worldPacket.ReadBits(2);
- _worldPacket >> unused.ID;
- _worldPacket >> unused.Quantity;
- }
+ return buffer;
+}
+
+void WorldPackets::Spells::CastSpell::Read()
+{
+ _worldPacket >> Cast;
+}
+
+void WorldPackets::Spells::PetCastSpell::Read()
+{
+ _worldPacket >> PetGUID;
+ _worldPacket >> Cast;
}
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;
diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h
index fa7b8e0b04a..fa5af7b2882 100644
--- a/src/server/game/Server/Packets/SpellPackets.h
+++ b/src/server/game/Server/Packets/SpellPackets.h
@@ -155,46 +155,6 @@ namespace WorldPackets
std::vector<AuraInfo> Auras;
};
- class SpellCastRequest final : public ClientPacket
- {
- public:
- struct SpellWeight
- {
- uint32 Type = 0;
- int32 ID = 0;
- uint32 Quantity = 0;
- };
-
- 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 = 0;
- uint32 SpellID = 0;
- uint32 Misc = 0;
- uint32 TargetFlags = 0;
- ObjectGuid UnitGuid;
- ObjectGuid ItemGuid;
-
- ObjectGuid SrcTransportGuid;
- ObjectGuid DstTransportGuid;
- Position SrcPos;
- Position DstPos;
- float Orientation = 0.0f;
-
- std::string Name;
- float Pitch = 0.0f;
- float Speed = 0.0f;
- ObjectGuid Guid;
- uint32 SendCastFlags = 0;
-
- MovementInfo movementInfo;
- };
-
struct TargetLocation
{
ObjectGuid Transport;
@@ -208,10 +168,59 @@ namespace WorldPackets
ObjectGuid Item;
Optional<TargetLocation> SrcLocation;
Optional<TargetLocation> DstLocation;
- Optional<float> Orientation; // Not found in JAM structures
+ Optional<float> Orientation;
std::string Name;
};
+ struct MissileTrajectoryRequest
+ {
+ float Pitch = 0.0f;
+ float Speed = 0.0f;
+ };
+
+ struct SpellWeight
+ {
+ uint32 Type = 0;
+ int32 ID = 0;
+ uint32 Quantity = 0;
+ };
+
+ struct SpellCastRequest
+ {
+ uint8 CastID = 0;
+ uint32 SpellID = 0;
+ uint32 Misc = 0;
+ uint8 SendCastFlags = 0;
+ SpellTargetData Target;
+ MissileTrajectoryRequest MissileTrajectory;
+ Optional<MovementInfo> MoveUpdate;
+ std::vector<SpellWeight> Weight;
+ ObjectGuid Charmer;
+ };
+
+ class CastSpell final : public ClientPacket
+ {
+ public:
+
+ CastSpell(WorldPacket&& packet) : ClientPacket(CMSG_CAST_SPELL, std::move(packet)) { }
+
+ void Read() override;
+
+ SpellCastRequest Cast;
+ };
+
+ class PetCastSpell final : public ClientPacket
+ {
+ public:
+
+ PetCastSpell(WorldPacket&& packet) : ClientPacket(CMSG_PET_CAST_SPELL, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid PetGUID;
+ SpellCastRequest Cast;
+ };
+
struct SpellMissStatus
{
uint8 Reason = 0;
@@ -392,18 +401,5 @@ namespace WorldPackets
}
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/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index cb8cd23482f..988a858e83b 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -255,7 +255,7 @@ void OpcodeTable::Initialize()
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_CAN_DUEL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- DEFINE_HANDLER(CMSG_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Spells::SpellCastRequest, &WorldSession::HandleCastSpellOpcode);
+ DEFINE_HANDLER(CMSG_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Spells::CastSpell, &WorldSession::HandleCastSpellOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHALLENGE_MODE_REQUEST_LEADERS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHALLENGE_MODE_REQUEST_MAP_STATS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANGE_BAG_SLOT_FLAG, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -650,7 +650,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_BATTLE_REQUEST_WILD, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_BATTLE_SCRIPT_ERROR_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_CANCEL_AURA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCancelAuraOpcode );
- DEFINE_HANDLER(CMSG_PET_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::SpellCastRequest, &WorldSession::HandlePetCastSpellOpcode);
+ DEFINE_HANDLER(CMSG_PET_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::PetCastSpell, &WorldSession::HandlePetCastSpellOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_LEARN_TALENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetLearnTalent );
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_NAME_CACHE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_NAME_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetNameQuery );
@@ -809,7 +809,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_SPELLCLICK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSpellClick );
DEFINE_OPCODE_HANDLER_OLD(CMSG_SPIRIT_HEALER_ACTIVATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSpiritHealerActivateOpcode);
DEFINE_HANDLER(CMSG_SPLIT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SplitItem, &WorldSession::HandleSplitItemOpcode);
- DEFINE_OPCODE_HANDLER_OLD(CMSG_STANDSTATECHANGE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleStandStateChangeOpcode );
+ DEFINE_HANDLER(CMSG_STAND_STATE_CHANGE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::StandStateChange, &WorldSession::HandleStandStateChangeOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_START_QUEST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_STOP_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_STORE_LOOT_IN_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -938,11 +938,7 @@ void OpcodeTable::Initialize()
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_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_NOTINRANGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_NOTIFICATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_CLOSED_NOTIFICATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1056,7 +1052,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_UPDATE_INVITE_LIST, 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_CANCEL_COMBAT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_ORPHAN_SPELL_VISUAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_SCENE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_SPELL_VISUAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1803,7 +1799,7 @@ void OpcodeTable::Initialize()
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_STANDSTATE_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_STAND_STATE_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_ELAPSED_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_ELAPSED_TIMERS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_LOOT_ROLL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1885,7 +1881,7 @@ void OpcodeTable::Initialize()
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_WEATHER, STATUS_NEVER, 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);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index 971c69a2151..fa0ffde42cb 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -719,7 +719,7 @@ enum OpcodeClient : uint32
CMSG_SPELLCLICK = 0x0BC2,
CMSG_SPIRIT_HEALER_ACTIVATE = 0x03EC,
CMSG_SPLIT_ITEM = 0x0795,
- CMSG_STANDSTATECHANGE = 0x0ABD,
+ CMSG_STAND_STATE_CHANGE = 0x0ABD,
CMSG_START_QUEST = 0xBADD,
CMSG_STOP_DANCE = 0xBADD,
CMSG_STORE_LOOT_IN_SLOT = 0xBADD,
@@ -846,11 +846,7 @@ enum OpcodeServer : uint32
SMSG_ATTACKERSTATEUPDATE = 0x1204,
SMSG_ATTACKSTART = 0x1D3E,
SMSG_ATTACKSTOP = 0x1382,
- SMSG_ATTACKSWING_BADFACING = 0xBADD,
- SMSG_ATTACKSWING_CANT_ATTACK = 0xBADD,
- SMSG_ATTACKSWING_DEADTARGET = 0xBADD,
SMSG_ATTACKSWING_ERROR = 0x0509,
- SMSG_ATTACKSWING_NOTINRANGE = 0xBADD,
SMSG_AUCTION_BIDDER_NOTIFICATION = 0xBADD,
SMSG_AUCTION_CLOSED_NOTIFICATION = 0x058E,
SMSG_AUCTION_COMMAND_RESULT = 0x0B2D,
@@ -1712,7 +1708,7 @@ enum OpcodeServer : uint32
SMSG_SPELL_START = 0x0803,
SMSG_SPELL_UPDATE_CHAIN_TARGETS = 0x0374,
SMSG_SPIRIT_HEALER_CONFIRM = 0x1331,
- SMSG_STANDSTATE_UPDATE = 0x1311,
+ SMSG_STAND_STATE_UPDATE = 0x1311,
SMSG_START_ELAPSED_TIMER = 0x0D2A,
SMSG_START_ELAPSED_TIMERS = 0x093F,
SMSG_START_LOOT_ROLL = 0x1B84,
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 17ca3e3c58c..166a432077c 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -1279,7 +1279,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co
case CMSG_MESSAGECHAT_YELL: // 0 3.5
case CMSG_INSPECT: // 0 3.5
//case CMSG_AREA_SPIRIT_HEALER_QUERY: // not profiled
- case CMSG_STANDSTATECHANGE: // not profiled
+ case CMSG_STAND_STATE_CHANGE: // not profiled
case CMSG_RANDOM_ROLL: // not profiled
case CMSG_TIME_SYNC_RESPONSE: // not profiled
case CMSG_TRAINER_BUY_SPELL: // not profiled
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 0707ffbb6fc..291ba0a9f66 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -203,6 +203,7 @@ namespace WorldPackets
class RepopRequest;
class RequestCemeteryList;
class ResurrectResponse;
+ class StandStateChange;
class UITimeRequest;
}
@@ -246,7 +247,8 @@ namespace WorldPackets
namespace Spells
{
class CancelAura;
- class SpellCastRequest;
+ class CastSpell;
+ class PetCastSpell;
class SetActionButton;
}
@@ -735,7 +737,7 @@ class WorldSession
void HandleZoneUpdateOpcode(WorldPacket& recvPacket);
void HandleSetSelectionOpcode(WorldPackets::Misc::SetSelection& packet);
- void HandleStandStateChangeOpcode(WorldPacket& recvPacket);
+ void HandleStandStateChangeOpcode(WorldPackets::Misc::StandStateChange& packet);
void HandleEmoteOpcode(WorldPacket& recvPacket);
void HandleContactListOpcode(WorldPacket& recvPacket);
void HandleAddFriendOpcode(WorldPacket& recvPacket);
@@ -946,7 +948,7 @@ class WorldSession
void HandleUseItemOpcode(WorldPacket& recvPacket);
void HandleOpenItemOpcode(WorldPacket& recvPacket);
- void HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest);
+ void HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& castRequest);
void HandleCancelCastOpcode(WorldPacket& recvPacket);
void HandleCancelAuraOpcode(WorldPackets::Spells::CancelAura& cancelAura);
void HandleCancelGrowthAuraOpcode(WorldPacket& recvPacket);
@@ -1029,7 +1031,7 @@ class WorldSession
void HandlePetRename(WorldPacket& recvData);
void HandlePetCancelAuraOpcode(WorldPacket& recvPacket);
void HandlePetSpellAutocastOpcode(WorldPacket& recvPacket);
- void HandlePetCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest);
+ void HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& castRequest);
void HandlePetLearnTalent(WorldPacket& recvPacket);
void HandleSetActionBarToggles(WorldPacket& recvData);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 819942901cb..9cf748ff912 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -41,6 +41,7 @@
#include "WeatherMgr.h"
#include "Pet.h"
#include "ReputationMgr.h"
+#include "MiscPackets.h"
class Aura;
//
@@ -6633,10 +6634,8 @@ void AuraEffect::HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mod
if (apply)
{
- WorldPacket data(SMSG_WEATHER, (4 + 4 + 1));
-
- data << uint32(GetMiscValue()) << 1.0f << uint8(0);
- target->GetSession()->SendPacket(&data);
+ WorldPackets::Misc::Weather weather(WeatherState(GetMiscValue()), 1.0f);
+ target->GetSession()->SendPacket(weather.Write());
}
else
{
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index d729d76a1d5..387a01dbf0a 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -109,34 +109,43 @@ void SpellDestination::RelocateOffset(Position const& offset)
_position.RelocateOffset(offset);
}
-SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0), m_strTarget()
+SpellCastTargets::SpellCastTargets() : m_targetMask(0), m_objectTarget(nullptr), m_itemTarget(nullptr),
+ m_itemTargetEntry(0), m_elevation(0.0f), m_speed(0.0f)
{
- m_objectTarget = NULL;
- m_itemTarget = NULL;
-
- m_itemTargetEntry = 0;
-
- 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)
+SpellCastTargets::SpellCastTargets(Unit* caster, WorldPackets::Spells::SpellTargetData const& spellTargetData) :
+ m_targetMask(spellTargetData.Flags), m_objectTarget(nullptr), m_itemTarget(nullptr),
+ m_objectTargetGUID(spellTargetData.Unit), m_itemTargetGUID(spellTargetData.Item),
+ m_itemTargetEntry(0), m_elevation(0.0f), m_speed(0.0f), m_strTarget(spellTargetData.Name)
{
- m_objectTarget = NULL;
- m_itemTarget = NULL;
- m_itemTargetEntry = 0;
+ if (spellTargetData.SrcLocation.HasValue)
+ {
+ m_src._transportGUID = spellTargetData.SrcLocation.Value.Transport;
+ Position* pos;
+ if (!m_src._transportGUID.IsEmpty())
+ pos = &m_src._transportOffset;
+ else
+ pos = &m_src._position;
- m_src._transportGUID = srcTransportGuid;
- if (m_src._transportGUID != ObjectGuid::Empty)
- m_src._transportOffset.Relocate(srcPos);
- else
- m_src._position.Relocate(srcPos);
+ pos->Relocate(spellTargetData.SrcLocation.Value.Location);
+ if (spellTargetData.Orientation.HasValue)
+ pos->SetOrientation(spellTargetData.Orientation.Value);
+ }
- m_dst._transportGUID = destTransportGuid;
- if (m_dst._transportGUID != ObjectGuid::Empty)
- m_dst._transportOffset.Relocate(destPos);
- else
- m_dst._position.Relocate(destPos);
+ if (spellTargetData.DstLocation.HasValue)
+ {
+ m_dst._transportGUID = spellTargetData.DstLocation.Value.Transport;
+ Position* pos;
+ if (!m_dst._transportGUID.IsEmpty())
+ pos = &m_dst._transportOffset;
+ else
+ pos = &m_dst._position;
+
+ pos->Relocate(spellTargetData.DstLocation.Value.Location);
+ if (spellTargetData.Orientation.HasValue)
+ pos->SetOrientation(spellTargetData.Orientation.Value);
+ }
Update(caster);
}
@@ -230,39 +239,6 @@ void SpellCastTargets::Write(WorldPackets::Spells::SpellTargetData& data)
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();
-
- if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM))
- {
- if (m_itemTarget)
- data << m_itemTarget->GetPackGUID();
- else
- data << uint8(0);
- }
-
- if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
- {
- data << m_src._transportGUID.WriteAsPacked(); // relative position guid here - transport for example
- if (!m_src._transportGUID.IsEmpty())
- data << m_src._transportOffset.PositionXYZStream();
- else
- data << m_src._position.PositionXYZStream();
- }
-
- if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
- {
- data << m_dst._transportGUID.WriteAsPacked(); // relative position guid here - transport for example
- if (!m_dst._transportGUID.IsEmpty())
- data << m_dst._transportOffset.PositionXYZStream();
- else
- data << m_dst._position.PositionXYZStream();
- }
-
- if (m_targetMask & TARGET_FLAG_STRING)
- data << m_strTarget;*/
}
ObjectGuid SpellCastTargets::GetOrigUnitTargetGUID() const
@@ -641,8 +617,8 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo)),
m_spellState = SPELL_STATE_NULL;
_triggeredCastFlags = triggerFlags;
- if (info->HasAttribute(SPELL_ATTR4_TRIGGERED))
- _triggeredCastFlags = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT);
+ if (info->HasAttribute(SPELL_ATTR4_CAN_CAST_WHILE_CASTING))
+ _triggeredCastFlags = TriggerCastFlags(uint32(_triggeredCastFlags) | TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_CAST_DIRECTLY);
m_CastItem = NULL;
m_castItemGUID.Clear();
@@ -665,7 +641,7 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo)),
m_procEx = 0;
focusObject = NULL;
m_cast_count = 0;
- m_glyphIndex = 0;
+ m_misc.Data = 0;
m_preCastSpell = 0;
m_triggeredByAuraSpell = NULL;
m_spellAura = NULL;
@@ -3744,7 +3720,7 @@ void Spell::SendCastResult(SpellCastResult result)
if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time
return;
- SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError);
+ SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError, SMSG_CAST_FAILED, m_misc.Data);
}
void Spell::SendPetCastResult(SpellCastResult result)
@@ -3756,10 +3732,10 @@ void Spell::SendPetCastResult(SpellCastResult result)
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
return;
- SendCastResult(owner->ToPlayer(), m_spellInfo, m_cast_count, result, SPELL_CUSTOM_ERROR_NONE, SMSG_PET_CAST_FAILED);
+ SendCastResult(owner->ToPlayer(), m_spellInfo, m_cast_count, result, SPELL_CUSTOM_ERROR_NONE, SMSG_PET_CAST_FAILED, m_misc.Data);
}
-void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, OpcodeServer opcode /*= SMSG_CAST_FAILED*/)
+void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, OpcodeServer opcode /*= SMSG_CAST_FAILED*/, uint32 misc /*= 0*/)
{
if (result == SPELL_CAST_OK)
return;
@@ -3870,6 +3846,12 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas
packet.FailedArg1 = missingItem; // first missing item
break;
}
+ case SPELL_FAILED_CANT_UNTALENT:
+ {
+ if (TalentEntry const* talent = sTalentStore.LookupEntry(misc))
+ packet.FailedArg1 = talent->SpellID;
+ break;
+ }
// TODO: SPELL_FAILED_NOT_STANDING
default:
break;
@@ -5606,12 +5588,25 @@ SpellCastResult Spell::CheckCast(bool strict)
break;
}
case SPELL_EFFECT_TALENT_SPEC_SELECT:
+ {
// can't change during already started arena/battleground
if (m_caster->GetTypeId() == TYPEID_PLAYER)
if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
if (bg->GetStatus() == STATUS_IN_PROGRESS)
return SPELL_FAILED_NOT_IN_BATTLEGROUND;
break;
+ }
+ case SPELL_EFFECT_REMOVE_TALENT:
+ {
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_TARGETS;
+ TalentEntry const* talent = sTalentStore.LookupEntry(m_misc.TalentId);
+ if (!talent)
+ return SPELL_FAILED_DONT_REPORT;
+ if (m_caster->ToPlayer()->HasSpellCooldown(talent->SpellID))
+ return SPELL_FAILED_CANT_UNTALENT;
+ break;
+ }
default:
break;
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index a8ff53b5cb1..48a62ab0e10 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -107,7 +107,7 @@ 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(Unit* caster, WorldPackets::Spells::SpellTargetData const& spellTargetData);
~SpellCastTargets();
void Read(ByteBuffer& data, Unit* caster);
@@ -364,6 +364,7 @@ class Spell
void EffectGiveCurrency(SpellEffIndex effIndex);
void EffectResurrectWithAura(SpellEffIndex effIndex);
void EffectCreateAreaTrigger(SpellEffIndex effIndex);
+ void EffectRemoveTalent(SpellEffIndex effIndex);
typedef std::set<Aura*> UsedSpellMods;
@@ -444,7 +445,7 @@ class Spell
void CheckSrc() { if (!m_targets.HasSrc()) m_targets.SetSrc(*m_caster); }
void CheckDst() { if (!m_targets.HasDst()) m_targets.SetDst(*m_caster); }
- static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, OpcodeServer opcode = SMSG_CAST_FAILED);
+ static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, OpcodeServer opcode = SMSG_CAST_FAILED, uint32 misc = 0);
void SendCastResult(SpellCastResult result);
void SendPetCastResult(SpellCastResult result);
void SendSpellStart();
@@ -475,7 +476,14 @@ class Spell
ObjectGuid m_castItemGUID;
uint32 m_castItemEntry;
uint8 m_cast_count;
- uint32 m_glyphIndex;
+ union
+ {
+ // Alternate names for this value
+ uint32 TalentId;
+ uint32 GlyphSlot;
+
+ uint32 Data;
+ } m_misc;
uint32 m_preCastSpell;
SpellCastTargets m_targets;
int8 m_comboPointGain;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 3eeb50a2d39..7c5ab810ce4 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -250,7 +250,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectUnused, //178 SPELL_EFFECT_178 unused
&Spell::EffectCreateAreaTrigger, //179 SPELL_EFFECT_CREATE_AREATRIGGER
&Spell::EffectNULL, //180 SPELL_EFFECT_UPDATE_AREATRIGGER
- &Spell::EffectNULL, //181 SPELL_EFFECT_REMOVE_TALENT
+ &Spell::EffectRemoveTalent, //181 SPELL_EFFECT_REMOVE_TALENT
&Spell::EffectNULL, //182 SPELL_EFFECT_182
&Spell::EffectNULL, //183 SPELL_EFFECT_183
&Spell::EffectNULL, //184 SPELL_EFFECT_REPUTATION
@@ -3938,11 +3938,17 @@ void Spell::EffectStuck(SpellEffIndex /*effIndex*/)
{
if (!player->GetDeathTimer())
player->RepopAtGraveyard();
-
+
+ return;
+ }
+
+ // the player dies if hearthstone is in cooldown, else the player is teleported to home
+ if (player->HasSpellCooldown(8690))
+ {
+ player->Kill(player);
return;
}
- // the player is teleported to home
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation(), TELE_TO_SPELL);
// Stuck spell trigger Hearthstone cooldown
@@ -3999,7 +4005,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
return;
- if (m_glyphIndex >= MAX_GLYPH_SLOT_INDEX)
+ if (m_misc.GlyphSlot >= MAX_GLYPH_SLOT_INDEX)
return;
Player* player = m_caster->ToPlayer();
@@ -4008,7 +4014,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)
// glyph sockets level requirement
uint8 minLevel = 0;
- switch (m_glyphIndex)
+ switch (m_misc.GlyphSlot)
{
case 0:
case 1:
@@ -4032,7 +4038,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)
{
if (GlyphPropertiesEntry const* newGlyphProperties = sGlyphPropertiesStore.LookupEntry(newGlyph))
{
- if (GlyphSlotEntry const* newGlyphSlot = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
+ if (GlyphSlotEntry const* newGlyphSlot = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_misc.GlyphSlot)))
{
if (newGlyphProperties->Type != newGlyphSlot->Type)
{
@@ -4042,26 +4048,26 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)
}
// remove old glyph
- if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_glyphIndex))
+ if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_misc.GlyphSlot))
{
if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph))
{
player->RemoveAurasDueToSpell(oldGlyphProperties->SpellID);
- player->SetGlyph(m_glyphIndex, 0);
+ player->SetGlyph(m_misc.GlyphSlot, 0);
}
}
player->CastSpell(m_caster, newGlyphProperties->SpellID, true);
- player->SetGlyph(m_glyphIndex, newGlyph);
+ player->SetGlyph(m_misc.GlyphSlot, newGlyph);
player->SendTalentsInfoData();
}
}
- else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_glyphIndex)) // Removing the glyph, get the old one
+ else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_misc.GlyphSlot)) // Removing the glyph, get the old one
{
if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph))
{
player->RemoveAurasDueToSpell(oldGlyphProperties->SpellID);
- player->SetGlyph(m_glyphIndex, 0);
+ player->SetGlyph(m_misc.GlyphSlot, 0);
player->SendTalentsInfoData();
}
}
@@ -5762,3 +5768,20 @@ void Spell::EffectCreateAreaTrigger(SpellEffIndex /*effIndex*/)
if (!areaTrigger->CreateAreaTrigger(sObjectMgr->GetGenerator<HighGuid::AreaTrigger>()->Generate(), triggerEntry, GetCaster(), GetSpellInfo(), pos))
delete areaTrigger;
}
+
+void Spell::EffectRemoveTalent(SpellEffIndex effIndex)
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ TalentEntry const* talent = sTalentStore.LookupEntry(m_misc.TalentId);
+ if (!talent)
+ return;
+
+ Player* player = unitTarget ? unitTarget->ToPlayer() : nullptr;
+ if (!player)
+ return;
+
+ player->RemoveTalent(talent);
+ player->SendTalentsInfoData();
+}
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 1f6b5238137..a70c73de6df 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -875,9 +875,71 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] =
{EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 177 SPELL_EFFECT_177
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 178 SPELL_EFFECT_178
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_DEST}, // 179 SPELL_EFFECT_CREATE_AREATRIGGER
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 180 SPELL_EFFECT_180
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 181 SPELL_EFFECT_181
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_UNIT}, // 182 SPELL_EFFECT_182
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 180 SPELL_EFFECT_UPDATE_AREATRIGGER
+ {EFFECT_IMPLICIT_TARGET_CASTER, TARGET_OBJECT_TYPE_UNIT}, // 181 SPELL_EFFECT_REMOVE_TALENT
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 182 SPELL_EFFECT_182
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 183 SPELL_EFFECT_183
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 184 SPELL_EFFECT_REPUTATION_2
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 185 SPELL_EFFECT_185
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 186 SPELL_EFFECT_186
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 187 SPELL_EFFECT_RANDOMIZE_ARCHAEOLOGY_DIGSITES
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 188 SPELL_EFFECT_188
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 189 SPELL_EFFECT_LOOT
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 190 SPELL_EFFECT_190
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 191 SPELL_EFFECT_TELEPORT_TO_DIGSITE
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 192 SPELL_EFFECT_192
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 193 SPELL_EFFECT_193
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 194 SPELL_EFFECT_194
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 195 SPELL_EFFECT_195
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 196 SPELL_EFFECT_196
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 197 SPELL_EFFECT_197
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 198 SPELL_EFFECT_198
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 199 SPELL_EFFECT_199
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 200 SPELL_EFFECT_HEAL_BATTLEPET_PCT
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 201 SPELL_EFFECT_ENABLE_BATTLE_PETS
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 202 SPELL_EFFECT_202
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 203 SPELL_EFFECT_203
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 204 SPELL_EFFECT_204
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 205 SPELL_EFFECT_205
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 206 SPELL_EFFECT_206
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 207 SPELL_EFFECT_207
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 208 SPELL_EFFECT_208
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 209 SPELL_EFFECT_209
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 210 SPELL_EFFECT_210
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 211 SPELL_EFFECT_211
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 212 SPELL_EFFECT_212
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 213 SPELL_EFFECT_213
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 214 SPELL_EFFECT_214
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 215 SPELL_EFFECT_215
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 216 SPELL_EFFECT_216
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 217 SPELL_EFFECT_217
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 218 SPELL_EFFECT_218
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 219 SPELL_EFFECT_219
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 220 SPELL_EFFECT_220
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 221 SPELL_EFFECT_221
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 222 SPELL_EFFECT_222
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 223 SPELL_EFFECT_223
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 224 SPELL_EFFECT_224
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 225 SPELL_EFFECT_225
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 226 SPELL_EFFECT_226
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 227 SPELL_EFFECT_227
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 228 SPELL_EFFECT_228
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 229 SPELL_EFFECT_229
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 230 SPELL_EFFECT_230
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 231 SPELL_EFFECT_231
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 232 SPELL_EFFECT_232
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 233 SPELL_EFFECT_233
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 234 SPELL_EFFECT_234
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 235 SPELL_EFFECT_235
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 236 SPELL_EFFECT_236
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 237 SPELL_EFFECT_237
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 238 SPELL_EFFECT_238
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 239 SPELL_EFFECT_239
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 240 SPELL_EFFECT_240
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 241 SPELL_EFFECT_241
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 242 SPELL_EFFECT_242
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 243 SPELL_EFFECT_243
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 244 SPELL_EFFECT_244
};
SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap effects)
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 5b9cfacb56b..b585588726e 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -186,6 +186,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_CONE_LINE = 0x00000004,
SPELL_ATTR0_CU_SHARE_DAMAGE = 0x00000008,
SPELL_ATTR0_CU_NO_INITIAL_THREAT = 0x00000010,
+ SPELL_ATTR0_CU_IS_TALENT = 0x00000020,
SPELL_ATTR0_CU_AURA_CC = 0x00000040,
SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
SPELL_ATTR0_CU_CHARGE = 0x00000200,
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 02d3e2e2ea1..d0eff5fff00 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -1251,73 +1251,8 @@ void SpellMgr::UnloadSpellInfoChains()
mSpellChains.clear();
}
-void SpellMgr::LoadSpellTalentRanks()
-{
- /* TODO: 6.x remove this
- // cleanup core data before reload - remove reference to ChainNode from SpellInfo
- UnloadSpellInfoChains();
-
- for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
- {
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
- if (!talentInfo)
- continue;
-
- SpellInfo const* lastSpell = NULL;
- for (uint8 rank = MAX_TALENT_RANK - 1; rank > 0; --rank)
- {
- if (talentInfo->RankID[rank])
- {
- lastSpell = GetSpellInfo(talentInfo->RankID[rank]);
- break;
- }
- }
-
- if (!lastSpell)
- continue;
-
- SpellInfo const* firstSpell = GetSpellInfo(talentInfo->RankID[0]);
- if (!firstSpell)
- {
- TC_LOG_ERROR("spells", "SpellMgr::LoadSpellTalentRanks: First Rank Spell %u for TalentEntry %u does not exist.", talentInfo->RankID[0], i);
- continue;
- }
-
- SpellInfo const* prevSpell = NULL;
- for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
- {
- uint32 spellId = talentInfo->RankID[rank];
- if (!spellId)
- break;
-
- SpellInfo const* currentSpell = GetSpellInfo(spellId);
- if (!currentSpell)
- {
- TC_LOG_ERROR("spells", "SpellMgr::LoadSpellTalentRanks: Spell %u (Rank: %u) for TalentEntry %u does not exist.", spellId, rank + 1, i);
- break;
- }
-
- SpellChainNode node;
- node.first = firstSpell;
- node.last = lastSpell;
- node.rank = rank + 1;
-
- node.prev = prevSpell;
- node.next = node.rank < MAX_TALENT_RANK ? GetSpellInfo(talentInfo->RankID[node.rank]) : NULL;
-
- mSpellChains[spellId] = node;
- mSpellInfoMap[spellId]->ChainEntry = &mSpellChains[spellId];
-
- prevSpell = currentSpell;
- }
- }*/
-}
-
void SpellMgr::LoadSpellRanks()
{
- // cleanup data and load spell ranks for talents from dbc
- LoadSpellTalentRanks();
-
uint32 oldMSTime = getMSTime();
// 0 1 2
@@ -1553,7 +1488,8 @@ void SpellMgr::LoadSpellLearnSpells()
node.active = fields[2].GetBool();
node.autoLearned = false;
- if (!GetSpellInfo(spell_id))
+ SpellInfo const* spellInfo = GetSpellInfo(spell_id);
+ if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` does not exist", spell_id);
continue;
@@ -1565,7 +1501,7 @@ void SpellMgr::LoadSpellLearnSpells()
continue;
}
- if (GetTalentBySpellID(node.spell))
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT))
{
TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped", spell_id, node.spell);
continue;
@@ -1603,7 +1539,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 = effect->TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentBySpellID(spell) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
+ dbc_node.autoLearned = effect->TargetA.GetTarget() == TARGET_UNIT_PET || entry->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spell);
@@ -1654,7 +1590,7 @@ void SpellMgr::LoadSpellLearnSpells()
{
if (itr->second.spell == mastery)
{
- TC_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically as mastery learned spell from TalentTab.dbc", masteryMainSpell, mastery);
+ TC_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically as mastery learned spell from ChrSpecialization.dbc", masteryMainSpell, mastery);
found = true;
break;
}
@@ -1711,7 +1647,7 @@ void SpellMgr::LoadSpellTargetPositions()
{
Field* fields = result->Fetch();
- uint32 Spell_ID = fields[0].GetUInt32();
+ uint32 spellId = fields[0].GetUInt32();
SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8());
SpellTargetPosition st;
@@ -1724,27 +1660,27 @@ void SpellMgr::LoadSpellTargetPositions()
MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId);
if (!mapEntry)
{
- TC_LOG_ERROR("sql.sql", "Spell (ID: %u, EffectIndex: %u) is using a non-existant MapID (ID: %u).", Spell_ID, effIndex, st.target_mapId);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u, EffectIndex: %u) is using a non-existant MapID (ID: %u).", spellId, effIndex, st.target_mapId);
continue;
}
if (st.target_X == 0 && st.target_Y == 0 && st.target_Z == 0)
{
- TC_LOG_ERROR("sql.sql", "Spell (ID: %u, EffectIndex: %u): target coordinates not provided.", Spell_ID, effIndex);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u, EffectIndex: %u): target coordinates not provided.", spellId, effIndex);
continue;
}
- SpellInfo const* spellInfo = GetSpellInfo(Spell_ID);
+ SpellInfo const* spellInfo = GetSpellInfo(spellId);
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.", spellId);
continue;
}
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);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u, EffectIndex: %u) listed in `spell_target_position` does not have an effect at index %u.", spellId, effIndex, effIndex);
continue;
}
@@ -1756,19 +1692,13 @@ void SpellMgr::LoadSpellTargetPositions()
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);
+ std::pair<uint32, SpellEffIndex> key = std::make_pair(spellId, effIndex);
mSpellTargetPositions[key] = st;
++count;
}
else
{
- TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have target TARGET_DEST_DB (17).", Spell_ID, effIndex);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u, EffectIndex: %u) listed in `spell_target_position` does not have target TARGET_DEST_DB (17).", spellId, effIndex);
continue;
}
@@ -1776,38 +1706,26 @@ void SpellMgr::LoadSpellTargetPositions()
/*
// Check all spells
- for (uint32 i = 1; i < GetSpellInfoStoreSize; ++i)
+ for (uint32 i = 1; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo const* spellInfo = GetSpellInfo(i);
if (!spellInfo)
continue;
- bool found = false;
- for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
+ for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
{
- switch (spellInfo->Effects[j].TargetA)
- {
- case TARGET_DEST_DB:
- found = true;
- break;
- }
- if (found)
- break;
- switch (spellInfo->Effects[j].TargetB)
- {
- case TARGET_DEST_DB:
- found = true;
- break;
- }
- if (found)
- break;
- }
- if (found)
- {
- if (!sSpellMgr->GetSpellTargetPosition(i))
- TC_LOG_DEBUG("spells", "Spell (ID: %u) does not have record in `spell_target_position`", i);
+ SpellEffectInfo const* effect = spellInfo->GetEffect(j);
+ if (!effect)
+ continue;
+
+ if (effect->TargetA.GetTarget() != TARGET_DEST_DB && effect->TargetB.GetTarget() != TARGET_DEST_DB)
+ continue;
+
+ if (!GetSpellTargetPosition(i, SpellEffIndex(j)))
+ TC_LOG_DEBUG("spells", "Spell (Id: %u, EffectIndex: %u) does not have record in `spell_target_position`.", i, j);
}
- }*/
+ }
+ */
TC_LOG_INFO("server.loading", ">> Loaded %u spell teleport coordinates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
@@ -2891,6 +2809,11 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
TC_LOG_INFO("server.loading", ">> Loaded %u spell custom attributes from DB in %u ms", count, GetMSTimeDiffToNow(oldMSTime2));
}
+ std::set<uint32> talentSpells;
+ for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
+ if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(i))
+ talentSpells.insert(talentInfo->SpellID);
+
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
spellInfo = mSpellInfoMap[i];
@@ -3004,6 +2927,9 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
if (spellInfo->SpellVisual[0] == 3879)
spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK;
+ if (talentSpells.count(spellInfo->Id))
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_IS_TALENT;
+
switch (spellInfo->SpellFamilyName)
{
case SPELLFAMILY_WARRIOR:
@@ -3761,7 +3687,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 45440: // Steam Tonk Controller
case 60256: // Collect Sample
// Crashes client on pressing ESC
- spellInfo->AttributesEx4 &= ~SPELL_ATTR4_TRIGGERED;
+ spellInfo->AttributesEx4 &= ~SPELL_ATTR4_CAN_CAST_WHILE_CASTING;
break;
case 96942: // Gaze of Occu'thar
case 101009: // Gaze of Occu'thar
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 74423f6e4f3..36ffe105c54 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -695,7 +695,6 @@ class SpellMgr
// Loading data at server startup
void UnloadSpellInfoChains();
- void LoadSpellTalentRanks();
void LoadSpellRanks();
void LoadSpellRequired();
void LoadSpellLearnSkills();
diff --git a/src/server/game/Tools/CharacterDatabaseCleaner.cpp b/src/server/game/Tools/CharacterDatabaseCleaner.cpp
index bd1d1897d5b..e065439b5ab 100644
--- a/src/server/game/Tools/CharacterDatabaseCleaner.cpp
+++ b/src/server/game/Tools/CharacterDatabaseCleaner.cpp
@@ -22,6 +22,7 @@
#include "World.h"
#include "Database/DatabaseEnv.h"
#include "SpellMgr.h"
+#include "SpellInfo.h"
#include "DBCStores.h"
void CharacterDatabaseCleaner::CleanDatabase()
@@ -128,7 +129,8 @@ void CharacterDatabaseCleaner::CleanCharacterSkills()
bool CharacterDatabaseCleaner::SpellCheck(uint32 spell_id)
{
- return sSpellMgr->GetSpellInfo(spell_id) && GetTalentBySpellID(spell_id) != nullptr;
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
+ return spellInfo && !spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT);
}
void CharacterDatabaseCleaner::CleanCharacterSpell()
diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp
index 9ad77761123..ecceb0b102f 100644
--- a/src/server/game/Weather/Weather.cpp
+++ b/src/server/game/Weather/Weather.cpp
@@ -30,6 +30,7 @@
#include "ScriptMgr.h"
#include "Opcodes.h"
#include "WorldSession.h"
+#include "MiscPackets.h"
/// Create the Weather object
Weather::Weather(uint32 zone, WeatherData const* weatherChances)
@@ -194,9 +195,8 @@ bool Weather::ReGenerate()
void Weather::SendWeatherUpdateToPlayer(Player* player)
{
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << uint32(GetWeatherState()) << (float)m_grade << uint8(0);
- player->GetSession()->SendPacket(&data);
+ WorldPackets::Misc::Weather weather(GetWeatherState(), m_grade);
+ player->GetSession()->SendPacket(weather.Write());
}
/// Send the new weather to all players in the zone
@@ -210,13 +210,10 @@ bool Weather::UpdateWeather()
WeatherState state = GetWeatherState();
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << uint32(state);
- data << (float)m_grade;
- data << uint8(0);
+ WorldPackets::Misc::Weather weather(state, m_grade);
//- Returns false if there were no players found to update
- if (!sWorld->SendZoneMessage(m_zone, &data))
+ if (!sWorld->SendZoneMessage(m_zone, weather.Write()))
return false;
///- Log the event
diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h
index 04d38b19c73..93a5ecd448f 100644
--- a/src/server/game/Weather/Weather.h
+++ b/src/server/game/Weather/Weather.h
@@ -43,7 +43,7 @@ struct WeatherData
uint32 ScriptId;
};
-enum WeatherState
+enum WeatherState : uint32
{
WEATHER_STATE_FINE = 0,
WEATHER_STATE_FOG = 1, // Used in some instance encounters.
diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp
index 8f599b8514b..883e622bf50 100644
--- a/src/server/game/Weather/WeatherMgr.cpp
+++ b/src/server/game/Weather/WeatherMgr.cpp
@@ -28,6 +28,7 @@
#include "WorldPacket.h"
#include "Opcodes.h"
#include "WorldSession.h"
+#include "MiscPackets.h"
namespace WeatherMgr
{
@@ -144,9 +145,8 @@ void LoadWeatherData()
void SendFineWeatherUpdateToPlayer(Player* player)
{
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << (uint32)WEATHER_STATE_FINE << (float)0.0f << uint8(0);
- player->GetSession()->SendPacket(&data);
+ WorldPackets::Misc::Weather weather(WEATHER_STATE_FINE);
+ player->GetSession()->SendPacket(weather.Write());
}
void Update(uint32 diff)
diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp
index e607bd3f082..7a34ba55110 100644
--- a/src/server/scripts/Commands/cs_learn.cpp
+++ b/src/server/scripts/Commands/cs_learn.cpp
@@ -204,7 +204,7 @@ public:
// learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
player->LearnSpellHighestRank(talentInfo->SpellID);
- player->AddTalent(talentInfo->SpellID, player->GetActiveTalentGroup(), true);
+ player->AddTalent(talentInfo, player->GetActiveTalentGroup(), true);
}
handler->SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp
index c06dba9dc4e..0ee987aadf6 100644
--- a/src/server/scripts/Commands/cs_list.cpp
+++ b/src/server/scripts/Commands/cs_list.cpp
@@ -435,11 +435,11 @@ public:
handler->PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, auras.size());
for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
- bool talent = (GetTalentBySpellID(itr->second->GetBase()->GetId()) != nullptr);
AuraApplication const* aurApp = itr->second;
Aura const* aura = aurApp->GetBase();
char const* name = aura->GetSpellInfo()->SpellName;
+ bool talent = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_IS_TALENT);
std::ostringstream ss_name;
ss_name << "|cffffffff|Hspell:" << aura->GetId() << "|h[" << name << "]|h|r";
diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp
index 626a0cbb086..41bd04c5dca 100644
--- a/src/server/scripts/Commands/cs_lookup.cpp
+++ b/src/server/scripts/Commands/cs_lookup.cpp
@@ -814,7 +814,7 @@ public:
SpellInfo const* learnSpellInfo = effect ? sSpellMgr->GetSpellInfo(effect->TriggerSpell) : NULL;
- bool talent = (GetTalentBySpellID(id) != nullptr);
+ bool talent = spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT);
bool passive = spellInfo->IsPassive();
bool active = target && target->HasAura(id);
@@ -886,7 +886,7 @@ public:
SpellInfo const* learnSpellInfo = effect ? sSpellMgr->GetSpellInfo(effect->TriggerSpell) : NULL;
- bool talent = (GetTalentBySpellID(id) != nullptr);
+ bool talent = spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT);
bool passive = spellInfo->IsPassive();
bool active = target && target->HasAura(id);
diff --git a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
index 2f10aa858f9..7550faeaec1 100644
--- a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
@@ -177,7 +177,7 @@ public:
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
- if (player->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && player->getStandState() == UNIT_STAND_STATE_SIT)
+ if (player->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && player->GetStandState() == UNIT_STAND_STATE_SIT)
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
index 463d1ee7e0b..3e9852ae909 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
@@ -22,6 +22,7 @@
#include "SpellInfo.h"
#include "WorldPacket.h"
#include "Opcodes.h"
+#include "Packets/MiscPackets.h"
enum Texts
{
@@ -146,9 +147,8 @@ class boss_ossirian : public CreatureScript
if (!map->IsDungeon())
return;
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << uint32(WEATHER_STATE_HEAVY_SANDSTORM) << float(1) << uint8(0);
- map->SendToPlayers(&data);
+ WorldPackets::Misc::Weather weather(WEATHER_STATE_HEAVY_SANDSTORM, 1.0f);
+ map->SendToPlayers(weather.Write());
for (uint8 i = 0; i < NUM_TORNADOS; ++i)
{
diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
index 4268cafa1ea..232261df951 100644
--- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp
+++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
@@ -547,7 +547,7 @@ public:
{
if (!HasEscortState(STATE_ESCORT_ESCORTING))
{
- if (me->getStandState() == UNIT_STAND_STATE_DEAD)
+ if (me->GetStandState() == UNIT_STAND_STATE_DEAD)
me->SetStandState(UNIT_STAND_STATE_STAND);
IsPostEvent = false;
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
index d15b8a53a9a..6a76d4c688e 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
@@ -21,6 +21,7 @@
#include "SpellScript.h"
#include "Transport.h"
#include "Player.h"
+#include "MoveSplineInit.h"
#include "halls_of_reflection.h"
enum Text
@@ -342,6 +343,20 @@ class npc_jaina_or_sylvanas_intro_hor : public CreatureScript
public:
npc_jaina_or_sylvanas_intro_hor() : CreatureScript("npc_jaina_or_sylvanas_intro_hor") { }
+ bool OnGossipHello(Player* player, Creature* creature) override
+ {
+ // override default gossip
+ if (InstanceScript* instance = creature->GetInstanceScript())
+ if (instance->GetData(DATA_QUEL_DELAR_EVENT) == IN_PROGRESS || instance->GetData(DATA_QUEL_DELAR_EVENT) == SPECIAL)
+ {
+ player->PlayerTalkClass->ClearMenus();
+ return true;
+ }
+
+ // load default gossip
+ return false;
+ }
+
struct npc_jaina_or_sylvanas_intro_horAI : public ScriptedAI
{
npc_jaina_or_sylvanas_intro_horAI(Creature* creature) : ScriptedAI(creature)
@@ -1998,6 +2013,13 @@ class at_hor_intro_start : public AreaTriggerScript
if (_instance->GetData(DATA_INTRO_EVENT) == NOT_STARTED)
_instance->SetData(DATA_INTRO_EVENT, IN_PROGRESS);
+ if (player->HasAura(SPELL_QUEL_DELAR_COMPULSION) && (player->GetQuestStatus(QUEST_HALLS_OF_REFLECTION_ALLIANCE) == QUEST_STATUS_INCOMPLETE ||
+ player->GetQuestStatus(QUEST_HALLS_OF_REFLECTION_HORDE) == QUEST_STATUS_INCOMPLETE) && _instance->GetData(DATA_QUEL_DELAR_EVENT) == NOT_STARTED)
+ {
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, IN_PROGRESS);
+ _instance->SetGuidData(DATA_QUEL_DELAR_INVOKER, player->GetGUID());
+ }
+
return true;
}
};
@@ -2330,6 +2352,395 @@ class npc_lumbering_abomination : public CreatureScript
}
};
+enum QuelDelarUther
+{
+ ACTION_UTHER_START_SCREAM = 1,
+ ACTION_UTHER_OUTRO = 2,
+
+ EVENT_UTHER_1 = 1,
+ EVENT_UTHER_2 = 2,
+ EVENT_UTHER_3 = 3,
+ EVENT_UTHER_4 = 4,
+ EVENT_UTHER_5 = 5,
+ EVENT_UTHER_6 = 6,
+ EVENT_UTHER_7 = 7,
+ EVENT_UTHER_8 = 8,
+ EVENT_UTHER_9 = 9,
+ EVENT_UTHER_10 = 10,
+ EVENT_UTHER_11 = 11,
+ EVENT_UTHER_FACING = 12,
+ EVENT_UTHER_KNEEL = 13,
+
+ SAY_UTHER_QUEL_DELAR_1 = 16,
+ SAY_UTHER_QUEL_DELAR_2 = 17,
+ SAY_UTHER_QUEL_DELAR_3 = 18,
+ SAY_UTHER_QUEL_DELAR_4 = 19,
+ SAY_UTHER_QUEL_DELAR_5 = 20,
+ SAY_UTHER_QUEL_DELAR_6 = 21,
+
+ SPELL_ESSENCE_OF_CAPTURED_1 = 73036
+};
+
+enum QuelDelarSword
+{
+ SPELL_WHIRLWIND_VISUAL = 70300,
+ SPELL_HEROIC_STRIKE = 29426,
+ SPELL_WHIRLWIND = 67716,
+ SPELL_BLADESTORM = 67541,
+
+ NPC_QUEL_DELAR = 37158,
+ POINT_TAKE_OFF = 1,
+
+ EVENT_QUEL_DELAR_INIT = 1,
+ EVENT_QUEL_DELAR_FLIGHT_INIT = 2,
+ EVENT_QUEL_DELAR_FLIGHT = 3,
+ EVENT_QUEL_DELAR_LAND = 4,
+ EVENT_QUEL_DELAR_FIGHT = 5,
+ EVENT_QUEL_DELAR_BLADESTORM = 6,
+ EVENT_QUEL_DELAR_HEROIC_STRIKE = 7,
+ EVENT_QUEL_DELAR_WHIRLWIND = 8,
+
+ SAY_QUEL_DELAR_SWORD = 0
+};
+
+enum QuelDelarMisc
+{
+ SAY_FROSTMOURNE_BUNNY = 0,
+ SPELL_QUEL_DELAR_WILL = 70698
+};
+
+Position const QuelDelarCenterPos = { 5309.259f, 2006.390f, 718.046f, 0.0f };
+Position const QuelDelarSummonPos = { 5298.473f, 1994.852f, 709.424f, 3.979351f };
+Position const QuelDelarMovement[] =
+{
+ { 5292.870f, 1998.950f, 718.046f, 0.0f },
+ { 5295.819f, 1991.912f, 707.707f, 0.0f },
+ { 5295.301f, 1989.782f, 708.696f, 0.0f }
+};
+
+Position const UtherQuelDelarMovement[] =
+{
+ { 5336.830f, 1981.700f, 709.319f, 0.0f },
+ { 5314.350f, 1993.440f, 707.726f, 0.0f }
+};
+
+class npc_uther_quel_delar : public CreatureScript
+{
+ public:
+ npc_uther_quel_delar() : CreatureScript("npc_uther_quel_delar") { }
+
+ struct npc_uther_quel_delarAI : public ScriptedAI
+ {
+ npc_uther_quel_delarAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = me->GetInstanceScript();
+ }
+
+ void Reset() override
+ {
+ // Prevent to break Uther in intro event during instance encounter
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) != IN_PROGRESS && _instance->GetData(DATA_QUEL_DELAR_EVENT) != SPECIAL)
+ return;
+
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_UTHER_1, 1);
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
+ {
+ if (damage >= me->GetHealth())
+ damage = me->GetHealth() - 1;
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_UTHER_START_SCREAM:
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, SPECIAL);
+ _events.ScheduleEvent(EVENT_UTHER_2, 0);
+ break;
+ case ACTION_UTHER_OUTRO:
+ _events.ScheduleEvent(EVENT_UTHER_6, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void MovementInform(uint32 /*type*/, uint32 pointId) override
+ {
+ switch (pointId)
+ {
+ case 1:
+ _events.ScheduleEvent(EVENT_UTHER_FACING, 1000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ // Prevent to break Uther in intro event during instance encounter
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) != IN_PROGRESS && _instance->GetData(DATA_QUEL_DELAR_EVENT) != SPECIAL)
+ return;
+
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_UTHER_1:
+ Talk(SAY_UTHER_QUEL_DELAR_1);
+ break;
+ case EVENT_UTHER_2:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ if (Unit* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_QUEL_DELAR_INVOKER)))
+ bunny->CastSpell(target, SPELL_QUEL_DELAR_WILL, true);
+ _events.ScheduleEvent(EVENT_UTHER_3, 2000);
+ break;
+ case EVENT_UTHER_3:
+ me->SummonCreature(NPC_QUEL_DELAR, QuelDelarSummonPos);
+ _events.ScheduleEvent(EVENT_UTHER_4, 2000);
+ break;
+ case EVENT_UTHER_4:
+ Talk(SAY_UTHER_QUEL_DELAR_2);
+ _events.ScheduleEvent(EVENT_UTHER_5, 8000);
+ break;
+ case EVENT_UTHER_5:
+ me->GetMotionMaster()->MovePoint(1, UtherQuelDelarMovement[0]);
+ break;
+ case EVENT_UTHER_6:
+ me->SetWalk(true);
+ me->GetMotionMaster()->MovePoint(0, UtherQuelDelarMovement[1]);
+ _events.ScheduleEvent(EVENT_UTHER_7, 5000);
+ break;
+ case EVENT_UTHER_7:
+ Talk(SAY_UTHER_QUEL_DELAR_3);
+ _events.ScheduleEvent(EVENT_UTHER_8, 12000);
+ break;
+ case EVENT_UTHER_8:
+ Talk(SAY_UTHER_QUEL_DELAR_4);
+ _events.ScheduleEvent(EVENT_UTHER_9, 7000);
+ break;
+ case EVENT_UTHER_9:
+ Talk(SAY_UTHER_QUEL_DELAR_5);
+ _events.ScheduleEvent(EVENT_UTHER_10, 10000);
+ break;
+ case EVENT_UTHER_10:
+ Talk(SAY_UTHER_QUEL_DELAR_6);
+ _events.ScheduleEvent(EVENT_UTHER_11, 5000);
+ break;
+ case EVENT_UTHER_11:
+ DoCast(me, SPELL_ESSENCE_OF_CAPTURED_1, true);
+ me->DespawnOrUnsummon(3000);
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, DONE);
+ break;
+ case EVENT_UTHER_FACING:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ me->SetFacingToObject(bunny);
+ _events.ScheduleEvent(EVENT_UTHER_KNEEL, 1000);
+ break;
+ case EVENT_UTHER_KNEEL:
+ me->HandleEmoteCommand(EMOTE_STATE_KNEEL);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap _events;
+ InstanceScript* _instance;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetHallsOfReflectionAI<npc_uther_quel_delarAI>(creature);
+ }
+};
+
+class npc_quel_delar_sword : public CreatureScript
+{
+ public:
+ npc_quel_delar_sword() : CreatureScript("npc_quel_delar_sword") { }
+
+ struct npc_quel_delar_swordAI : public ScriptedAI
+ {
+ npc_quel_delar_swordAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = me->GetInstanceScript();
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+ _intro = true;
+ }
+
+ void Reset() override
+ {
+ _events.Reset();
+ me->SetSpeed(MOVE_FLIGHT, 4.5f, true);
+ DoCast(SPELL_WHIRLWIND_VISUAL);
+ if (_intro)
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_INIT, 0);
+ else
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ }
+
+ void EnterCombat(Unit* /*victim*/) override
+ {
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_HEROIC_STRIKE, 4000);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_BLADESTORM, 6000);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_WHIRLWIND, 6000);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_UTHER_QUEL_DELAR)))
+ uther->AI()->DoAction(ACTION_UTHER_OUTRO);
+ }
+
+ void MovementInform(uint32 type, uint32 pointId) override
+ {
+ if (type != EFFECT_MOTION_TYPE)
+ return;
+
+ switch (pointId)
+ {
+ case POINT_TAKE_OFF:
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FLIGHT, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (!UpdateVictim())
+ {
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_QUEL_DELAR_INIT:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ bunny->AI()->Talk(SAY_FROSTMOURNE_BUNNY);
+ _intro = false;
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FLIGHT_INIT, 2500);
+ break;
+ case EVENT_QUEL_DELAR_FLIGHT_INIT:
+ me->GetMotionMaster()->MoveTakeoff(POINT_TAKE_OFF, QuelDelarMovement[0]);
+ break;
+ case EVENT_QUEL_DELAR_FLIGHT:
+ {
+ Movement::MoveSplineInit init(me);
+ FillCirclePath(QuelDelarCenterPos, 18.0f, 718.046f, init.Path(), true);
+ init.SetFly();
+ init.SetCyclic();
+ init.SetAnimation(Movement::ToFly);
+ init.Launch();
+
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_LAND, 15000);
+ break;
+ }
+ case EVENT_QUEL_DELAR_LAND:
+ me->StopMoving();
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveLand(0, QuelDelarMovement[1]);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FIGHT, 6000);
+ break;
+ case EVENT_QUEL_DELAR_FIGHT:
+ Talk(SAY_QUEL_DELAR_SWORD);
+ me->GetMotionMaster()->MovePoint(0, QuelDelarMovement[2]);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_QUEL_DELAR_BLADESTORM:
+ DoCast(me, SPELL_BLADESTORM);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_BLADESTORM, 10000);
+ break;
+ case EVENT_QUEL_DELAR_HEROIC_STRIKE:
+ DoCastVictim(SPELL_HEROIC_STRIKE);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_HEROIC_STRIKE, 6000);
+ break;
+ case EVENT_QUEL_DELAR_WHIRLWIND:
+ DoCastAOE(SPELL_WHIRLWIND);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_WHIRLWIND, 1000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ }
+
+ private:
+ void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
+ {
+ float step = clockwise ? -M_PI / 8.0f : M_PI / 8.0f;
+ float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
+
+ for (uint8 i = 0; i < 16; angle += step, ++i)
+ {
+ G3D::Vector3 point;
+ point.x = centerPos.GetPositionX() + radius * cosf(angle);
+ point.y = centerPos.GetPositionY() + radius * sinf(angle);
+ point.z = z;
+ path.push_back(point);
+ }
+ }
+
+ EventMap _events;
+ InstanceScript* _instance;
+ bool _intro;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetHallsOfReflectionAI<npc_quel_delar_swordAI>(creature);
+ }
+};
+
+// 5660
+class at_hor_uther_quel_delar_start : public AreaTriggerScript
+{
+ public:
+ at_hor_uther_quel_delar_start() : AreaTriggerScript("at_hor_uther_quel_delar_start") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
+ {
+ if (player->IsGameMaster())
+ return true;
+
+ InstanceScript* _instance = player->GetInstanceScript();
+
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) == IN_PROGRESS)
+ if (Creature* uther = ObjectAccessor::GetCreature(*player, _instance->GetGuidData(DATA_UTHER_QUEL_DELAR)))
+ uther->AI()->DoAction(ACTION_UTHER_START_SCREAM);
+
+ return true;
+ }
+};
+
// 72900 - Start Halls of Reflection Quest AE
class spell_hor_start_halls_of_reflection_quest_ae : public SpellScriptLoader
{
@@ -2447,6 +2858,7 @@ void AddSC_halls_of_reflection()
new at_hor_waves_restarter();
new at_hor_impenetrable_door();
new at_hor_shadow_throne();
+ new at_hor_uther_quel_delar_start();
new npc_jaina_or_sylvanas_intro_hor();
new npc_jaina_or_sylvanas_escape_hor();
new npc_the_lich_king_escape_hor();
@@ -2461,6 +2873,8 @@ void AddSC_halls_of_reflection()
new npc_raging_ghoul();
new npc_risen_witch_doctor();
new npc_lumbering_abomination();
+ new npc_uther_quel_delar();
+ new npc_quel_delar_sword();
new spell_hor_start_halls_of_reflection_quest_ae();
new spell_hor_evasion();
new spell_hor_gunship_cannon_fire();
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
index 9594617fa9a..d2f9ab5d262 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
@@ -46,7 +46,13 @@ enum DataTypes
DATA_ESCAPE_LEADER = 10,
DATA_ICEWALL = 11,
DATA_ICEWALL_TARGET = 12,
- DATA_GUNSHIP = 13
+ DATA_GUNSHIP = 13,
+
+ // Quest stuff
+ DATA_QUEL_DELAR_EVENT = 14,
+ DATA_FROSTMOURNE_ALTAR_BUNNY = 15,
+ DATA_UTHER_QUEL_DELAR = 16,
+ DATA_QUEL_DELAR_INVOKER = 17
};
enum CreatureIds
@@ -131,7 +137,8 @@ enum InstanceEvents
EVENT_NEXT_WAVE = 2,
EVENT_DO_WIPE = 3,
EVENT_ADD_WAVE = 4,
- EVENT_SPAWN_ESCAPE_EVENT = 5
+ EVENT_SPAWN_ESCAPE_EVENT = 5,
+ EVENT_QUEL_DELAR_SUMMON_UTHER = 6
};
enum InstanceEventIds
@@ -160,7 +167,17 @@ enum InstanceSpells
// Gunship
SPELL_GUNSHIP_CANNON_FIRE = 70017,
SPELL_GUNSHIP_CANNON_FIRE_MISSILE_ALLIANCE = 70021,
- SPELL_GUNSHIP_CANNON_FIRE_MISSILE_HORDE = 70246
+ SPELL_GUNSHIP_CANNON_FIRE_MISSILE_HORDE = 70246,
+
+ // Halls of Reflection quest
+ SPELL_QUEL_DELAR_COMPULSION = 70013,
+ SPELL_ESSENCE_OF_CAPTURED = 70720
+};
+
+enum InstanceQuests
+{
+ QUEST_HALLS_OF_REFLECTION_ALLIANCE = 24480,
+ QUEST_HALLS_OF_REFLECTION_HORDE = 24561
};
enum InstanceWorldStates
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
index ae2023fd255..820821e4151 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
@@ -73,6 +73,8 @@ Position const SpawnPos[] =
{ 5299.250f, 2035.998f, 707.7781f, 5.026548f }
};
+Position const UtherQuelDalarPos = { 5302.001f, 1988.698f, 707.7781f, 3.700098f };
+
class instance_halls_of_reflection : public InstanceMapScript
{
public:
@@ -89,6 +91,7 @@ class instance_halls_of_reflection : public InstanceMapScript
_waveCount = 0;
_introState = NOT_STARTED;
_frostswornGeneralState = NOT_STARTED;
+ _quelDelarState = NOT_STARTED;
events.Reset();
}
@@ -159,6 +162,9 @@ class instance_halls_of_reflection : public InstanceMapScript
case NPC_ICE_WALL_TARGET:
IcewallTargetGUID = creature->GetGUID();
break;
+ case NPC_UTHER:
+ UtherGUID = creature->GetGUID();
+ break;
default:
break;
}
@@ -439,6 +445,18 @@ class instance_halls_of_reflection : public InstanceMapScript
HandleGameObject(ShadowThroneDoorGUID, true);
_frostswornGeneralState = data;
break;
+ case DATA_QUEL_DELAR_EVENT:
+ if (data == IN_PROGRESS)
+ {
+ if (_quelDelarState == NOT_STARTED)
+ {
+ if (Creature* bunny = instance->GetCreature(FrostmourneAltarBunnyGUID))
+ bunny->CastSpell((Unit*)NULL, SPELL_ESSENCE_OF_CAPTURED);
+ events.ScheduleEvent(EVENT_QUEL_DELAR_SUMMON_UTHER, 2000);
+ }
+ }
+ _quelDelarState = data;
+ break;
default:
break;
}
@@ -446,6 +464,18 @@ class instance_halls_of_reflection : public InstanceMapScript
SaveToDB();
}
+ void SetGuidData(uint32 type, ObjectGuid data) override
+ {
+ switch (type)
+ {
+ case DATA_QUEL_DELAR_INVOKER:
+ QuelDelarInvokerGUID = data;
+ break;
+ default:
+ break;
+ }
+ }
+
// wave scheduling, checked when wave npcs die
void OnUnitDeath(Unit* unit) override
{
@@ -491,6 +521,9 @@ class instance_halls_of_reflection : public InstanceMapScript
case EVENT_SPAWN_ESCAPE_EVENT:
SpawnEscapeEvent();
break;
+ case EVENT_QUEL_DELAR_SUMMON_UTHER:
+ instance->SummonCreature(NPC_UTHER, UtherQuelDalarPos);
+ break;
}
}
@@ -649,6 +682,8 @@ class instance_halls_of_reflection : public InstanceMapScript
return _introState;
case DATA_FROSTSWORN_GENERAL:
return _frostswornGeneralState;
+ case DATA_QUEL_DELAR_EVENT:
+ return _quelDelarState;
default:
break;
}
@@ -682,6 +717,12 @@ class instance_halls_of_reflection : public InstanceMapScript
return IcewallGUID;
case DATA_ICEWALL_TARGET:
return IcewallTargetGUID;
+ case DATA_FROSTMOURNE_ALTAR_BUNNY:
+ return FrostmourneAltarBunnyGUID;
+ case DATA_UTHER_QUEL_DELAR:
+ return UtherGUID;
+ case DATA_QUEL_DELAR_INVOKER:
+ return QuelDelarInvokerGUID;
default:
break;
}
@@ -691,7 +732,7 @@ class instance_halls_of_reflection : public InstanceMapScript
void WriteSaveDataMore(std::ostringstream& data) override
{
- data << _introState << ' ' << _frostswornGeneralState;
+ data << _introState << ' ' << _frostswornGeneralState << ' ' << _quelDelarState;
}
void ReadSaveDataMore(std::istringstream& data) override
@@ -708,6 +749,12 @@ class instance_halls_of_reflection : public InstanceMapScript
SetData(DATA_FROSTSWORN_GENERAL, DONE);
else
SetData(DATA_FROSTSWORN_GENERAL, NOT_STARTED);
+
+ data >> temp;
+ if (temp == DONE)
+ SetData(DATA_QUEL_DELAR_EVENT, DONE);
+ else
+ SetData(DATA_QUEL_DELAR_EVENT, NOT_STARTED);
}
private:
@@ -731,6 +778,7 @@ class instance_halls_of_reflection : public InstanceMapScript
uint32 _waveCount;
uint32 _introState;
uint32 _frostswornGeneralState;
+ uint32 _quelDelarState;
EventMap events;
GuidSet waveGuidList[8];
@@ -740,6 +788,8 @@ class instance_halls_of_reflection : public InstanceMapScript
ObjectGuid CaptainGUID;
ObjectGuid IcewallGUID;
ObjectGuid IcewallTargetGUID;
+ ObjectGuid QuelDelarInvokerGUID;
+ ObjectGuid UtherGUID;
GuidSet GunshipCannonGUIDs;
GuidSet GunshipStairGUIDs;
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
index 3c068915585..5dcf4854943 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
@@ -353,9 +353,9 @@ static bool IsEncounterFinished(Unit* who)
if (!mkii || !vx001 || !aerial)
return false;
- if (mkii->getStandState() == UNIT_STAND_STATE_DEAD &&
- vx001->getStandState() == UNIT_STAND_STATE_DEAD &&
- aerial->getStandState() == UNIT_STAND_STATE_DEAD)
+ if (mkii->GetStandState() == UNIT_STAND_STATE_DEAD &&
+ vx001->GetStandState() == UNIT_STAND_STATE_DEAD &&
+ aerial->GetStandState() == UNIT_STAND_STATE_DEAD)
{
who->Kill(mkii);
who->Kill(vx001);
diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp
index f73930181f0..91c796a6e69 100644
--- a/src/server/scripts/Northrend/zone_zuldrak.cpp
+++ b/src/server/scripts/Northrend/zone_zuldrak.cpp
@@ -313,7 +313,7 @@ public:
{
player->KilledMonsterCredit(gymerDummy->GetEntry(), gymerDummy->GetGUID());
gymerDummy->CastSpell(gymerDummy, SPELL_GYMER_LOCK_EXPLOSION, true);
- gymerDummy->DespawnOrUnsummon();
+ gymerDummy->DespawnOrUnsummon(4 * IN_MILLISECONDS);
}
}
return true;
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
index 9aa1981eabb..38ccf33a612 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
@@ -535,7 +535,7 @@ class boss_kaelthas : public CreatureScript
case 2:
Advisor = (ObjectAccessor::GetCreature(*me, m_auiAdvisorGuid[0]));
- if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD))
+ if (Advisor && (Advisor->GetStandState() == UNIT_STAND_STATE_DEAD))
{
Talk(SAY_INTRO_SANGUINAR);
@@ -569,7 +569,7 @@ class boss_kaelthas : public CreatureScript
case 4:
Advisor = (ObjectAccessor::GetCreature(*me, m_auiAdvisorGuid[1]));
- if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD))
+ if (Advisor && (Advisor->GetStandState() == UNIT_STAND_STATE_DEAD))
{
Talk(SAY_INTRO_CAPERNIAN);
@@ -603,7 +603,7 @@ class boss_kaelthas : public CreatureScript
case 6:
Advisor = (ObjectAccessor::GetCreature(*me, m_auiAdvisorGuid[2]));
- if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD))
+ if (Advisor && (Advisor->GetStandState() == UNIT_STAND_STATE_DEAD))
{
Talk(SAY_INTRO_TELONICUS);
@@ -638,7 +638,7 @@ class boss_kaelthas : public CreatureScript
case 8:
Advisor = (ObjectAccessor::GetCreature(*me, m_auiAdvisorGuid[3]));
- if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD))
+ if (Advisor && (Advisor->GetStandState() == UNIT_STAND_STATE_DEAD))
{
Phase = 2;
instance->SetData(DATA_KAELTHASEVENT, 2);
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 00071c4804e..65b25564401 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -452,7 +452,7 @@ class spell_dk_death_coil : public SpellScriptLoader
{
SpellInfo const* DCD = sSpellMgr->EnsureSpellInfo(SPELL_DK_DEATH_COIL_DAMAGE);
SpellEffectInfo const* eff = DCD->GetEffect(EFFECT_0);
- int32 bp = caster->SpellDamageBonusDone(target, DCD, eff->CalcValue(caster), DIRECT_DAMAGE, eff);
+ int32 bp = caster->SpellDamageBonusDone(target, DCD, eff->CalcValue(caster), SPELL_DIRECT_DAMAGE, eff);
caster->CastCustomSpell(target, SPELL_DK_DEATH_COIL_BARRIER, &bp, nullptr, nullptr, true);
}
@@ -658,11 +658,7 @@ class spell_dk_festering_strike : public SpellScriptLoader
{
PrepareSpellScript(spell_dk_festering_strike_SpellScript);
- public:
- spell_dk_festering_strike_SpellScript() { }
-
- private:
- bool Validate(SpellInfo const* spellInfo) override
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DK_FROST_FEVER) || !sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_PLAGUE) || !sSpellMgr->GetSpellInfo(SPELL_DK_CHAINS_OF_ICE))
return false;
@@ -671,7 +667,7 @@ class spell_dk_festering_strike : public SpellScriptLoader
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
- int32 extraDuration = GetSpellInfo()->GetEffect(EFFECT_2)->CalcValue();
+ int32 extraDuration = GetEffectValue();
Unit* target = GetHitUnit();
ObjectGuid casterGUID = GetCaster()->GetGUID();
@@ -726,6 +722,11 @@ class spell_dk_ghoul_explode : public SpellScriptLoader
return true;
}
+ void HandleDamage(SpellEffIndex /*effIndex*/)
+ {
+ SetHitDamage(GetCaster()->CountPctFromMaxHealth(GetEffectInfo(EFFECT_2)->CalcValue(GetCaster())));
+ }
+
void Suicide(SpellEffIndex /*effIndex*/)
{
if (Unit* unitTarget = GetHitUnit())
@@ -737,6 +738,7 @@ class spell_dk_ghoul_explode : public SpellScriptLoader
void Register() override
{
+ OnEffectHitTarget += SpellEffectFn(spell_dk_ghoul_explode_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
OnEffectHitTarget += SpellEffectFn(spell_dk_ghoul_explode_SpellScript::Suicide, EFFECT_1, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
@@ -760,7 +762,8 @@ class spell_dk_glyph_of_deaths_embrace : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return (GetTarget()->GetCreatureType() == CREATURE_TYPE_UNDEAD && GetTarget()->GetOwner());
+ Unit* actionTarget = eventInfo.GetActionTarget();
+ return actionTarget && actionTarget->GetCreatureType() == CREATURE_TYPE_UNDEAD && actionTarget->GetOwner();
}
void Register() override
@@ -793,6 +796,11 @@ class spell_dk_glyph_of_runic_power : public SpellScriptLoader
return true;
}
+ bool Load() override
+ {
+ return GetUnitOwner()->getClass() == CLASS_DEATH_KNIGHT;
+ }
+
bool CheckProc(ProcEventInfo& eventInfo)
{
return eventInfo.GetSpellInfo() && (eventInfo.GetSpellInfo()->GetAllEffectsMechanicMask() & (1 << MECHANIC_SNARE | 1 << MECHANIC_ROOT | 1 << MECHANIC_FREEZE));
@@ -801,8 +809,7 @@ class spell_dk_glyph_of_runic_power : public SpellScriptLoader
void HandleProc(ProcEventInfo& eventInfo)
{
if (Unit* target = eventInfo.GetProcTarget())
- if (target->getClass() == CLASS_DEATH_KNIGHT)
- target->CastSpell(target, SPELL_DK_GLYPH_OF_RUNIC_POWER_TRIGGERED, true);
+ target->CastSpell(target, SPELL_DK_GLYPH_OF_RUNIC_POWER_TRIGGERED, true);
}
void Register() override
@@ -945,7 +952,7 @@ class spell_dk_raise_dead : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- GetCaster()->CastSpell(((Unit*)nullptr), GetSpellInfo()->GetEffect(EFFECT_0)->CalcValue(), true);
+ GetCaster()->CastSpell(((Unit*)nullptr), GetEffectValue(), true);
}
void Register() override
@@ -1075,19 +1082,23 @@ class spell_dk_will_of_the_necropolis : public SpellScriptLoader
{
PrepareAuraScript(spell_dk_will_of_the_necropolis_AuraScript);
- bool Validate(SpellInfo const* /*spellInfo*/) override
+ bool Validate(SpellInfo const* spellInfo) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DK_WILL_OF_THE_NECROPOLIS))
return false;
+ if (!spellInfo->GetEffect(EFFECT_0))
+ return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (GetTarget()->HasAura(SPELL_DK_WILL_OF_THE_NECROPOLIS))
+ Unit* target = GetTarget();
+
+ if (target->HasAura(SPELL_DK_WILL_OF_THE_NECROPOLIS))
return false;
- return GetTarget()->HealthBelowPctDamaged(30, eventInfo.GetDamageInfo()->GetDamage());
+ return target->HealthBelowPctDamaged(GetSpellInfo()->GetEffect(EFFECT_0)->CalcValue(target), eventInfo.GetDamageInfo()->GetDamage());
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp
index 669fb8838fb..dd002dedee5 100644
--- a/src/server/scripts/Spells/spell_druid.cpp
+++ b/src/server/scripts/Spells/spell_druid.cpp
@@ -164,7 +164,7 @@ class spell_dru_eclipse_energize : public SpellScriptLoader
Player* caster = GetCaster()->ToPlayer();
// No boomy, no deal.
- if (caster->GetActiveTalentSpec() != TALENT_SPEC_DRUID_BALANCE)
+ if (caster->GetSpecId(caster->GetActiveTalentGroup()) != TALENT_SPEC_DRUID_BALANCE)
return;
switch (GetSpellInfo()->Id)
diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp
index 44dd17e5624..e6e97a9d04a 100644
--- a/src/server/scripts/Spells/spell_holiday.cpp
+++ b/src/server/scripts/Spells/spell_holiday.cpp
@@ -64,7 +64,7 @@ class spell_love_is_in_the_air_romantic_picnic : public SpellScriptLoader
Unit* caster = GetCaster();
// If our player is no longer sit, remove all auras
- if (target->getStandState() != UNIT_STAND_STATE_SIT)
+ if (target->GetStandState() != UNIT_STAND_STATE_SIT)
{
target->RemoveAura(SPELL_ROMANTIC_PICNIC_ACHIEV);
target->RemoveAura(GetAura());
@@ -83,7 +83,7 @@ class spell_love_is_in_the_air_romantic_picnic : public SpellScriptLoader
target->VisitNearbyWorldObject(INTERACTION_DISTANCE*2, searcher);
for (std::list<Player*>::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr)
{
- if ((*itr) != target && (*itr)->HasAura(GetId())) // && (*itr)->getStandState() == UNIT_STAND_STATE_SIT)
+ if ((*itr) != target && (*itr)->HasAura(GetId())) // && (*itr)->GetStandState() == UNIT_STAND_STATE_SIT)
{
if (caster)
{
diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h
index df770c2aa47..4d4624b63dd 100644
--- a/src/server/shared/Debugging/Errors.h
+++ b/src/server/shared/Debugging/Errors.h
@@ -49,4 +49,10 @@ namespace Trinity
#define ASSERT WPAssert
+template <typename T> inline T* ASSERT_NOTNULL(T* pointer)
+{
+ ASSERT(pointer);
+ return pointer;
+}
+
#endif