aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp29
-rw-r--r--src/server/game/Server/Packets/CombatLogPackets.cpp43
-rw-r--r--src/server/game/Server/Packets/CombatLogPackets.h52
-rw-r--r--src/server/game/Server/Packets/SpellPackets.cpp284
-rw-r--r--src/server/game/Server/Packets/SpellPackets.h120
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp4
-rw-r--r--src/server/game/Spells/Spell.cpp206
-rw-r--r--src/server/game/Spells/Spell.h10
8 files changed, 565 insertions, 183 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e4f12614b33..65b2904fdbf 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -65,6 +65,7 @@
#include "ChatPackets.h"
#include "MovementPackets.h"
#include "CombatPackets.h"
+#include "CombatLogPackets.h"
#include <cmath>
@@ -4728,22 +4729,20 @@ void Unit::RemoveAllGameObjects()
void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log)
{
- WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+4+1+4+4+1+1+4+4+1)); // we guess size
- data << log->target->GetPackGUID();
- data << log->attacker->GetPackGUID();
- data << uint32(log->SpellID);
- data << uint32(log->damage); // damage amount
+ WorldPackets::CombatLog::SpellNonMeleeDamageLog packet;
+ packet.Me = log->target->GetGUID();
+ packet.CasterGUID = log->attacker->GetGUID();
+ packet.SpellID = log->SpellID;
+ packet.Damage = log->damage;
int32 overkill = log->damage - log->target->GetHealth();
- data << uint32(overkill > 0 ? overkill : 0); // overkill
- data << uint8 (log->schoolMask); // damage school
- data << uint32(log->absorb); // AbsorbedDamage
- data << uint32(log->resist); // resist
- data << uint8 (log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
- data << uint8 (log->unused); // unused
- data << uint32(log->blocked); // blocked
- data << uint32(log->HitInfo);
- data << uint8 (0); // flag to use extend data
- SendMessageToSet(&data, true);
+ packet.Overkill = (overkill > 0 ? overkill : 0);
+ packet.SchoolMask = log->schoolMask;
+ packet.ShieldBlock = log->blocked;
+ packet.Resisted = log->resist;
+ packet.Absorbed = log->absorb;
+ packet.Periodic = false;
+ packet.Flags = log->HitInfo;
+ SendMessageToSet(packet.Write(), true);
}
void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
diff --git a/src/server/game/Server/Packets/CombatLogPackets.cpp b/src/server/game/Server/Packets/CombatLogPackets.cpp
new file mode 100644
index 00000000000..128cc0d342f
--- /dev/null
+++ b/src/server/game/Server/Packets/CombatLogPackets.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "CombatLogPackets.h"
+#include "SpellPackets.h"
+
+WorldPacket const* WorldPackets::CombatLog::SpellNonMeleeDamageLog::Write()
+{
+ _worldPacket << Me;
+ _worldPacket << CasterGUID;
+ _worldPacket << SpellID;
+ _worldPacket << Damage;
+ _worldPacket << Overkill;
+ _worldPacket << SchoolMask;
+ _worldPacket << ShieldBlock;
+ _worldPacket << Resisted;
+ _worldPacket << Absorbed;
+
+ _worldPacket.WriteBit(Periodic);
+ _worldPacket.WriteBits(Flags, 9);
+ _worldPacket.WriteBit(false); // Debug info
+ _worldPacket.WriteBit(LogData.HasValue);
+ _worldPacket.FlushBits();
+
+ if (LogData.HasValue)
+ _worldPacket << LogData.Value;
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/CombatLogPackets.h b/src/server/game/Server/Packets/CombatLogPackets.h
new file mode 100644
index 00000000000..6cca0127ef6
--- /dev/null
+++ b/src/server/game/Server/Packets/CombatLogPackets.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CombatLogPackets_h__
+#define CombatLogPackets_h__
+
+#include "Packet.h"
+#include "SpellPackets.h"
+
+namespace WorldPackets
+{
+ namespace CombatLog
+ {
+ class SpellNonMeleeDamageLog final : public ServerPacket
+ {
+ public:
+ SpellNonMeleeDamageLog() : ServerPacket(SMSG_SPELLNONMELEEDAMAGELOG, 60) { }
+
+ WorldPacket const* Write() override;
+
+ int32 Absorbed;
+ int32 ShieldBlock;
+ ObjectGuid Me;
+ int32 SpellID;
+ int32 Resisted;
+ bool Periodic;
+ uint8 SchoolMask;
+ ObjectGuid CasterGUID;
+ Optional<Spells::SpellCastLogData> LogData;
+ int32 Damage;
+ // Optional<SpellNonMeleeDamageLogDebugInfo> Debug Info;
+ int32 Flags;
+ int32 Overkill;
+ };
+ }
+}
+
+#endif // CombatLogPackets_h__
diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp
index 1e181d37ff9..022b5c8da37 100644
--- a/src/server/game/Server/Packets/SpellPackets.cpp
+++ b/src/server/game/Server/Packets/SpellPackets.cpp
@@ -243,168 +243,172 @@ void WorldPackets::Spells::SpellCastRequest::Read()
}
}
-WorldPacket const* WorldPackets::Spells::SendSpellStart::Write()
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::TargetLocation const& targetLocation)
{
- uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
+ data << targetLocation.Transport;
+ // data << targetLocation.Location.PositionXYZStream();
+ data << targetLocation.Location.m_positionX;
+ data << targetLocation.Location.m_positionY;
+ data << targetLocation.Location.m_positionZ;
+ return data;
+}
- if ((spell->IsTriggered() && !spell->m_spellInfo->IsAutoRepeatRangedSpell()) || spell->GetTriggeredByAuraSpell())
- castFlags |= CAST_FLAG_PENDING;
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellTargetData const& spellTargetData)
+{
+ data.WriteBits(spellTargetData.Flags, 21);
+ data.WriteBit(spellTargetData.SrcLocation.HasValue);
+ data.WriteBit(spellTargetData.DstLocation.HasValue);
+ data.WriteBit(spellTargetData.Orientation.HasValue);
+ data.WriteBits(spellTargetData.Name.size(), 7);
+ data.FlushBits();
- if ((spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ||
- (spell->GetCaster()->GetTypeId() == TYPEID_UNIT && spell->GetCaster()->ToCreature()->IsPet()))
- && spell->m_spellInfo->PowerType != POWER_HEALTH)
- castFlags |= CAST_FLAG_POWER_LEFT_SELF;
+ data << spellTargetData.Unit;
+ data << spellTargetData.Item;
- if (spell->m_spellInfo->RuneCostID && spell->m_spellInfo->PowerType == POWER_RUNES)
- castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
+ if (spellTargetData.SrcLocation.HasValue)
+ data << spellTargetData.SrcLocation.Value;
+ if (spellTargetData.DstLocation.HasValue)
+ data << spellTargetData.DstLocation.Value;
- if (spell->m_CastItem)
- _worldPacket << spell->m_CastItem->GetGUID();
- else
- _worldPacket << spell->GetCaster()->GetGUID();
- _worldPacket << spell->GetCaster()->GetGUID();
- _worldPacket << uint8(spell->m_cast_count);
- _worldPacket << uint32(spell->m_spellInfo->Id);
- _worldPacket << uint32(castFlags);
- _worldPacket << uint32(spell->GetCastTime());
+ if (spellTargetData.Orientation.HasValue)
+ data << spellTargetData.Orientation.Value;
- uint32 HitTargets = 0;
- _worldPacket << HitTargets;
- uint32 MissTargets = 0;
- _worldPacket << MissTargets;
- uint32 MissStatus = 0;
- _worldPacket << MissStatus;
+ data.WriteString(spellTargetData.Name);
- _worldPacket.ResetBitPos();
+ return data;
+}
- _worldPacket.WriteBits(spell->m_targets.GetTargetMask(), 21);
-
- bool HasSourceLocation = (spell->m_targets.GetTargetMask() & TARGET_FLAG_SOURCE_LOCATION) && spell->m_targets.GetSrc();
- bool HasDestLocation = (spell->m_targets.GetTargetMask() & TARGET_FLAG_DEST_LOCATION) && spell->m_targets.GetDst();
- bool HasOrientation = false;
- uint32 NameLen = spell->m_targets.GetTargetString().length();
-
- _worldPacket.WriteBit(HasSourceLocation);
- _worldPacket.WriteBit(HasDestLocation);
- _worldPacket.WriteBit(HasOrientation);
- _worldPacket.WriteBits(NameLen, 7);
-
- ObjectGuid targetGuid = spell->m_targets.GetObjectTargetGUID();
- ObjectGuid itemTargetGuid = spell->m_targets.GetItemTargetGUID();
-
- _worldPacket << targetGuid;
- _worldPacket << itemTargetGuid;
-
- if (HasSourceLocation)
- {
- _worldPacket << spell->m_targets.GetSrc()->_transportGUID;
- float x, y, z;
- spell->m_targets.GetSrc()->_transportOffset.GetPosition(x, y, z);
- _worldPacket << x;
- _worldPacket << y;
- _worldPacket << z;
- }
-
- if (HasDestLocation)
- {
- _worldPacket << spell->m_targets.GetDst()->_transportGUID;
- float x, y, z;
- spell->m_targets.GetDst()->_transportOffset.GetPosition(x, y, z);
- _worldPacket << x;
- _worldPacket << y;
- _worldPacket << z;
- }
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellMissStatus const& spellMissStatus)
+{
+ data.WriteBits(spellMissStatus.Reason, 4);
+ data.WriteBits(spellMissStatus.ReflectStatus, 4);
+ // No need to flush bits as we written exactly 8 bits (1 byte)
+ return data;
+}
- //if (HasOrientation)
- // _worldPacket << float(0);
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellPowerData const& spellPowerData)
+{
+ data << spellPowerData.Cost;
+ data << spellPowerData.Type;
+ return data;
+}
- _worldPacket.WriteString(spell->m_targets.GetTargetString());
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::RuneData const& runeData)
+{
+ data << runeData.Start;
+ data << runeData.Count;
- uint32 SpellPowerData = 0;
- _worldPacket << SpellPowerData;
+ data.WriteBits(runeData.Cooldowns.size(), 3);
+ data.FlushBits();
-
- _worldPacket << uint32(0); // TravelTime
- _worldPacket << spell->m_targets.GetElevation();
+ for (uint8 cd : runeData.Cooldowns)
+ data << cd;
- _worldPacket << uint32(0); // Ammo DisplayID
- _worldPacket << uint8(0); // Ammo InventoryType
-
- _worldPacket << uint8(0); // DestLocSpellCastIndex
+ return data;
+}
- uint32 TargetPoints = 0;
- _worldPacket << TargetPoints;
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::MissileTrajectoryResult const& missileTrajectory)
+{
+ data << missileTrajectory.TravelTime;
+ data << missileTrajectory.Pitch;
+ return data;
+}
- _worldPacket << uint32(0); // CreatureImmunities School
- _worldPacket << uint32(0); // CreatureImmunities Value
-
- _worldPacket << uint32(0); // SpellHealPrediction Points
- _worldPacket << uint8(0); // SpellHealPrediction Type
- ObjectGuid BeaconGUID;
- _worldPacket << BeaconGUID; // SpellHealPrediction BeaconGUID
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellAmmo const& spellAmmo)
+{
+ data << spellAmmo.DisplayID;
+ data << spellAmmo.InventoryType;
+ return data;
+}
- /*for (uint32 i = 0; i < HitTargets; ++i)
- {
- ObjectGuid HitTargetGUID;
- _worldPacket << HitTargetGUID;
- }
- for (uint32 i = 0; i < MissTargets; ++i)
- {
- ObjectGuid MissTargetGUID;
- _worldPacket << MissTargetGUID;
- }
- for (uint32 i = 0; i < MissStatus; ++i)
- {
- _worldPacket.ResetBitPos();
- uint32 MissReason = 0;
- _worldPacket.WriteBits(MissReason, 4);
- uint32 ReflectStatus = 0;
- if (MissReason == 11)
- _worldPacket.WriteBits(ReflectStatus, 4);
- }
- for (uint32 i = 0; i < SpellPowerData; ++i)
- {
- //uint32 Cost
- //uint8 PowerType
- }
- for (uint32 i = 0; i < TargetPoints; ++i)
- {
- //Transport Guid
- //XYZ
- }*/
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::ProjectileVisualData const& projectileVisual)
+{
+ data << projectileVisual.ID[0];
+ data << projectileVisual.ID[1];
+ return data;
+}
- _worldPacket.ResetBitPos();
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::CreatureImmunities const& immunities)
+{
+ data << immunities.School;
+ data << immunities.Value;
+ return data;
+}
- _worldPacket.WriteBits(0, 18); // CastFlagsEx
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellHealPrediction const& spellPred)
+{
+ data << spellPred.Points;
+ data << spellPred.Type;
+ data << spellPred.BeaconGUID;
+ return data;
+}
- bool HasRuneData = false;
- bool HasProjectileVisual = false;
-
- _worldPacket.WriteBit(HasRuneData);
- _worldPacket.WriteBit(HasProjectileVisual);
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellCastData const& spellCastData)
+{
+ data << spellCastData.CasterGUID;
+ data << spellCastData.CasterUnit;
+ data << spellCastData.CastID;
+ data << spellCastData.SpellID;
+ data << spellCastData.CastFlags;
+ data << spellCastData.CastTime;
+ data << uint32(spellCastData.HitTargets.size());
+ data << uint32(spellCastData.MissTargets.size());
+ data << uint32(spellCastData.MissStatus.size());
+ data << spellCastData.Target;
+ data << uint32(spellCastData.RemainingPower.size());
+ data << spellCastData.MissileTrajectory;
+ data << spellCastData.Ammo;
+ data << spellCastData.DestLocSpellCastIndex;
+ data << uint32(spellCastData.TargetPoints.size());
+ data << spellCastData.Immunities;
+ data << spellCastData.Predict;
+
+ for (ObjectGuid const& target : spellCastData.HitTargets)
+ data << target;
+
+ for (ObjectGuid const& target : spellCastData.MissTargets)
+ data << target;
+
+ for (WorldPackets::Spells::SpellMissStatus const& status : spellCastData.MissStatus)
+ data << status;
+
+ for (WorldPackets::Spells::SpellPowerData const& power : spellCastData.RemainingPower)
+ data << power;
+
+ for (WorldPackets::Spells::TargetLocation const& targetLoc : spellCastData.TargetPoints)
+ data << targetLoc;
+
+ data.WriteBits(spellCastData.CastFlagsEx, 18);
+ data.WriteBit(spellCastData.RemainingRunes.HasValue);
+ data.WriteBit(spellCastData.ProjectileVisual.HasValue);
+ data.FlushBits();
- /*if (HasRuneData)
- {
- _worldPacket << uint8(0); // Start
- _worldPacket << uint8(0); // Count
- _worldPacket.ResetBitPos();
+ if (spellCastData.RemainingRunes.HasValue)
+ data << spellCastData.RemainingRunes.Value;
- uint32 CooldownCount = 0;
- _worldPacket.WriteBits(CooldownCount, 3);
- for (uint32 i = 0; i < CooldownCount; ++i)
- {
- _worldPacket << uint8(0); // Cooldowns
- }
- }*/
+ if (spellCastData.ProjectileVisual.HasValue)
+ data << spellCastData.ProjectileVisual.Value;
- /*if (HasProjectileVisual)
- {
- for (uint32 i = 0; i < 2; ++i)
- {
- _worldPacket << uint32(0); // Id
- }
- }*/
+ return data;
+}
+
+WorldPacket const* WorldPackets::Spells::SpellStart::Write()
+{
+ _worldPacket << Cast;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Spells::SpellGo::Write()
+{
+ _worldPacket << Cast;
+
+ _worldPacket.WriteBit(LogData.HasValue);
+ _worldPacket.FlushBits();
+
+ if (LogData.HasValue)
+ _worldPacket << LogData.Value;
return &_worldPacket;
}
@@ -475,4 +479,4 @@ WorldPacket const* WorldPackets::Spells::SendRemovedSpell::Write()
_worldPacket << uint32(spellId);
return &_worldPacket;
-} \ No newline at end of file
+}
diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h
index 6971b730742..5597f21516c 100644
--- a/src/server/game/Server/Packets/SpellPackets.h
+++ b/src/server/game/Server/Packets/SpellPackets.h
@@ -154,15 +154,116 @@ namespace WorldPackets
MovementInfo movementInfo;
};
+
+ struct TargetLocation
+ {
+ ObjectGuid Transport;
+ Position Location;
+ };
+
+ struct SpellTargetData
+ {
+ uint32 Flags = 0;
+ ObjectGuid Unit;
+ ObjectGuid Item;
+ Optional<TargetLocation> SrcLocation;
+ Optional<TargetLocation> DstLocation;
+ Optional<float> Orientation; // Not found in JAM structures
+ std::string Name;
+ };
+
+ struct SpellMissStatus
+ {
+ uint8 Reason = 0;
+ uint8 ReflectStatus = 0;
+ };
+
+ struct SpellPowerData
+ {
+ int32 Cost = 0;
+ int8 Type = 0;
+ };
+
+ struct RuneData
+ {
+ uint8 Start = 0;
+ uint8 Count = 0;
+ std::vector<uint8> Cooldowns;
+ };
+
+ struct MissileTrajectoryResult
+ {
+ uint32 TravelTime = 0;
+ float Pitch = 0.0f;
+ };
+
+ struct SpellAmmo
+ {
+ int32 DisplayID = 0;
+ int8 InventoryType = 0;
+ };
+
+ struct ProjectileVisualData
+ {
+ int32 ID[2];
+ };
+
+ struct CreatureImmunities
+ {
+ uint32 School = 0;
+ uint32 Value = 0;
+ };
+
+ struct SpellHealPrediction
+ {
+ ObjectGuid BeaconGUID;
+ uint32 Points = 0;
+ uint8 Type = 0;
+ };
+
+ struct SpellCastData
+ {
+ ObjectGuid CasterGUID;
+ ObjectGuid CasterUnit;
+ uint8 CastID = 0;
+ int32 SpellID = 0;
+ uint32 CastFlags = 0;
+ uint32 CastFlagsEx = 0;
+ uint32 CastTime = 0;
+ std::vector<ObjectGuid> HitTargets;
+ std::vector<ObjectGuid> MissTargets;
+ std::vector<SpellMissStatus> MissStatus;
+ SpellTargetData Target;
+ std::vector<SpellPowerData> RemainingPower;
+ Optional<RuneData> RemainingRunes;
+ MissileTrajectoryResult MissileTrajectory;
+ SpellAmmo Ammo;
+ Optional<ProjectileVisualData> ProjectileVisual;
+ uint8 DestLocSpellCastIndex = 0;
+ std::vector<TargetLocation> TargetPoints;
+ CreatureImmunities Immunities;
+ SpellHealPrediction Predict;
+ };
- class SendSpellStart final : public ServerPacket
+ class SpellGo final : public ServerPacket
{
public:
- SendSpellStart() : ServerPacket(SMSG_SPELL_START) { }
+ SpellGo() : ServerPacket(SMSG_SPELL_GO) { }
WorldPacket const* Write() override;
- Spell* spell;
+ Optional<SpellCastLogData> LogData;
+ SpellCastData Cast;
+ };
+
+ class SpellStart final : public ServerPacket
+ {
+ public:
+ SpellStart() : ServerPacket(SMSG_SPELL_START) { }
+
+ WorldPacket const* Write() override;
+
+ SpellCastData Cast;
};
class LearnedSpells final : public ServerPacket
@@ -198,7 +299,7 @@ namespace WorldPackets
ObjectGuid CasterUnit;
uint32 SpellID = 0;
- uint8 Reason = 0;
+ uint16 Reason = 0;
uint8 CastID = 0;
};
@@ -237,6 +338,17 @@ 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);
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 671f0deb919..534208f5453 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -1307,7 +1307,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLINTERRUPTLOG, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLLOGEXECUTE, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLLOGMISS, STATUS_UNHANDLED);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLNONMELEEDAMAGELOG, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLNONMELEEDAMAGELOG, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLORDAMAGE_IMMUNE, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELLSTEALLOG, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_CATEGORY_COOLDOWN, STATUS_NEVER);
@@ -1315,7 +1315,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_DELAYED, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_FAILED_OTHER, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_FAILURE, STATUS_NEVER);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_GO, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_GO, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_START, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_UPDATE_CHAIN_TARGETS, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPIRIT_HEALER_CONFIRM, STATUS_UNHANDLED);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 303a885c39c..a056ca958fd 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -196,9 +196,41 @@ void SpellCastTargets::Read(ByteBuffer& data, Unit* caster)
Update(caster);
}
-void SpellCastTargets::Write(ByteBuffer& data)
+void SpellCastTargets::Write(WorldPackets::Spells::SpellTargetData& data)
{
- data << uint32(m_targetMask);
+ data.Flags = m_targetMask;
+
+ if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET))
+ data.Unit = m_objectTargetGUID;
+
+ if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM) && m_itemTarget)
+ data.Item = m_itemTarget->GetGUID();
+
+ if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
+ {
+ WorldPackets::Spells::TargetLocation& target = data.SrcLocation.Value;
+ target.Transport = m_src._transportGUID; // relative position guid here - transport for example
+ if (!m_src._transportGUID.IsEmpty())
+ target.Location = m_src._transportOffset;
+ else
+ target.Location = m_src._position;
+ data.SrcLocation.HasValue = true;
+ }
+
+ if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ WorldPackets::Spells::TargetLocation& target = data.DstLocation.Value;
+ target.Transport = m_dst._transportGUID; // relative position guid here - transport for example
+ if (!m_dst._transportGUID.IsEmpty())
+ target.Location = m_dst._transportOffset;
+ else
+ target.Location = m_dst._position;
+ data.DstLocation.HasValue = true;
+ }
+
+ if (m_targetMask & TARGET_FLAG_STRING)
+ data.Name = m_strTarget;
+ /*data << uint32(m_targetMask);
if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET))
data << m_objectTargetGUID.WriteAsPacked();
@@ -230,7 +262,7 @@ void SpellCastTargets::Write(ByteBuffer& data)
}
if (m_targetMask & TARGET_FLAG_STRING)
- data << m_strTarget;
+ data << m_strTarget;*/
}
ObjectGuid SpellCastTargets::GetOrigUnitTargetGUID() const
@@ -3849,7 +3881,7 @@ void Spell::SendSpellStart()
if (!IsNeedSendToClient())
return;
- //TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id);
+ TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id);
uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
@@ -3864,9 +3896,80 @@ void Spell::SendSpellStart()
if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNES)
castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
- WorldPackets::Spells::SendSpellStart spellStart;
- spellStart.spell = this;
+ WorldPackets::Spells::SpellStart packet;
+ WorldPackets::Spells::SpellCastData& castData = packet.Cast;
+
+ if (m_CastItem)
+ castData.CasterGUID = m_CastItem->GetGUID();
+ else
+ castData.CasterGUID = m_caster->GetGUID();
+
+ castData.CasterUnit = m_caster->GetGUID();
+ castData.CastID = m_cast_count; // pending spell cast?
+ castData.SpellID = m_spellInfo->Id;
+ castData.CastFlags = castFlags;
+ castData.CastTime = m_casttime;
+
+ m_targets.Write(castData.Target);
+
+ if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
+ {
+ /// @todo Implement multiple power types
+ WorldPackets::Spells::SpellPowerData powerData;
+ powerData.Type = m_spellInfo->PowerType;
+ powerData.Cost = m_caster->GetPower((Powers)m_spellInfo->PowerType);
+ castData.RemainingPower.push_back(powerData);
+ }
+
+ if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
+ {
+ WorldPackets::Spells::RuneData& runeData = castData.RemainingRunes.Value;
+ //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature
+ //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster
+ if (Player* player = m_caster->ToPlayer())
+ {
+ runeData.Start = m_runesState; // runes state before
+ runeData.Count = player->GetRunesState(); // runes state after
+ for (uint8 i = 0; i < MAX_RUNES; ++i)
+ {
+ // float casts ensure the division is performed on floats as we need float result
+ float baseCd = float(player->GetRuneBaseCooldown(i));
+ runeData.Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed
+ }
+ }
+ else
+ {
+ runeData.Start = 0;
+ runeData.Count = 0;
+ for (uint8 i = 0; i < MAX_RUNES; ++i)
+ runeData.Cooldowns.push_back(0);
+ }
+
+ castData.RemainingRunes.HasValue = true;
+ }
+
+ /** @todo implement spell ammo packet data
+ if (castFlags & CAST_FLAG_PROJECTILE)
+ {
+ castData.Ammo.DisplayID = 0;
+ castData.Ammo.InventoryType = 0;
+ }**/
+
+ /** @todo implement spell immunity packet data
+ if (castFlags & CAST_FLAG_IMMUNITY)
+ {
+ castData.Immunities.School = 0;
+ castData.Immunities.Value = 0;
+ }**/
+ /** @todo implement heal prediction packet data
+ if (castFlags & CAST_FLAG_HEAL_PREDICTION)
+ {
+ castData.Predict.BeconGUID = ??
+ castData.Predict.Points = 0;
+ castData.Predict.Type = 0;
+ }**/
+
/*WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2));
if (m_CastItem)
data << m_CastItem->GetPackGUID();
@@ -3929,7 +4032,7 @@ void Spell::SendSpellStart()
// data.append(0);
}*/
- m_caster->SendMessageToSet(spellStart.Write(), true);
+ m_caster->SendMessageToSet(packet.Write(), true);
}
void Spell::SendSpellGo()
@@ -3938,7 +4041,7 @@ void Spell::SendSpellGo()
if (!IsNeedSendToClient())
return;
- //TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id);
+ TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id);
uint32 castFlags = CAST_FLAG_UNKNOWN_9;
@@ -3970,7 +4073,68 @@ void Spell::SendSpellGo()
if (!m_spellInfo->StartRecoveryTime)
castFlags |= CAST_FLAG_NO_GCD;
- WorldPacket data(SMSG_SPELL_GO, 50); // guess size
+ WorldPackets::Spells::SpellGo packet;
+ WorldPackets::Spells::SpellCastData& castData = packet.Cast;
+
+ if (m_CastItem)
+ castData.CasterGUID = m_CastItem->GetGUID();
+ else
+ castData.CasterGUID = m_caster->GetGUID();
+
+ castData.CasterUnit = m_caster->GetGUID();
+ castData.CastID = m_cast_count; // pending spell cast?
+ castData.SpellID = m_spellInfo->Id;
+ castData.CastFlags = castFlags;
+ castData.CastTime = getMSTime();
+
+ /// @todo implement multiple targets
+ if (m_targets.GetUnitTarget())
+ castData.HitTargets.push_back(m_targets.GetUnitTargetGUID());
+
+ m_targets.Write(castData.Target);
+
+ if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
+ {
+ /// @todo Implement multiple power types
+ WorldPackets::Spells::SpellPowerData powerData;
+ powerData.Type = m_spellInfo->PowerType;
+ powerData.Cost = m_caster->GetPower((Powers)m_spellInfo->PowerType);
+ castData.RemainingPower.push_back(powerData);
+ }
+
+ if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
+ {
+ WorldPackets::Spells::RuneData& runeData = castData.RemainingRunes.Value;
+ //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature
+ //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster
+ if (Player* player = m_caster->ToPlayer())
+ {
+ runeData.Start = m_runesState; // runes state before
+ runeData.Count = player->GetRunesState(); // runes state after
+ for (uint8 i = 0; i < MAX_RUNES; ++i)
+ {
+ // float casts ensure the division is performed on floats as we need float result
+ float baseCd = float(player->GetRuneBaseCooldown(i));
+ runeData.Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed
+ }
+ }
+ else
+ {
+ runeData.Start = 0;
+ runeData.Count = 0;
+ for (uint8 i = 0; i < MAX_RUNES; ++i)
+ runeData.Cooldowns.push_back(0);
+ }
+
+ castData.RemainingRunes.HasValue = true;
+ }
+
+ if (castFlags & CAST_FLAG_ADJUST_MISSILE)
+ {
+ castData.MissileTrajectory.TravelTime = m_delayMoment;
+ castData.MissileTrajectory.Pitch = m_targets.GetElevation();
+ }
+ /*WorldPacket data(SMSG_SPELL_GO, 50); // guess size
if (m_CastItem)
data << m_CastItem->GetPackGUID();
@@ -3986,7 +4150,7 @@ void Spell::SendSpellGo()
WriteSpellGoTargets(&data);
- m_targets.Write(data);
+ //m_targets.Write(data);
if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
data << uint32(m_caster->GetPower((Powers)m_spellInfo->PowerType));
@@ -4034,7 +4198,7 @@ void Spell::SendSpellGo()
if (m_targets.GetTargetMask() & TARGET_FLAG_EXTRA_TARGETS)
{
data << uint32(0); // Extra targets count
- /*
+
for (uint8 i = 0; i < count; ++i)
{
data << float(0); // Target Position X
@@ -4042,10 +4206,10 @@ void Spell::SendSpellGo()
data << float(0); // Target Position Z
data << uint64(0); // Target Guid
}
- */
- }
+
+ }*/
- m_caster->SendMessageToSet(&data, true);
+ m_caster->SendMessageToSet(packet.Write(), true);
}
/// Writes miss and hit targets for a SMSG_SPELL_GO packet
@@ -4365,7 +4529,7 @@ void Spell::TakeCastItem()
bool expendable = false;
bool withoutCharges = false;
- for (uint32 i = 0; i < proto->Effects.size(); ++i)
+ for (int i = 0; i < proto->Effects.size(); ++i)
{
// item has limited charges
if (proto->Effects[i].Charges)
@@ -4607,7 +4771,7 @@ void Spell::TakeReagents()
// if CastItem is also spell reagent
if (castItemTemplate && castItemTemplate->ItemId == itemid)
{
- for (uint32 s = 0; s < castItemTemplate->Effects.size(); ++s)
+ for (int s = 0; s < castItemTemplate->Effects.size(); ++s)
{
// CastItem will be used up and does not count as reagent
int32 charges = m_CastItem->GetSpellCharges(s);
@@ -6343,15 +6507,15 @@ SpellCastResult Spell::CheckItems()
case SPELL_EFFECT_CREATE_MANA_GEM:
{
uint32 item_id = effect->ItemType;
- ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item_id);
+ ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item_id);
- if (!proto)
+ if (!pProto)
return SPELL_FAILED_ITEM_AT_MAX_CHARGES;
- if (Item* item = player->GetItemByEntry(item_id))
+ if (Item* pitem = player->GetItemByEntry(item_id))
{
- for (uint32 x = 0; x < proto->Effects.size(); ++x)
- if (proto->Effects[x].Charges != 0 && item->GetSpellCharges(x) == proto->Effects[x].Charges)
+ for (int x = 0; x < pProto->Effects.size(); ++x)
+ if (pProto->Effects[x].Charges != 0 && pitem->GetSpellCharges(x) == pProto->Effects[x].Charges)
return SPELL_FAILED_ITEM_AT_MAX_CHARGES;
}
break;
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 8accaf896d0..33e4923d2f1 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -25,6 +25,14 @@
#include "SpellInfo.h"
#include "PathGenerator.h"
+namespace WorldPackets
+{
+ namespace Spells
+ {
+ struct SpellTargetData;
+ }
+}
+
class Unit;
class Player;
class GameObject;
@@ -103,7 +111,7 @@ class SpellCastTargets
~SpellCastTargets();
void Read(ByteBuffer& data, Unit* caster);
- void Write(ByteBuffer& data);
+ void Write(WorldPackets::Spells::SpellTargetData& data);
uint32 GetTargetMask() const { return m_targetMask; }
void SetTargetMask(uint32 newMask) { m_targetMask = newMask; }