Merge branch 'Spells' of https://github.com/TrinityCore/TrinityCore into Spells

This commit is contained in:
Rat
2014-12-04 19:24:09 +01:00
8 changed files with 562 additions and 180 deletions
+14 -15
View File
@@ -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__
+141 -137
View File
@@ -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;
}
}
+116 -4
View File
@@ -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);
+2 -2
View File
@@ -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);
+185 -21
View File
@@ -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;
+9 -1
View File
@@ -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; }