internal Spell(Unit caster, SpellInfo info, SpellCastingOptions options) { Logging.LogSpell($"Created new spell, current count: {++SpellAliveCount}"); spellManager = caster.World.SpellManager; spellCastFlags = options.SpellFlags; casterMovementFlags = options.MovementFlags ?? caster.MovementInfo.Flags; SchoolMask = info.SchoolMask; CastTime = CastTimeLeft = EffectDamage = EffectHealing = 0; Caster = OriginalCaster = caster; SpellInfo = info; IsTriggered = spellCastFlags.HasTargetFlag(SpellCastFlags.TriggeredByAura); if (IsTriggered) { spellCastFlags |= SpellCastFlags.IgnoreTargetCheck | SpellCastFlags.IgnoreRangeCheck; } if (info.HasAttribute(SpellExtraAttributes.CanCastWhileCasting)) { spellCastFlags |= SpellCastFlags.IgnoreCastInProgress | SpellCastFlags.CastDirectly; } if (info.HasAttribute(SpellExtraAttributes.IgnoreGcd)) { spellCastFlags |= SpellCastFlags.IgnoreGcd; } if (info.HasAttribute(SpellExtraAttributes.IgnoreCasterAuras)) { spellCastFlags |= SpellCastFlags.IgnoreCasterAuras; } CanReflect = SpellInfo.DamageClass == SpellDamageClass.Magic && !SpellInfo.HasAttribute(SpellAttributes.CantBeReflected) && !SpellInfo.HasAttribute(SpellAttributes.UnaffectedByInvulnerability) && !SpellInfo.IsPassive && !SpellInfo.IsPositive; ExplicitTargets = options.Targets ?? new SpellExplicitTargets(); ImplicitTargets = new SpellImplicitTargets(this); spellManager.Add(this); }
public static bool HasTargetFlag(this SpellCastFlags baseFlags, SpellCastFlags flag) { return((baseFlags & flag) == flag); }
void SendSpellGo() { // not send invisible spell casting if (!IsNeedSendToClient()) { return; } SpellCastFlags castFlags = SpellCastFlags.Unk9; // triggered spells with spell visual != 0 if ((IsTriggered() && !m_spellInfo.IsAutoRepeatRangedSpell()))// || m_triggeredByAuraSpell) { castFlags |= SpellCastFlags.Pending; } if ((m_caster.GetTypeId() == ObjectType.Player || (m_caster.GetTypeId() == ObjectType.Unit && m_caster.ToCreature().isPet())) && m_spellInfo.PowerType != Powers.Health) { castFlags |= SpellCastFlags.PowerLeftSelf; // should only be sent to self, but the current messaging doesn't make that possible } if ((m_caster.GetTypeId() == ObjectType.Player) && (m_caster.getClass() == (byte)Class.Deathknight) && m_spellInfo.RuneCostID != 0 && m_spellInfo.PowerType == Powers.Runes) { castFlags |= SpellCastFlags.Unk19; // same as in SMSG_SPELL_START castFlags |= SpellCastFlags.RuneList; // rune cooldowns list } if (m_spellInfo.HasEffect(SpellEffects.ActivateRune)) { castFlags |= SpellCastFlags.RuneList; // rune cooldowns list castFlags |= SpellCastFlags.Unk19; // same as in SMSG_SPELL_START } if (m_targets.HasTraj()) { castFlags |= SpellCastFlags.AdjustMissile; } PacketWriter data = new PacketWriter(Opcodes.SMSG_SpellGo); if (m_CastItem != null) { data.WriteUInt64(m_CastItem.GetPackGUID()); } else { data.WriteUInt64(m_caster.GetPackGUID()); } data.WriteUInt64(m_caster.GetPackGUID()); data.WriteUInt8(m_cast_count); // pending spell cast? data.WriteUInt32(m_spellInfo.Id); // spellId data.WriteUInt32((uint)castFlags); // cast flags data.WriteUInt32(0); //m_timer); data.WriteUnixTime(); // timestamp WriteSpellGoTargets(ref data); m_targets.Write(ref data); //if (castFlags & CAST_FLAG_POWER_LEFT_SELF) //data.WriteUInt32(m_caster.GetPower((Powers)m_spellInfo->PowerType)); if (Convert.ToBoolean(castFlags & SpellCastFlags.RuneList)) // rune cooldowns list { //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 Player player = m_caster.ToPlayer(); if (player != null) { data.WriteUInt8(m_runesState); // runes state before //data.WriteUInt8(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)); //data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed } } } if (Convert.ToBoolean(castFlags & SpellCastFlags.AdjustMissile)) { //data << m_targets.GetElevation(); data.WriteUInt32((uint)m_delayMoment); } if (Convert.ToBoolean(castFlags & SpellCastFlags.Projectile)) { data.WriteUInt32(0); // Ammo display ID data.WriteUInt32(0); // Inventory Type } if (Convert.ToBoolean(castFlags & SpellCastFlags.VisualChain)) { data.WriteUInt32(0); data.WriteUInt32(0); } //if (m_targets.GetTargetMask() & TARGET_FLAG_DEST_LOCATION) { //data << uint8(0); } //if (m_targets.GetTargetMask() & TARGET_FLAG_EXTRA_TARGETS) { //data.WriteUInt32(0); // Extra targets count /* * for (uint8 i = 0; i < count; ++i) * { * data << float(0); // Target Position X * data << float(0); // Target Position Y * data << float(0); // Target Position Z * data << uint64(0); // Target Guid * } * */ } m_caster.SendMessageToSet(data, true); }
void SendSpellStart() { if (!IsNeedSendToClient()) { return; } SpellCastFlags castFlags = SpellCastFlags.HasTrajectory; if ((IsTriggered() && !m_spellInfo.IsAutoRepeatRangedSpell())) //|| m_triggeredByAuraSpell) { castFlags |= SpellCastFlags.Pending; } if ((m_caster is Player) || (m_caster is Unit) && m_caster.ToCreature().isPet() && m_spellInfo.PowerType != Powers.Health) { castFlags |= SpellCastFlags.PowerLeftSelf; } if (m_spellInfo.RuneCostID != 0 && m_spellInfo.PowerType == Powers.Runes) { castFlags |= SpellCastFlags.Unk19; } PacketWriter data = new PacketWriter(Opcodes.SMSG_SpellStart); if (m_CastItem != null) { data.WriteUInt64(m_CastItem.GetPackGUID()); } else { data.WriteUInt64(m_caster.GetPackGUID()); } data.WriteUInt64(m_caster.GetPackGUID()); data.WriteUInt8((byte)m_cast_count); // pending spell cast? data.WriteUInt32(m_spellInfo.Id); // spellId data.WriteUInt32((uint)castFlags); // cast flags data.WriteUInt32(0); //m_timer); // delay? data.WriteInt32(m_casttime); m_targets.Write(ref data); //if (castFlags & (SpellCastFlags.PowerLeftSelf)) //data.WriteUInt32(m_caster.GetPower((Powers)m_spellInfo.PowerType)); if (Convert.ToBoolean(castFlags & SpellCastFlags.RuneList)) // rune cooldowns list { //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 Player player = m_caster.ToPlayer(); if (player != null) { data.WriteUInt8(m_runesState); // runes state before //data.WriteUInt8(player.GetRunesState()); // runes state after //for (var 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)); //data.WriteUInt8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed } } else { data.WriteUInt8(0); data.WriteUInt8(0); } } if (Convert.ToBoolean(castFlags & SpellCastFlags.Projectile)) { data.WriteUInt32(0); // Ammo display ID data.WriteUInt32(0); // Inventory Type } if (Convert.ToBoolean(castFlags & SpellCastFlags.Immunity)) { data.WriteUInt32(0); data.WriteUInt32(0); } if (Convert.ToBoolean(castFlags & SpellCastFlags.HealPrediction)) { data.WriteUInt32(0); data.WriteUInt8(0); // unkByte } m_caster.SendMessageToSet(data, true); }
public SpellCastingOptions(SpellExplicitTargets targets = null, SpellCastFlags castFlags = 0, MovementFlags?movementFlags = null) { Targets = targets; SpellFlags = castFlags; MovementFlags = movementFlags; }
internal void TriggerSpell(SpellInfo spellInfo, Unit target, SpellCastFlags extraCastFlags = 0) { CastSpell(spellInfo, new SpellCastingOptions(new SpellExplicitTargets { Target = target }, SpellCastFlags.TriggeredByAura | extraCastFlags)); }