diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Server/Packets/SpellPackets.cpp | 280 | ||||
-rw-r--r-- | src/server/game/Server/Packets/SpellPackets.h | 118 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 206 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 10 |
5 files changed, 451 insertions, 165 deletions
diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index 7c536363335..97c98e5e145 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -245,168 +245,170 @@ 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 - } - }*/ +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; } diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index e9ae7ada77b..6e95efd63f2 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 SpellGo final : public ServerPacket + { + public: + SpellGo() : ServerPacket(SMSG_SPELL_GO) { } + + WorldPacket const* Write() override; + + Optional<SpellCastLogData> LogData; + SpellCastData Cast; + }; - class SendSpellStart final : public ServerPacket + class SpellStart final : public ServerPacket { public: - SendSpellStart() : ServerPacket(SMSG_SPELL_START) { } + SpellStart() : ServerPacket(SMSG_SPELL_START) { } WorldPacket const* Write() override; - Spell* spell; + SpellCastData Cast; }; class LearnedSpells final : public ServerPacket @@ -227,6 +328,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 79671b85892..f8df17eb3f7 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -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; } |