/* * Copyright (C) 2012-2018 CypherCore * * 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 3 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 . */ using Framework.Constants; using Framework.Dynamic; using Framework.GameMath; using Game.BattleGrounds; using Game.BattlePets; using Game.Combat; using Game.DataStorage; using Game.Entities; using Game.Garrisons; using Game.Groups; using Game.Guilds; using Game.Loots; using Game.Maps; using Game.Movement; using Game.Network.Packets; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; namespace Game.Spells { public partial class Spell { [SpellEffectHandler(SpellEffectName.Null)] [SpellEffectHandler(SpellEffectName.Portal)] [SpellEffectHandler(SpellEffectName.BindSight)] [SpellEffectHandler(SpellEffectName.CallPet)] [SpellEffectHandler(SpellEffectName.Effect171)] [SpellEffectHandler(SpellEffectName.Effect177)] [SpellEffectHandler(SpellEffectName.PortalTeleport)] [SpellEffectHandler(SpellEffectName.RitualBase)] [SpellEffectHandler(SpellEffectName.RitualActivatePortal)] [SpellEffectHandler(SpellEffectName.Dodge)] [SpellEffectHandler(SpellEffectName.Evade)] [SpellEffectHandler(SpellEffectName.Weapon)] [SpellEffectHandler(SpellEffectName.Defense)] [SpellEffectHandler(SpellEffectName.SpellDefense)] [SpellEffectHandler(SpellEffectName.Language)] [SpellEffectHandler(SpellEffectName.Spawn)] [SpellEffectHandler(SpellEffectName.Stealth)] [SpellEffectHandler(SpellEffectName.Detect)] [SpellEffectHandler(SpellEffectName.ForceCriticalHit)] [SpellEffectHandler(SpellEffectName.Attack)] [SpellEffectHandler(SpellEffectName.ThreatAll)] [SpellEffectHandler(SpellEffectName.Effect112)] [SpellEffectHandler(SpellEffectName.TeleportGraveyard)] [SpellEffectHandler(SpellEffectName.Effect122)] [SpellEffectHandler(SpellEffectName.Effect175)] [SpellEffectHandler(SpellEffectName.Effect178)] void EffectUnused(uint effIndex) { } void EffectResurrectNew(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || unitTarget.IsAlive()) return; if (!unitTarget.IsTypeId(TypeId.Player)) return; if (!unitTarget.IsInWorld) return; Player target = unitTarget.ToPlayer(); if (target.IsResurrectRequested()) // already have one active request return; int health = damage; int mana = effectInfo.MiscValue; ExecuteLogEffectResurrect(effIndex, target); target.SetResurrectRequestData(m_caster, (uint)health, (uint)mana, 0); SendResurrectRequest(target); } [SpellEffectHandler(SpellEffectName.Instakill)] void EffectInstaKill(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsAlive()) return; if (unitTarget.IsTypeId(TypeId.Player)) if (unitTarget.ToPlayer().GetCommandStatus(PlayerCommandStates.God)) return; if (m_caster == unitTarget) // prevent interrupt message finish(); SpellInstakillLog data = new SpellInstakillLog(); data.Target = unitTarget.GetGUID(); data.Caster = m_caster.GetGUID(); data.SpellID = m_spellInfo.Id; m_caster.SendMessageToSet(data, true); m_caster.DealDamage(unitTarget, (uint)unitTarget.GetHealth(), null, DamageEffectType.NoDamage, SpellSchoolMask.Normal, null, false); } void EffectEnvironmentalDMG(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsAlive()) return; // CalcAbsorbResist already in Player::EnvironmentalDamage if (unitTarget.IsTypeId(TypeId.Player)) unitTarget.ToPlayer().EnvironmentalDamage(EnviromentalDamage.Fire, (uint)damage); else { DamageInfo damageInfo = new DamageInfo(m_caster, unitTarget, (uint)damage, m_spellInfo, m_spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); m_caster.CalcAbsorbResist(damageInfo); SpellNonMeleeDamage log = new SpellNonMeleeDamage(m_caster, unitTarget, m_spellInfo.Id, m_SpellVisual, m_spellInfo.GetSchoolMask(), m_castId); log.damage = (uint)damage; log.absorb = damageInfo.GetAbsorb(); log.resist = damageInfo.GetResist(); m_caster.SendSpellNonMeleeDamageLog(log); } } [SpellEffectHandler(SpellEffectName.SchoolDamage)] void EffectSchoolDmg(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) return; if (unitTarget != null && unitTarget.IsAlive()) { bool apply_direct_bonus = true; // Meteor like spells (divided damage to targets) if (m_spellInfo.HasAttribute(SpellCustomAttributes.ShareDamage)) { int count = m_UniqueTargetInfo.Count(targetInfo => { return Convert.ToBoolean(targetInfo.effectMask & (1 << (int)effIndex)); }); // divide to all targets if (count != 0) damage /= count; } switch (m_spellInfo.SpellFamilyName) { case SpellFamilyNames.Generic: { switch (m_spellInfo.Id) // better way to check unknown { // Consumption case 28865: damage = m_caster.GetMap().GetDifficultyID() == Difficulty.None ? 2750 : 4250; break; // percent from health with min case 25599: // Thundercrash { damage = (int)unitTarget.GetHealth() / 2; if (damage < 200) damage = 200; break; } // arcane charge. must only affect demons (also undead?) case 45072: { if (unitTarget.GetCreatureType() != CreatureType.Demon && unitTarget.GetCreatureType() != CreatureType.Undead) return; break; } // Gargoyle Strike case 51963: { // about +4 base spell dmg per level damage = (int)(m_caster.getLevel() - 60) * 4 + 60; break; } } break; } case SpellFamilyNames.Warrior: { // Victory Rush if (m_spellInfo.Id == 34428) MathFunctions.ApplyPct(ref damage, m_caster.GetTotalAttackPowerValue(WeaponAttackType.BaseAttack)); // Shockwave else if (m_spellInfo.Id == 46968) { int pct = m_caster.CalculateSpellDamage(unitTarget, m_spellInfo, 2); if (pct > 0) damage += (int)MathFunctions.CalculatePct(m_caster.GetTotalAttackPowerValue(WeaponAttackType.BaseAttack), pct); break; } break; } case SpellFamilyNames.Warlock: { break; } case SpellFamilyNames.Priest: { break; } case SpellFamilyNames.Druid: { // Ferocious Bite if (m_caster.IsTypeId(TypeId.Player) && m_spellInfo.SpellFamilyFlags[3].HasAnyFlag(0x1000u)) { // converts each extra point of energy ( up to 25 energy ) into additional damage int energy = -(m_caster.ModifyPower(PowerType.Energy, -25)); // 25 energy = 100% more damage MathFunctions.AddPct(ref damage, energy * 4); } break; } case SpellFamilyNames.Deathknight: { // Blood Boil - bonus for diseased targets if (m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x00040000u)) { if (unitTarget.GetAuraEffect(AuraType.PeriodicDamage, SpellFamilyNames.Deathknight, new FlagArray128(0, 0, 0x00000002), m_caster.GetGUID()) != null) { damage += m_damage / 2; damage += (int)(m_caster.GetTotalAttackPowerValue(WeaponAttackType.BaseAttack) * 0.035f); } } break; } } if (m_originalCaster != null && apply_direct_bonus) { uint bonus = m_originalCaster.SpellDamageBonusDone(unitTarget, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); damage = (int)(bonus + (bonus * variance)); damage = (int)unitTarget.SpellDamageBonusTaken(m_originalCaster, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); } m_damage += damage; } } [SpellEffectHandler(SpellEffectName.Dummy)] void EffectDummy(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget && !gameObjTarget && !itemTarget) return; // selection by spell family switch (m_spellInfo.SpellFamilyName) { case SpellFamilyNames.Paladin: switch (m_spellInfo.Id) { case 31789: // Righteous Defense (step 1) { // Clear targets for eff 1 foreach (var hit in m_UniqueTargetInfo) hit.effectMask &= ~Convert.ToUInt32(1 << 1); // not empty (checked), copy var attackers = unitTarget.getAttackers(); // remove invalid attackers foreach (var att in attackers) if (!att.IsValidAttackTarget(m_caster)) attackers.Remove(att); // selected from list 3 int maxTargets = Math.Min(3, attackers.Count); for (uint i = 0; i < maxTargets; ++i) { Unit attacker = attackers.SelectRandom(); AddUnitTarget(attacker, 1 << 1); attackers.Remove(attacker); } // now let next effect cast spell at each target. return; } } break; } // pet auras PetAura petSpell = Global.SpellMgr.GetPetAura(m_spellInfo.Id, (byte)effIndex); if (petSpell != null) { m_caster.AddPetAura(petSpell); return; } // normal DB scripted effect Log.outDebug(LogFilter.Spells, "Spell ScriptStart spellid {0} in EffectDummy({1})", m_spellInfo.Id, effIndex); m_caster.GetMap().ScriptsStart(ScriptsType.Spell, (uint)((int)m_spellInfo.Id | (int)(effIndex << 24)), m_caster, unitTarget); // Script based implementation. Must be used only for not good for implementation in core spell effects // So called only for not proccessed cases if (gameObjTarget) Global.ScriptMgr.OnDummyEffect(m_caster, m_spellInfo.Id, effIndex, gameObjTarget); else if (unitTarget && unitTarget.IsTypeId(TypeId.Unit)) Global.ScriptMgr.OnDummyEffect(m_caster, m_spellInfo.Id, effIndex, unitTarget.ToCreature()); else if (itemTarget) Global.ScriptMgr.OnDummyEffect(m_caster, m_spellInfo.Id, effIndex, itemTarget); } [SpellEffectHandler(SpellEffectName.TriggerSpell)] [SpellEffectHandler(SpellEffectName.TriggerSpellWithValue)] void EffectTriggerSpell(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget && effectHandleMode != SpellEffectHandleMode.Launch) return; uint triggered_spell_id = effectInfo.TriggerSpell; // @todo move those to spell scripts if (effectInfo.Effect == SpellEffectName.TriggerSpell && effectHandleMode == SpellEffectHandleMode.LaunchTarget) { // special cases switch (triggered_spell_id) { // Vanish (not exist) case 18461: { unitTarget.RemoveMovementImpairingAuras(); unitTarget.RemoveAurasByType(AuraType.ModStalked); return; } // Demonic Empowerment -- succubus case 54437: { unitTarget.RemoveMovementImpairingAuras(); unitTarget.RemoveAurasByType(AuraType.ModStalked); unitTarget.RemoveAurasByType(AuraType.ModStun); // Cast Lesser Invisibility unitTarget.CastSpell(unitTarget, 7870, true); return; } // Brittle Armor - (need add max stack of 24575 Brittle Armor) case 29284: { // Brittle Armor SpellInfo spell = Global.SpellMgr.GetSpellInfo(24575); if (spell == null) return; for (uint j = 0; j < spell.StackAmount; ++j) m_caster.CastSpell(unitTarget, spell.Id, true); return; } // Mercurial Shield - (need add max stack of 26464 Mercurial Shield) case 29286: { // Mercurial Shield SpellInfo spell = Global.SpellMgr.GetSpellInfo(26464); if (spell == null) return; for (uint j = 0; j < spell.StackAmount; ++j) m_caster.CastSpell(unitTarget, spell.Id, true); return; } // Cloak of Shadows case 35729: { uint dispelMask = SpellInfo.GetDispelMask(DispelType.ALL); foreach (var iter in unitTarget.GetAppliedAuras()) { // remove all harmful spells on you... SpellInfo spell = iter.Value.GetBase().GetSpellInfo(); if ((spell.DmgClass == SpellDmgClass.Magic // only affect magic spells || (Convert.ToBoolean(spell.GetDispelMask() & dispelMask)) // ignore positive and passive auras && !iter.Value.IsPositive() && !iter.Value.GetBase().IsPassive())) { m_caster.RemoveAura(iter); } } return; } } } // normal case SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id); if (spellInfo == null) { Log.outDebug(LogFilter.Spells, "Spell.EffectTriggerSpell spell {0} tried to trigger unknown spell {1}", m_spellInfo.Id, triggered_spell_id); return; } SpellCastTargets targets = new SpellCastTargets(); if (effectHandleMode == SpellEffectHandleMode.LaunchTarget) { if (!spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, m_caster.GetMap().GetDifficultyID())) return; targets.SetUnitTarget(unitTarget); } else //if (effectHandleMode == SpellEffectHandleMode.Launch) { if (spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, m_caster.GetMap().GetDifficultyID()) && effectInfo.GetProvidedTargetMask().HasAnyFlag(SpellCastTargetFlags.UnitMask)) return; if (spellInfo.GetExplicitTargetMask().HasAnyFlag(SpellCastTargetFlags.DestLocation)) targets.SetDst(m_targets); targets.SetUnitTarget(m_caster); } Dictionary values = new Dictionary(); // set basepoints for trigger with value effect if (effectInfo.Effect == SpellEffectName.TriggerSpellWithValue) { values.Add(SpellValueMod.BasePoint0, damage); values.Add(SpellValueMod.BasePoint1, damage); values.Add(SpellValueMod.BasePoint2, damage); } // original caster guid only for GO cast m_caster.CastSpell(targets, spellInfo, values, TriggerCastFlags.FullMask, null, null, m_originalCasterGUID); } [SpellEffectHandler(SpellEffectName.TriggerMissile)] [SpellEffectHandler(SpellEffectName.TriggerMissileSpellWithValue)] void EffectTriggerMissileSpell(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget && effectHandleMode != SpellEffectHandleMode.Hit) return; uint triggered_spell_id = effectInfo.TriggerSpell; // normal case SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id); if (spellInfo == null) { Log.outDebug(LogFilter.Spells, "Spell.EffectTriggerMissileSpell spell {0} tried to trigger unknown spell {1}", m_spellInfo.Id, triggered_spell_id); return; } SpellCastTargets targets = new SpellCastTargets(); if (effectHandleMode == SpellEffectHandleMode.HitTarget) { if (!spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, m_caster.GetMap().GetDifficultyID())) return; targets.SetUnitTarget(unitTarget); } else //if (effectHandleMode == SpellEffectHandleMode.Hit) { if (spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, m_caster.GetMap().GetDifficultyID()) && effectInfo.GetProvidedTargetMask().HasAnyFlag(SpellCastTargetFlags.UnitMask)) return; if (spellInfo.GetExplicitTargetMask().HasAnyFlag(SpellCastTargetFlags.DestLocation)) targets.SetDst(m_targets); targets.SetUnitTarget(m_caster); } Dictionary values = new Dictionary(); // set basepoints for trigger with value effect if (effectInfo.Effect == SpellEffectName.TriggerMissileSpellWithValue) { // maybe need to set value only when basepoints == 0? values.Add(SpellValueMod.BasePoint0, damage); values.Add(SpellValueMod.BasePoint1, damage); values.Add(SpellValueMod.BasePoint2, damage); } // original caster guid only for GO cast m_caster.CastSpell(targets, spellInfo, values, TriggerCastFlags.FullMask, null, null, m_originalCasterGUID); } [SpellEffectHandler(SpellEffectName.ForceCast)] [SpellEffectHandler(SpellEffectName.ForceCastWithValue)] [SpellEffectHandler(SpellEffectName.ForceCast2)] void EffectForceCast(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; uint triggered_spell_id = effectInfo.TriggerSpell; // normal case SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id); if (spellInfo == null) { Log.outError(LogFilter.Spells, "Spell.EffectForceCast of spell {0}: triggering unknown spell id {1}", m_spellInfo.Id, triggered_spell_id); return; } if (effectInfo.Effect == SpellEffectName.ForceCast && damage != 0) { switch (m_spellInfo.Id) { case 52588: // Skeletal Gryphon Escape case 48598: // Ride Flamebringer Cue unitTarget.RemoveAura((uint)damage); break; case 52463: // Hide In Mine Car case 52349: // Overtake unitTarget.CastCustomSpell(unitTarget, spellInfo.Id, damage, 0, 0, true, null, null, m_originalCasterGUID); return; } } Dictionary values = new Dictionary(); // set basepoints for trigger with value effect if (effectInfo.Effect == SpellEffectName.ForceCastWithValue) { // maybe need to set value only when basepoints == 0? values.Add(SpellValueMod.BasePoint0, damage); values.Add(SpellValueMod.BasePoint1, damage); values.Add(SpellValueMod.BasePoint2, damage); } SpellCastTargets targets = new SpellCastTargets(); targets.SetUnitTarget(m_caster); unitTarget.CastSpell(targets, spellInfo, values, TriggerCastFlags.FullMask); } [SpellEffectHandler(SpellEffectName.TriggerSpell2)] void EffectTriggerRitualOfSummoning(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; uint triggered_spell_id = effectInfo.TriggerSpell; SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id); if (spellInfo == null) { Log.outError(LogFilter.Spells, "EffectTriggerRitualOfSummoning of spell {0}: triggering unknown spell id {1}", m_spellInfo.Id, triggered_spell_id); return; } finish(); m_caster.CastSpell(null, spellInfo, false); } [SpellEffectHandler(SpellEffectName.Jump)] void EffectJump(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) return; if (m_caster.IsInFlight()) return; if (unitTarget == null) return; float x, y, z; unitTarget.GetContactPoint(m_caster, out x, out y, out z, SharedConst.ContactDistance); float speedXY, speedZ; CalculateJumpSpeeds(effectInfo, m_caster.GetExactDist2d(x, y), out speedXY, out speedZ); JumpArrivalCastArgs arrivalCast = new JumpArrivalCastArgs(); arrivalCast.SpellId = effectInfo.TriggerSpell; arrivalCast.Target = unitTarget.GetGUID(); m_caster.GetMotionMaster().MoveJump(x, y, z, 0.0f, speedXY, speedZ, EventId.Jump, false, arrivalCast); } [SpellEffectHandler(SpellEffectName.JumpDest)] void EffectJumpDest(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Launch) return; if (m_caster.IsInFlight()) return; if (!m_targets.HasDst()) return; float speedXY, speedZ; CalculateJumpSpeeds(effectInfo, m_caster.GetExactDist2d(destTarget), out speedXY, out speedZ); JumpArrivalCastArgs arrivalCast = new JumpArrivalCastArgs(); arrivalCast.SpellId = effectInfo.TriggerSpell; m_caster.GetMotionMaster().MoveJump(destTarget, speedXY, speedZ, EventId.Jump, !m_targets.GetObjectTargetGUID().IsEmpty(), arrivalCast); } void CalculateJumpSpeeds(SpellEffectInfo effInfo, float dist, out float speedXY, out float speedZ) { if (effInfo.MiscValue != 0) speedZ = (float)effInfo.MiscValue / 10; else if (effInfo.MiscValueB != 0) speedZ = (float)effInfo.MiscValueB / 10; else speedZ = 10.0f; speedXY = dist * 10.0f / speedZ; } [SpellEffectHandler(SpellEffectName.TeleportUnits)] void EffectTeleportUnits(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || unitTarget.IsInFlight()) return; // If not exist data for dest location - return if (!m_targets.HasDst()) { Log.outError(LogFilter.Spells, "Spell.EffectTeleportUnits - does not have a destination for spellId {0}.", m_spellInfo.Id); return; } // Init dest coordinates uint mapid = destTarget.GetMapId(); if (mapid == 0xFFFFFFFF) mapid = unitTarget.GetMapId(); float x, y, z, orientation; destTarget.GetPosition(out x, out y, out z, out orientation); if (orientation == 0 && m_targets.GetUnitTarget() != null) orientation = m_targets.GetUnitTarget().GetOrientation(); Log.outDebug(LogFilter.Spells, "Spell.EffectTeleportUnits - teleport unit to {0} {1} {2} {3} {4}\n", mapid, x, y, z, orientation); Player player = unitTarget.ToPlayer(); if (player) { // Custom loading screen uint customLoadingScreenId = (uint)effectInfo.MiscValue; if (customLoadingScreenId != 0) player.SendPacket(new CustomLoadScreen(m_spellInfo.Id, customLoadingScreenId)); player.TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TeleportToOptions.Spell | TeleportToOptions.NotLeaveCombat : 0); } else if (mapid == unitTarget.GetMapId()) unitTarget.NearTeleportTo(x, y, z, orientation, unitTarget == m_caster); else { Log.outError(LogFilter.Spells, "Spell.EffectTeleportUnits - spellId {0} attempted to teleport creature to a different map.", m_spellInfo.Id); return; } // post effects for TARGET_DEST_DB switch (m_spellInfo.Id) { // Dimensional Ripper - Everlook case 23442: { int r = RandomHelper.IRand(0, 119); if (r >= 70) // 7/12 success { if (r < 100) // 4/12 evil twin m_caster.CastSpell(m_caster, 23445, true); else // 1/12 fire m_caster.CastSpell(m_caster, 23449, true); } return; } // Ultrasafe Transporter: Toshley's Station case 36941: { if (RandomHelper.randChance(50)) // 50% success { int rand_eff = RandomHelper.IRand(1, 7); switch (rand_eff) { case 1: // soul split - evil m_caster.CastSpell(m_caster, 36900, true); break; case 2: // soul split - good m_caster.CastSpell(m_caster, 36901, true); break; case 3: // Increase the size m_caster.CastSpell(m_caster, 36895, true); break; case 4: // Decrease the size m_caster.CastSpell(m_caster, 36893, true); break; case 5: // Transform { if (m_caster.ToPlayer().GetTeam() == Team.Alliance) m_caster.CastSpell(m_caster, 36897, true); else m_caster.CastSpell(m_caster, 36899, true); break; } case 6: // chicken m_caster.CastSpell(m_caster, 36940, true); break; case 7: // evil twin m_caster.CastSpell(m_caster, 23445, true); break; } } return; } // Dimensional Ripper - Area 52 case 36890: { if (RandomHelper.randChance(50)) // 50% success { int rand_eff = RandomHelper.IRand(1, 4); switch (rand_eff) { case 1: // soul split - evil m_caster.CastSpell(m_caster, 36900, true); break; case 2: // soul split - good m_caster.CastSpell(m_caster, 36901, true); break; case 3: // Increase the size m_caster.CastSpell(m_caster, 36895, true); break; case 4: // Transform { if (m_caster.ToPlayer().GetTeam() == Team.Alliance) m_caster.CastSpell(m_caster, 36897, true); else m_caster.CastSpell(m_caster, 36899, true); break; } } } return; } } } [SpellEffectHandler(SpellEffectName.ApplyAura)] void EffectApplyAura(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (m_spellAura == null || unitTarget == null) return; Contract.Assert(unitTarget == m_spellAura.GetOwner()); m_spellAura._ApplyEffectForTargets(effIndex); } [SpellEffectHandler(SpellEffectName.ApplyAreaAuraEnemy)] [SpellEffectHandler(SpellEffectName.ApplyAreaAuraFriend)] [SpellEffectHandler(SpellEffectName.ApplyAreaAuraOwner)] [SpellEffectHandler(SpellEffectName.ApplyAreaAuraParty)] [SpellEffectHandler(SpellEffectName.ApplyAreaAuraPet)] [SpellEffectHandler(SpellEffectName.ApplyAreaAuraRaid)] void EffectApplyAreaAura(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (m_spellAura == null || unitTarget == null) return; Contract.Assert(unitTarget == m_spellAura.GetOwner()); m_spellAura._ApplyEffectForTargets(effIndex); } [SpellEffectHandler(SpellEffectName.UnlearnSpecialization)] void EffectUnlearnSpecialization(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); uint spellToUnlearn = effectInfo.TriggerSpell; player.RemoveSpell(spellToUnlearn); Log.outDebug(LogFilter.Spells, "Spell: Player {0} has unlearned spell {1} from NpcGUID: {2}", player.GetGUID().ToString(), spellToUnlearn, m_caster.GetGUID().ToString()); } [SpellEffectHandler(SpellEffectName.PowerDrain)] void EffectPowerDrain(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (effectInfo.MiscValue < 0 || effectInfo.MiscValue >= (byte)PowerType.Max) return; PowerType powerType = (PowerType)effectInfo.MiscValue; if (unitTarget == null || !unitTarget.IsAlive() || unitTarget.GetPowerType() != powerType || damage < 0) return; // add spell damage bonus uint bonus = m_caster.SpellDamageBonusDone(unitTarget, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); damage = (int)(bonus + (bonus * variance)); damage = (int)unitTarget.SpellDamageBonusTaken(m_caster, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); int newDamage = -(unitTarget.ModifyPower(powerType, -damage)); float gainMultiplier = 0.0f; // Don't restore from self drain if (m_caster != unitTarget) { gainMultiplier = effectInfo.CalcValueMultiplier(m_originalCaster, this); int gain = (int)(newDamage * gainMultiplier); m_caster.EnergizeBySpell(m_caster, m_spellInfo.Id, gain, powerType); } ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, (uint)newDamage, gainMultiplier); } [SpellEffectHandler(SpellEffectName.SendEvent)] void EffectSendEvent(uint effIndex) { // we do not handle a flag dropping or clicking on flag in Battlegroundby sendevent system if (effectHandleMode != SpellEffectHandleMode.HitTarget && effectHandleMode != SpellEffectHandleMode.Hit) return; WorldObject target = null; // call events for object target if present if (effectHandleMode == SpellEffectHandleMode.HitTarget) { if (unitTarget != null) target = unitTarget; else if (gameObjTarget != null) target = gameObjTarget; } else // if (effectHandleMode == SpellEffectHandleMode.Hit) { // let's prevent executing effect handler twice in case when spell effect is capable of targeting an object // this check was requested by scripters, but it has some downsides: // now it's impossible to script (using sEventScripts) a cast which misses all targets // or to have an ability to script the moment spell hits dest (in a case when there are object targets present) if (effectInfo.GetProvidedTargetMask().HasAnyFlag(SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.GameobjectMask)) return; // some spells have no target entries in dbc and they use focus target if (focusObject != null) target = focusObject; // @todo there should be a possibility to pass dest target to event script } Log.outDebug(LogFilter.Spells, "Spell ScriptStart {0} for spellid {1} in EffectSendEvent ", effectInfo.MiscValue, m_spellInfo.Id); ZoneScript zoneScript = m_caster.GetZoneScript(); InstanceScript instanceScript = m_caster.GetInstanceScript(); if (zoneScript != null) zoneScript.ProcessEvent(target, (uint)effectInfo.MiscValue); else if (instanceScript != null) // needed in case Player is the caster instanceScript.ProcessEvent(target, (uint)effectInfo.MiscValue); m_caster.GetMap().ScriptsStart(ScriptsType.Event, (uint)effectInfo.MiscValue, m_caster, target); } [SpellEffectHandler(SpellEffectName.PowerBurn)] void EffectPowerBurn(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (effectInfo.MiscValue < 0 || effectInfo.MiscValue >= (int)PowerType.Max) return; PowerType powerType = (PowerType)effectInfo.MiscValue; if (unitTarget == null || !unitTarget.IsAlive() || unitTarget.GetPowerType() != powerType || damage < 0) return; int newDamage = -(unitTarget.ModifyPower(powerType, -damage)); // NO - Not a typo - EffectPowerBurn uses effect value multiplier - not effect damage multiplier float dmgMultiplier = effectInfo.CalcValueMultiplier(m_originalCaster, this); // add log data before multiplication (need power amount, not damage) ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, (uint)newDamage, 0.0f); newDamage = (int)(newDamage * dmgMultiplier); m_damage += newDamage; } [SpellEffectHandler(SpellEffectName.Heal)] void EffectHeal(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) return; if (unitTarget != null && unitTarget.IsAlive() && damage >= 0) { // Try to get original caster Unit caster = !m_originalCasterGUID.IsEmpty() ? m_originalCaster : m_caster; // Skip if m_originalCaster not available if (caster == null) return; int addhealth = damage; // Vessel of the Naaru (Vial of the Sunwell trinket) if (m_spellInfo.Id == 45064) { // Amount of heal - depends from stacked Holy Energy int damageAmount = 0; AuraEffect aurEff = m_caster.GetAuraEffect(45062, 0); if (aurEff != null) { damageAmount += aurEff.GetAmount(); m_caster.RemoveAurasDueToSpell(45062); } addhealth += damageAmount; } // Runic Healing Injector (heal increased by 25% for engineers - 3.2.0 patch change) else if (m_spellInfo.Id == 67489) { Player player = m_caster.ToPlayer(); if (player != null) if (player.HasSkill(SkillType.Engineering)) MathFunctions.AddPct(ref addhealth, 25); } // Death Pact - return pct of max health to caster else if (m_spellInfo.SpellFamilyName == SpellFamilyNames.Deathknight && m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x00080000u)) addhealth = (int)caster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)caster.CountPctFromMaxHealth(damage), DamageEffectType.Heal, effectInfo); else { addhealth = (int)caster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)addhealth, DamageEffectType.Heal, effectInfo); uint bonus = caster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)addhealth, DamageEffectType.Heal, effectInfo); damage = (int)(bonus + (bonus * variance)); } addhealth = (int)unitTarget.SpellHealingBonusTaken(caster, m_spellInfo, (uint)addhealth, DamageEffectType.Heal, effectInfo); // Remove Grievious bite if fully healed if (unitTarget.HasAura(48920) && ((uint)(unitTarget.GetHealth() + (ulong)addhealth) >= unitTarget.GetMaxHealth())) unitTarget.RemoveAura(48920); m_damage -= addhealth; } } [SpellEffectHandler(SpellEffectName.HealPct)] void EffectHealPct(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsAlive() || damage < 0) return; // Skip if m_originalCaster not available if (m_originalCaster == null) return; uint heal = m_originalCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)unitTarget.CountPctFromMaxHealth(damage), DamageEffectType.Heal, effectInfo); heal = unitTarget.SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, DamageEffectType.Heal, effectInfo); m_healing += (int)heal; } [SpellEffectHandler(SpellEffectName.HealMechanical)] void EffectHealMechanical(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsAlive() || damage < 0) return; // Skip if m_originalCaster not available if (m_originalCaster == null) return; uint heal = m_originalCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)damage, DamageEffectType.Heal, effectInfo); heal += (uint)(heal * variance); m_healing += (int)unitTarget.SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, DamageEffectType.Heal, effectInfo); } [SpellEffectHandler(SpellEffectName.HealthLeech)] void EffectHealthLeech(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsAlive() || damage < 0) return; uint bonus = m_caster.SpellDamageBonusDone(unitTarget, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); damage = (int)(bonus + (bonus * variance)); damage = (int)unitTarget.SpellDamageBonusTaken(m_caster, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); Log.outDebug(LogFilter.Spells, "HealthLeech :{0}", damage); float healMultiplier = effectInfo.CalcValueMultiplier(m_originalCaster, this); m_damage += damage; // get max possible damage, don't count overkill for heal uint healthGain = (uint)(-unitTarget.GetHealthGain(-damage) * healMultiplier); if (m_caster.IsAlive()) { healthGain = m_caster.SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, DamageEffectType.Heal, effectInfo); healthGain = m_caster.SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, DamageEffectType.Heal, effectInfo); HealInfo healInfo = new HealInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellSchoolMask); m_caster.HealBySpell(healInfo); } } public void DoCreateItem(uint i, uint itemtype, byte context = 0, List bonusListIds = null) { if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); uint newitemid = itemtype; ItemTemplate pProto = Global.ObjectMgr.GetItemTemplate(newitemid); if (pProto == null) { player.SendEquipError(InventoryResult.ItemNotFound); return; } // bg reward have some special in code work BattlegroundTypeId bgType = 0; switch ((BattlegroundMarks)m_spellInfo.Id) { case BattlegroundMarks.SpellAvMarkWinner: case BattlegroundMarks.SpellAvMarkLoser: bgType = BattlegroundTypeId.AV; break; case BattlegroundMarks.SpellWsMarkWinner: case BattlegroundMarks.SpellWsMarkLoser: bgType = BattlegroundTypeId.WS; break; case BattlegroundMarks.SpellAbMarkWinner: case BattlegroundMarks.SpellAbMarkLoser: bgType = BattlegroundTypeId.AB; break; default: break; } uint num_to_add = (uint)damage; if (num_to_add < 1) num_to_add = 1; if (num_to_add > pProto.GetMaxStackSize()) num_to_add = pProto.GetMaxStackSize(); // this is bad, should be done using spell_loot_template (and conditions) // the chance of getting a perfect result float perfectCreateChance = 0.0f; // the resulting perfect item if successful uint perfectItemType = itemtype; // get perfection capability and chance if (SkillPerfectItems.CanCreatePerfectItem(player, m_spellInfo.Id, ref perfectCreateChance, ref perfectItemType)) if (RandomHelper.randChance(perfectCreateChance)) // if the roll succeeds... newitemid = perfectItemType; // the perfect item replaces the regular one // init items_count to 1, since 1 item will be created regardless of specialization int items_count = 1; // the chance to create additional items float additionalCreateChance = 0.0f; // the maximum number of created additional items byte additionalMaxNum = 0; // get the chance and maximum number for creating extra items if (SkillExtraItems.CanCreateExtraItems(player, m_spellInfo.Id, ref additionalCreateChance, ref additionalMaxNum)) { // roll with this chance till we roll not to create or we create the max num while (RandomHelper.randChance(additionalCreateChance) && items_count <= additionalMaxNum) ++items_count; } // really will be created more items num_to_add *= (uint)items_count; // can the player store the new item? List dest = new List(); uint no_space = 0; InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, newitemid, num_to_add, out no_space); if (msg != InventoryResult.Ok) { // convert to possible store amount if (msg == InventoryResult.InvFull || msg == InventoryResult.ItemMaxCount) num_to_add -= no_space; else { // if not created by another reason from full inventory or unique items amount limitation player.SendEquipError(msg, null, null, newitemid); return; } } if (num_to_add != 0) { // create the new item and store it Item pItem = player.StoreNewItem(dest, newitemid, true, ItemEnchantment.GenerateItemRandomPropertyId(newitemid), null, context, bonusListIds); // was it successful? return error if not if (pItem == null) { player.SendEquipError(InventoryResult.ItemNotFound); return; } // set the "Crafted by ..." property of the item if (pItem.GetTemplate().GetClass() != ItemClass.Consumable && pItem.GetTemplate().GetClass() != ItemClass.Quest && newitemid != 6265 && newitemid != 6948) pItem.SetGuidValue(ItemFields.Creator, player.GetGUID()); // send info to the client player.SendNewItem(pItem, num_to_add, true, bgType == 0); if (pItem.GetQuality() > ItemQuality.Epic || (pItem.GetQuality() == ItemQuality.Epic && pItem.GetItemLevel(player) >= GuildConst.MinNewsItemLevel)) { Guild guild = player.GetGuild(); if (guild != null) guild.AddGuildNews(GuildNews.ItemCrafted, player.GetGUID(), 0, pProto.GetId()); } // we succeeded in creating at least one item, so a levelup is possible if (bgType == 0) player.UpdateCraftSkill(m_spellInfo.Id); } } [SpellEffectHandler(SpellEffectName.CreateItem)] void EffectCreateItem(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; DoCreateItem(effIndex, effectInfo.ItemType); ExecuteLogEffectCreateItem(effIndex, effectInfo.ItemType); } [SpellEffectHandler(SpellEffectName.CreateLoot)] void EffectCreateItem2(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); uint item_id = effectInfo.ItemType; if (item_id != 0) DoCreateItem(effIndex, item_id); // special case: fake item replaced by generate using spell_loot_template if (m_spellInfo.IsLootCrafting()) { if (item_id != 0) { if (!player.HasItemCount(item_id)) return; // remove reagent uint count = 1; player.DestroyItemCount(item_id, count, true); // create some random items player.AutoStoreLoot(m_spellInfo.Id, LootStorage.Spell); } else player.AutoStoreLoot(m_spellInfo.Id, LootStorage.Spell); // create some random items player.UpdateCraftSkill(m_spellInfo.Id); } // @todo ExecuteLogEffectCreateItem(i, GetEffect(i].ItemType); } [SpellEffectHandler(SpellEffectName.CreateRandomItem)] void EffectCreateRandomItem(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); // create some random items player.AutoStoreLoot(m_spellInfo.Id, LootStorage.Spell); // @todo ExecuteLogEffectCreateItem(i, GetEffect(i].ItemType); } [SpellEffectHandler(SpellEffectName.PersistentAreaAura)] void EffectPersistentAA(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (m_spellAura == null) { Unit caster = m_caster.GetEntry() == SharedConst.WorldTrigger ? m_originalCaster : m_caster; float radius = effectInfo.CalcRadius(caster); // Caster not in world, might be spell triggered from aura removal if (!caster.IsInWorld) return; DynamicObject dynObj = new DynamicObject(false); if (!dynObj.CreateDynamicObject(caster.GetMap().GenerateLowGuid(HighGuid.DynamicObject), caster, m_spellInfo, destTarget, radius, DynamicObjectType.AreaSpell, m_SpellVisual)) return; Aura aura = Aura.TryCreate(m_spellInfo, m_castId, SpellConst.MaxEffectMask, dynObj, caster, m_spellValue.EffectBasePoints, null, ObjectGuid.Empty, ObjectGuid.Empty, m_castItemLevel); if (aura != null) { m_spellAura = aura; m_spellAura._RegisterForTargets(); } else return; } Contract.Assert(m_spellAura.GetDynobjOwner()); m_spellAura._ApplyEffectForTargets(effIndex); } [SpellEffectHandler(SpellEffectName.Energize)] void EffectEnergize(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; if (!unitTarget.IsAlive()) return; if (effectInfo.MiscValue < 0 || effectInfo.MiscValue >= (byte)PowerType.Max) return; PowerType power = (PowerType)effectInfo.MiscValue; if (unitTarget.GetMaxPower(power) == 0) return; // Some level depends spells int level_multiplier = 0; int level_diff = 0; switch (m_spellInfo.Id) { case 9512: // Restore Energy level_diff = (int)m_caster.getLevel() - 40; level_multiplier = 2; break; case 24571: // Blood Fury level_diff = (int)m_caster.getLevel() - 60; level_multiplier = 10; break; case 24532: // Burst of Energy level_diff = (int)m_caster.getLevel() - 60; level_multiplier = 4; break; case 31930: // Judgements of the Wise case 63375: // Primal Wisdom case 68082: // Glyph of Seal of Command damage = (int)MathFunctions.CalculatePct(unitTarget.GetCreateMana(), damage); break; case 67490: // Runic Mana Injector (mana gain increased by 25% for engineers - 3.2.0 patch change) { Player player = m_caster.ToPlayer(); if (player != null) if (player.HasSkill(SkillType.Engineering)) MathFunctions.AddPct(ref damage, 25); break; } default: break; } if (level_diff > 0) damage -= level_multiplier * level_diff; if (damage < 0 && power != PowerType.LunarPower) return; m_caster.EnergizeBySpell(unitTarget, m_spellInfo.Id, damage, power); // Mad Alchemist's Potion if (m_spellInfo.Id == 45051) { // find elixirs on target bool guardianFound = false; bool battleFound = false; foreach (var app in unitTarget.GetAppliedAuras()) { uint spell_id = app.Value.GetBase().GetId(); if (!guardianFound) if (Global.SpellMgr.IsSpellMemberOfSpellGroup(spell_id, SpellGroup.ElixirGuardian)) guardianFound = true; if (!battleFound) if (Global.SpellMgr.IsSpellMemberOfSpellGroup(spell_id, SpellGroup.ElixirBattle)) battleFound = true; if (battleFound && guardianFound) break; } // get all available elixirs by mask and spell level List avalibleElixirs = new List(); if (!guardianFound) Global.SpellMgr.GetSetOfSpellsInSpellGroup(SpellGroup.ElixirGuardian, out avalibleElixirs); if (!battleFound) Global.SpellMgr.GetSetOfSpellsInSpellGroup(SpellGroup.ElixirBattle, out avalibleElixirs); foreach (int spellId in avalibleElixirs) { SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)spellId); if (spellInfo.SpellLevel < m_spellInfo.SpellLevel || spellInfo.SpellLevel > unitTarget.getLevel()) avalibleElixirs.Remove(spellId); else if (Global.SpellMgr.IsSpellMemberOfSpellGroup((uint)spellId, SpellGroup.ElixirShattrath)) avalibleElixirs.Remove(spellId); else if (Global.SpellMgr.IsSpellMemberOfSpellGroup((uint)spellId, SpellGroup.ElixirUnstable)) avalibleElixirs.Remove(spellId); } if (!avalibleElixirs.Empty()) { // cast random elixir on target m_caster.CastSpell(unitTarget, (uint)avalibleElixirs.SelectRandom(), true, m_CastItem); } } } [SpellEffectHandler(SpellEffectName.EnergizePct)] void EffectEnergizePct(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; if (!unitTarget.IsAlive()) return; if (effectInfo.MiscValue < 0 || effectInfo.MiscValue >= (byte)PowerType.Max) return; PowerType power = (PowerType)effectInfo.MiscValue; uint maxPower = (uint)unitTarget.GetMaxPower(power); if (maxPower == 0) return; int gain = (int)MathFunctions.CalculatePct(maxPower, damage); m_caster.EnergizeBySpell(unitTarget, m_spellInfo.Id, gain, power); } void SendLoot(ObjectGuid guid, LootType loottype) { Player player = m_caster.ToPlayer(); if (player == null) return; if (gameObjTarget != null) { // Players shouldn't be able to loot gameobjects that are currently despawned if (!gameObjTarget.isSpawned() && !player.IsGameMaster()) { Log.outError(LogFilter.Spells, "Possible hacking attempt: Player {0} [{1}] tried to loot a gameobject [{2}] which is on respawn time without being in GM mode!", player.GetName(), player.GetGUID().ToString(), gameObjTarget.GetGUID().ToString()); return; } // special case, already has GossipHello inside so return and avoid calling twice if (gameObjTarget.GetGoType() == GameObjectTypes.Goober) { gameObjTarget.Use(m_caster); return; } if (Global.ScriptMgr.OnGossipHello(player, gameObjTarget)) return; if (gameObjTarget.GetAI().GossipHello(player, true)) return; switch (gameObjTarget.GetGoType()) { case GameObjectTypes.Door: case GameObjectTypes.Button: gameObjTarget.UseDoorOrButton(0, false, player); return; case GameObjectTypes.QuestGiver: player.PrepareGossipMenu(gameObjTarget, gameObjTarget.GetGoInfo().QuestGiver.gossipID, true); player.SendPreparedGossip(gameObjTarget); return; case GameObjectTypes.SpellFocus: // triggering linked GO uint trapEntry = gameObjTarget.GetGoInfo().SpellFocus.linkedTrap; if (trapEntry != 0) gameObjTarget.TriggeringLinkedGameObject(trapEntry, m_caster); return; case GameObjectTypes.Chest: // @todo possible must be moved to loot release (in different from linked triggering) if (gameObjTarget.GetGoInfo().Chest.triggeredEvent != 0) { Log.outDebug(LogFilter.Spells, "Chest ScriptStart id {0} for GO {1}", gameObjTarget.GetGoInfo().Chest.triggeredEvent, gameObjTarget.GetSpawnId()); player.GetMap().ScriptsStart(ScriptsType.Event, gameObjTarget.GetGoInfo().Chest.triggeredEvent, player, gameObjTarget); } // triggering linked GO uint _trapEntry = gameObjTarget.GetGoInfo().Chest.linkedTrap; if (_trapEntry != 0) gameObjTarget.TriggeringLinkedGameObject(_trapEntry, m_caster); break; // Don't return, let loots been taken default: break; } } // Send loot player.SendLoot(guid, loottype); } [SpellEffectHandler(SpellEffectName.OpenLock)] void EffectOpenLock(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!m_caster.IsTypeId(TypeId.Player)) { Log.outDebug(LogFilter.Spells, "WORLD: Open Lock - No Player Caster!"); return; } Player player = m_caster.ToPlayer(); uint lockId = 0; ObjectGuid guid = ObjectGuid.Empty; // Get lockId if (gameObjTarget != null) { GameObjectTemplate goInfo = gameObjTarget.GetGoInfo(); // Arathi Basin banner opening. // @todo Verify correctness of this check if ((goInfo.type == GameObjectTypes.Button && goInfo.Button.noDamageImmune != 0) || (goInfo.type == GameObjectTypes.Goober && goInfo.Goober.requireLOS != 0)) { //CanUseBattlegroundObject() already called in CheckCast() // in Battlegroundcheck Battleground bg = player.GetBattleground(); if (bg) { bg.EventPlayerClickedOnFlag(player, gameObjTarget); return; } } else if (goInfo.type == GameObjectTypes.FlagStand) { //CanUseBattlegroundObject() already called in CheckCast() // in Battlegroundcheck Battleground bg = player.GetBattleground(); if (bg) { if (bg.GetTypeID(true) == BattlegroundTypeId.EY) bg.EventPlayerClickedOnFlag(player, gameObjTarget); return; } } else if (m_spellInfo.Id == 1842 && gameObjTarget.GetGoInfo().type == GameObjectTypes.Trap && gameObjTarget.GetOwner() != null) { gameObjTarget.SetLootState(LootState.JustDeactivated); return; } // @todo Add script for spell 41920 - Filling, becouse server it freze when use this spell // handle outdoor pvp object opening, return true if go was registered for handling // these objects must have been spawned by outdoorpvp! else if (gameObjTarget.GetGoInfo().type == GameObjectTypes.Goober && Global.OutdoorPvPMgr.HandleOpenGo(player, gameObjTarget)) return; lockId = goInfo.GetLockId(); guid = gameObjTarget.GetGUID(); } else if (itemTarget != null) { lockId = itemTarget.GetTemplate().GetLockID(); guid = itemTarget.GetGUID(); } else { Log.outDebug(LogFilter.Spells, "WORLD: Open Lock - No GameObject/Item Target!"); return; } SkillType skillId = SkillType.None; int reqSkillValue = 0; int skillValue = 0; SpellCastResult res = CanOpenLock(effIndex, lockId, ref skillId, ref reqSkillValue, ref skillValue); if (res != SpellCastResult.SpellCastOk) { SendCastResult(res); return; } if (gameObjTarget != null) SendLoot(guid, LootType.Skinning); else if (itemTarget != null) { itemTarget.SetFlag(ItemFields.Flags, ItemFieldFlags.Unlocked); itemTarget.SetState(ItemUpdateState.Changed, itemTarget.GetOwner()); } // not allow use skill grow at item base open if (m_CastItem == null && skillId != SkillType.None) { // update skill if really known uint pureSkillValue = player.GetPureSkillValue(skillId); if (pureSkillValue != 0) { if (gameObjTarget != null) { // Allow one skill-up until respawned if (!gameObjTarget.IsInSkillupList(player.GetGUID()) && player.UpdateGatherSkill(skillId, pureSkillValue, (uint)reqSkillValue)) gameObjTarget.AddToSkillupList(player.GetGUID()); } else if (itemTarget != null) { // Do one skill-up player.UpdateGatherSkill(skillId, pureSkillValue, (uint)reqSkillValue); } } } ExecuteLogEffectOpenLock(effIndex, gameObjTarget != null ? gameObjTarget : (WorldObject)itemTarget); } [SpellEffectHandler(SpellEffectName.SummonChangeItem)] void EffectSummonChangeItem(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!m_caster.IsTypeId(TypeId.Player)) return; Player player = m_caster.ToPlayer(); // applied only to using item if (m_CastItem == null) return; // ... only to item in own inventory/bank/equip_slot if (m_CastItem.GetOwnerGUID() != player.GetGUID()) return; uint newitemid = effectInfo.ItemType; if (newitemid == 0) return; ushort pos = m_CastItem.GetPos(); Item pNewItem = Item.CreateItem(newitemid, 1, player); if (pNewItem == null) return; for (var j = EnchantmentSlot.Perm; j <= EnchantmentSlot.Temp; ++j) if (m_CastItem.GetEnchantmentId(j) != 0) pNewItem.SetEnchantment(j, m_CastItem.GetEnchantmentId(j), m_CastItem.GetEnchantmentDuration(j), m_CastItem.GetEnchantmentCharges(j)); if (m_CastItem.GetUInt32Value(ItemFields.Durability) < m_CastItem.GetUInt32Value(ItemFields.MaxDurability)) { double lossPercent = 1 - m_CastItem.GetUInt32Value(ItemFields.Durability) / (double)m_CastItem.GetUInt32Value(ItemFields.MaxDurability); player.DurabilityLoss(pNewItem, lossPercent); } if (player.IsInventoryPos(pos)) { List dest = new List(); InventoryResult msg = player.CanStoreItem(m_CastItem.GetBagSlot(), m_CastItem.GetSlot(), dest, pNewItem, true); if (msg == InventoryResult.Ok) { player.DestroyItem(m_CastItem.GetBagSlot(), m_CastItem.GetSlot(), true); // prevent crash at access and unexpected charges counting with item update queue corrupt if (m_CastItem == m_targets.GetItemTarget()) m_targets.SetItemTarget(null); m_CastItem = null; m_castItemGUID.Clear(); m_castItemEntry = 0; m_castItemLevel = -1; player.StoreItem(dest, pNewItem, true); return; } } else if (Player.IsBankPos(pos)) { List dest = new List(); InventoryResult msg = player.CanBankItem(m_CastItem.GetBagSlot(), m_CastItem.GetSlot(), dest, pNewItem, true); if (msg == InventoryResult.Ok) { player.DestroyItem(m_CastItem.GetBagSlot(), m_CastItem.GetSlot(), true); // prevent crash at access and unexpected charges counting with item update queue corrupt if (m_CastItem == m_targets.GetItemTarget()) m_targets.SetItemTarget(null); m_CastItem = null; m_castItemGUID.Clear(); m_castItemEntry = 0; m_castItemLevel = -1; player.BankItem(dest, pNewItem, true); return; } } else if (Player.IsEquipmentPos(pos)) { ushort dest; player.DestroyItem(m_CastItem.GetBagSlot(), m_CastItem.GetSlot(), true); InventoryResult msg = player.CanEquipItem(m_CastItem.GetSlot(), out dest, pNewItem, true); if (msg == InventoryResult.Ok || msg == InventoryResult.ClientLockedOut) { if (msg == InventoryResult.ClientLockedOut) dest = EquipmentSlot.MainHand; // prevent crash at access and unexpected charges counting with item update queue corrupt if (m_CastItem == m_targets.GetItemTarget()) m_targets.SetItemTarget(null); m_CastItem = null; m_castItemGUID.Clear(); m_castItemEntry = 0; m_castItemLevel = -1; player.EquipItem(dest, pNewItem, true); player.AutoUnequipOffhandIfNeed(); return; } } } [SpellEffectHandler(SpellEffectName.Proficiency)] void EffectProficiency(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!m_caster.IsTypeId(TypeId.Player)) return; Player p_target = m_caster.ToPlayer(); uint subClassMask = (uint)m_spellInfo.EquippedItemSubClassMask; if (m_spellInfo.EquippedItemClass == ItemClass.Weapon && !Convert.ToBoolean(p_target.GetWeaponProficiency() & subClassMask)) { p_target.AddWeaponProficiency(subClassMask); p_target.SendProficiency(ItemClass.Weapon, p_target.GetWeaponProficiency()); } if (m_spellInfo.EquippedItemClass == ItemClass.Armor && !Convert.ToBoolean(p_target.GetArmorProficiency() & subClassMask)) { p_target.AddArmorProficiency(subClassMask); p_target.SendProficiency(ItemClass.Armor, p_target.GetArmorProficiency()); } } [SpellEffectHandler(SpellEffectName.Summon)] void EffectSummonType(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; uint entry = (uint)effectInfo.MiscValue; if (entry == 0) return; SummonPropertiesRecord properties = CliDB.SummonPropertiesStorage.LookupByKey(effectInfo.MiscValueB); if (properties == null) { Log.outError(LogFilter.Spells, "EffectSummonType: Unhandled summon type {0}", effectInfo.MiscValueB); return; } if (m_originalCaster == null) return; int duration = m_spellInfo.CalcDuration(m_originalCaster); TempSummon summon = null; // determine how many units should be summoned uint numSummons; // some spells need to summon many units, for those spells number of summons is stored in effect value // however so far noone found a generic check to find all of those (there's no related data in summonproperties.dbc // and in spell attributes, possibly we need to add a table for those) // so here's a list of MiscValueB values, which is currently most generic check switch (effectInfo.MiscValueB) { case 64: case 61: case 1101: case 66: case 648: case 2301: case 1061: case 1261: case 629: case 181: case 715: case 1562: case 833: case 1161: case 713: numSummons = (uint)(damage > 0 ? damage : 1); break; default: numSummons = 1; break; } switch (properties.Category) { case SummonCategory.Wild: case SummonCategory.Ally: case SummonCategory.Unk: if (Convert.ToBoolean(properties.Flags & 512)) { SummonGuardian(effIndex, entry, properties, numSummons); break; } switch (properties.Type) { case SummonType.Pet: case SummonType.Guardian: case SummonType.Guardian2: case SummonType.Minion: SummonGuardian(effIndex, entry, properties, numSummons); break; // Summons a vehicle, but doesn't force anyone to enter it (see SUMMON_CATEGORY_VEHICLE) case SummonType.Vehicle: case SummonType.Vehicle2: summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id); break; case SummonType.LightWell: case SummonType.Totem: { summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id); if (summon == null || !summon.IsTotem()) return; if (damage != 0) // if not spell info, DB values used { summon.SetMaxHealth((uint)damage); summon.SetHealth((uint)damage); } break; } case SummonType.Minipet: { summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id); if (summon == null || !summon.HasUnitTypeMask(UnitTypeMask.Minion)) return; summon.SelectLevel(); // some summoned creaters have different from 1 DB data for level/hp summon.SetUInt64Value(UnitFields.NpcFlags, (ulong)summon.GetCreatureTemplate().Npcflag); summon.SetFlag(UnitFields.Flags, UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc); summon.GetAI().EnterEvadeMode(); break; } default: { float radius = effectInfo.CalcRadius(); TempSummonType summonType = (duration == 0) ? TempSummonType.DeadDespawn : TempSummonType.TimedDespawn; for (uint count = 0; count < numSummons; ++count) { Position pos = new Position(); if (count == 0) pos = destTarget; else // randomize position for multiple summons m_caster.GetRandomPoint(destTarget, radius, out pos); summon = m_originalCaster.SummonCreature(entry, pos, summonType, (uint)duration); if (summon == null) continue; if (properties.Category == SummonCategory.Ally) { summon.SetOwnerGUID(m_originalCaster.GetGUID()); summon.SetFaction(m_originalCaster.getFaction()); summon.SetUInt32Value(UnitFields.CreatedBySpell, m_spellInfo.Id); } ExecuteLogEffectSummonObject(effIndex, summon); } return; } }//switch break; case SummonCategory.Pet: SummonGuardian(effIndex, entry, properties, numSummons); break; case SummonCategory.Puppet: summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id); break; case SummonCategory.Vehicle: // Summoning spells (usually triggered by npc_spellclick) that spawn a vehicle and that cause the clicker // to cast a ride vehicle spell on the summoned unit. summon = m_originalCaster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_caster, m_spellInfo.Id); if (summon == null || !summon.IsVehicle()) return; // The spell that this effect will trigger. It has SPELL_AURA_CONTROL_VEHICLE uint spellId = SharedConst.VehicleSpellRideHardcoded; SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effectInfo.CalcValue()); if (spellInfo != null && spellInfo.HasAura(m_originalCaster.GetMap().GetDifficultyID(), AuraType.ControlVehicle)) spellId = spellInfo.Id; // Hard coded enter vehicle spell m_originalCaster.CastSpell(summon, spellId, true); uint faction = properties.Faction; if (faction == 0) faction = m_originalCaster.getFaction(); summon.SetFaction(faction); break; } if (summon != null) { summon.SetCreatorGUID(m_originalCaster.GetGUID()); ExecuteLogEffectSummonObject(effIndex, summon); } } [SpellEffectHandler(SpellEffectName.LearnSpell)] void EffectLearnSpell(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; if (!unitTarget.IsTypeId(TypeId.Player)) { if (unitTarget.IsPet()) EffectLearnPetSpell(effIndex); return; } Player player = unitTarget.ToPlayer(); uint spellToLearn = (m_spellInfo.Id == 483 || m_spellInfo.Id == 55884) ? (uint)damage : effectInfo.TriggerSpell; player.LearnSpell(spellToLearn, false); Log.outDebug(LogFilter.Spells, "Spell: Player {0} has learned spell {1} from NpcGUID={2}", player.GetGUID().ToString(), spellToLearn, m_caster.GetGUID().ToString()); } [SpellEffectHandler(SpellEffectName.Dispel)] void EffectDispel(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; // Create dispel mask by dispel type uint dispel_type = (uint)effectInfo.MiscValue; uint dispelMask = SpellInfo.GetDispelMask((DispelType)dispel_type); List dispel_list = unitTarget.GetDispellableAuraList(m_caster, dispelMask); if (dispel_list.Empty()) return; // Ok if exist some buffs for dispel try dispel it List success_list = new List(); DispelFailed dispelFailed = new DispelFailed(); dispelFailed.CasterGUID = m_caster.GetGUID(); dispelFailed.VictimGUID = unitTarget.GetGUID(); dispelFailed.SpellID = m_spellInfo.Id; // dispel N = damage buffs (or while exist buffs for dispel) for (int count = 0; count < damage && !dispel_list.Empty();) { // Random select buff for dispel var pair = dispel_list[RandomHelper.IRand(0, dispel_list.Count - 1)]; int chance = pair.aura.CalcDispelChance(unitTarget, !unitTarget.IsFriendlyTo(m_caster)); // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance." if (chance == 0) { dispel_list.Remove(pair); continue; } else { if (RandomHelper.randChance(chance)) { bool alreadyListed = false; foreach (var successPair in success_list) { var successValue = successPair.value; if (successPair.aura.GetId() == pair.aura.GetId()) { ++successPair.value; alreadyListed = true; } } if (!alreadyListed) success_list.Add(new DispelCharges(pair.aura, 1)); --pair.value; if (pair.value <= 0) dispel_list.Remove(pair); } else dispelFailed.FailedSpells.Add(pair.aura.GetId()); ++count; } } if (!dispelFailed.FailedSpells.Empty()) m_caster.SendMessageToSet(dispelFailed, true); if (success_list.Empty()) return; SpellDispellLog spellDispellLog = new SpellDispellLog(); spellDispellLog.IsBreak = false; // TODO: use me spellDispellLog.IsSteal = false; spellDispellLog.TargetGUID = unitTarget.GetGUID(); spellDispellLog.CasterGUID = m_caster.GetGUID(); spellDispellLog.DispelledBySpellID = m_spellInfo.Id; foreach (var dispellCharge in success_list) { var dispellData = new SpellDispellData(); dispellData.SpellID = dispellCharge.aura.GetId(); dispellData.Harmful = false; // TODO: use me //dispellData.Rolled = none; // TODO: use me //dispellData.Needed = none; // TODO: use me unitTarget.RemoveAurasDueToSpellByDispel(dispellCharge.aura.GetId(), m_spellInfo.Id, dispellCharge.aura.GetCasterGUID(), m_caster, dispellCharge.value); spellDispellLog.DispellData.Add(dispellData); } m_caster.SendMessageToSet(spellDispellLog, true); CallScriptSuccessfulDispel(effIndex); } [SpellEffectHandler(SpellEffectName.DualWield)] void EffectDualWield(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; unitTarget.SetCanDualWield(true); if (unitTarget.IsTypeId(TypeId.Unit)) unitTarget.ToCreature().UpdateDamagePhysical(WeaponAttackType.OffAttack); } [SpellEffectHandler(SpellEffectName.Pull)] void EffectPull(uint effIndex) { // @todo create a proper pull towards distract spell center for distract EffectUnused(effIndex); } [SpellEffectHandler(SpellEffectName.Distract)] void EffectDistract(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; // Check for possible target if (unitTarget == null || unitTarget.IsInCombat()) return; // target must be OK to do this if (unitTarget.HasUnitState(UnitState.Confused | UnitState.Stunned | UnitState.Fleeing)) return; unitTarget.SetFacingTo(unitTarget.GetAngle(destTarget)); unitTarget.ClearUnitState(UnitState.Moving); if (unitTarget.IsTypeId(TypeId.Unit)) unitTarget.GetMotionMaster().MoveDistract((uint)(damage * Time.InMilliseconds)); } [SpellEffectHandler(SpellEffectName.Pickpocket)] void EffectPickPocket(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!m_caster.IsTypeId(TypeId.Player)) return; // victim must be creature and attackable if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Unit) || m_caster.IsFriendlyTo(unitTarget)) return; // victim have to be alive and humanoid or undead if (unitTarget.IsAlive() && (unitTarget.GetCreatureTypeMask() & (uint)CreatureType.MaskHumanoidOrUndead) != 0) m_caster.ToPlayer().SendLoot(unitTarget.GetGUID(), LootType.Pickpocketing); } [SpellEffectHandler(SpellEffectName.AddFarsight)] void EffectAddFarsight(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!m_caster.IsTypeId(TypeId.Player)) return; float radius = effectInfo.CalcRadius(); int duration = m_spellInfo.CalcDuration(m_caster); // Caster not in world, might be spell triggered from aura removal if (!m_caster.IsInWorld) return; DynamicObject dynObj = new DynamicObject(true); if (!dynObj.CreateDynamicObject(m_caster.GetMap().GenerateLowGuid(HighGuid.DynamicObject), m_caster, m_spellInfo, destTarget, radius, DynamicObjectType.FarsightFocus, m_SpellVisual)) return; dynObj.SetDuration(duration); dynObj.SetCasterViewpoint(); } [SpellEffectHandler(SpellEffectName.UntrainTalents)] void EffectUntrainTalents(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || m_caster.IsTypeId(TypeId.Player)) return; ObjectGuid guid = m_caster.GetGUID(); if (!guid.IsEmpty()) // the trainer is the caster unitTarget.ToPlayer().SendRespecWipeConfirm(guid, unitTarget.ToPlayer().GetNextResetTalentsCost()); } [SpellEffectHandler(SpellEffectName.TeleportUnitsFaceCaster)] void EffectTeleUnitsFaceCaster(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; if (unitTarget.IsInFlight()) return; float dis = effectInfo.CalcRadius(m_caster); float fx, fy, fz; m_caster.GetClosePoint(out fx, out fy, out fz, unitTarget.GetObjectSize(), dis); unitTarget.NearTeleportTo(fx, fy, fz, -m_caster.GetOrientation(), unitTarget == m_caster); } [SpellEffectHandler(SpellEffectName.SkillStep)] void EffectLearnSkill(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget.IsTypeId(TypeId.Player)) return; if (damage < 0) return; uint skillid = (uint)effectInfo.MiscValue; SkillRaceClassInfoRecord rcEntry = Global.DB2Mgr.GetSkillRaceClassInfo(skillid, unitTarget.GetRace(), unitTarget.GetClass()); if (rcEntry == null) return; SkillTiersEntry tier = Global.ObjectMgr.GetSkillTier(rcEntry.SkillTierID); if (tier == null) return; ushort skillval = unitTarget.ToPlayer().GetPureSkillValue((SkillType)skillid); unitTarget.ToPlayer().SetSkill(skillid, (uint)effectInfo.CalcValue(), Math.Max(skillval, (ushort)1), tier.Value[damage - 1]); } [SpellEffectHandler(SpellEffectName.PlayMovie)] void EffectPlayMovie(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget.IsTypeId(TypeId.Player)) return; uint movieId = (uint)effectInfo.MiscValue; if (!CliDB.MovieStorage.ContainsKey(movieId)) return; unitTarget.ToPlayer().SendMovieStart(movieId); } [SpellEffectHandler(SpellEffectName.TradeSkill)] void EffectTradeSkill(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!m_caster.IsTypeId(TypeId.Player)) return; // uint skillid = GetEffect(i].MiscValue; // ushort skillmax = unitTarget.ToPlayer().(skillid); // m_caster.ToPlayer().SetSkill(skillid, skillval?skillval:1, skillmax+75); } [SpellEffectHandler(SpellEffectName.EnchantItem)] void EffectEnchantItemPerm(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (itemTarget == null) return; Player player = m_caster.ToPlayer(); if (player == null) return; // Handle vellums if (itemTarget.IsVellum()) { // destroy one vellum from stack uint count = 1; player.DestroyItemCount(itemTarget, ref count, true); unitTarget = player; // and add a scroll DoCreateItem(effIndex, effectInfo.ItemType); itemTarget = null; m_targets.SetItemTarget(null); } else { // do not increase skill if vellum used if (!(m_CastItem && m_CastItem.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.NoReagentCost))) player.UpdateCraftSkill(m_spellInfo.Id); uint enchant_id = (uint)effectInfo.MiscValue; if (enchant_id == 0) return; SpellItemEnchantmentRecord pEnchant = CliDB.SpellItemEnchantmentStorage.LookupByKey(enchant_id); if (pEnchant == null) return; // item can be in trade slot and have owner diff. from caster Player item_owner = itemTarget.GetOwner(); if (item_owner == null) return; if (item_owner != player && player.GetSession().HasPermission(RBACPermissions.LogGmTrade)) { Log.outCommand(player.GetSession().GetAccountId(), "GM {0} (Account: {1}) enchanting(perm): {2} (Entry: {3}) for player: {4} (Account: {5})", player.GetName(), player.GetSession().GetAccountId(), itemTarget.GetTemplate().GetName(), itemTarget.GetEntry(), item_owner.GetName(), item_owner.GetSession().GetAccountId()); } // remove old enchanting before applying new if equipped item_owner.ApplyEnchantment(itemTarget, EnchantmentSlot.Perm, false); itemTarget.SetEnchantment(EnchantmentSlot.Perm, enchant_id, 0, 0, m_caster.GetGUID()); // add new enchanting if equipped item_owner.ApplyEnchantment(itemTarget, EnchantmentSlot.Perm, true); item_owner.RemoveTradeableItem(itemTarget); itemTarget.ClearSoulboundTradeable(item_owner); } } [SpellEffectHandler(SpellEffectName.EnchantItemPrismatic)] void EffectEnchantItemPrismatic(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (itemTarget == null) return; Player player = m_caster.ToPlayer(); if (player == null) return; uint enchantId = (uint)effectInfo.MiscValue; if (enchantId == 0) return; SpellItemEnchantmentRecord enchant = CliDB.SpellItemEnchantmentStorage.LookupByKey(enchantId); if (enchant == null) return; // support only enchantings with add socket in this slot { bool add_socket = false; for (byte i = 0; i < ItemConst.MaxItemEnchantmentEffects; ++i) { if (enchant.Effect[i] == ItemEnchantmentType.PrismaticSocket) { add_socket = true; break; } } if (!add_socket) { Log.outError(LogFilter.Spells, "Spell.EffectEnchantItemPrismatic: attempt apply enchant spell {0} with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC ({1}) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET ({2}), not suppoted yet.", m_spellInfo.Id, SpellEffectName.EnchantItemPrismatic, ItemEnchantmentType.PrismaticSocket); return; } } // item can be in trade slot and have owner diff. from caster Player item_owner = itemTarget.GetOwner(); if (item_owner == null) return; if (item_owner != player && player.GetSession().HasPermission(RBACPermissions.LogGmTrade)) { Log.outCommand(player.GetSession().GetAccountId(), "GM {0} (Account: {1}) enchanting(perm): {2} (Entry: {3}) for player: {4} (Account: {5})", player.GetName(), player.GetSession().GetAccountId(), itemTarget.GetTemplate().GetName(), itemTarget.GetEntry(), item_owner.GetName(), item_owner.GetSession().GetAccountId()); } // remove old enchanting before applying new if equipped item_owner.ApplyEnchantment(itemTarget, EnchantmentSlot.Prismatic, false); itemTarget.SetEnchantment(EnchantmentSlot.Prismatic, enchantId, 0, 0, m_caster.GetGUID()); // add new enchanting if equipped item_owner.ApplyEnchantment(itemTarget, EnchantmentSlot.Prismatic, true); item_owner.RemoveTradeableItem(itemTarget); itemTarget.ClearSoulboundTradeable(item_owner); } [SpellEffectHandler(SpellEffectName.EnchantItemTemporary)] void EffectEnchantItemTmp(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; Player player = m_caster.ToPlayer(); if (player == null) return; if (itemTarget == null) return; uint enchant_id = (uint)effectInfo.MiscValue; if (enchant_id == 0) { Log.outError(LogFilter.Spells, "Spell {0} Effect {1} (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id", m_spellInfo.Id, effIndex); return; } SpellItemEnchantmentRecord pEnchant = CliDB.SpellItemEnchantmentStorage.LookupByKey(enchant_id); if (pEnchant == null) { Log.outError(LogFilter.Spells, "Spell {0} Effect {1} (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id {2}", m_spellInfo.Id, effIndex, enchant_id); return; } // select enchantment duration uint duration; // rogue family enchantments exception by duration if (m_spellInfo.Id == 38615) duration = 1800; // 30 mins // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints) else if (m_spellInfo.SpellFamilyName == SpellFamilyNames.Rogue) duration = 3600; // 1 hour // shaman family enchantments else if (m_spellInfo.SpellFamilyName == SpellFamilyNames.Shaman) duration = 3600; // 30 mins // other cases with this SpellVisual already selected else if (m_spellInfo.GetSpellVisual() == 215) duration = 1800; // 30 mins // some fishing pole bonuses except Glow Worm which lasts full hour else if (m_spellInfo.GetSpellVisual() == 563 && m_spellInfo.Id != 64401) duration = 600; // 10 mins else if (m_spellInfo.Id == 29702) duration = 300; // 5 mins else if (m_spellInfo.Id == 37360) duration = 300; // 5 mins // default case else duration = 3600; // 1 hour // item can be in trade slot and have owner diff. from caster Player item_owner = itemTarget.GetOwner(); if (item_owner == null) return; if (item_owner != player && player.GetSession().HasPermission(RBACPermissions.LogGmTrade)) { Log.outCommand(player.GetSession().GetAccountId(), "GM {0} (Account: {1}) enchanting(temp): {2} (Entry: {3}) for player: {4} (Account: {5})", player.GetName(), player.GetSession().GetAccountId(), itemTarget.GetTemplate().GetName(), itemTarget.GetEntry(), item_owner.GetName(), item_owner.GetSession().GetAccountId()); } // remove old enchanting before applying new if equipped item_owner.ApplyEnchantment(itemTarget, EnchantmentSlot.Temp, false); itemTarget.SetEnchantment(EnchantmentSlot.Temp, enchant_id, duration * 1000, 0, m_caster.GetGUID()); // add new enchanting if equipped item_owner.ApplyEnchantment(itemTarget, EnchantmentSlot.Temp, true); } [SpellEffectHandler(SpellEffectName.Tamecreature)] void EffectTameCreature(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!m_caster.GetPetGUID().IsEmpty()) return; if (unitTarget == null) return; if (!unitTarget.IsTypeId(TypeId.Unit)) return; Creature creatureTarget = unitTarget.ToCreature(); if (creatureTarget.IsPet()) return; if (m_caster.GetClass() != Class.Hunter) return; // cast finish successfully finish(); Pet pet = m_caster.CreateTamedPetFrom(creatureTarget, m_spellInfo.Id); if (pet == null) // in very specific state like near world end/etc. return; // "kill" original creature creatureTarget.DespawnOrUnsummon(); uint level = (creatureTarget.GetLevelForTarget(m_caster) < (m_caster.GetLevelForTarget(creatureTarget) - 5)) ? (m_caster.GetLevelForTarget(creatureTarget) - 5) : creatureTarget.GetLevelForTarget(m_caster); // prepare visual effect for levelup pet.SetUInt32Value(UnitFields.Level, level - 1); // add to world pet.GetMap().AddToMap(pet.ToCreature()); // visual effect for levelup pet.SetUInt32Value(UnitFields.Level, level); // caster have pet now m_caster.SetMinion(pet, true); if (m_caster.IsTypeId(TypeId.Player)) { pet.SavePetToDB(PetSaveMode.AsCurrent); m_caster.ToPlayer().PetSpellInitialize(); } } [SpellEffectHandler(SpellEffectName.SummonPet)] void EffectSummonPet(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; Player owner = null; if (m_originalCaster != null) { owner = m_originalCaster.ToPlayer(); if (owner == null && m_originalCaster.IsTotem()) owner = m_originalCaster.GetCharmerOrOwnerPlayerOrPlayerItself(); } uint petentry = (uint)effectInfo.MiscValue; if (owner == null) { SummonPropertiesRecord properties = CliDB.SummonPropertiesStorage.LookupByKey(67); if (properties != null) SummonGuardian(effIndex, petentry, properties, 1); return; } Pet OldSummon = owner.GetPet(); // if pet requested type already exist if (OldSummon != null) { if (petentry == 0 || OldSummon.GetEntry() == petentry) { // pet in corpse state can't be summoned if (OldSummon.IsDead()) return; Contract.Assert(OldSummon.GetMap() == owner.GetMap()); float px, py, pz; owner.GetClosePoint(out px, out py, out pz, OldSummon.GetObjectSize()); OldSummon.NearTeleportTo(px, py, pz, OldSummon.GetOrientation()); if (owner.IsTypeId(TypeId.Player) && OldSummon.isControlled()) owner.ToPlayer().PetSpellInitialize(); return; } if (owner.IsTypeId(TypeId.Player)) owner.ToPlayer().RemovePet(OldSummon, (OldSummon.getPetType() == PetType.Hunter ? PetSaveMode.AsDeleted : PetSaveMode.NotInSlot), false); else return; } float x, y, z; owner.GetClosePoint(out x, out y, out z, owner.GetObjectSize()); Pet pet = owner.SummonPet(petentry, x, y, z, owner.Orientation, PetType.Summon, 0); if (!pet) return; if (m_caster.IsTypeId(TypeId.Unit)) { if (m_caster.IsTotem()) pet.SetReactState(ReactStates.Aggressive); else pet.SetReactState(ReactStates.Defensive); } pet.SetUInt32Value(UnitFields.CreatedBySpell, m_spellInfo.Id); // generate new name for summon pet string new_name = Global.ObjectMgr.GeneratePetName(petentry); if (!string.IsNullOrEmpty(new_name)) pet.SetName(new_name); ExecuteLogEffectSummonObject(effIndex, pet); } [SpellEffectHandler(SpellEffectName.LearnPetSpell)] void EffectLearnPetSpell(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; if (unitTarget.ToPlayer() != null) { EffectLearnSpell(effIndex); return; } Pet pet = unitTarget.ToPet(); if (pet == null) return; SpellInfo learn_spellproto = Global.SpellMgr.GetSpellInfo(effectInfo.TriggerSpell); if (learn_spellproto == null) return; pet.learnSpell(learn_spellproto.Id); pet.SavePetToDB(PetSaveMode.AsCurrent); pet.GetOwner().PetSpellInitialize(); } [SpellEffectHandler(SpellEffectName.AttackMe)] void EffectTaunt(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; // this effect use before aura Taunt apply for prevent taunt already attacking target // for spell as marked "non effective at already attacking target" if (unitTarget == null || !unitTarget.CanHaveThreatList() || unitTarget.GetVictim() == m_caster) { SendCastResult(SpellCastResult.DontReport); return; } if (!unitTarget.GetThreatManager().getOnlineContainer().empty()) { // Also use this effect to set the taunter's threat to the taunted creature's highest value float myThreat = unitTarget.GetThreatManager().getThreat(m_caster); float topThreat = unitTarget.GetThreatManager().getOnlineContainer().getMostHated().getThreat(); if (topThreat > myThreat) unitTarget.GetThreatManager().addThreat(m_caster, topThreat - myThreat); //Set aggro victim to caster HostileReference forcedVictim = unitTarget.GetThreatManager().getOnlineContainer().getReferenceByTarget(m_caster); if (forcedVictim != null) unitTarget.GetThreatManager().setCurrentVictim(forcedVictim); } if (unitTarget.ToCreature().IsAIEnabled && !unitTarget.ToCreature().HasReactState(ReactStates.Passive)) unitTarget.ToCreature().GetAI().AttackStart(m_caster); } [SpellEffectHandler(SpellEffectName.WeaponDamageNoschool)] [SpellEffectHandler(SpellEffectName.WeaponPercentDamage)] [SpellEffectHandler(SpellEffectName.WeaponDamage)] [SpellEffectHandler(SpellEffectName.NormalizedWeaponDmg)] void EffectWeaponDmg(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) return; if (unitTarget == null || !unitTarget.IsAlive()) return; // multiple weapon dmg effect workaround // execute only the last weapon damage // and handle all effects at once for (var i = effIndex + 1; i < SpellConst.MaxEffects; ++i) { var effect = GetEffect(i); if (effect == null) continue; switch (effect.Effect) { case SpellEffectName.WeaponDamage: case SpellEffectName.WeaponDamageNoschool: case SpellEffectName.NormalizedWeaponDmg: case SpellEffectName.WeaponPercentDamage: return; // we must calculate only at last weapon effect } } // some spell specific modifiers float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage int fixed_bonus = 0; int spell_bonus = 0; // bonus specific for spell switch (m_spellInfo.SpellFamilyName) { case SpellFamilyNames.Warrior: { // Devastate (player ones) if (m_spellInfo.SpellFamilyFlags[1].HasAnyFlag(0x40u)) { // Player can apply only 58567 Sunder Armor effect. bool needCast = !unitTarget.HasAura(58567, m_caster.GetGUID()); if (needCast) m_caster.CastSpell(unitTarget, 58567, true); Aura aur = unitTarget.GetAura(58567, m_caster.GetGUID()); if (aur != null) { int num = (needCast ? 0 : 1); if (num != 0) aur.ModStackAmount(num); fixed_bonus += (aur.GetStackAmount() - 1) * CalculateDamage(2, unitTarget); } } break; } case SpellFamilyNames.Rogue: { // Hemorrhage if (m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x2000000u)) { if (m_caster.IsTypeId(TypeId.Player)) m_caster.ToPlayer().AddComboPoints(1, this); // 50% more damage with daggers if (m_caster.IsTypeId(TypeId.Player)) { Item item = m_caster.ToPlayer().GetWeaponForAttack(m_attackType, true); if (item != null) if (item.GetTemplate().GetSubClass() == (uint)ItemSubClassWeapon.Dagger) totalDamagePercentMod *= 1.5f; } } break; } case SpellFamilyNames.Shaman: { // Skyshatter Harness item set bonus // Stormstrike AuraEffect aurEff = m_caster.IsScriptOverriden(m_spellInfo, 5634); if (aurEff != null) m_caster.CastSpell(m_caster, 38430, true, null, aurEff); break; } case SpellFamilyNames.Druid: { // Mangle (Cat): CP if (m_spellInfo.SpellFamilyFlags[1].HasAnyFlag(0x400u)) { if (m_caster.IsTypeId(TypeId.Player)) m_caster.ToPlayer().AddComboPoints(1, this); } break; } case SpellFamilyNames.Hunter: { // Kill Shot - bonus damage from Ranged Attack Power if (m_spellInfo.SpellFamilyFlags[1].HasAnyFlag(0x800000u)) spell_bonus += (int)(0.45f * m_caster.GetTotalAttackPowerValue(WeaponAttackType.RangedAttack)); break; } case SpellFamilyNames.Deathknight: { // Blood Strike if (m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x400000u)) { SpellEffectInfo effect = GetEffect(2); if (effect != null) { float bonusPct = effect.CalcValue(m_caster) * unitTarget.GetDiseasesByCaster(m_caster.GetGUID()) / 2.0f; // Death Knight T8 Melee 4P Bonus AuraEffect aurEff = m_caster.GetAuraEffect(64736, 0); if (aurEff != null) MathFunctions.AddPct(ref bonusPct, aurEff.GetAmount()); MathFunctions.AddPct(ref totalDamagePercentMod, bonusPct); } break; } break; } } bool normalized = false; float weaponDamagePercentMod = 1.0f; foreach (SpellEffectInfo effect in GetEffects()) { if (effect == null) continue; switch (effect.Effect) { case SpellEffectName.WeaponDamage: case SpellEffectName.WeaponDamageNoschool: fixed_bonus += CalculateDamage(effect.EffectIndex, unitTarget); break; case SpellEffectName.NormalizedWeaponDmg: fixed_bonus += CalculateDamage(effect.EffectIndex, unitTarget); normalized = true; break; case SpellEffectName.WeaponPercentDamage: MathFunctions.ApplyPct(ref weaponDamagePercentMod, CalculateDamage(effect.EffectIndex, unitTarget)); break; default: break; // not weapon damage effect, just skip } } // if (addPctMods) { percent mods are added in Unit::CalculateDamage } else { percent mods are added in Unit::MeleeDamageBonusDone } // this distinction is neccessary to properly inform the client about his autoattack damage values from Script_UnitDamage bool addPctMods = !m_spellInfo.HasAttribute(SpellAttr6.NoDonePctDamageMods) && m_spellSchoolMask.HasAnyFlag(SpellSchoolMask.Normal); if (addPctMods) { UnitMods unitMod; switch (m_attackType) { default: case WeaponAttackType.BaseAttack: unitMod = UnitMods.DamageMainHand; break; case WeaponAttackType.OffAttack: unitMod = UnitMods.DamageOffHand; break; case WeaponAttackType.RangedAttack: unitMod = UnitMods.DamageRanged; break; } float weapon_total_pct = m_caster.GetModifierValue(unitMod, UnitModifierType.TotalPCT); if (fixed_bonus != 0) fixed_bonus = (int)(fixed_bonus * weapon_total_pct); if (spell_bonus != 0) spell_bonus = (int)(spell_bonus * weapon_total_pct); } uint weaponDamage = m_caster.CalculateDamage(m_attackType, normalized, addPctMods); // Sequence is important foreach (SpellEffectInfo effect in GetEffects()) { if (effect == null) continue; // We assume that a spell have at most one fixed_bonus // and at most one weaponDamagePercentMod switch (effect.Effect) { case SpellEffectName.WeaponDamage: case SpellEffectName.WeaponDamageNoschool: case SpellEffectName.NormalizedWeaponDmg: weaponDamage += (uint)fixed_bonus; break; case SpellEffectName.WeaponPercentDamage: weaponDamage = (uint)(weaponDamage * weaponDamagePercentMod); break; default: break; // not weapon damage effect, just skip } } weaponDamage += (uint)spell_bonus; weaponDamage = (uint)(weaponDamage * totalDamagePercentMod); // prevent negative damage uint eff_damage = Math.Max(weaponDamage, 0); // Add melee damage bonuses (also check for negative) uint damage = m_caster.MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo); m_damage += (int)unitTarget.MeleeDamageBonusTaken(m_caster, damage, m_attackType, m_spellInfo); } [SpellEffectHandler(SpellEffectName.Threat)] void EffectThreat(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsAlive() || !m_caster.IsAlive()) return; if (!unitTarget.CanHaveThreatList()) return; unitTarget.AddThreat(m_caster, damage); } [SpellEffectHandler(SpellEffectName.HealMaxHealth)] void EffectHealMaxHealth(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsAlive()) return; int addhealth = 0; // damage == 0 - heal for caster max health if (damage == 0) addhealth = (int)m_caster.GetMaxHealth(); else addhealth = (int)(unitTarget.GetMaxHealth() - unitTarget.GetHealth()); m_healing += addhealth; } [SpellEffectHandler(SpellEffectName.InterruptCast)] void EffectInterruptCast(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) return; if (unitTarget == null || !unitTarget.IsAlive()) return; // @todo not all spells that used this effect apply cooldown at school spells // also exist case: apply cooldown to interrupted cast only and to all spells // there is no CURRENT_AUTOREPEAT_SPELL spells that can be interrupted for (var i = CurrentSpellTypes.Generic; i < CurrentSpellTypes.AutoRepeat; ++i) { Spell spell = unitTarget.GetCurrentSpell(i); if (spell != null) { SpellInfo curSpellInfo = spell.m_spellInfo; // check if we can interrupt spell if ((spell.getState() == SpellState.Casting || (spell.getState() == SpellState.Preparing && spell.GetCastTime() > 0.0f)) && (curSpellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence)) && ((i == CurrentSpellTypes.Generic && curSpellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.Interrupt)) || (i == CurrentSpellTypes.Channeled && curSpellInfo.HasChannelInterruptFlag(SpellChannelInterruptFlags.Interrupt)))) { if (m_originalCaster != null) { int duration = m_spellInfo.GetDuration(); unitTarget.GetSpellHistory().LockSpellSchool(curSpellInfo.GetSchoolMask(), (uint)unitTarget.ModSpellDuration(m_spellInfo, unitTarget, duration, false, (uint)(1 << (int)effIndex))); m_originalCaster.ProcSkillsAndAuras(unitTarget, ProcFlags.DoneSpellMagicDmgClassNeg, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null); } ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo.Id); unitTarget.InterruptSpell(i, false); } } } } [SpellEffectHandler(SpellEffectName.SummonObjectWild)] void EffectSummonObjectWild(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; uint gameobject_id = (uint)effectInfo.MiscValue; GameObject pGameObj = new GameObject(); WorldObject target = focusObject; if (target == null) target = m_caster; float x, y, z; if (m_targets.HasDst()) destTarget.GetPosition(out x, out y, out z); else m_caster.GetClosePoint(out x, out y, out z, SharedConst.DefaultWorldObjectSize); Map map = target.GetMap(); Quaternion rotation = new Quaternion(Matrix3.fromEulerAnglesZYX(target.GetOrientation(), 0.0f, 0.0f)); if (!pGameObj.Create(gameobject_id, map, m_caster.GetPhaseMask(), new Position(x, y, z, target.GetOrientation()), rotation, 255, GameObjectState.Ready)) return; pGameObj.CopyPhaseFrom(m_caster); int duration = m_spellInfo.CalcDuration(m_caster); pGameObj.SetRespawnTime(duration > 0 ? duration / Time.InMilliseconds : 0); pGameObj.SetSpellId(m_spellInfo.Id); ExecuteLogEffectSummonObject(effIndex, pGameObj); // Wild object not have owner and check clickable by players map.AddToMap(pGameObj); if (pGameObj.GetGoType() == GameObjectTypes.FlagDrop) { Player player = m_caster.ToPlayer(); if (player != null) { Battleground bg = player.GetBattleground(); if (bg) bg.SetDroppedFlagGUID(pGameObj.GetGUID(), (player.GetTeam() == Team.Alliance ? TeamId.Horde : TeamId.Alliance)); } } GameObject linkedTrap = pGameObj.GetLinkedTrap(); if (linkedTrap) { linkedTrap.CopyPhaseFrom(m_caster); linkedTrap.SetRespawnTime(duration > 0 ? duration / Time.InMilliseconds : 0); linkedTrap.SetSpellId(m_spellInfo.Id); ExecuteLogEffectSummonObject(effIndex, linkedTrap); } } [SpellEffectHandler(SpellEffectName.ScriptEffect)] void EffectScriptEffect(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; // @todo we must implement hunter pet summon at login there (spell 6962) switch (m_spellInfo.SpellFamilyName) { case SpellFamilyNames.Generic: { switch (m_spellInfo.Id) { case 45204: // Clone Me! m_caster.CastSpell(unitTarget, (uint)damage, true); break; case 55693: // Remove Collapsing Cave Aura if (unitTarget == null) return; unitTarget.RemoveAurasDueToSpell((uint)effectInfo.CalcValue()); break; // Bending Shinbone case 8856: { if (itemTarget == null && !m_caster.IsTypeId(TypeId.Player)) return; uint spell_id = RandomHelper.Rand32(20) != 0 ? 8854u : 8855u; m_caster.CastSpell(m_caster, spell_id, true, null); return; } // Brittle Armor - need remove one 24575 Brittle Armor aura case 24590: unitTarget.RemoveAuraFromStack(24575); return; // Mercurial Shield - need remove one 26464 Mercurial Shield aura case 26465: unitTarget.RemoveAuraFromStack(26464); return; // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell) case 22539: case 22972: case 22975: case 22976: case 22977: case 22978: case 22979: case 22980: case 22981: case 22982: case 22983: case 22984: case 22985: { if (unitTarget == null || !unitTarget.IsAlive()) return; // Onyxia Scale Cloak if (unitTarget.HasAura(22683)) return; // Shadow Flame m_caster.CastSpell(unitTarget, 22682, true); return; } // Mirren's Drinking Hat case 29830: { uint item = 0; switch (RandomHelper.IRand(1, 6)) { case 1: case 2: case 3: item = 23584; break; // Loch Modan Lager case 4: case 5: item = 23585; break; // Stouthammer Lite case 6: item = 23586; break; // Aerie Peak Pale Ale } if (item != 0) DoCreateItem(effIndex, item); break; } case 20589: // Escape artist case 30918: // Improved Sprint { // Removes snares and roots. unitTarget.RemoveMovementImpairingAuras(); break; } // Plant Warmaul Ogre Banner case 32307: Player caster = m_caster.ToPlayer(); if (caster != null) { caster.RewardPlayerAndGroupAtEvent(18388, unitTarget); Creature target = unitTarget.ToCreature(); if (target != null) { target.setDeathState(DeathState.Corpse); target.RemoveCorpse(); } } break; // Mug Transformation case 41931: { if (!m_caster.IsTypeId(TypeId.Player)) return; byte bag = 19; byte slot = 0; Item item = null; while (bag != 0) // 256 = 0 due to var type { item = m_caster.ToPlayer().GetItemByPos(bag, slot); if (item != null && item.GetEntry() == 38587) break; ++slot; if (slot == 39) { slot = 0; ++bag; } } if (bag != 0) { if (m_caster.ToPlayer().GetItemByPos(bag, slot).GetCount() == 1) m_caster.ToPlayer().RemoveItem(bag, slot, true); else m_caster.ToPlayer().GetItemByPos(bag, slot).SetCount(m_caster.ToPlayer().GetItemByPos(bag, slot).GetCount() - 1); // Spell 42518 (Braufest - Gratisprobe des Braufest herstellen) m_caster.CastSpell(m_caster, 42518, true); return; } break; } // Brutallus - Burn case 45141: case 45151: { //Workaround for Range ... should be global for every ScriptEffect float radius = effectInfo.CalcRadius(); if (unitTarget != null && unitTarget.IsTypeId(TypeId.Player) && unitTarget.GetDistance(m_caster) >= radius && !unitTarget.HasAura(46394) && unitTarget != m_caster) unitTarget.CastSpell(unitTarget, 46394, true); break; } // Goblin Weather Machine case 46203: { if (unitTarget == null) return; uint spellId = 0; switch (RandomHelper.IRand(1, 4)) { case 0: spellId = 46740; break; case 1: spellId = 46739; break; case 2: spellId = 46738; break; case 3: spellId = 46736; break; } unitTarget.CastSpell(unitTarget, spellId, true); break; } // 5, 000 Gold case 46642: { if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; unitTarget.ToPlayer().ModifyMoney(5000 * MoneyConstants.Gold); break; } // Death Knight Initiate Visual case 51519: { if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Unit)) return; uint iTmpSpellId = 0; switch (unitTarget.GetDisplayId()) { case 25369: iTmpSpellId = 51552; break; // bloodelf female case 25373: iTmpSpellId = 51551; break; // bloodelf male case 25363: iTmpSpellId = 51542; break; // draenei female case 25357: iTmpSpellId = 51541; break; // draenei male case 25361: iTmpSpellId = 51537; break; // dwarf female case 25356: iTmpSpellId = 51538; break; // dwarf male case 25372: iTmpSpellId = 51550; break; // forsaken female case 25367: iTmpSpellId = 51549; break; // forsaken male case 25362: iTmpSpellId = 51540; break; // gnome female case 25359: iTmpSpellId = 51539; break; // gnome male case 25355: iTmpSpellId = 51534; break; // human female case 25354: iTmpSpellId = 51520; break; // human male case 25360: iTmpSpellId = 51536; break; // nightelf female case 25358: iTmpSpellId = 51535; break; // nightelf male case 25368: iTmpSpellId = 51544; break; // orc female case 25364: iTmpSpellId = 51543; break; // orc male case 25371: iTmpSpellId = 51548; break; // tauren female case 25366: iTmpSpellId = 51547; break; // tauren male case 25370: iTmpSpellId = 51545; break; // troll female case 25365: iTmpSpellId = 51546; break; // troll male default: return; } unitTarget.CastSpell(unitTarget, iTmpSpellId, true); Creature npc = unitTarget.ToCreature(); npc.LoadEquipment(); return; } // Emblazon Runeblade case 51770: { if (m_originalCaster == null) return; m_originalCaster.CastSpell(m_originalCaster, (uint)damage, false); break; } // Deathbolt from Thalgran Blightbringer // reflected by Freya's Ward // Retribution by Sevenfold Retribution case 51854: { if (unitTarget == null) return; if (unitTarget.HasAura(51845)) unitTarget.CastSpell(m_caster, 51856, true); else m_caster.CastSpell(unitTarget, 51855, true); break; } // Summon Ghouls On Scarlet Crusade case 51904: { if (!m_targets.HasDst()) return; float x, y, z; float radius = effectInfo.CalcRadius(); for (byte i = 0; i < 15; ++i) { m_caster.GetRandomPoint(destTarget, radius, out x, out y, out z); m_caster.CastSpell(x, y, z, 54522, true); } break; } case 52173: // Coyote Spirit Despawn case 60243: // Blood Parrot Despawn if (unitTarget.IsTypeId(TypeId.Unit) && unitTarget.ToCreature().IsSummon()) unitTarget.ToTempSummon().UnSummon(); return; case 52479: // Gift of the Harvester if (unitTarget != null && m_originalCaster != null) m_originalCaster.CastSpell(unitTarget, Convert.ToBoolean(RandomHelper.IRand(0, 1)) ? (uint)damage : 52505, true); return; case 53110: // Devour Humanoid if (unitTarget != null) unitTarget.CastSpell(m_caster, (uint)damage, true); return; case 57347: // Retrieving (Wintergrasp RP-GG pickup spell) { if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Unit) || !m_caster.IsTypeId(TypeId.Player)) return; unitTarget.ToCreature().DespawnOrUnsummon(); return; } case 57349: // Drop RP-GG (Wintergrasp RP-GG at death drop spell) { if (!m_caster.IsTypeId(TypeId.Player)) return; // Delete item from inventory at death m_caster.ToPlayer().DestroyItemCount((uint)damage, 5, true); return; } case 58418: // Portal to Orgrimmar case 58420: // Portal to Stormwind { if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player) || effIndex != 0) return; uint spellID = (uint)GetEffect(0).CalcValue(); uint questID = (uint)GetEffect(1).CalcValue(); if (unitTarget.ToPlayer().GetQuestStatus(questID) == QuestStatus.Complete) unitTarget.CastSpell(unitTarget, spellID, true); return; } case 58941: // Rock Shards if (unitTarget != null && m_originalCaster != null) { for (uint i = 0; i < 3; ++i) { m_originalCaster.CastSpell(unitTarget, 58689, true); m_originalCaster.CastSpell(unitTarget, 58692, true); } if (m_originalCaster.GetMap().GetDifficultyID() == Difficulty.None) { m_originalCaster.CastSpell(unitTarget, 58695, true); m_originalCaster.CastSpell(unitTarget, 58696, true); } else { m_originalCaster.CastSpell(unitTarget, 60883, true); m_originalCaster.CastSpell(unitTarget, 60884, true); } } return; case 58983: // Big Blizzard Bear { if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; // Prevent stacking of mounts and client crashes upon dismounting unitTarget.RemoveAurasByType(AuraType.Mounted); // Triggered spell id dependent on riding skilll ushort skillval = unitTarget.ToPlayer().GetSkillValue(SkillType.Riding); if (skillval != 0) { if (skillval >= 150) unitTarget.CastSpell(unitTarget, 58999, true); else unitTarget.CastSpell(unitTarget, 58997, true); } return; } case 59317: // Teleporting { if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; // return from top if (unitTarget.ToPlayer().GetAreaId() == 4637) unitTarget.CastSpell(unitTarget, 59316, true); // teleport atop else unitTarget.CastSpell(unitTarget, 59314, true); return; } case 62482: // Grab Crate { if (unitTarget != null) { Unit seat = m_caster.GetVehicleBase(); if (seat != null) { Unit parent = seat.GetVehicleBase(); if (parent != null) { // @todo a hack, range = 11, should after some time cast, otherwise too far m_caster.CastSpell(parent, 62496, true); unitTarget.CastSpell(parent, (uint)GetEffect(0).CalcValue()); } } } return; } case 60123: // Lightwell { if (!m_caster.IsTypeId(TypeId.Unit) || !m_caster.ToCreature().IsSummon()) return; uint spell_heal; switch (m_caster.GetEntry()) { case 31897: spell_heal = 7001; break; case 31896: spell_heal = 27873; break; case 31895: spell_heal = 27874; break; case 31894: spell_heal = 28276; break; case 31893: spell_heal = 48084; break; case 31883: spell_heal = 48085; break; default: Log.outError(LogFilter.Spells, "Unknown Lightwell spell caster {0}", m_caster.GetEntry()); return; } // proc a spellcast Aura chargesAura = m_caster.GetAura(59907); if (chargesAura != null) { m_caster.CastSpell(unitTarget, spell_heal, true, null, null, m_caster.ToTempSummon().GetSummonerGUID()); if (chargesAura.ModCharges(-1)) m_caster.ToTempSummon().UnSummon(); } return; } // Stoneclaw Totem case 55328: // Rank 1 case 55329: // Rank 2 case 55330: // Rank 3 case 55332: // Rank 4 case 55333: // Rank 5 case 55335: // Rank 6 case 55278: // Rank 7 case 58589: // Rank 8 case 58590: // Rank 9 case 58591: // Rank 10 { int basepoints0 = damage; // Cast Absorb on totems for (byte slot = (int)SummonSlot.Totem; slot < SharedConst.MaxTotemSlot; ++slot) { if (unitTarget.m_SummonSlot[slot].IsEmpty()) continue; Creature totem = unitTarget.GetMap().GetCreature(unitTarget.m_SummonSlot[slot]); if (totem != null && totem.IsTotem()) { m_caster.CastCustomSpell(totem, 55277, basepoints0, 0, 0, true); } } // Glyph of Stoneclaw Totem AuraEffect aur = unitTarget.GetAuraEffect(63298, 0); if (aur != null) { basepoints0 *= aur.GetAmount(); m_caster.CastCustomSpell(unitTarget, 55277, basepoints0, 0, 0, true); } break; } case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster { if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Unit)) return; if (RandomHelper.randChance(50)) // chance unknown, using 50 return; uint[] spellPlayer = new uint[5] { 45674, // Bigger! 45675, // Shrunk 45678, // Yellow 45682, // Ghost 45684 // Polymorph }; uint[] spellTarget = new uint[5] { 45673, // Bigger! 45672, // Shrunk 45677, // Yellow 45681, // Ghost 45683 // Polymorph }; m_caster.CastSpell(m_caster, spellPlayer[RandomHelper.IRand(0, 4)], true); unitTarget.CastSpell(unitTarget, spellTarget[RandomHelper.IRand(0, 4)], true); break; } } break; } case SpellFamilyNames.Paladin: { // Judgement (seal trigger) if (m_spellInfo.GetCategory() == (int)SpellCategories.Judgement) { if (unitTarget == null || !unitTarget.IsAlive()) return; uint spellId1 = 0; uint spellId2 = 0; // Judgement self add switch switch (m_spellInfo.Id) { case 53407: spellId1 = 20184; break; // Judgement of Justice case 20271: // Judgement of Light case 57774: spellId1 = 20185; break; // Judgement of Light case 53408: spellId1 = 20186; break; // Judgement of Wisdom default: Log.outError(LogFilter.Spells, "Unsupported Judgement (seal trigger) spell (Id: {0}) in Spell.EffectScriptEffect", m_spellInfo.Id); return; } // all seals have aura dummy in 2 effect foreach (var app in m_caster.GetAppliedAuras()) { Aura aura = app.Value.GetBase(); if (aura.GetSpellInfo().GetSpellSpecific() == SpellSpecificType.Seal) { AuraEffect aureff = aura.GetEffect(2); if (aureff != null) if (aureff.GetAuraType() == AuraType.Dummy) { if (Global.SpellMgr.GetSpellInfo((uint)aureff.GetAmount()) != null) spellId2 = (uint)aureff.GetAmount(); break; } if (spellId2 == 0) { switch (app.Key) { // Seal of light, Seal of wisdom, Seal of justice case 20165: case 20166: case 20164: spellId2 = 54158; break; } } break; } } if (spellId1 != 0) m_caster.CastSpell(unitTarget, spellId1, true); if (spellId2 != 0) m_caster.CastSpell(unitTarget, spellId2, true); return; } break; } } // normal DB scripted effect Log.outDebug(LogFilter.Spells, "Spell ScriptStart spellid {0} in EffectScriptEffect({1})", m_spellInfo.Id, effIndex); m_caster.GetMap().ScriptsStart(ScriptsType.Spell, (uint)((int)m_spellInfo.Id | (int)(effIndex << 24)), m_caster, unitTarget); } [SpellEffectHandler(SpellEffectName.Sanctuary)] [SpellEffectHandler(SpellEffectName.Sanctuary2)] void EffectSanctuary(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; unitTarget.getHostileRefManager().UpdateVisibility(); var attackers = unitTarget.getAttackers(); foreach (var unit in attackers) { if (!unit.CanSeeOrDetect(unitTarget)) unit.AttackStop(); } unitTarget.m_lastSanctuaryTime = Time.GetMSTime(); // Vanish allows to remove all threat and cast regular stealth so other spells can be used if (m_caster.IsTypeId(TypeId.Player) && m_spellInfo.SpellFamilyName == SpellFamilyNames.Rogue && m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x00000800u)) { m_caster.ToPlayer().RemoveAurasByType(AuraType.ModRoot); m_caster.ToPlayer().RemoveAurasByType(AuraType.ModRoot2); // Overkill if (m_caster.ToPlayer().HasSpell(58426)) m_caster.CastSpell(m_caster, 58427, true); } } [SpellEffectHandler(SpellEffectName.AddComboPoints)] void EffectAddComboPoints(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; if (m_caster.m_playerMovingMe == null) return; if (damage <= 0) return; m_caster.m_playerMovingMe.AddComboPoints((sbyte)damage, this); } [SpellEffectHandler(SpellEffectName.Duel)] void EffectDuel(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !m_caster.IsTypeId(TypeId.Player) || !unitTarget.IsTypeId(TypeId.Player)) return; Player caster = m_caster.ToPlayer(); Player target = unitTarget.ToPlayer(); // caster or target already have requested duel if (caster.duel != null || target.duel != null || target.GetSocial() == null || target.GetSocial().HasIgnore(caster.GetGUID())) return; // Players can only fight a duel in zones with this flag AreaTableRecord casterAreaEntry = CliDB.AreaTableStorage.LookupByKey(caster.GetAreaId()); if (casterAreaEntry != null && !casterAreaEntry.Flags[0].HasAnyFlag(AreaFlags.AllowDuels)) { SendCastResult(SpellCastResult.NoDueling); // Dueling isn't allowed here return; } AreaTableRecord targetAreaEntry = CliDB.AreaTableStorage.LookupByKey(target.GetAreaId()); if (targetAreaEntry != null && !targetAreaEntry.Flags[0].HasAnyFlag(AreaFlags.AllowDuels)) { SendCastResult(SpellCastResult.NoDueling); // Dueling isn't allowed here return; } //CREATE DUEL FLAG OBJECT GameObject pGameObj = new GameObject(); int gameobject_id = effectInfo.MiscValue; Position pos = new Position() { posX = m_caster.GetPositionX() + (unitTarget.GetPositionX() - m_caster.GetPositionX()) / 2, posY = m_caster.GetPositionY() + (unitTarget.GetPositionY() - m_caster.GetPositionY()) / 2, posZ = m_caster.GetPositionZ(), Orientation = m_caster.GetOrientation() }; Map map = m_caster.GetMap(); Quaternion rotation = new Quaternion(Matrix3.fromEulerAnglesZYX(pos.GetOrientation(), 0.0f, 0.0f)); if (!pGameObj.Create((uint)gameobject_id, map, m_caster.GetPhaseMask(), pos, rotation, 0, GameObjectState.Ready)) return; pGameObj.CopyPhaseFrom(m_caster); pGameObj.SetUInt32Value(GameObjectFields.Faction, m_caster.getFaction()); pGameObj.SetUInt32Value(GameObjectFields.Level, m_caster.getLevel() + 1); int duration = m_spellInfo.CalcDuration(m_caster); pGameObj.SetRespawnTime(duration > 0 ? duration / Time.InMilliseconds : 0); pGameObj.SetSpellId(m_spellInfo.Id); ExecuteLogEffectSummonObject(effIndex, pGameObj); m_caster.AddGameObject(pGameObj); map.AddToMap(pGameObj); //END // Send request DuelRequested packet = new DuelRequested(); packet.ArbiterGUID = pGameObj.GetGUID(); packet.RequestedByGUID = caster.GetGUID(); packet.RequestedByWowAccount = caster.GetSession().GetAccountGUID(); caster.SendPacket(packet); target.SendPacket(packet); // create duel-info DuelInfo duel = new DuelInfo(); duel.initiator = caster; duel.opponent = target; duel.startTime = 0; duel.startTimer = 0; duel.isMounted = (GetSpellInfo().Id == 62875); // Mounted Duel caster.duel = duel; DuelInfo duel2 = new DuelInfo(); duel2.initiator = caster; duel2.opponent = caster; duel2.startTime = 0; duel2.startTimer = 0; duel2.isMounted = (GetSpellInfo().Id == 62875); // Mounted Duel target.duel = duel2; caster.SetGuidValue(PlayerFields.DuelArbiter, pGameObj.GetGUID()); target.SetGuidValue(PlayerFields.DuelArbiter, pGameObj.GetGUID()); Global.ScriptMgr.OnPlayerDuelRequest(target, caster); } [SpellEffectHandler(SpellEffectName.Stuck)] void EffectStuck(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!WorldConfig.GetBoolValue(WorldCfg.CastUnstuck)) return; Player player = m_caster.ToPlayer(); if (player == null) return; Log.outDebug(LogFilter.Spells, "Spell Effect: Stuck"); Log.outInfo(LogFilter.Spells, "Player {0} (guid {1}) used auto-unstuck future at map {2} ({3}, {4}, {5})", player.GetName(), player.GetGUID().ToString(), player.GetMapId(), player.GetPositionX(), player.GetPositionY(), player.GetPositionZ()); if (player.IsInFlight()) return; // if player is dead without death timer is teleported to graveyard, otherwise not apply the effect if (player.IsDead()) { if (player.GetDeathTimer() == 0) player.RepopAtGraveyard(); return; } // the player dies if hearthstone is in cooldown, else the player is teleported to home if (player.GetSpellHistory().HasCooldown(8690)) { player.KillSelf(); return; } player.TeleportTo(player.GetHomebind(), TeleportToOptions.Spell); // Stuck spell trigger Hearthstone cooldown SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(8690); if (spellInfo == null) return; Spell spell = new Spell(player, spellInfo, TriggerCastFlags.FullMask); spell.SendSpellCooldown(); } [SpellEffectHandler(SpellEffectName.SummonPlayer)] void EffectSummonPlayer(uint effIndex) { // workaround - this effect should not use target map if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; unitTarget.ToPlayer().SendSummonRequestFrom(m_caster); } [SpellEffectHandler(SpellEffectName.ActivateObject)] void EffectActivateObject(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (gameObjTarget == null) return; ScriptInfo activateCommand = new ScriptInfo(); activateCommand.command = ScriptCommands.ActivateObject; // int unk = effectInfo.MiscValue; // This is set for EffectActivateObject spells; needs research gameObjTarget.GetMap().ScriptCommandStart(activateCommand, 0, m_caster, gameObjTarget); } [SpellEffectHandler(SpellEffectName.ApplyGlyph)] void EffectApplyGlyph(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; Player player = m_caster.ToPlayer(); if (player == null) return; List glyphs = player.GetGlyphs(player.GetActiveTalentGroup()); int replacedGlyph = glyphs.Count; for (int i = 0; i < glyphs.Count; ++i) { List activeGlyphBindableSpells = Global.DB2Mgr.GetGlyphBindableSpells(glyphs[i]); if (activeGlyphBindableSpells.Contains(m_misc.SpellId)) { replacedGlyph = i; player.RemoveAurasDueToSpell(CliDB.GlyphPropertiesStorage.LookupByKey(glyphs[i]).SpellID); break; } } uint glyphId = (uint)effectInfo.MiscValue; if (replacedGlyph < glyphs.Count) { if (glyphId != 0) glyphs[replacedGlyph] = glyphId; else glyphs.RemoveAt(replacedGlyph); } else if (glyphId != 0) glyphs.Add(glyphId); GlyphPropertiesRecord glyphProperties = CliDB.GlyphPropertiesStorage.LookupByKey(glyphId); if (glyphProperties != null) player.CastSpell(player, glyphProperties.SpellID, true); ActiveGlyphs activeGlyphs = new ActiveGlyphs(); activeGlyphs.Glyphs.Add(new GlyphBinding(m_misc.SpellId, (ushort)glyphId)); activeGlyphs.IsFullUpdate = false; player.SendPacket(activeGlyphs); } [SpellEffectHandler(SpellEffectName.EnchantHeldItem)] void EffectEnchantHeldItem(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; // this is only item spell effect applied to main-hand weapon of target player (players in area) if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player item_owner = unitTarget.ToPlayer(); Item item = item_owner.GetItemByPos(InventorySlots.Bag0, EquipmentSlot.MainHand); if (item == null) return; // must be equipped if (!item.IsEquipped()) return; if (effectInfo.MiscValue != 0) { uint enchant_id = (uint)effectInfo.MiscValue; int duration = m_spellInfo.GetDuration(); //Try duration index first .. if (duration == 0) duration = damage;//+1; //Base points after .. if (duration == 0) duration = 10 * Time.InMilliseconds; //10 seconds for enchants which don't have listed duration if (m_spellInfo.Id == 14792) // Venomhide Poison duration = 5 * Time.Minute * Time.InMilliseconds; SpellItemEnchantmentRecord pEnchant = CliDB.SpellItemEnchantmentStorage.LookupByKey(enchant_id); if (pEnchant == null) return; // Always go to temp enchantment slot EnchantmentSlot slot = EnchantmentSlot.Temp; // Enchantment will not be applied if a different one already exists if (item.GetEnchantmentId(slot) != 0 && item.GetEnchantmentId(slot) != enchant_id) return; // Apply the temporary enchantment item.SetEnchantment(slot, enchant_id, (uint)duration, 0, m_caster.GetGUID()); item_owner.ApplyEnchantment(item, slot, true); } } [SpellEffectHandler(SpellEffectName.Disenchant)] void EffectDisEnchant(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (itemTarget == null || itemTarget.GetTemplate().DisenchantID == 0) return; Player caster = m_caster.ToPlayer(); if (caster != null) { caster.UpdateCraftSkill(m_spellInfo.Id); caster.SendLoot(itemTarget.GetGUID(), LootType.Disenchanting); } // item will be removed at disenchanting end } [SpellEffectHandler(SpellEffectName.Inebriate)] void EffectInebriate(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); byte currentDrunk = player.GetDrunkValue(); int drunkMod = damage; if (currentDrunk + drunkMod > 100) { currentDrunk = 100; if (RandomHelper.randChance() < 25.0f) player.CastSpell(player, 67468, false); // Drunken Vomit } else currentDrunk += (byte)drunkMod; player.SetDrunkValue(currentDrunk, m_CastItem != null ? m_CastItem.GetEntry() : 0); } [SpellEffectHandler(SpellEffectName.FeedPet)] void EffectFeedPet(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; Player player = m_caster.ToPlayer(); if (player == null) return; Item foodItem = itemTarget; if (foodItem == null) return; Pet pet = player.GetPet(); if (pet == null) return; if (!pet.IsAlive()) return; int benefit = (int)pet.GetCurrentFoodBenefitLevel(foodItem.GetTemplate().GetBaseItemLevel()); if (benefit <= 0) return; ExecuteLogEffectDestroyItem(effIndex, foodItem.GetEntry()); uint count = 1; player.DestroyItemCount(foodItem, ref count, true); // @todo fix crash when a spell has two effects, both pointed at the same item target m_caster.CastCustomSpell(pet, effectInfo.TriggerSpell, benefit, 0, 0, true); } [SpellEffectHandler(SpellEffectName.DismissPet)] void EffectDismissPet(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsPet()) return; Pet pet = unitTarget.ToPet(); ExecuteLogEffectUnsummonObject(effIndex, pet); pet.GetOwner().RemovePet(pet, PetSaveMode.NotInSlot); } [SpellEffectHandler(SpellEffectName.SummonObjectSlot1)] void EffectSummonObject(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; uint go_id = (uint)effectInfo.MiscValue; byte slot = (byte)(effectInfo.Effect - SpellEffectName.SummonObjectSlot1); ObjectGuid guid = m_caster.m_ObjectSlot[slot]; if (!guid.IsEmpty()) { GameObject obj = m_caster.GetMap().GetGameObject(guid); if (obj != null) { // Recast case - null spell id to make auras not be removed on object remove from world if (m_spellInfo.Id == obj.GetSpellId()) obj.SetSpellId(0); m_caster.RemoveGameObject(obj, true); } m_caster.m_ObjectSlot[slot].Clear(); } GameObject go = new GameObject(); float x, y, z; // If dest location if present if (m_targets.HasDst()) destTarget.GetPosition(out x, out y, out z); // Summon in random point all other units if location present else m_caster.GetClosePoint(out x, out y, out z, SharedConst.DefaultWorldObjectSize); Map map = m_caster.GetMap(); Quaternion rotation = new Quaternion(Matrix3.fromEulerAnglesZYX(m_caster.GetOrientation(), 0.0f, 0.0f)); if (!go.Create(go_id, map, m_caster.GetPhaseMask(), new Position(x, y, z, m_caster.GetOrientation()), rotation, 255, GameObjectState.Ready)) return; go.CopyPhaseFrom(m_caster); int duration = m_spellInfo.CalcDuration(m_caster); go.SetRespawnTime(duration > 0 ? duration / Time.InMilliseconds : 0); go.SetSpellId(m_spellInfo.Id); m_caster.AddGameObject(go); ExecuteLogEffectSummonObject(effIndex, go); map.AddToMap(go); m_caster.m_ObjectSlot[slot] = go.GetGUID(); } [SpellEffectHandler(SpellEffectName.Resurrect)] void EffectResurrect(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; if (unitTarget.IsAlive() || !unitTarget.IsInWorld) return; Player target = unitTarget.ToPlayer(); if (target.IsResurrectRequested()) // already have one active request return; uint health = (uint)target.CountPctFromMaxHealth(damage); uint mana = (uint)MathFunctions.CalculatePct(target.GetMaxPower(PowerType.Mana), damage); ExecuteLogEffectResurrect(effIndex, target); target.SetResurrectRequestData(m_caster, health, mana, 0); SendResurrectRequest(target); } [SpellEffectHandler(SpellEffectName.AddExtraAttacks)] void EffectAddExtraAttacks(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsAlive()) return; if (unitTarget.m_extraAttacks != 0) return; unitTarget.m_extraAttacks = (uint)damage; ExecuteLogEffectExtraAttacks(effIndex, unitTarget, (uint)damage); } [SpellEffectHandler(SpellEffectName.Parry)] void EffectParry(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (m_caster.IsTypeId(TypeId.Player)) m_caster.ToPlayer().SetCanParry(true); } [SpellEffectHandler(SpellEffectName.Block)] void EffectBlock(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (m_caster.IsTypeId(TypeId.Player)) m_caster.ToPlayer().SetCanBlock(true); } [SpellEffectHandler(SpellEffectName.Leap)] void EffectLeap(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || unitTarget.IsInFlight()) return; if (!m_targets.HasDst()) return; Position pos = destTarget.GetPosition(); pos = unitTarget.GetFirstCollisionPosition(unitTarget.GetDistance(pos.posX, pos.posY, pos.posZ + 2.0f), 0.0f); unitTarget.NearTeleportTo(pos.posX, pos.posY, pos.posZ, pos.Orientation, unitTarget == m_caster); } [SpellEffectHandler(SpellEffectName.Reputation)] void EffectReputation(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); int repChange = damage; int factionId = effectInfo.MiscValue; FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(factionId); if (factionEntry == null) return; repChange = player.CalculateReputationGain(ReputationSource.Spell, 0, repChange, factionId); player.GetReputationMgr().ModifyReputation(factionEntry, repChange); } [SpellEffectHandler(SpellEffectName.QuestComplete)] void EffectQuestComplete(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); uint questId = (uint)effectInfo.MiscValue; if (questId != 0) { Quest quest = Global.ObjectMgr.GetQuestTemplate(questId); if (quest == null) return; ushort logSlot = player.FindQuestSlot(questId); if (logSlot < SharedConst.MaxQuestLogSize) player.AreaExploredOrEventHappens(questId); else if (quest.HasFlag(QuestFlags.Tracking)) // Check if the quest is used as a serverside flag. player.SetRewardedQuest(questId); // If so, set status to rewarded without broadcasting it to client. } } [SpellEffectHandler(SpellEffectName.ForceDeselect)] void EffectForceDeselect(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; ClearTarget clearTarget = new ClearTarget(); clearTarget.Guid = m_caster.GetGUID(); m_caster.SendMessageToSet(clearTarget, true); } [SpellEffectHandler(SpellEffectName.SelfResurrect)] void EffectSelfResurrect(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (m_caster == null || m_caster.IsAlive()) return; if (!m_caster.IsTypeId(TypeId.Player)) return; if (!m_caster.IsInWorld) return; uint health = 0; int mana = 0; // flat case if (damage < 0) { health = (uint)-damage; mana = effectInfo.MiscValue; } // percent case else { health = (uint)m_caster.CountPctFromMaxHealth(damage); if (m_caster.GetMaxPower(PowerType.Mana) > 0) mana = MathFunctions.CalculatePct(m_caster.GetMaxPower(PowerType.Mana), damage); } Player player = m_caster.ToPlayer(); player.ResurrectPlayer(0.0f); player.SetHealth(health); player.SetPower(PowerType.Mana, mana); player.SetPower(PowerType.Rage, 0); player.SetFullPower(PowerType.Energy); player.SetPower(PowerType.Focus, 0); player.SpawnCorpseBones(); } [SpellEffectHandler(SpellEffectName.Skinning)] void EffectSkinning(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget.IsTypeId(TypeId.Unit)) return; if (!m_caster.IsTypeId(TypeId.Player)) return; Creature creature = unitTarget.ToCreature(); int targetLevel = (int)creature.GetLevelForTarget(m_caster); SkillType skill = creature.GetCreatureTemplate().GetRequiredLootSkill(); m_caster.ToPlayer().SendLoot(creature.GetGUID(), LootType.Skinning); creature.RemoveFlag(UnitFields.Flags, UnitFlags.Skinnable); creature.SetFlag(ObjectFields.DynamicFlags, UnitDynFlags.Lootable); uint reqValue = (uint)(targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel - 10) * 10 : targetLevel * 5); uint skillValue = m_caster.ToPlayer().GetPureSkillValue(skill); // Double chances for elites m_caster.ToPlayer().UpdateGatherSkill(skill, skillValue, reqValue, (uint)(creature.isElite() ? 2 : 1)); } [SpellEffectHandler(SpellEffectName.Charge)] void EffectCharge(uint effIndex) { if (unitTarget == null) return; if (effectHandleMode == SpellEffectHandleMode.LaunchTarget) { float speed = MathFunctions.fuzzyGt(m_spellInfo.Speed, 0.0f) ? m_spellInfo.Speed : MotionMaster.SPEED_CHARGE; SpellEffectExtraData spellEffectExtraData = null; if (effectInfo.MiscValueB != 0) { spellEffectExtraData = new SpellEffectExtraData(); spellEffectExtraData.Target = unitTarget.GetGUID(); spellEffectExtraData.SpellVisualId = (uint)effectInfo.MiscValueB; } // Spell is not using explicit target - no generated path if (m_preGeneratedPath.GetPathType() == PathType.Blank) { Position pos = unitTarget.GetFirstCollisionPosition(unitTarget.GetObjectSize(), unitTarget.GetRelativeAngle(m_caster.GetPosition())); m_caster.GetMotionMaster().MoveCharge(pos.posX, pos.posY, pos.posZ, speed, EventId.Charge, false, unitTarget, spellEffectExtraData); } else m_caster.GetMotionMaster().MoveCharge(m_preGeneratedPath, speed, unitTarget, spellEffectExtraData); } if (effectHandleMode == SpellEffectHandleMode.HitTarget) { // not all charge effects used in negative spells if (!m_spellInfo.IsPositive() && m_caster.IsTypeId(TypeId.Player)) m_caster.Attack(unitTarget, true); if (effectInfo.TriggerSpell != 0) m_caster.CastSpell(unitTarget, effectInfo.TriggerSpell, true, null, null, m_originalCasterGUID); } } [SpellEffectHandler(SpellEffectName.ChargeDest)] void EffectChargeDest(uint effIndex) { if (destTarget == null) return; if (effectHandleMode == SpellEffectHandleMode.Launch) { Position pos = destTarget.GetPosition(); float angle = m_caster.GetRelativeAngle(pos.posX, pos.posY); float dist = m_caster.GetDistance(pos); pos = m_caster.GetFirstCollisionPosition(dist, angle); m_caster.GetMotionMaster().MoveCharge(pos.posX, pos.posY, pos.posZ); } else if (effectHandleMode == SpellEffectHandleMode.Hit) { if (effectInfo.TriggerSpell != 0) m_caster.CastSpell(destTarget.GetPositionX(), destTarget.GetPositionY(), destTarget.GetPositionZ(), effectInfo.TriggerSpell, true, null, null, m_originalCasterGUID); } } [SpellEffectHandler(SpellEffectName.KnockBack)] [SpellEffectHandler(SpellEffectName.KnockBackDest)] void EffectKnockBack(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget) return; Creature creatureTarget = unitTarget.ToCreature(); if (creatureTarget) if (creatureTarget.isWorldBoss() || creatureTarget.IsDungeonBoss()) return; // Spells with SPELL_EFFECT_KNOCK_BACK (like Thunderstorm) can't knockback target if target has ROOT/STUN if (unitTarget.HasUnitState(UnitState.Root | UnitState.Stunned)) return; // Instantly interrupt non melee spells being casted if (unitTarget.IsNonMeleeSpellCast(true)) unitTarget.InterruptNonMeleeSpells(true); float ratio = 0.1f; float speedxy = effectInfo.MiscValue * ratio; float speedz = damage * ratio; if (speedxy < 0.1f && speedz < 0.1f) return; float x, y; if (effectInfo.Effect == SpellEffectName.KnockBackDest) { if (m_targets.HasDst()) destTarget.GetPosition(out x, out y); else return; } else //if (GetEffect(i].Effect == SPELL_EFFECT_KNOCK_BACK) { m_caster.GetPosition(out x, out y); } unitTarget.KnockbackFrom(x, y, speedxy, speedz); } [SpellEffectHandler(SpellEffectName.LeapBack)] void EffectLeapBack(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) return; if (unitTarget == null) return; float speedxy = effectInfo.MiscValue / 10.0f; float speedz = damage / 10.0f; // Disengage unitTarget.JumpTo(speedxy, speedz, m_spellInfo.IconFileDataId != 132572); } [SpellEffectHandler(SpellEffectName.ClearQuest)] void EffectQuestClear(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); uint quest_id = (uint)effectInfo.MiscValue; Quest quest = Global.ObjectMgr.GetQuestTemplate(quest_id); if (quest == null) return; QuestStatus oldStatus = player.GetQuestStatus(quest_id); // Player has never done this quest if (oldStatus == QuestStatus.None) return; // remove all quest entries for 'entry' from quest log for (byte slot = 0; slot < SharedConst.MaxQuestLogSize; ++slot) { uint logQuest = player.GetQuestSlotQuestId(slot); if (logQuest == quest_id) { player.SetQuestSlot(slot, 0); // we ignore unequippable quest items in this case, it's still be equipped player.TakeQuestSourceItem(logQuest, false); if (quest.HasFlag(QuestFlags.Pvp)) { player.pvpInfo.IsHostile = player.pvpInfo.IsInHostileArea || player.HasPvPForcingQuest(); player.UpdatePvPState(); } } } player.RemoveActiveQuest(quest_id, false); player.RemoveRewardedQuest(quest_id); Global.ScriptMgr.OnQuestStatusChange(player, quest_id); Global.ScriptMgr.OnQuestStatusChange(player, quest, oldStatus, QuestStatus.None); } [SpellEffectHandler(SpellEffectName.SendTaxi)] void EffectSendTaxi(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; unitTarget.ToPlayer().ActivateTaxiPathTo((uint)effectInfo.MiscValue, m_spellInfo.Id); } [SpellEffectHandler(SpellEffectName.PullTowards)] [SpellEffectHandler(SpellEffectName.PullTowardsDest)] void EffectPullTowards(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget) return; Position pos = new Position(); if (effectInfo.Effect == SpellEffectName.PullTowardsDest) { if (m_targets.HasDst()) pos.Relocate(destTarget); else return; } else { pos.Relocate(m_caster.GetPosition()); } float speedXY = effectInfo.MiscValue * 0.1f; float speedZ = (float)(unitTarget.GetDistance(pos) / speedXY * 0.5f * MotionMaster.gravity); unitTarget.GetMotionMaster().MoveJump(pos, speedXY, speedZ); } [SpellEffectHandler(SpellEffectName.ChangeRaidMarker)] void EffectChangeRaidMarker(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; Player player = m_caster.ToPlayer(); if (!player || !m_targets.HasDst()) return; Group group = player.GetGroup(); if (!group || (group.isRaidGroup() && !group.IsLeader(player.GetGUID()) && !group.IsAssistant(player.GetGUID()))) return; float x, y, z; destTarget.GetPosition(out x, out y, out z); group.AddRaidMarker((byte)damage, player.GetMapId(), x, y, z); } [SpellEffectHandler(SpellEffectName.DispelMechanic)] void EffectDispelMechanic(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; int mechanic = effectInfo.MiscValue; List> dispel_list = new List>(); var auras = unitTarget.GetOwnedAuras(); foreach (var pair in auras) { Aura aura = pair.Value; if (aura.GetApplicationOfTarget(unitTarget.GetGUID()) == null) continue; if (RandomHelper.randChance(aura.CalcDispelChance(unitTarget, !unitTarget.IsFriendlyTo(m_caster)))) if (Convert.ToBoolean(aura.GetSpellInfo().GetAllEffectsMechanicMask() & (1 << mechanic))) dispel_list.Add(new KeyValuePair(aura.GetId(), aura.GetCasterGUID())); } while (!dispel_list.Empty()) { unitTarget.RemoveAura(dispel_list[0].Key, dispel_list[0].Value, 0, AuraRemoveMode.EnemySpell); dispel_list.RemoveAt(0); } } [SpellEffectHandler(SpellEffectName.ResurrectPet)] void EffectSummonDeadPet(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; Player player = m_caster.ToPlayer(); if (player == null) return; Pet pet = player.GetPet(); if (pet != null && pet.IsAlive()) return; if (damage < 0) return; float x, y, z; player.GetPosition(out x, out y, out z); if (pet == null) { player.SummonPet(0, x, y, z, player.Orientation, PetType.Summon, 0); pet = player.GetPet(); } if (pet == null) return; player.GetMap().CreatureRelocation(pet, x, y, z, player.GetOrientation()); pet.SetUInt32Value(ObjectFields.DynamicFlags, (uint)UnitDynFlags.HideModel); pet.RemoveFlag(UnitFields.Flags, UnitFlags.Skinnable); pet.setDeathState(DeathState.Alive); pet.ClearUnitState(UnitState.AllState); pet.SetHealth(pet.CountPctFromMaxHealth(damage)); pet.InitializeAI(); player.PetSpellInitialize(); pet.SavePetToDB(PetSaveMode.AsCurrent); } [SpellEffectHandler(SpellEffectName.DestroyAllTotems)] void EffectDestroyAllTotems(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; int mana = 0; for (byte slot = (int)SummonSlot.Totem; slot < SharedConst.MaxTotemSlot; ++slot) { if (m_caster.m_SummonSlot[slot].IsEmpty()) continue; Creature totem = m_caster.GetMap().GetCreature(m_caster.m_SummonSlot[slot]); if (totem != null && totem.IsTotem()) { uint spell_id = totem.GetUInt32Value(UnitFields.CreatedBySpell); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id); if (spellInfo != null) { var costs = spellInfo.CalcPowerCost(m_caster, spellInfo.GetSchoolMask()); var m = costs.Find(cost => cost.Power == PowerType.Mana); if (m != null) mana += m.Amount; } totem.ToTotem().UnSummon(); } } MathFunctions.ApplyPct(ref mana, damage); if (mana != 0) m_caster.CastCustomSpell(m_caster, 39104, mana, 0, 0, true); } [SpellEffectHandler(SpellEffectName.DurabilityDamage)] void EffectDurabilityDamage(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; int slot = effectInfo.MiscValue; // -1 means all player equipped items and -2 all items if (slot < 0) { unitTarget.ToPlayer().DurabilityPointsLossAll(damage, (slot < -1)); ExecuteLogEffectDurabilityDamage(effIndex, unitTarget, -1, -1); return; } // invalid slot value if (slot >= InventorySlots.BagEnd) return; Item item = unitTarget.ToPlayer().GetItemByPos(InventorySlots.Bag0, (byte)slot); if (item != null) { unitTarget.ToPlayer().DurabilityPointsLoss(item, damage); ExecuteLogEffectDurabilityDamage(effIndex, unitTarget, (int)item.GetEntry(), slot); } } [SpellEffectHandler(SpellEffectName.DurabilityDamagePct)] void EffectDurabilityDamagePCT(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; int slot = effectInfo.MiscValue; // FIXME: some spells effects have value -1/-2 // Possibly its mean -1 all player equipped items and -2 all items if (slot < 0) { unitTarget.ToPlayer().DurabilityLossAll(damage / 100.0f, (slot < -1)); return; } // invalid slot value if (slot >= InventorySlots.BagEnd) return; if (damage <= 0) return; Item item = unitTarget.ToPlayer().GetItemByPos(InventorySlots.Bag0, (byte)slot); if (item != null) unitTarget.ToPlayer().DurabilityLoss(item, damage / 100.0f); } [SpellEffectHandler(SpellEffectName.ModifyThreatPercent)] void EffectModifyThreatPercent(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; unitTarget.GetThreatManager().modifyThreatPercent(m_caster, damage); } [SpellEffectHandler(SpellEffectName.TransDoor)] void EffectTransmitted(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; uint name_id = (uint)effectInfo.MiscValue; var overrideSummonedGameObjects = m_caster.GetAuraEffectsByType(AuraType.OverrideSummonedObject); foreach (AuraEffect aurEff in overrideSummonedGameObjects) { if (aurEff.GetMiscValue() == name_id) { name_id = (uint)aurEff.GetMiscValueB(); break; } } GameObjectTemplate goinfo = Global.ObjectMgr.GetGameObjectTemplate(name_id); if (goinfo == null) { Log.outError(LogFilter.Sql, "Gameobject (Entry: {0}) not exist and not created at spell (ID: {1}) cast", name_id, m_spellInfo.Id); return; } float fx, fy, fz; if (m_targets.HasDst()) destTarget.GetPosition(out fx, out fy, out fz); //FIXME: this can be better check for most objects but still hack else if (effectInfo.HasRadius() && m_spellInfo.Speed == 0) { float dis = effectInfo.CalcRadius(m_originalCaster); m_caster.GetClosePoint(out fx, out fy, out fz, SharedConst.DefaultWorldObjectSize, dis); } else { //GO is always friendly to it's creator, get range for friends float min_dis = m_spellInfo.GetMinRange(true); float max_dis = m_spellInfo.GetMaxRange(true); float dis = (float)RandomHelper.NextDouble() * (max_dis - min_dis) + min_dis; m_caster.GetClosePoint(out fx, out fy, out fz, SharedConst.DefaultWorldObjectSize, dis); } Map cMap = m_caster.GetMap(); // if gameobject is summoning object, it should be spawned right on caster's position if (goinfo.type == GameObjectTypes.Ritual) m_caster.GetPosition(out fx, out fy, out fz); GameObject pGameObj = new GameObject(); Position pos = new Position(fx, fy, fz, m_caster.GetOrientation()); Quaternion rotation = new Quaternion(Matrix3.fromEulerAnglesZYX(m_caster.GetOrientation(), 0.0f, 0.0f)); if (!pGameObj.Create(name_id, cMap, m_caster.GetPhaseMask(), pos, rotation, 255, GameObjectState.Ready)) return; pGameObj.CopyPhaseFrom(m_caster); int duration = m_spellInfo.CalcDuration(m_caster); switch (goinfo.type) { case GameObjectTypes.FishingNode: { pGameObj.SetFaction(m_caster.getFaction()); ObjectGuid bobberGuid = pGameObj.GetGUID(); // client requires fishing bobber guid in channel object slot 0 to be usable m_caster.SetDynamicStructuredValue(UnitDynamicFields.ChannelObjects, 0, bobberGuid); m_caster.AddGameObject(pGameObj); // will removed at spell cancel // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo)) // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME) int lastSec = 0; switch (RandomHelper.IRand(0, 3)) { case 0: lastSec = 3; break; case 1: lastSec = 7; break; case 2: lastSec = 13; break; case 3: lastSec = 17; break; } duration = duration - lastSec * Time.InMilliseconds + 5 * Time.InMilliseconds; break; } case GameObjectTypes.Ritual: { if (m_caster.IsTypeId(TypeId.Player)) { pGameObj.AddUniqueUse(m_caster.ToPlayer()); m_caster.AddGameObject(pGameObj); // will be removed at spell cancel } break; } case GameObjectTypes.DuelArbiter: // 52991 m_caster.AddGameObject(pGameObj); break; case GameObjectTypes.FishingHole: case GameObjectTypes.Chest: default: break; } pGameObj.SetRespawnTime(duration > 0 ? duration / Time.InMilliseconds : 0); pGameObj.SetOwnerGUID(m_caster.GetGUID()); pGameObj.SetSpellId(m_spellInfo.Id); ExecuteLogEffectSummonObject(effIndex, pGameObj); Log.outDebug(LogFilter.Spells, "AddObject at SpellEfects.cpp EffectTransmitted"); cMap.AddToMap(pGameObj); GameObject linkedTrap = pGameObj.GetLinkedTrap(); if (linkedTrap != null) { linkedTrap.CopyPhaseFrom(m_caster); linkedTrap.SetRespawnTime(duration > 0 ? duration / Time.InMilliseconds : 0); linkedTrap.SetSpellId(m_spellInfo.Id); linkedTrap.SetOwnerGUID(m_caster.GetGUID()); ExecuteLogEffectSummonObject(effIndex, linkedTrap); } } [SpellEffectHandler(SpellEffectName.Prospecting)] void EffectProspecting(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; Player player = m_caster.ToPlayer(); if (player == null) return; if (itemTarget == null || !itemTarget.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.IsProspectable)) return; if (itemTarget.GetCount() < 5) return; if (WorldConfig.GetBoolValue(WorldCfg.SkillProspecting)) { uint SkillValue = player.GetPureSkillValue(SkillType.Jewelcrafting); uint reqSkillValue = itemTarget.GetTemplate().GetRequiredSkillRank(); player.UpdateGatherSkill(SkillType.Jewelcrafting, SkillValue, reqSkillValue); } player.SendLoot(itemTarget.GetGUID(), LootType.Prospecting); } [SpellEffectHandler(SpellEffectName.Milling)] void EffectMilling(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; Player player = m_caster.ToPlayer(); if (player == null) return; if (itemTarget == null || !itemTarget.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.IsMillable)) return; if (itemTarget.GetCount() < 5) return; if (WorldConfig.GetBoolValue(WorldCfg.SkillMilling)) { uint SkillValue = player.GetPureSkillValue(SkillType.Inscription); uint reqSkillValue = itemTarget.GetTemplate().GetRequiredSkillRank(); player.UpdateGatherSkill(SkillType.Inscription, SkillValue, reqSkillValue); } player.SendLoot(itemTarget.GetGUID(), LootType.Milling); } [SpellEffectHandler(SpellEffectName.Skill)] void EffectSkill(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; Log.outDebug(LogFilter.Spells, "WORLD: SkillEFFECT"); } /* There is currently no need for this effect. We handle it in Battleground.cpp If we would handle the resurrection here, the spiritguide would instantly disappear as the player revives, and so we wouldn't see the spirit heal visual effect on the npc. This is why we use a half sec delay between the visual effect and the resurrection itself */ void EffectSpiritHeal(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; } // remove insignia spell effect [SpellEffectHandler(SpellEffectName.SkinPlayerCorpse)] void EffectSkinPlayerCorpse(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; Log.outDebug(LogFilter.Spells, "Effect: SkinPlayerCorpse"); Player player = m_caster.ToPlayer(); Player target = unitTarget.ToPlayer(); if (player == null || target == null || target.IsAlive()) return; target.RemovedInsignia(player); } [SpellEffectHandler(SpellEffectName.StealBeneficialBuff)] void EffectStealBeneficialBuff(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; Log.outDebug(LogFilter.Spells, "Effect: StealBeneficialBuff"); if (unitTarget == null || unitTarget == m_caster) // can't steal from self return; List> steal_list = new List>(); // Create dispel mask by dispel type uint dispelMask = SpellInfo.GetDispelMask((DispelType)effectInfo.MiscValue); var auras = unitTarget.GetOwnedAuras(); foreach (var map in auras) { Aura aura = map.Value; AuraApplication aurApp = aura.GetApplicationOfTarget(unitTarget.GetGUID()); if (aurApp == null) continue; if (Convert.ToBoolean(aura.GetSpellInfo().GetDispelMask() & dispelMask)) { // Need check for passive? this if (!aurApp.IsPositive() || aura.IsPassive() || aura.GetSpellInfo().HasAttribute(SpellAttr4.NotStealable)) continue; // The charges / stack amounts don't count towards the total number of auras that can be dispelled. // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) . 50% chance to dispell // Polymorph instead of 1 / (5 + 1) . 16%. bool dispelCharges = aura.GetSpellInfo().HasAttribute(SpellAttr7.DispelCharges); byte charges = dispelCharges ? aura.GetCharges() : aura.GetStackAmount(); if (charges > 0) steal_list.Add(Tuple.Create(aura, charges)); } } if (steal_list.Empty()) return; // Ok if exist some buffs for dispel try dispel it List> success_list = new List>(); DispelFailed dispelFailed = new DispelFailed(); dispelFailed.CasterGUID = m_caster.GetGUID(); dispelFailed.VictimGUID = unitTarget.GetGUID(); dispelFailed.SpellID = m_spellInfo.Id; // dispel N = damage buffs (or while exist buffs for dispel) for (int count = 0; count < damage && !steal_list.Empty();) { // Random select buff for dispel var pair = steal_list[RandomHelper.IRand(0, steal_list.Count - 1)]; int chance = pair.Item1.CalcDispelChance(unitTarget, !unitTarget.IsFriendlyTo(m_caster)); // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance." if (chance == 0) { steal_list.Remove(pair); continue; } else { if (RandomHelper.randChance(chance)) { success_list.Add(new KeyValuePair(pair.Item1.GetId(), pair.Item1.GetCasterGUID())); var temp = pair.Item2; --temp; pair = Tuple.Create(pair.Item1, temp); if (pair.Item2 <= 0) steal_list.Remove(pair); } else dispelFailed.FailedSpells.Add(pair.Item1.GetId()); ++count; } } if (!dispelFailed.FailedSpells.Empty()) m_caster.SendMessageToSet(dispelFailed, true); if (success_list.Empty()) return; SpellDispellLog spellDispellLog = new SpellDispellLog(); spellDispellLog.IsBreak = false; // TODO: use me spellDispellLog.IsSteal = true; spellDispellLog.TargetGUID = unitTarget.GetGUID(); spellDispellLog.CasterGUID = m_caster.GetGUID(); spellDispellLog.DispelledBySpellID = m_spellInfo.Id; foreach (var dispell in success_list) { var dispellData = new SpellDispellData(); dispellData.SpellID = dispell.Key; dispellData.Harmful = false; // TODO: use me //dispellData.Rolled = none; // TODO: use me //dispellData.Needed = none; // TODO: use me unitTarget.RemoveAurasDueToSpellBySteal(dispell.Key, dispell.Value, m_caster); spellDispellLog.DispellData.Add(dispellData); } m_caster.SendMessageToSet(spellDispellLog, true); } [SpellEffectHandler(SpellEffectName.KillCredit)] void EffectKillCreditPersonal(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; unitTarget.ToPlayer().KilledMonsterCredit((uint)effectInfo.MiscValue); } [SpellEffectHandler(SpellEffectName.KillCredit2)] void EffectKillCredit(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; int creatureEntry = effectInfo.MiscValue; if (creatureEntry != 0) unitTarget.ToPlayer().RewardPlayerAndGroupAtEvent((uint)creatureEntry, unitTarget); } [SpellEffectHandler(SpellEffectName.QuestFail)] void EffectQuestFail(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; unitTarget.ToPlayer().FailQuest((uint)effectInfo.MiscValue); } [SpellEffectHandler(SpellEffectName.QuestStart)] void EffectQuestStart(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget) return; Player player = unitTarget.ToPlayer(); if (!player) return; Quest quest = Global.ObjectMgr.GetQuestTemplate((uint)effectInfo.MiscValue); if (quest != null) { if (!player.CanTakeQuest(quest, false)) return; if (quest.IsAutoAccept() && player.CanAddQuest(quest, false)) { player.AddQuestAndCheckCompletion(quest, null); player.PlayerTalkClass.SendQuestGiverQuestDetails(quest, player.GetGUID(), true, true); } else player.PlayerTalkClass.SendQuestGiverQuestDetails(quest, player.GetGUID(), true, false); } } [SpellEffectHandler(SpellEffectName.ActivateRune)] void EffectActivateRune(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Launch) return; if (!m_caster.IsTypeId(TypeId.Player)) return; Player player = m_caster.ToPlayer(); if (player.GetClass() != Class.Deathknight) return; // needed later m_runesState = m_caster.ToPlayer().GetRunesState(); uint count = (uint)damage; if (count == 0) count = 1; // first restore fully depleted runes for (byte j = 0; j < player.GetMaxPower(PowerType.Runes) && count > 0; ++j) { if (player.GetRuneCooldown(j) == player.GetRuneBaseCooldown()) { player.SetRuneCooldown(j, 0); --count; } } // then the rest if we still got something left for (byte j = 0; j < player.GetMaxPower(PowerType.Runes) && count > 0; ++j) { player.SetRuneCooldown(j, 0); --count; } } [SpellEffectHandler(SpellEffectName.CreateTamedPet)] void EffectCreateTamedPet(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player) || !unitTarget.GetPetGUID().IsEmpty() || unitTarget.GetClass() != Class.Hunter) return; uint creatureEntry = (uint)effectInfo.MiscValue; Pet pet = unitTarget.CreateTamedPetFrom(creatureEntry, m_spellInfo.Id); if (pet == null) return; // relocate float px, py, pz; unitTarget.GetClosePoint(out px, out py, out pz, pet.GetObjectSize(), SharedConst.PetFollowDist, pet.GetFollowAngle()); pet.Relocate(px, py, pz, unitTarget.GetOrientation()); // add to world pet.GetMap().AddToMap(pet.ToCreature()); // unitTarget has pet now unitTarget.SetMinion(pet, true); if (unitTarget.IsTypeId(TypeId.Player)) { pet.SavePetToDB(PetSaveMode.AsCurrent); unitTarget.ToPlayer().PetSpellInitialize(); } } [SpellEffectHandler(SpellEffectName.DiscoverTaxi)] void EffectDiscoverTaxi(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; uint nodeid = (uint)effectInfo.MiscValue; if (CliDB.TaxiNodesStorage.ContainsKey(nodeid)) unitTarget.ToPlayer().GetSession().SendDiscoverNewTaxiNode(nodeid); } [SpellEffectHandler(SpellEffectName.TitanGrip)] void EffectTitanGrip(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (m_caster.IsTypeId(TypeId.Player)) m_caster.ToPlayer().SetCanTitanGrip(true, (uint)effectInfo.MiscValue); } [SpellEffectHandler(SpellEffectName.RedirectThreat)] void EffectRedirectThreat(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget != null) m_caster.SetRedirectThreat(unitTarget.GetGUID(), (uint)damage); } [SpellEffectHandler(SpellEffectName.GameObjectDamage)] void EffectGameObjectDamage(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (gameObjTarget == null) return; Unit caster = m_originalCaster; if (caster == null) return; FactionTemplateRecord casterFaction = caster.GetFactionTemplateEntry(); FactionTemplateRecord targetFaction = CliDB.FactionTemplateStorage.LookupByKey(gameObjTarget.GetUInt32Value(GameObjectFields.Faction)); // Do not allow to damage GO's of friendly factions (ie: Wintergrasp Walls/Ulduar Storm Beacons) if (targetFaction == null || (casterFaction != null && targetFaction != null && !casterFaction.IsFriendlyTo(targetFaction))) gameObjTarget.ModifyHealth(-damage, caster, GetSpellInfo().Id); } [SpellEffectHandler(SpellEffectName.GameobjectRepair)] void EffectGameObjectRepair(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (gameObjTarget == null) return; gameObjTarget.ModifyHealth(damage, m_caster); } [SpellEffectHandler(SpellEffectName.GameobjectSetDestructionState)] void EffectGameObjectSetDestructionState(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (gameObjTarget == null || m_originalCaster == null) return; Player player = m_originalCaster.GetCharmerOrOwnerPlayerOrPlayerItself(); gameObjTarget.SetDestructibleState((GameObjectDestructibleState)effectInfo.MiscValue, player, true); } void SummonGuardian(uint i, uint entry, SummonPropertiesRecord properties, uint numGuardians) { Unit caster = m_originalCaster; if (caster == null) return; if (caster.IsTotem()) caster = caster.ToTotem().GetOwner(); // in another case summon new uint level = caster.getLevel(); // level of pet summoned using engineering item based at engineering skill level if (m_CastItem != null && caster.IsTypeId(TypeId.Player)) { ItemTemplate proto = m_CastItem.GetTemplate(); if (proto != null) if (proto.GetRequiredSkill() == (uint)SkillType.Engineering) { ushort skill202 = caster.ToPlayer().GetSkillValue(SkillType.Engineering); if (skill202 != 0) level = (uint)(skill202 / 5); } } float radius = 5.0f; int duration = m_spellInfo.CalcDuration(m_originalCaster); TempSummonType summonType = (duration == 0) ? TempSummonType.DeadDespawn : TempSummonType.TimedDespawn; Map map = caster.GetMap(); for (uint count = 0; count < numGuardians; ++count) { Position pos = new Position(); if (count == 0) pos = destTarget; else // randomize position for multiple summons m_caster.GetRandomPoint(destTarget, radius, out pos); TempSummon summon = map.SummonCreature(entry, pos, properties, (uint)duration, caster, m_spellInfo.Id); if (summon == null) return; if (summon.HasUnitTypeMask(UnitTypeMask.Guardian)) ((Guardian)summon).InitStatsForLevel(level); if (properties != null && properties.Category == SummonCategory.Ally) summon.SetFaction(caster.getFaction()); if (summon.HasUnitTypeMask(UnitTypeMask.Minion) && m_targets.HasDst()) ((Minion)summon).SetFollowAngle(m_caster.GetAngle(summon.GetPosition())); if (summon.GetEntry() == 27893) { uint weapon = m_caster.GetUInt32Value(PlayerFields.VisibleItem + (EquipmentSlot.MainHand * 2)); if (weapon != 0) { summon.SetDisplayId(11686); summon.SetVirtualItem(0, weapon); } else summon.SetDisplayId(1126); } summon.GetAI().EnterEvadeMode(); ExecuteLogEffectSummonObject(i, summon); } } [SpellEffectHandler(SpellEffectName.AllowRenamePet)] void EffectRenamePet(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Unit) || !unitTarget.IsPet() || unitTarget.ToPet().getPetType() != PetType.Hunter) return; unitTarget.SetByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PetFlags, UnitPetFlags.CanBeRenamed); } [SpellEffectHandler(SpellEffectName.PlayMusic)] void EffectPlayMusic(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; uint soundid = (uint)effectInfo.MiscValue; if (!CliDB.SoundKitStorage.ContainsKey(soundid)) { Log.outError(LogFilter.Spells, "EffectPlayMusic: Sound (Id: {0}) not exist in spell {1}.", soundid, m_spellInfo.Id); return; } unitTarget.ToPlayer().SendPacket(new PlayMusic(soundid)); } [SpellEffectHandler(SpellEffectName.TalentSpecSelect)] void EffectActivateSpec(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); uint specID = m_misc.SpecializationId; ChrSpecializationRecord spec = CliDB.ChrSpecializationStorage.LookupByKey(specID); // Safety checks done in Spell::CheckCast if (!spec.IsPetSpecialization()) player.ActivateTalentGroup(spec); else player.GetPet().SetSpecialization(specID); } [SpellEffectHandler(SpellEffectName.PlaySound)] void EffectPlaySound(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget) return; Player player = unitTarget.ToPlayer(); if (!player) return; switch (m_spellInfo.Id) { case 91604: // Restricted Flight Area player.GetSession().SendNotification(CypherStrings.ZoneNoflyzone); break; default: break; } uint soundId = (uint)effectInfo.MiscValue; if (!CliDB.SoundKitStorage.ContainsKey(soundId)) { Log.outError(LogFilter.Spells, "EffectPlaySound: Sound (Id: {0}) not exist in spell {1}.", soundId, m_spellInfo.Id); return; } player.PlayDirectSound(soundId, player); } [SpellEffectHandler(SpellEffectName.RemoveAura)] void EffectRemoveAura(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; // there may be need of specifying casterguid of removed auras unitTarget.RemoveAurasDueToSpell(effectInfo.TriggerSpell); } [SpellEffectHandler(SpellEffectName.DamageFromMaxHealthPCT)] void EffectDamageFromMaxHealthPCT(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; m_damage += (int)unitTarget.CountPctFromMaxHealth(damage); } [SpellEffectHandler(SpellEffectName.GiveCurrency)] void EffectGiveCurrency(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; if (!CliDB.CurrencyTypesStorage.ContainsKey(effectInfo.MiscValue)) return; unitTarget.ToPlayer().ModifyCurrency((CurrencyTypes)effectInfo.MiscValue, damage); } [SpellEffectHandler(SpellEffectName.CastButton)] void EffectCastButtons(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!m_caster.IsTypeId(TypeId.Player)) return; Player p_caster = m_caster.ToPlayer(); int button_id = effectInfo.MiscValue + 132; int n_buttons = effectInfo.MiscValueB; for (; n_buttons != 0; --n_buttons, ++button_id) { ActionButton ab = p_caster.GetActionButton((byte)button_id); if (ab == null || ab.GetButtonType() != ActionButtonType.Spell) continue; //! Action button data is unverified when it's set so it can be "hacked" //! to contain invalid spells, so filter here. uint spell_id = ab.GetAction(); if (spell_id == 0) continue; SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id); if (spellInfo == null) continue; if (!p_caster.HasSpell(spell_id) || p_caster.GetSpellHistory().HasCooldown(spell_id)) continue; if (!spellInfo.HasAttribute(SpellAttr9.SummonPlayerTotem)) continue; TriggerCastFlags triggerFlags = (TriggerCastFlags.IgnoreGCD | TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.CastDirectly | TriggerCastFlags.DontReportCastError); m_caster.CastSpell(m_caster, spell_id, triggerFlags); } } [SpellEffectHandler(SpellEffectName.RechargeItem)] void EffectRechargeItem(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null) return; Player player = unitTarget.ToPlayer(); if (player == null) return; Item item = player.GetItemByEntry(effectInfo.ItemType); if (item != null) { ItemTemplate proto = item.GetTemplate(); for (int x = 0; x < proto.Effects.Count && x < 5; ++x) item.SetSpellCharges(x, proto.Effects[x].Charges); item.SetState(ItemUpdateState.Changed, player); } } [SpellEffectHandler(SpellEffectName.Bind)] void EffectBind(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); WorldLocation homeLoc = new WorldLocation(); uint areaId = player.GetAreaId(); if (effectInfo.MiscValue != 0) areaId = (uint)effectInfo.MiscValue; if (m_targets.HasDst()) homeLoc.WorldRelocate(destTarget); else { homeLoc.Relocate(player.GetPosition()); homeLoc.SetMapId(player.GetMapId()); } player.SetHomebind(homeLoc, areaId); player.SendBindPointUpdate(); Log.outDebug(LogFilter.Spells, "EffectBind: New homebind MapId: {0}, AreaId: {1}, {2}, ", homeLoc.GetMapId(), areaId, homeLoc); // zone update PlayerBound packet = new PlayerBound(m_caster.GetGUID(), areaId); player.SendPacket(packet); } [SpellEffectHandler(SpellEffectName.SummonRafFriend)] void EffectSummonRaFFriend(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!m_caster.IsTypeId(TypeId.Player) || unitTarget == null || !unitTarget.IsTypeId(TypeId.Player)) return; m_caster.CastSpell(unitTarget, effectInfo.TriggerSpell, true); } [SpellEffectHandler(SpellEffectName.UnlockGuildVaultTab)] void EffectUnlockGuildVaultTab(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; // Safety checks done in Spell.CheckCast Player caster = m_caster.ToPlayer(); Guild guild = caster.GetGuild(); if (guild != null) guild.HandleBuyBankTab(caster.GetSession(), (byte)(effectInfo.BasePoints - 1)); // Bank tabs start at zero internally } [SpellEffectHandler(SpellEffectName.ResurrectWithAura)] void EffectResurrectWithAura(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (unitTarget == null || !unitTarget.IsInWorld) return; Player target = unitTarget.ToPlayer(); if (target == null) return; if (unitTarget.IsAlive()) return; if (target.IsResurrectRequested()) // already have one active request return; uint health = (uint)target.CountPctFromMaxHealth(damage); uint mana = (uint)MathFunctions.CalculatePct(target.GetMaxPower(PowerType.Mana), damage); uint resurrectAura = 0; if (Global.SpellMgr.GetSpellInfo(effectInfo.TriggerSpell) != null) resurrectAura = effectInfo.TriggerSpell; if (resurrectAura != 0 && target.HasAura(resurrectAura)) return; ExecuteLogEffectResurrect(effIndex, target); target.SetResurrectRequestData(m_caster, health, mana, resurrectAura); SendResurrectRequest(target); } [SpellEffectHandler(SpellEffectName.CreateAreaTrigger)] void EffectCreateAreaTrigger(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!m_targets.HasDst()) return; // trigger entry/miscvalue relation is currently unknown, for now use MiscValue as trigger entry uint triggerEntry = (uint)effectInfo.MiscValue; int duration = GetSpellInfo().CalcDuration(GetCaster()); AreaTrigger areaTrigger = new AreaTrigger(); if (!areaTrigger.CreateAreaTrigger((uint)effectInfo.MiscValue, GetCaster(), null, GetSpellInfo(), destTarget.GetPosition(), duration, m_SpellVisual, m_castId)) areaTrigger.Dispose(); } [SpellEffectHandler(SpellEffectName.RemoveTalent)] void EffectRemoveTalent(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; TalentRecord talent = CliDB.TalentStorage.LookupByKey(m_misc.TalentId); if (talent == null) return; Player player = unitTarget ? unitTarget.ToPlayer() : null; if (player == null) return; player.RemoveTalent(talent); player.SendTalentsInfoData(); } [SpellEffectHandler(SpellEffectName.DestroyItem)] void EffectDestroyItem(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; Player player = unitTarget.ToPlayer(); SpellEffectInfo effect = GetEffect(effIndex); uint itemId = effect.ItemType; Item item = player.GetItemByEntry(itemId); if (item) player.DestroyItem(item.GetBagSlot(), item.GetSlot(), true); } [SpellEffectHandler(SpellEffectName.LearnGarrisonBuilding)] void EffectLearnGarrisonBuilding(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; Garrison garrison = unitTarget.ToPlayer().GetGarrison(); if (garrison != null) garrison.LearnBlueprint((uint)GetEffect(effIndex).MiscValue); } [SpellEffectHandler(SpellEffectName.CreateGarrison)] void EffectCreateGarrison(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; unitTarget.ToPlayer().CreateGarrison((uint)GetEffect(effIndex).MiscValue); } [SpellEffectHandler(SpellEffectName.CreateConversation)] void EffectCreateConversation(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!m_targets.HasDst()) return; Conversation.CreateConversation((uint)effectInfo.MiscValue, GetCaster(), destTarget.GetPosition(), new List() { GetCaster().GetGUID() }, GetSpellInfo()); } [SpellEffectHandler(SpellEffectName.AddGarrisonFollower)] void EffectAddGarrisonFollower(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; Garrison garrison = unitTarget.ToPlayer().GetGarrison(); if (garrison != null) garrison.AddFollower((uint)GetEffect(effIndex).MiscValue); } [SpellEffectHandler(SpellEffectName.CreateHeirloomItem)] void EffectCreateHeirloomItem(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; Player player = m_caster.ToPlayer(); if (!player) return; CollectionMgr collectionMgr = player.GetSession().GetCollectionMgr(); if (collectionMgr == null) return; List bonusList = new List(); bonusList.Add(collectionMgr.GetHeirloomBonus(m_misc.Data0)); DoCreateItem(effIndex, m_misc.Data0, 0, bonusList); ExecuteLogEffectCreateItem(effIndex, m_misc.Data0); } [SpellEffectHandler(SpellEffectName.ActivateGarrisonBuilding)] void EffectActivateGarrisonBuilding(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; Garrison garrison = unitTarget.ToPlayer().GetGarrison(); if (garrison != null) garrison.ActivateBuilding((uint)GetEffect(effIndex).MiscValue); } [SpellEffectHandler(SpellEffectName.HealBattlepetPct)] void EffectHealBattlePetPct(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; BattlePetMgr battlePetMgr = unitTarget.ToPlayer().GetSession().GetBattlePetMgr(); if (battlePetMgr != null) battlePetMgr.HealBattlePetsPct((byte)GetEffect(effIndex).BasePoints); } [SpellEffectHandler(SpellEffectName.EnableBattlePets)] void EffectEnableBattlePets(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; Player plr = unitTarget.ToPlayer(); plr.SetFlag(PlayerFields.Flags, PlayerFlags.PetBattlesUnlocked); plr.GetSession().GetBattlePetMgr().UnlockSlot(0); } [SpellEffectHandler(SpellEffectName.LaunchQuestChoice)] void EffectLaunchQuestChoice(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsPlayer()) return; unitTarget.ToPlayer().SendPlayerChoice(GetCaster().GetGUID(), effectInfo.MiscValue); } [SpellEffectHandler(SpellEffectName.UncageBattlepet)] void EffectUncageBattlePet(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (!m_CastItem || !m_caster || !m_caster.IsTypeId(TypeId.Player)) return; Player plr = m_caster.ToPlayer(); // are we allowed to learn battle pets without it? /*if (plr.HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_PET_BATTLES_UNLOCKED)) return; // send some error*/ uint speciesId = m_CastItem.GetModifier(ItemModifier.BattlePetSpeciesId); ushort breed = (ushort)(m_CastItem.GetModifier(ItemModifier.BattlePetBreedData) & 0xFFFFFF); byte quality = (byte)((m_CastItem.GetModifier(ItemModifier.BattlePetBreedData) >> 24) & 0xFF); ushort level = (ushort)m_CastItem.GetModifier(ItemModifier.BattlePetLevel); uint creatureId = m_CastItem.GetModifier(ItemModifier.BattlePetDisplayId); BattlePetSpeciesRecord speciesEntry = CliDB.BattlePetSpeciesStorage.LookupByKey(speciesId); if (speciesEntry == null) return; BattlePetMgr battlePetMgr = plr.GetSession().GetBattlePetMgr(); if (battlePetMgr == null) return; // TODO: This means if you put your highest lvl pet into cage, you won't be able to uncage it again which is probably wrong. // We will need to store maxLearnedLevel somewhere to avoid this behaviour. if (battlePetMgr.GetMaxPetLevel() < level) { battlePetMgr.SendError(BattlePetError.TooHighLevelToUncage, creatureId); // or speciesEntry.CreatureID SendCastResult(SpellCastResult.CantAddBattlePet); return; } if (battlePetMgr.GetPetCount(speciesId) >= SharedConst.MaxBattlePetsPerSpecies) { battlePetMgr.SendError(BattlePetError.CantHaveMorePetsOfThatType, creatureId); // or speciesEntry.CreatureID SendCastResult(SpellCastResult.CantAddBattlePet); return; } battlePetMgr.AddPet(speciesId, creatureId, breed, quality, level); if (!plr.HasSpell(speciesEntry.SummonSpellID)) plr.LearnSpell(speciesEntry.SummonSpellID, false); plr.DestroyItem(m_CastItem.GetBagSlot(), m_CastItem.GetSlot(), true); m_CastItem = null; } [SpellEffectHandler(SpellEffectName.UpgradeHeirloom)] void EffectUpgradeHeirloom(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; Player player = m_caster.ToPlayer(); if (player) { CollectionMgr collectionMgr = player.GetSession().GetCollectionMgr(); if (collectionMgr != null) collectionMgr.UpgradeHeirloom(m_misc.Data0, m_castItemEntry); } } [SpellEffectHandler(SpellEffectName.ApplyEnchantIllusion)] void EffectApplyEnchantIllusion(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!itemTarget) return; Player player = m_caster.ToPlayer(); if (!player || player.GetGUID() != itemTarget.GetOwnerGUID()) return; itemTarget.SetState(ItemUpdateState.Changed, player); itemTarget.SetModifier(ItemModifier.EnchantIllusionAllSpecs, (uint)effectInfo.MiscValue); if (itemTarget.IsEquipped()) player.SetUInt16Value(PlayerFields.VisibleItem + 1 + (itemTarget.GetSlot() * 2), 1, itemTarget.GetVisibleItemVisual(player)); player.RemoveTradeableItem(itemTarget); itemTarget.ClearSoulboundTradeable(player); } [SpellEffectHandler(SpellEffectName.UpdatePlayerPhase)] void EffectUpdatePlayerPhase(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; unitTarget.UpdateAreaAndZonePhase(); } [SpellEffectHandler(SpellEffectName.UpdateZoneAurasPhases)] void EffectUpdateZoneAurasAndPhases(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsTypeId(TypeId.Player)) return; unitTarget.ToPlayer().UpdateAreaDependentAuras(unitTarget.GetAreaId()); } [SpellEffectHandler(SpellEffectName.GiveArtifactPower)] void EffectGiveArtifactPower(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) return; if (!m_caster.IsTypeId(TypeId.Player)) return; Aura artifactAura = m_caster.GetAura(PlayerConst.ArtifactsAllWeaponsGeneralWeaponEquippedPassive); if (artifactAura != null) { Item artifact = m_caster.ToPlayer().GetItemByGuid(artifactAura.GetCastItemGUID()); if (artifact) artifact.GiveArtifactXp((ulong)damage, m_CastItem, (uint)effectInfo.MiscValue); } } [SpellEffectHandler(SpellEffectName.GiveArtifactPowerNoBonus)] void EffectGiveArtifactPowerNoBonus(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) return; if (!unitTarget || !m_caster.IsTypeId(TypeId.Player)) return; Aura artifactAura = unitTarget.GetAura(PlayerConst.ArtifactsAllWeaponsGeneralWeaponEquippedPassive); if (artifactAura != null) { Item artifact = unitTarget.ToPlayer().GetItemByGuid(artifactAura.GetCastItemGUID()); if (artifact) artifact.GiveArtifactXp((ulong)damage, m_CastItem, 0); } } [SpellEffectHandler(SpellEffectName.PlayScene)] void EffectPlayScene(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.Hit) return; if (m_caster.GetTypeId() != TypeId.Player) return; m_caster.ToPlayer().GetSceneMgr().PlayScene((uint)effectInfo.MiscValue, destTarget); } [SpellEffectHandler(SpellEffectName.GiveHonor)] void EffectGiveHonor(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || unitTarget.GetTypeId() != TypeId.Player) return; PvPCredit packet = new PvPCredit(); packet.Honor = damage; packet.OriginalHonor = damage; Player playerTarget = unitTarget.ToPlayer(); playerTarget.AddHonorXP((uint)damage); playerTarget.SendPacket(packet); } [SpellEffectHandler(SpellEffectName.LearnTransmogSet)] void EffectLearnTransmogSet(uint effIndex) { if (effectHandleMode != SpellEffectHandleMode.HitTarget) return; if (!unitTarget || !unitTarget.IsPlayer()) return; unitTarget.ToPlayer().GetSession().GetCollectionMgr().AddTransmogSet((uint)effectInfo.MiscValue); } } public class DispelCharges { public DispelCharges(Aura _aura, byte _value) { aura = _aura; value = _value; } public Aura aura; public byte value; } }