Merge branch 'Spells' of https://github.com/TrinityCore/TrinityCore into Spells
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellPowerData const& spellPowerData)
|
||||
{
|
||||
data << spellPowerData.Cost;
|
||||
data << spellPowerData.Type;
|
||||
return data;
|
||||
}
|
||||
|
||||
_worldPacket << targetGuid;
|
||||
_worldPacket << itemTargetGuid;
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::RuneData const& runeData)
|
||||
{
|
||||
data << runeData.Start;
|
||||
data << runeData.Count;
|
||||
|
||||
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;
|
||||
}
|
||||
data.WriteBits(runeData.Cooldowns.size(), 3);
|
||||
data.FlushBits();
|
||||
|
||||
//if (HasOrientation)
|
||||
// _worldPacket << float(0);
|
||||
for (uint8 cd : runeData.Cooldowns)
|
||||
data << cd;
|
||||
|
||||
_worldPacket.WriteString(spell->m_targets.GetTargetString());
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32 SpellPowerData = 0;
|
||||
_worldPacket << SpellPowerData;
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::MissileTrajectoryResult const& missileTrajectory)
|
||||
{
|
||||
data << missileTrajectory.TravelTime;
|
||||
data << missileTrajectory.Pitch;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
_worldPacket << uint32(0); // TravelTime
|
||||
_worldPacket << spell->m_targets.GetElevation();
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellAmmo const& spellAmmo)
|
||||
{
|
||||
data << spellAmmo.DisplayID;
|
||||
data << spellAmmo.InventoryType;
|
||||
return data;
|
||||
}
|
||||
|
||||
_worldPacket << uint32(0); // Ammo DisplayID
|
||||
_worldPacket << uint8(0); // Ammo InventoryType
|
||||
|
||||
_worldPacket << uint8(0); // DestLocSpellCastIndex
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::ProjectileVisualData const& projectileVisual)
|
||||
{
|
||||
data << projectileVisual.ID[0];
|
||||
data << projectileVisual.ID[1];
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32 TargetPoints = 0;
|
||||
_worldPacket << TargetPoints;
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::CreatureImmunities const& immunities)
|
||||
{
|
||||
data << immunities.School;
|
||||
data << immunities.Value;
|
||||
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::SpellHealPrediction const& spellPred)
|
||||
{
|
||||
data << spellPred.Points;
|
||||
data << spellPred.Type;
|
||||
data << spellPred.BeaconGUID;
|
||||
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::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;
|
||||
|
||||
_worldPacket.ResetBitPos();
|
||||
for (ObjectGuid const& target : spellCastData.HitTargets)
|
||||
data << target;
|
||||
|
||||
_worldPacket.WriteBits(0, 18); // CastFlagsEx
|
||||
for (ObjectGuid const& target : spellCastData.MissTargets)
|
||||
data << target;
|
||||
|
||||
bool HasRuneData = false;
|
||||
bool HasProjectileVisual = false;
|
||||
|
||||
_worldPacket.WriteBit(HasRuneData);
|
||||
_worldPacket.WriteBit(HasProjectileVisual);
|
||||
for (WorldPackets::Spells::SpellMissStatus const& status : spellCastData.MissStatus)
|
||||
data << status;
|
||||
|
||||
/*if (HasRuneData)
|
||||
{
|
||||
_worldPacket << uint8(0); // Start
|
||||
_worldPacket << uint8(0); // Count
|
||||
_worldPacket.ResetBitPos();
|
||||
for (WorldPackets::Spells::SpellPowerData const& power : spellCastData.RemainingPower)
|
||||
data << power;
|
||||
|
||||
uint32 CooldownCount = 0;
|
||||
_worldPacket.WriteBits(CooldownCount, 3);
|
||||
for (uint32 i = 0; i < CooldownCount; ++i)
|
||||
{
|
||||
_worldPacket << uint8(0); // Cooldowns
|
||||
}
|
||||
}*/
|
||||
for (WorldPackets::Spells::TargetLocation const& targetLoc : spellCastData.TargetPoints)
|
||||
data << targetLoc;
|
||||
|
||||
/*if (HasProjectileVisual)
|
||||
{
|
||||
for (uint32 i = 0; i < 2; ++i)
|
||||
{
|
||||
_worldPacket << uint32(0); // Id
|
||||
}
|
||||
}*/
|
||||
data.WriteBits(spellCastData.CastFlagsEx, 18);
|
||||
data.WriteBit(spellCastData.RemainingRunes.HasValue);
|
||||
data.WriteBit(spellCastData.ProjectileVisual.HasValue);
|
||||
data.FlushBits();
|
||||
|
||||
if (spellCastData.RemainingRunes.HasValue)
|
||||
data << spellCastData.RemainingRunes.Value;
|
||||
|
||||
if (spellCastData.ProjectileVisual.HasValue)
|
||||
data << spellCastData.ProjectileVisual.Value;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Spells::SpellStart::Write()
|
||||
{
|
||||
_worldPacket << Cast;
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Spells::SpellGo::Write()
|
||||
{
|
||||
_worldPacket << Cast;
|
||||
|
||||
_worldPacket.WriteBit(LogData.HasValue);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
if (LogData.HasValue)
|
||||
_worldPacket << LogData.Value;
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
@@ -475,4 +479,4 @@ WorldPacket const* WorldPackets::Spells::SendRemovedSpell::Write()
|
||||
_worldPacket << uint32(spellId);
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
class SendSpellStart final : public ServerPacket
|
||||
struct SpellCastData
|
||||
{
|
||||
ObjectGuid CasterGUID;
|
||||
ObjectGuid CasterUnit;
|
||||
uint8 CastID = 0;
|
||||
int32 SpellID = 0;
|
||||
uint32 CastFlags = 0;
|
||||
uint32 CastFlagsEx = 0;
|
||||
uint32 CastTime = 0;
|
||||
std::vector<ObjectGuid> HitTargets;
|
||||
std::vector<ObjectGuid> MissTargets;
|
||||
std::vector<SpellMissStatus> MissStatus;
|
||||
SpellTargetData Target;
|
||||
std::vector<SpellPowerData> RemainingPower;
|
||||
Optional<RuneData> RemainingRunes;
|
||||
MissileTrajectoryResult MissileTrajectory;
|
||||
SpellAmmo Ammo;
|
||||
Optional<ProjectileVisualData> ProjectileVisual;
|
||||
uint8 DestLocSpellCastIndex = 0;
|
||||
std::vector<TargetLocation> TargetPoints;
|
||||
CreatureImmunities Immunities;
|
||||
SpellHealPrediction Predict;
|
||||
};
|
||||
|
||||
class SpellGo final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user