diff options
Diffstat (limited to 'src')
31 files changed, 376 insertions, 229 deletions
diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index e3f2e7b9cfe..14bf90eb8a2 100755 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -44,7 +44,7 @@ int CombatAI::Permissible(const Creature * /*creature*/) return PERMIT_BASE_NO; } -int ArchorAI::Permissible(const Creature * /*creature*/) +int ArcherAI::Permissible(const Creature * /*creature*/) { return PERMIT_BASE_NO; } @@ -54,11 +54,6 @@ int TurretAI::Permissible(const Creature * /*creature*/) return PERMIT_BASE_NO; } -int AOEAI::Permissible(const Creature * /*creature*/) -{ - return PERMIT_BASE_NO; -} - int VehicleAI::Permissible(const Creature * /*creature*/) { return PERMIT_BASE_NO; @@ -174,13 +169,13 @@ void CasterAI::UpdateAI(const uint32 diff) } ////////////// -//ArchorAI +//ArcherAI ////////////// -ArchorAI::ArchorAI(Creature *c) : CreatureAI(c) +ArcherAI::ArcherAI(Creature *c) : CreatureAI(c) { if (!me->m_spells[0]) - sLog->outError("ArchorAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); + sLog->outError("ArcherAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); m_minRange = GetSpellMinRange(me->m_spells[0], false); if (!m_minRange) @@ -189,7 +184,7 @@ ArchorAI::ArchorAI(Creature *c) : CreatureAI(c) me->m_SightDistance = me->m_CombatDistance; } -void ArchorAI::AttackStart(Unit *who) +void ArcherAI::AttackStart(Unit *who) { if (!who) return; @@ -209,7 +204,7 @@ void ArchorAI::AttackStart(Unit *who) me->GetMotionMaster()->MoveIdle(); } -void ArchorAI::UpdateAI(const uint32 /*diff*/) +void ArcherAI::UpdateAI(const uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -258,36 +253,6 @@ void TurretAI::UpdateAI(const uint32 /*diff*/) } ////////////// -//AOEAI -////////////// - -AOEAI::AOEAI(Creature *c) : CreatureAI(c) -{ - if (!me->m_spells[0]) - sLog->outError("AOEAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); - - me->SetVisible(true);//visible to see all spell anims - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);//can't be targeted - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_1);//can't be damaged - me->SetDisplayId(11686);//invisible model, around a size of a player -} - -bool AOEAI::CanAIAttack(const Unit * /*who*/) const -{ - return false; -} - -void AOEAI::AttackStart(Unit * /*who*/) -{ -} - -void AOEAI::UpdateAI(const uint32 /*diff*/) -{ - if (!me->HasAura(me->m_spells[0])) - me->CastSpell(me, me->m_spells[0], false); -} - -////////////// //VehicleAI ////////////// diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h index 6e8f195282c..4aa28c934e7 100755 --- a/src/server/game/AI/CoreAI/CombatAI.h +++ b/src/server/game/AI/CoreAI/CombatAI.h @@ -64,10 +64,10 @@ class CasterAI : public CombatAI float m_attackDist; }; -struct ArchorAI : public CreatureAI +struct ArcherAI : public CreatureAI { public: - explicit ArchorAI(Creature *c); + explicit ArcherAI(Creature *c); void AttackStart(Unit *who); void UpdateAI(const uint32 diff); @@ -89,16 +89,6 @@ struct TurretAI : public CreatureAI float m_minRange; }; -struct AOEAI : public CreatureAI -{ - public: - explicit AOEAI(Creature *c); - bool CanAIAttack(const Unit *who) const; - void AttackStart(Unit *who); - void UpdateAI(const uint32 diff); - - static int Permissible(const Creature *); -}; #define VEHICLE_CONDITION_CHECK_TIME 1000 #define VEHICLE_DISMISS_TIME 5000 struct VehicleAI : public CreatureAI diff --git a/src/server/game/AI/CreatureAIRegistry.cpp b/src/server/game/AI/CreatureAIRegistry.cpp index 3f97135db64..6fb04746111 100755 --- a/src/server/game/AI/CreatureAIRegistry.cpp +++ b/src/server/game/AI/CreatureAIRegistry.cpp @@ -45,10 +45,9 @@ namespace AIRegistry (new CreatureAIFactory<PetAI>("PetAI"))->RegisterSelf(); (new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf(); (new CreatureAIFactory<CombatAI>("CombatAI"))->RegisterSelf(); - (new CreatureAIFactory<ArchorAI>("ArchorAI"))->RegisterSelf(); + (new CreatureAIFactory<ArcherAI>("ArcherAI"))->RegisterSelf(); (new CreatureAIFactory<TurretAI>("TurretAI"))->RegisterSelf(); (new CreatureAIFactory<CreatureEventAI>("EventAI"))->RegisterSelf(); - (new CreatureAIFactory<AOEAI>("AOEAI"))->RegisterSelf(); (new CreatureAIFactory<VehicleAI>("VehicleAI"))->RegisterSelf(); (new CreatureAIFactory<SmartAI>("SmartAI"))->RegisterSelf(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 4c2bf540505..194c3f687de 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2446,8 +2446,9 @@ void Player::RegenerateAll() if (m_regenTimerCount >= 2000) { // Not in combat or they have regeneration - if (!isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) || - HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT) || IsPolymorphed()) + if (!isInCombat() || IsPolymorphed() || m_baseHealthRegen || + HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) || + HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT)) { RegenerateHealth(); } @@ -2600,7 +2601,7 @@ void Player::RegenerateHealth() // normal regen case (maybe partly in combat case) else if (!isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT)) { - addvalue = OCTRegenHPPerSpirit()* HealthIncreaseRate; + addvalue = OCTRegenHPPerSpirit() * HealthIncreaseRate; if (!isInCombat()) { AuraEffectList const& mModHealthRegenPct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT); @@ -2781,6 +2782,7 @@ void Player::SetGameMaster(bool on) m_ExtraFlags |= PLAYER_EXTRA_GM_ON; setFaction(35); SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); + SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS); if (Pet* pet = GetPet()) { @@ -2814,6 +2816,7 @@ void Player::SetGameMaster(bool on) m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON; setFactionForRace(getRace()); RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); + RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS); if (Pet* pet = GetPet()) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 4190f6ef9e1..414791b73c6 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3158,9 +3158,6 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellEntry const* newAura, uint *oldGUID = castItemGUID; } - // refresh charges - foundAura->SetCharges(foundAura->CalcMaxCharges(caster)); - // try to increase stack amount foundAura->ModStackAmount(1); return foundAura; @@ -3279,7 +3276,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) if (aurApp->GetRemoveMode()) return; - aura->HandleAuraSpecificMods(aurApp, caster, true); + aura->HandleAuraSpecificMods(aurApp, caster, true, false); // apply effects of the aura for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS; ++i) @@ -3361,7 +3358,7 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMo if (!auraStateFound) ModifyAuraState(auraState, false); - aura->HandleAuraSpecificMods(aurApp, caster, false); + aura->HandleAuraSpecificMods(aurApp, caster, false, false); // only way correctly remove all auras from list //if (removedAuras != m_removedAurasCount) new aura may be added diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index e4180910bb3..3b2fc825b74 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -584,14 +584,15 @@ enum UnitFlags // Value masks for UNIT_FIELD_FLAGS_2 enum UnitFlags2 { - UNIT_FLAG2_FEIGN_DEATH = 0x00000001, - UNIT_FLAG2_UNK1 = 0x00000002, // Hide unit model (show only player equip) - UNIT_FLAG2_COMPREHEND_LANG = 0x00000008, - UNIT_FLAG2_MIRROR_IMAGE = 0x00000010, - UNIT_FLAG2_FORCE_MOVE = 0x00000040, - UNIT_FLAG2_DISARM_OFFHAND = 0x00000080, - UNIT_FLAG2_DISARM_RANGED = 0x00000400, //this does not disable ranged weapon display (maybe additional flag needed?) - UNIT_FLAG2_REGENERATE_POWER = 0x00000800 + UNIT_FLAG2_FEIGN_DEATH = 0x00000001, + UNIT_FLAG2_UNK1 = 0x00000002, // Hide unit model (show only player equip) + UNIT_FLAG2_COMPREHEND_LANG = 0x00000008, + UNIT_FLAG2_MIRROR_IMAGE = 0x00000010, + UNIT_FLAG2_FORCE_MOVE = 0x00000040, + UNIT_FLAG2_DISARM_OFFHAND = 0x00000080, + UNIT_FLAG2_DISARM_RANGED = 0x00000400, // this does not disable ranged weapon display (maybe additional flag needed?) + UNIT_FLAG2_REGENERATE_POWER = 0x00000800, + UNIT_FLAG2_ALLOW_CHEAT_SPELLS = 0x00040000, // allows casting spells with AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL }; /// Non Player Character flags diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 22876b1467f..d072cd0c970 100755 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1574,12 +1574,6 @@ void ObjectMgr::LoadCreatures() data.phaseMask = 1; } - if (data.npcflag & UNIT_NPC_FLAG_SPELLCLICK) - { - sLog->outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with npcflag UNIT_NPC_FLAG_SPELLCLICK (%u) set, it is expected to be set by code handling `npc_spellclick_spells` content.", guid, data.id, UNIT_NPC_FLAG_SPELLCLICK); - data.npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK; - } - // Add to grid if not managed by the game event or pool system if (gameEvent == 0 && PoolId == 0) AddCreatureToGrid(guid, &data); diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index cf70085de7f..184c25f8f6d 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -272,8 +272,8 @@ enum SpellAttr0 SPELL_ATTR0_PASSIVE = 0x00000040, // 6 Passive spell SPELL_ATTR0_HIDDEN_CLIENTSIDE = 0x00000080, // 7 Spells with this attribute are not visible in spellbook or aura bar SPELL_ATTR0_HIDE_IN_COMBAT_LOG = 0x00000100, // 8 This attribite controls whether spell appears in combat logs - SPELL_ATTR0_UNK9 = 0x00000200, // 9 - SPELL_ATTR0_UNK10 = 0x00000400, // 10 on next swing 2 + SPELL_ATTR0_TARGET_MAINHAND_ITEM = 0x00000200, // 9 Client automatically selects item from mainhand slot as a cast target + SPELL_ATTR0_UNK10 = 0x00000400, // 10 SPELL_ATTR0_UNK11 = 0x00000800, // 11 SPELL_ATTR0_DAYTIME_ONLY = 0x00001000, // 12 only useable at daytime, not set in 2.4.2 SPELL_ATTR0_NIGHT_ONLY = 0x00002000, // 13 only useable at night, not set in 2.4.2 @@ -285,7 +285,7 @@ enum SpellAttr0 SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION = 0x00080000, // 19 spelldamage depends on caster level SPELL_ATTR0_STOP_ATTACK_TARGET = 0x00100000, // 20 Stop attack after use this spell (and not begin attack if use) SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK = 0x00200000, // 21 Cannot be dodged/parried/blocked - SPELL_ATTR0_UNK22 = 0x00400000, // 22 shoot spells + SPELL_ATTR0_FORCE_FACING_TARGET = 0x00400000, // 22 Client automatically forces player to face target when casting SPELL_ATTR0_CASTABLE_WHILE_DEAD = 0x00800000, // 23 castable while dead? SPELL_ATTR0_CASTABLE_WHILE_MOUNTED = 0x01000000, // 24 castable while mounted SPELL_ATTR0_DISABLED_WHILE_ACTIVE = 0x02000000, // 25 Activate and start cooldown after aura fade or remove summoned creature or go @@ -301,11 +301,11 @@ enum SpellAttr1 { SPELL_ATTR1_DISMISS_PET = 0x00000001, // 0 dismiss pet and not allow to summon new one? SPELL_ATTR1_DRAIN_ALL_POWER = 0x00000002, // 1 use all power (Only paladin Lay of Hands and Bunyanize) - SPELL_ATTR1_CHANNELED_1 = 0x00000004, // 2 channeled target + SPELL_ATTR1_CHANNELED_1 = 0x00000004, // 2 SPELL_ATTR1_PUT_CASTER_IN_COMBAT = 0x00000008, // 3 spells that cause a caster to enter a combat SPELL_ATTR1_UNK4 = 0x00000010, // 4 stealth and whirlwind SPELL_ATTR1_NOT_BREAK_STEALTH = 0x00000020, // 5 Not break stealth - SPELL_ATTR1_CHANNELED_2 = 0x00000040, // 6 channeled self + SPELL_ATTR1_CHANNELED_2 = 0x00000040, // 6 SPELL_ATTR1_NEGATIVE = 0x00000080, // 7 SPELL_ATTR1_NOT_IN_COMBAT_TARGET = 0x00000100, // 8 Spell req target not to be in combat state SPELL_ATTR1_UNK9 = 0x00000200, // 9 melee spells @@ -323,7 +323,7 @@ enum SpellAttr1 SPELL_ATTR1_UNK21 = 0x00200000, // 21 SPELL_ATTR1_REQ_COMBO_POINTS2 = 0x00400000, // 22 Req combo points on target SPELL_ATTR1_UNK23 = 0x00800000, // 23 - SPELL_ATTR1_UNK24 = 0x01000000, // 24 Req fishing pole?? + SPELL_ATTR1_UNK24 = 0x01000000, // 24 only fishing spells SPELL_ATTR1_UNK25 = 0x02000000, // 25 SPELL_ATTR1_UNK26 = 0x04000000, // 26 works correctly with [target=focus] and [target=mouseover] macros? SPELL_ATTR1_UNK27 = 0x08000000, // 27 @@ -518,7 +518,7 @@ enum SpellAttr7 SPELL_ATTR7_UNK0 = 0x00000001, // 0 Shaman's new spells (Call of the ...), Feign Death. SPELL_ATTR7_UNK1 = 0x00000002, // 1 Not set in 3.2.2a. SPELL_ATTR7_REACTIVATE_AT_RESURRECT = 0x00000004, // 2 Paladin's auras and 65607 only. - SPELL_ATTR7_DISABLED_CLIENT_SIDE = 0x00000008, // 3 used only by client to disable spells client-side. some sort of special player flag (0x40000) bypasses that restriction + SPELL_ATTR7_IS_CHEAT_SPELL = 0x00000008, // 3 Cannot cast if caster doesn't have UnitFlag2 & UNIT_FLAG2_ALLOW_CHEAT_SPELLS SPELL_ATTR7_UNK4 = 0x00000010, // 4 Only 66109 test spell. SPELL_ATTR7_SUMMON_PLAYER_TOTEM = 0x00000020, // 5 Only Shaman player totems. SPELL_ATTR7_UNK6 = 0x00000040, // 6 Dark Surge, Surge of Light, Burning Breath triggers (boss spells). diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 38c33d0a030..a4c136c7885 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -377,7 +377,7 @@ m_baseAmount(baseAmount ? *baseAmount : m_spellProto->EffectBasePoints[m_effInde m_canBeRecalculated(true), m_spellmod(NULL), m_isPeriodic(false), m_periodicTimer(0), m_tickNumber(0) { - CalculatePeriodic(caster, true); + CalculatePeriodic(caster, true, false); m_amount = CalculateAmount(caster); @@ -403,7 +403,6 @@ void AuraEffect::GetTargetList(std::list<Unit *> & targetList) const void AuraEffect::GetApplicationList(std::list<AuraApplication*> & applicationList) const { Aura::ApplicationMap const & targetMap = GetBase()->GetApplicationMap(); - // remove all targets which were not added to new list - they no longer deserve area aura for (Aura::ApplicationMap::const_iterator appIter = targetMap.begin(); appIter != targetMap.end(); ++appIter) { if (appIter->second->HasEffect(GetEffIndex())) @@ -766,7 +765,7 @@ int32 AuraEffect::CalculateAmount(Unit * caster) return amount; } -void AuraEffect::CalculatePeriodic(Unit * caster, bool create) +void AuraEffect::CalculatePeriodic(Unit * caster, bool create, bool load) { m_amplitude = m_spellProto->EffectAmplitude[m_effIndex]; @@ -790,9 +789,7 @@ void AuraEffect::CalculatePeriodic(Unit * caster, bool create) break; case SPELL_AURA_PERIODIC_TRIGGER_SPELL: if (GetId() == 51912) - { m_amplitude = 3000; - } m_isPeriodic = true; break; case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: @@ -840,19 +837,30 @@ void AuraEffect::CalculatePeriodic(Unit * caster, bool create) } } - if (create) - { - // Start periodic on next tick or at aura apply - if (m_amplitude && !(m_spellProto->AttributesEx5 & SPELL_ATTR5_START_PERIODIC_AT_APPLY)) - m_periodicTimer += m_amplitude; - } - else if (m_amplitude) // load aura from character_aura + if (load) // aura loaded from db { - m_tickNumber = GetBase()->GetDuration() / m_amplitude; - m_periodicTimer = GetBase()->GetDuration() % m_amplitude; + m_tickNumber = m_amplitude ? GetBase()->GetDuration() / m_amplitude : 0; + m_periodicTimer = m_amplitude ? GetBase()->GetDuration() % m_amplitude : 0; if (m_spellProto->AttributesEx5 & SPELL_ATTR5_START_PERIODIC_AT_APPLY) ++m_tickNumber; } + else // aura just created or reapplied + { + m_tickNumber = 0; + // reset periodic timer on aura create or on reapply when aura isn't dot + // possibly we should not reset periodic timers only when aura is triggered by proc + // or maybe there's a spell attribute somewhere + bool resetPeriodicTimer = create + || ((GetAuraType() != SPELL_AURA_PERIODIC_DAMAGE) && (GetAuraType() != SPELL_AURA_PERIODIC_DAMAGE_PERCENT)); + + if (resetPeriodicTimer) + { + m_periodicTimer = 0; + // Start periodic on next tick or at aura apply + if (m_amplitude && !(m_spellProto->AttributesEx5 & SPELL_ATTR5_START_PERIODIC_AT_APPLY)) + m_periodicTimer += m_amplitude; + } + } } void AuraEffect::CalculateSpellMod() @@ -2476,7 +2484,7 @@ void AuraEffect::TriggerSpell(Unit * target, Unit * caster) const Creature* c = triggerTarget->ToCreature(); if (!c || (c && !sScriptMgr->OnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex()), triggerTarget->ToCreature())) || (c && !c->AI()->sOnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex())))) - sLog->outError("AuraEffect::TriggerSpell: Spell %u has value 0 in EffectTriggered[%d] and is therefor not handled. Define as custom case?", GetId(), GetEffIndex()); + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::TriggerSpell: Spell %u has non-existent spell %u in EffectTriggered[%d] and is therefor not triggered.", GetId(), triggerSpellId, GetEffIndex()); } } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 3f6c6b5587c..2a5a0e72805 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -42,7 +42,7 @@ class AuraEffect void SetPeriodicTimer(int32 periodicTimer) { m_periodicTimer = periodicTimer; } int32 CalculateAmount(Unit * caster); - void CalculatePeriodic(Unit * caster, bool create = false); + void CalculatePeriodic(Unit * caster, bool create = false, bool load = false); void CalculateSpellMod(); void ChangeAmount(int32 newAmount, bool mark = true, bool onStackOrReapply = false); void RecalculateAmount() { if (!CanBeRecalculated()) return; ChangeAmount(CalculateAmount(GetCaster()), false); } diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index fe62d786689..822392747aa 100755 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -726,6 +726,16 @@ void Aura::RefreshDuration() m_timeCla = 1 * IN_MILLISECONDS; } +void Aura::RefreshTimers() +{ + m_maxDuration = CalcMaxDuration(); + RefreshDuration(); + Unit * caster = GetCaster(); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (HasEffect(i)) + GetEffect(i)->CalculatePeriodic(caster, false, false); +} + void Aura::SetCharges(uint8 charges) { if (m_procCharges == charges) @@ -770,9 +780,22 @@ void Aura::SetStackAmount(uint8 stackAmount) { m_stackAmount = stackAmount; Unit * caster = GetCaster(); + + std::list<AuraApplication*> applications; + GetApplicationList(applications); + + for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr) + if (!(*apptItr)->GetRemoveMode()) + HandleAuraSpecificMods(*apptItr, caster, false, true); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (HasEffect(i)) m_effects[i]->ChangeAmount(m_effects[i]->CalculateAmount(caster), false, true); + + for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr) + if (!(*apptItr)->GetRemoveMode()) + HandleAuraSpecificMods(*apptItr, caster, true, true); + SetNeedClientUpdateForTargets(); } @@ -802,7 +825,12 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode) SetStackAmount(stackAmount); if (refresh) - RefreshDuration(); + { + RefreshTimers(); + + // reset charges + SetCharges(CalcMaxCharges()); + } SetNeedClientUpdateForTargets(); return false; } @@ -871,7 +899,7 @@ void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint { m_effects[i]->SetAmount(amount[i]); m_effects[i]->SetCanBeRecalculated(recalculateMask & (1<<i)); - m_effects[i]->CalculatePeriodic(caster); + m_effects[i]->CalculatePeriodic(caster, false, true); m_effects[i]->CalculateSpellMod(); m_effects[i]->RecalculateAmount(caster); } @@ -904,6 +932,15 @@ void Aura::HandleAllEffects(AuraApplication * aurApp, uint8 mode, bool apply) m_effects[i]->HandleEffect(aurApp, mode, apply); } +void Aura::GetApplicationList(std::list<AuraApplication*> & applicationList) const +{ + for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter) + { + if (appIter->second->GetEffectMask()) + applicationList.push_back(appIter->second); + } +} + void Aura::SetNeedClientUpdateForTargets() const { for (ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter) @@ -911,7 +948,7 @@ void Aura::SetNeedClientUpdateForTargets() const } // trigger effects on real aura apply/remove -void Aura::HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, bool apply) +void Aura::HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, bool apply, bool onReapply) { Unit * target = aurApp->GetTarget(); AuraRemoveMode removeMode = aurApp->GetRemoveMode(); @@ -1157,7 +1194,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, else { // Remove Linked Auras - if (removeMode != AURA_REMOVE_BY_DEATH) + if (!onReapply && removeMode != AURA_REMOVE_BY_DEATH) { if (uint32 customAttr = sSpellMgr->GetSpellCustomAttr(GetId())) { @@ -1297,7 +1334,11 @@ void Aura::HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, switch(GetId()) { case 48018: // Demonic Circle - target->RemoveGameObject(GetId(), true); + // Do not remove GO when aura is removed by stack + // to prevent remove GO added by new spell + // old one is already removed + if (!onReapply) + target->RemoveGameObject(GetId(), true); target->RemoveAura(62388); break; } diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 342ff59b02c..69792a6e513 100755 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -127,6 +127,7 @@ class Aura int32 GetDuration() const { return m_duration; } void SetDuration(int32 duration, bool withMods = false); void RefreshDuration(); + void RefreshTimers(); bool IsExpired() const { return !GetDuration();} bool IsPermanent() const { return GetMaxDuration() == -1; } @@ -166,12 +167,13 @@ class Aura // Helpers for targets ApplicationMap const & GetApplicationMap() {return m_applications;} + void GetApplicationList(std::list<AuraApplication*> & applicationList) const; const AuraApplication * GetApplicationOfTarget (uint64 const & guid) const { ApplicationMap::const_iterator itr = m_applications.find(guid); if (itr != m_applications.end()) return itr->second; return NULL; } AuraApplication * GetApplicationOfTarget (uint64 const & guid) { ApplicationMap::iterator itr = m_applications.find(guid); if (itr != m_applications.end()) return itr->second; return NULL; } bool IsAppliedOnTarget(uint64 const & guid) const { return m_applications.find(guid) != m_applications.end(); } void SetNeedClientUpdateForTargets() const; - void HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, bool apply); + void HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, bool apply, bool onReapply); bool CanBeAppliedOn(Unit *target); bool CheckAreaTarget(Unit *target); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 0402c9bd8fe..72bf8f9c31c 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1427,9 +1427,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool if (m_originalCaster) { - bool refresh; m_spellAura = Aura::TryRefreshStackOrCreate(aurSpellInfo, effectMask, unit, - m_originalCaster, (aurSpellInfo == m_spellInfo)? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, 0, &refresh); + m_originalCaster, (aurSpellInfo == m_spellInfo)? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem); if (m_spellAura) { // Set aura stack amount to desired value @@ -1437,8 +1436,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool m_spellAura->SetStackAmount(m_spellValue->AuraStackAmount); // Now Reduce spell duration using data received at spell hit - // if we're refreshing aura, recalculate max duration, to avoid applying mods twice - int32 duration = refresh ? m_spellAura->CalcMaxDuration() : m_spellAura->GetMaxDuration(); + int32 duration = m_spellAura->GetMaxDuration(); int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup, aurSpellInfo); float diminishMod = unit->ApplyDiminishingToDuration(m_diminishGroup, duration, m_originalCaster, m_diminishLevel, limitduration); @@ -4608,6 +4606,9 @@ SpellCastResult Spell::CheckCast(bool strict) } } + if (m_spellInfo->AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL && !m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS)) + return SPELL_FAILED_SPELL_UNAVAILABLE; + // Check global cooldown if (strict && !m_IsTriggeredSpell && HasGlobalCooldown()) return SPELL_FAILED_NOT_READY; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 0412ed49a40..10c4fd7b059 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -424,6 +424,9 @@ void Spell::SpellDamageSchoolDmg(SpellEffIndex effIndex) damage = unitTarget->CountPctFromMaxHealth(50); break; } + case 29142: // Eyesore Blaster + case 35139: // Throw Boom's Doom + case 55269: // Deathly Stare case 56578: // Rapid-Fire Harpoon case 62775: // Tympanic Tantrum { diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 1eb1f419f85..66b0e15ae26 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3800,14 +3800,10 @@ void SpellMgr::LoadSpellCustomAttr() case 57761: // Fireball! case 39805: // Lightning Overload case 64823: // Item - Druid T8 Balance 4P Bonus - case 44401: + case 44401: // Missile Barrage spellInfo->procCharges = 1; ++count; break; - case 53390: // Tidal Wave - spellInfo->procCharges = 2; - ++count; - break; case 44544: // Fingers of Frost spellInfo->EffectSpellClassMask[0] = flag96(685904631, 1151048, 0); ++count; @@ -4021,7 +4017,7 @@ void SpellMgr::LoadSpellCustomAttr() case 63024: // Gravity Bomb case 64234: // Gravity Bomb (25m) spellInfo->MaxAffectedTargets = 1; - count++; + ++count; break; case 62834: // Boom // This hack is here because we suspect our implementation of spell effect execution on targets @@ -4030,7 +4026,7 @@ void SpellMgr::LoadSpellCustomAttr() // The above situation causes the visual for this spell to be bugged, so we remove the instakill // effect and implement a script hack for that. spellInfo->Effect[EFFECT_1] = 0; - count++; + ++count; break; // ENDOF ULDUAR SPELLS // @@ -4112,10 +4108,6 @@ void SpellMgr::LoadSpellCustomAttr() spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; ++count; break; - case 71340: // Pact of the Darkfallen (Blood-Queen Lana'thel) - spellInfo->DurationIndex = 21; - ++count; - break; case 71266: // Swarming Shadows case 72890: // Swarming Shadows spellInfo->AreaGroupId = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel @@ -4251,7 +4243,7 @@ void SpellMgr::LoadEnchantCustomAttr() if (!ench) continue; mEnchantCustomAttr[enchId] = true; - count++; + ++count; break; } } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp index 4ee8affda74..f125630fc45 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp @@ -311,14 +311,13 @@ class spell_baltharus_enervating_brand : public SpellScriptLoader void HandleTriggerSpell(AuraEffect const* aurEff) { PreventDefaultAction(); - if (Unit* target = GetTarget()) - { - uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[aurEff->GetEffIndex()]; - target->CastSpell(target, triggerSpellId, true); + Unit* target = GetTarget(); + uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[aurEff->GetEffIndex()]; + target->CastSpell(target, triggerSpellId, true); - if (target->GetDistance(GetCaster()) <= 12.0f) - target->CastSpell(GetCaster(), SPELL_SIPHONED_MIGHT, true); - } + if (Unit * caster = GetCaster()) + if (target->GetDistance(caster) <= 12.0f) + target->CastSpell(caster, SPELL_SIPHONED_MIGHT, true); } void Register() diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp index 679a9370633..3a555da9a81 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp @@ -465,11 +465,12 @@ class spell_tyrannus_mark_of_rimefang : public SpellScriptLoader void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (!GetCaster() || GetCaster()->GetTypeId() != TYPEID_UNIT) + Unit * caster = GetCaster(); + if (!caster || caster->GetTypeId() != TYPEID_UNIT) return; - if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - if (Creature* rimefang = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_RIMEFANG))) + if (InstanceScript* instance = caster->GetInstanceScript()) + if (Creature* rimefang = ObjectAccessor::GetCreature(*caster, instance->GetData64(DATA_RIMEFANG))) rimefang->AI()->SetGUID(GetTarget()->GetGUID(), GUID_HOARFROST); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp index b67ca2beb8e..c2f2b93089c 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp @@ -439,14 +439,17 @@ class spell_festergut_blighted_spores : public SpellScriptLoader void ExtraEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - uint32 inoculatedId = sSpellMgr->GetSpellIdForDifficulty(SPELL_INOCULATED, GetCaster()); - uint32 currStack = 0; - if (Aura const* inoculate = GetTarget()->GetAura(inoculatedId)) - currStack = inoculate->GetStackAmount(); - - GetTarget()->CastSpell(GetTarget(), SPELL_INOCULATED, true); - ++currStack; - GetCaster()->ToCreature()->AI()->SetData(DATA_INOCULATED_STACK, currStack); + if (Unit * caster = GetCaster()) + { + uint32 inoculatedId = sSpellMgr->GetSpellIdForDifficulty(SPELL_INOCULATED, caster); + uint32 currStack = 0; + if (Aura const* inoculate = GetTarget()->GetAura(inoculatedId)) + currStack = inoculate->GetStackAmount(); + + GetTarget()->CastSpell(GetTarget(), SPELL_INOCULATED, true); + ++currStack; + caster->ToCreature()->AI()->SetData(DATA_INOCULATED_STACK, currStack); + } } void Register() diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index 048cabdccfc..f760d415ac4 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -971,10 +971,12 @@ class spell_deathwhisper_mana_barrier : public SpellScriptLoader void HandlePeriodicTick(AuraEffect const* /*aurEff*/) { PreventDefaultAction(); - Unit* caster = GetCaster(); - int32 missingHealth = int32(caster->GetMaxHealth() - caster->GetHealth()); - caster->ModifyHealth(missingHealth); - caster->ModifyPower(POWER_MANA, -missingHealth); + if (Unit* caster = GetCaster()) + { + int32 missingHealth = int32(caster->GetMaxHealth() - caster->GetHealth()); + caster->ModifyHealth(missingHealth); + caster->ModifyPower(POWER_MANA, -missingHealth); + } } void Register() diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 2bb009a36d3..bb57325d8c0 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -717,10 +717,12 @@ class spell_putricide_gaseous_bloat : public SpellScriptLoader void HandleExtraEffect(AuraEffect const* /*aurEff*/) { Unit* target = GetTarget(); - Unit* caster = GetCaster(); - target->RemoveAuraFromStack(GetSpellProto()->Id, GetCasterGUID()); - if (!target->HasAura(GetId()) && caster && caster->GetTypeId() == TYPEID_UNIT) - caster->ToCreature()->DespawnOrUnsummon(); + if (Unit* caster = GetCaster()) + { + target->RemoveAuraFromStack(GetSpellProto()->Id, GetCasterGUID()); + if (!target->HasAura(GetId())&& caster->GetTypeId() == TYPEID_UNIT) + caster->ToCreature()->DespawnOrUnsummon(); + } } void Register() diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 2f81ad96ef1..908813e241c 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -671,35 +671,38 @@ class spell_malygos_vortex_visual : public SpellScriptLoader void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - std::list<HostileReference*> &m_threatlist = GetCaster()->getThreatManager().getThreatList(); - for (std::list<HostileReference*>::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + if (Unit * caster = GetCaster()) { - if (Unit* target = (*itr)->getTarget()) + std::list<HostileReference*> &m_threatlist = caster->getThreatManager().getThreatList(); + for (std::list<HostileReference*>::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) { - Player* targetPlayer = target->ToPlayer(); + if (Unit* target = (*itr)->getTarget()) + { + Player* targetPlayer = target->ToPlayer(); - if (!targetPlayer || targetPlayer->isGameMaster()) - continue; + if (!targetPlayer || targetPlayer->isGameMaster()) + continue; - if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - { - // teleport spell - i am not sure but might be it must be casted by each vehicle when its passenger leaves it - if (Creature* trigger = GetCaster()->GetMap()->GetCreature(instance->GetData64(DATA_TRIGGER))) - trigger->CastSpell(targetPlayer, SPELL_VORTEX_6, true); + if (InstanceScript* instance = caster->GetInstanceScript()) + { + // teleport spell - i am not sure but might be it must be casted by each vehicle when its passenger leaves it + if (Creature* trigger = caster->GetMap()->GetCreature(instance->GetData64(DATA_TRIGGER))) + trigger->CastSpell(targetPlayer, SPELL_VORTEX_6, true); + } } } - } - if (Creature* malygos = GetCaster()->ToCreature()) - { - // This is a hack, we have to re add players to the threat list because when they enter to the vehicles they are removed. - // Anyway even with this issue, the boss does not enter in evade mode - this prevents iterate an empty list in the next vortex execution. - malygos->SetInCombatWithZone(); + if (Creature* malygos = caster->ToCreature()) + { + // This is a hack, we have to re add players to the threat list because when they enter to the vehicles they are removed. + // Anyway even with this issue, the boss does not enter in evade mode - this prevents iterate an empty list in the next vortex execution. + malygos->SetInCombatWithZone(); - malygos->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + malygos->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - malygos->GetMotionMaster()->MoveChase(GetCaster()->getVictim()); - malygos->RemoveAura(SPELL_VORTEX_1); + malygos->GetMotionMaster()->MoveChase(caster->getVictim()); + malygos->RemoveAura(SPELL_VORTEX_1); + } } } diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp index 2a6d8f606f0..ec8abc257d6 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp @@ -254,8 +254,9 @@ class spell_eregos_planar_shift : public SpellScriptLoader void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (Creature* caster = GetCaster()->ToCreature()) - caster->AI()->DoAction(ACTION_SET_NORMAL_EVENTS); + if (Unit * caster = GetCaster()) + if (Creature* creatureCaster = caster->ToCreature()) + creatureCaster->AI()->DoAction(ACTION_SET_NORMAL_EVENTS); } void Register() diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp index d7025897eb8..6ba9db3d407 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp @@ -244,27 +244,33 @@ class spell_varos_centrifuge_shield : public SpellScriptLoader { PrepareAuraScript(spell_varos_centrifuge_shield_AuraScript); - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + bool Load() { - if (!GetCaster()->ToCreature()) - return; + Unit * caster = GetCaster(); + return (caster && caster->ToCreature()); + } - // flags taken from sniffs - // UNIT_FLAG_UNK_9 -> means passive but it is not yet implemented in core - if (GetCaster()->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_PASSIVE|UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_UNK_6)) + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit * caster = GetCaster()) { - GetCaster()->ToCreature()->SetReactState(REACT_PASSIVE); - GetCaster()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_PASSIVE|UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_UNK_6); + // flags taken from sniffs + // UNIT_FLAG_UNK_9 -> means passive but it is not yet implemented in core + if (caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_PASSIVE|UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_UNK_6)) + { + caster->ToCreature()->SetReactState(REACT_PASSIVE); + caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_PASSIVE|UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_UNK_6); + } } } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (!GetCaster()->ToCreature()) - return; - - GetCaster()->ToCreature()->SetReactState(REACT_AGGRESSIVE); - GetCaster()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_PASSIVE|UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_UNK_6); + if (Unit * caster = GetCaster()) + { + caster->ToCreature()->SetReactState(REACT_AGGRESSIVE); + caster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_PASSIVE|UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_UNK_6); + } } void Register() diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_freya.cpp index a633674075b..1f49381d0dd 100644 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_freya.cpp @@ -94,7 +94,7 @@ enum FreyaSpells SPELL_FLUX_PLUS = 62251, SPELL_FLUX_MINUS = 62252, SPELL_SOLAR_FLARE = 62240, - SPELL_UNSTABLE_SUNBEAM = 62207, // Trigger 62211 + SPELL_UNSTABLE_SUN_BEAM_SUMMON = 62207, // Trigger 62221 // Stack Removing of Attuned to Nature SPELL_REMOVE_25STACK = 62521, @@ -147,6 +147,7 @@ enum FreyaSpells SPELL_SUMMON_NATURE_BOMB = 64606, // Unstable Sun Beam + SPELL_UNSTABLE_SUN_BEAM = 62211, SPELL_UNSTABLE_ENERGY = 62217, SPELL_PHOTOSYNTHESIS = 62209, SPELL_UNSTABLE_SUN_BEAM_TRIGGERED = 62243, @@ -738,8 +739,8 @@ class boss_elder_brightleaf : public CreatureScript case EVENT_UNSTABLE_SUN_BEAM: Position pos; me->GetRandomNearPosition(pos, 20.0f); - me->SummonCreature(NPC_UNSTABLE_SUN_BEAM, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), 0); - events.ScheduleEvent(EVENT_UNSTABLE_SUN_BEAM, urand(7000, 15000)); + me->CastSpell(me, SPELL_UNSTABLE_SUN_BEAM_SUMMON, true); + events.ScheduleEvent(EVENT_UNSTABLE_SUN_BEAM, urand(10000, 15000)); break; case EVENT_SOLAR_FLARE: { @@ -755,7 +756,7 @@ class boss_elder_brightleaf : public CreatureScript me->AddAura(SPELL_FLUX_AURA, me); if (Aura* Flux = me->GetAura(SPELL_FLUX_AURA)) Flux->SetStackAmount(urand(1, 8)); - events.ScheduleEvent(EVENT_FLUX, 5000); + events.ScheduleEvent(EVENT_FLUX, 7500); break; } } @@ -1459,10 +1460,10 @@ class npc_unstable_sun_beam : public CreatureScript { npc_unstable_sun_beamAI(Creature* creature) : Scripted_NoMovementAI(creature) { - despawnTimer = 10000; + despawnTimer = urand(7000, 12000); instance = me->GetInstanceScript(); DoCast(me, SPELL_PHOTOSYNTHESIS); - DoCast(me, SPELL_UNSTABLE_SUNBEAM); + DoCast(me, SPELL_UNSTABLE_SUN_BEAM); me->SetReactState(REACT_PASSIVE); } @@ -1485,7 +1486,7 @@ class npc_unstable_sun_beam : public CreatureScript { if (target && spell->Id == SPELL_UNSTABLE_ENERGY) { - target->RemoveAurasDueToSpell(SPELL_UNSTABLE_SUNBEAM); + target->RemoveAurasDueToSpell(SPELL_UNSTABLE_SUN_BEAM); target->RemoveAurasDueToSpell(SPELL_UNSTABLE_SUN_BEAM_TRIGGERED); } } diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_general_vezax.cpp index 52a2f220260..79570d86a0e 100644 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_general_vezax.cpp @@ -448,7 +448,8 @@ class spell_mark_of_the_faceless : public SpellScriptLoader void HandleEffectPeriodic(AuraEffect const* aurEff) { - GetCaster()->CastCustomSpell(SPELL_MARK_OF_THE_FACELESS_DAMAGE, SPELLVALUE_BASE_POINT1, aurEff->GetAmount(), GetTarget(), true); + if (Unit * caster = GetCaster()) + caster->CastCustomSpell(SPELL_MARK_OF_THE_FACELESS_DAMAGE, SPELLVALUE_BASE_POINT1, aurEff->GetAmount(), GetTarget(), true); } void Register() diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp index d83d3d022c7..c3eedcc8e2f 100644 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp @@ -910,7 +910,7 @@ class spell_biting_cold : public SpellScriptLoader Unit* target = GetTarget(); bool found = false; - if (!caster || !target) + if (!caster) return; for (TargetList::iterator itr = listOfTargets.begin(); itr != listOfTargets.end(); ++itr) diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp index 7121f139d50..866cb60d3d0 100644 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp @@ -185,11 +185,11 @@ class boss_kologarn : public CreatureScript instance->SetData64(DATA_RIGHT_ARM, who->GetGUID()); } + if (!isEncounterInProgress) + return; + if (!apply) { - if (!isEncounterInProgress) - return; - who->CastSpell(me, SPELL_ARM_DEAD_DAMAGE, true); if (Creature* rubbleStalker = who->FindNearestCreature(NPC_RUBBLE_STALKER, 70.0f)) diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp index ada8261e9ad..b41a825d276 100644 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp @@ -179,7 +179,7 @@ class boss_xt002 : public CreatureScript CreatureAI* GetAI(Creature* pCreature) const { - return GetUlduarAI<boss_xt002_AI>(pCreature); + return GetUlduarAI<boss_xt002_AI>(pCreature); } struct boss_xt002_AI : public BossAI @@ -188,18 +188,28 @@ class boss_xt002 : public CreatureScript { } + // Achievement related + bool HealthRecovered; // Did a scrapbot recover XT-002's health during the encounter? + bool HardMode; // Are we in hard mode? Or: was the heart killed during phase 2? + bool GravityBombCasualty; // Did someone die because of Gravity Bomb damage? + uint8 _phase; uint8 _heartExposed; uint32 transferHealth; bool enterHardMode; - bool hardMode; + void Reset() { - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE); + _Reset(); + + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + HealthRecovered = false; + GravityBombCasualty = false; + HardMode = false; - hardMode = false; enterHardMode = false; _phase = 1; @@ -233,9 +243,9 @@ class boss_xt002 : public CreatureScript switch (action) { case ACTION_ENTER_HARD_MODE: - if (!hardMode) + if (!HardMode) { - hardMode = true; + HardMode = true; // Enter hard mode enterHardMode = true; @@ -276,7 +286,7 @@ class boss_xt002 : public CreatureScript void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) { - if (!hardMode && _phase == 1 && !HealthAbovePct(100 - 25 * (_heartExposed+1))) + if (!HardMode && _phase == 1 && !HealthAbovePct(100 - 25 * (_heartExposed+1))) ExposeHeart(); } @@ -331,6 +341,12 @@ class boss_xt002 : public CreatureScript DoMeleeAttackIfReady(); } + void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) + { + if (apply && who->GetEntry() == NPC_XS013_SCRAPBOT) + HealthRecovered = true; + } + void ExposeHeart() { //Make untargetable @@ -385,7 +401,7 @@ class boss_xt002 : public CreatureScript heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); heart->RemoveAurasDueToSpell(SPELL_EXPOSED_HEART); - if (!hardMode) + if (!HardMode) { if (!transferHealth) transferHealth = (heart->GetMaxHealth() - heart->GetHealth()); @@ -396,6 +412,7 @@ class boss_xt002 : public CreatureScript }; }; +typedef boss_xt002::boss_xt002_AI XT002AI; /*------------------------------------------------------- * @@ -653,11 +670,19 @@ class mob_boombot : public CreatureScript // Casting done from player and caster source has the same targetinfo flags, // so that can't be the issue // See InstantKillEvent class - // Schedule 1ms delayed + // Schedule 1s delayed me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1*IN_MILLISECONDS)); } } + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + // No melee attack + } + private: InstanceScript* _instance; bool _boomed; @@ -683,7 +708,7 @@ public: struct mob_life_sparkAI : public ScriptedAI { mob_life_sparkAI(Creature* pCreature) : ScriptedAI(pCreature) - { + { m_pInstance = pCreature->GetInstanceScript(); } @@ -751,14 +776,14 @@ class spell_xt002_searing_light_spawn_life_spark : public SpellScriptLoader } }; -class spell_xt002_gravity_bomb_spawn_void_zone : public SpellScriptLoader +class spell_xt002_gravity_bomb_aura : public SpellScriptLoader { public: - spell_xt002_gravity_bomb_spawn_void_zone() : SpellScriptLoader("spell_xt002_gravity_bomb_spawn_void_zone") { } + spell_xt002_gravity_bomb_aura() : SpellScriptLoader("spell_xt002_gravity_bomb_aura") { } - class spell_xt002_gravity_bomb_spawn_void_zone_AuraScript : public AuraScript + class spell_xt002_gravity_bomb_aura_AuraScript : public AuraScript { - PrepareAuraScript(spell_xt002_gravity_bomb_spawn_void_zone_AuraScript); + PrepareAuraScript(spell_xt002_gravity_bomb_aura_AuraScript); bool Validate(SpellEntry const* /*spell*/) { @@ -775,15 +800,63 @@ class spell_xt002_gravity_bomb_spawn_void_zone : public SpellScriptLoader plr->CastSpell(plr, SPELL_SUMMON_VOID_ZONE, true); } + void OnPeriodic(AuraEffect const* aurEff) + { + Unit* xt002 = GetCaster(); + if (!xt002) + return; + + Unit* owner = GetOwner()->ToUnit(); + if (!owner) + return; + + if (aurEff->GetAmount() >= owner->GetHealth()) + if (XT002AI* xt002AI = CAST_AI(XT002AI, xt002->GetAI())) + xt002AI->GravityBombCasualty = true; + } + void Register() { - AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_spawn_void_zone_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_xt002_gravity_bomb_aura_AuraScript::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DAMAGE); + AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_aura_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); } }; AuraScript* GetAuraScript() const { - return new spell_xt002_gravity_bomb_spawn_void_zone_AuraScript(); + return new spell_xt002_gravity_bomb_aura_AuraScript(); + } +}; + +class spell_xt002_gravity_bomb_damage : public SpellScriptLoader +{ + public: + spell_xt002_gravity_bomb_damage() : SpellScriptLoader("spell_xt002_gravity_bomb_damage") { } + + class spell_xt002_gravity_bomb_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_gravity_bomb_damage_SpellScript); + + void HandleScript(SpellEffIndex /*eff*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + if (GetHitDamage() >= GetHitUnit()->GetHealth()) + if (XT002AI* xt002AI = CAST_AI(XT002AI, GetCaster()->GetAI())) + xt002AI->GravityBombCasualty = true; + } + + void Register() + { + OnEffect += SpellEffectFn(spell_xt002_gravity_bomb_damage_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_xt002_gravity_bomb_damage_SpellScript(); } }; @@ -955,6 +1028,57 @@ class spell_xt002_stand : public SpellScriptLoader } }; +class achievement_nerf_engineering : public AchievementCriteriaScript +{ + public: + achievement_nerf_engineering() : AchievementCriteriaScript("achievement_nerf_engineering") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target) + return false; + + if (XT002AI* xt002AI = CAST_AI(XT002AI, target->GetAI())) + return !xt002AI->HealthRecovered; + + return false; + } +}; + +class achievement_heartbreaker : public AchievementCriteriaScript +{ + public: + achievement_heartbreaker() : AchievementCriteriaScript("achievement_heartbreaker") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target) + return false; + + if (XT002AI* xt002AI = CAST_AI(XT002AI, target->GetAI())) + return xt002AI->HardMode; + + return false; + } +}; + +class achievement_nerf_gravity_bombs : public AchievementCriteriaScript +{ + public: + achievement_nerf_gravity_bombs() : AchievementCriteriaScript("achievement_nerf_gravity_bombs") { } + + bool OnCheck(Player* source, Unit* target) + { + if (!target) + return false; + + if (XT002AI* xt002AI = CAST_AI(XT002AI, target->GetAI())) + return !xt002AI->GravityBombCasualty; + + return false; + } +}; + void AddSC_boss_xt002() { new mob_xt002_heart(); @@ -966,9 +1090,14 @@ void AddSC_boss_xt002() new boss_xt002(); new spell_xt002_searing_light_spawn_life_spark(); - new spell_xt002_gravity_bomb_spawn_void_zone(); + new spell_xt002_gravity_bomb_aura(); + new spell_xt002_gravity_bomb_damage(); new spell_xt002_heart_overload_periodic(); new spell_xt002_tympanic_tantrum(); new spell_xt002_submerged(); new spell_xt002_stand(); + + new achievement_nerf_engineering(); + new achievement_heartbreaker(); + new achievement_nerf_gravity_bombs(); } diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp index e03c69f4672..ead4cd439e2 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp @@ -21,7 +21,7 @@ #define GOSSIP_START_EVENT "Get your people to safety, we'll keep the Blue Dragonflight's forces at bay." #define GOSSIP_ITEM_1 "Activate the crystals when we get in trouble, right" -#define GOSSIP_I_WANT_IN "Sorry, I'm late! Can I get in to help my friends?" +#define GOSSIP_I_WANT_IN "I'm not fighting, so send me in now!" #define SPAWN_TIME 20000 enum PortalCreatures diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index f30ced7b4b0..0b27375fcf3 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -363,12 +363,17 @@ public: if (aurEff->GetAmount() > 0) return; + Unit * caster = GetCaster(); + + if (!caster) + return; + uint32 spellId = SPELL_SNIPER_TRAINING_BUFF_R1 + GetId() - SPELL_SNIPER_TRAINING_R1; Unit * pTarget = GetTarget(); if (!pTarget->HasAura(spellId)) { SpellEntry const * triggeredSpellInfo = sSpellStore.LookupEntry(spellId); - Unit* triggerCaster = GetTriggeredSpellCaster(triggeredSpellInfo, GetCaster(), pTarget); + Unit* triggerCaster = GetTriggeredSpellCaster(triggeredSpellInfo, caster, pTarget); triggerCaster->CastSpell(pTarget, triggeredSpellInfo, true, 0, aurEff); } } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 7bb8426b35a..8c0f17d8d95 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -644,23 +644,21 @@ public: { if (Unit* caster = GetCaster()) { - if (Unit* target = GetTarget()) + Unit* target = GetTarget(); + if (Player* player = caster->GetCharmerOrOwnerPlayerOrPlayerItself()) { - if (Player* player = caster->GetCharmerOrOwnerPlayerOrPlayerItself()) + switch(target->GetEntry()) { - switch(target->GetEntry()) - { - case NPC_FROSTWORG: - target->CastSpell(player, SPELL_FROSTWORG_CREDIT, true); - target->CastSpell(target, SPELL_IMMOLATION, true); - target->CastSpell(target, SPELL_ABLAZE, true); - break; - case NPC_FROSTGIANT: - target->CastSpell(player, SPELL_FROSTGIANT_CREDIT, true); - target->CastSpell(target, SPELL_IMMOLATION, true); - target->CastSpell(target, SPELL_ABLAZE, true); - break; - } + case NPC_FROSTWORG: + target->CastSpell(player, SPELL_FROSTWORG_CREDIT, true); + target->CastSpell(target, SPELL_IMMOLATION, true); + target->CastSpell(target, SPELL_ABLAZE, true); + break; + case NPC_FROSTGIANT: + target->CastSpell(player, SPELL_FROSTGIANT_CREDIT, true); + target->CastSpell(target, SPELL_IMMOLATION, true); + target->CastSpell(target, SPELL_ABLAZE, true); + break; } } } |
