diff options
Diffstat (limited to 'src')
168 files changed, 3774 insertions, 1884 deletions
diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index b9d385ba675..f4555649210 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -33,21 +33,24 @@ class GameObjectAI explicit GameObjectAI(GameObject* g) : go(g) {} virtual ~GameObjectAI() {} - virtual void UpdateAI(const uint32 /*diff*/) {} + virtual void UpdateAI(uint32 /*diff*/) {} virtual void InitializeAI() { Reset(); } virtual void Reset() {}; - static int Permissible(const GameObject* go); + static int Permissible(GameObject const* go); - virtual bool GossipHello(Player* /*player*/) {return false;} - virtual bool GossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) {return false;} - virtual bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) {return false;} - virtual bool QuestAccept(Player* /*player*/, Quest const* /*quest*/) {return false;} - virtual bool QuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) {return false;} - virtual uint32 GetDialogStatus(Player* /*player*/) {return 100;} + virtual bool GossipHello(Player* /*player*/) { return false; } + virtual bool GossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) { return false; } + virtual bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, char const* /*code*/) { return false; } + virtual bool QuestAccept(Player* /*player*/, Quest const* /*quest*/) { return false; } + virtual bool QuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) { return false; } + virtual uint32 GetDialogStatus(Player* /*player*/) { return 100; } virtual void Destroyed(Player* /*player*/, uint32 /*eventId*/) {} + virtual uint32 GetData(uint32 /*id*/) { return 0; } + virtual void SetData64(uint32 /*id*/, uint64 /*value*/) {} + virtual uint64 GetData64(uint32 /*id*/) { return 0; } virtual void SetData(uint32 /*id*/, uint32 /*value*/) {} virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) {} virtual void OnStateChanged(uint32 /*state*/, Unit* /*unit*/) { } @@ -58,8 +61,8 @@ class NullGameObjectAI : public GameObjectAI public: explicit NullGameObjectAI(GameObject* g); - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} - static int Permissible(const GameObject* /*go*/) { return PERMIT_BASE_IDLE; } + static int Permissible(GameObject const* /*go*/) { return PERMIT_BASE_IDLE; } }; #endif diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 295768f9d3e..bcec8d273b9 100755 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -109,17 +109,25 @@ void PetAI::UpdateAI(const uint32 diff) } else if (owner && me->GetCharmInfo()) //no victim { - Unit* nextTarget = SelectNextTarget(); + // Only aggressive pets do target search every update. + // Defensive pets do target search only in these cases: + // * Owner attacks something - handled by OwnerAttacked() + // * Owner receives damage - handled by OwnerDamagedBy() + // * Pet is in combat and current target dies - handled by KilledUnit() + if (me->HasReactState(REACT_AGGRESSIVE)) + { + Unit* nextTarget = SelectNextTarget(); - if (me->HasReactState(REACT_PASSIVE)) - _stopAttack(); - else if (nextTarget) - AttackStart(nextTarget); + if (nextTarget) + AttackStart(nextTarget); + else + HandleReturnMovement(); + } else HandleReturnMovement(); } else if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) // no charm info and no victim - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle()); + HandleReturnMovement(); if (!me->GetCharmInfo()) return; @@ -302,6 +310,47 @@ void PetAI::AttackStart(Unit* target) DoAttack(target, true); } +void PetAI::OwnerDamagedBy(Unit* attacker) +{ + // Called when owner takes damage. Allows defensive pets to know + // that their owner might need help + + if (!attacker) + return; + + // Passive pets don't do anything + if (me->HasReactState(REACT_PASSIVE)) + return; + + // Prevent pet from disengaging from current target + if (me->getVictim() && me->getVictim()->isAlive()) + return; + + // Continue to evaluate and attack if necessary + AttackStart(attacker); +} + +void PetAI::OwnerAttacked(Unit* target) +{ + // Called when owner attacks something. Allows defensive pets to know + // that they need to assist + + // Target might be NULL if called from spell with invalid cast targets + if (!target) + return; + + // Passive pets don't do anything + if (me->HasReactState(REACT_PASSIVE)) + return; + + // Prevent pet from disengaging from current target + if (me->getVictim() && me->getVictim()->isAlive()) + return; + + // Continue to evaluate and attack if necessary + AttackStart(target); +} + Unit* PetAI::SelectNextTarget() { // Provides next target selection after current target death diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index 730ab12a3ca..ed3e2305556 100755 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -40,6 +40,8 @@ class PetAI : public CreatureAI void KilledUnit(Unit* /*victim*/); void AttackStart(Unit* target); void MovementInform(uint32 moveType, uint32 data); + void OwnerDamagedBy(Unit* attacker); + void OwnerAttacked(Unit* target); private: bool _isVisible(Unit*) const; diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp index 0739b62b605..d12d3c098e8 100755 --- a/src/server/game/AI/CoreAI/TotemAI.cpp +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -27,8 +27,7 @@ #include "GridNotifiersImpl.h" #include "CellImpl.h" -int -TotemAI::Permissible(const Creature* creature) +int TotemAI::Permissible(Creature const* creature) { if (creature->isTotem()) return PERMIT_BASE_PROACTIVE; @@ -41,8 +40,7 @@ TotemAI::TotemAI(Creature* c) : CreatureAI(c), i_victimGuid(0) ASSERT(c->isTotem()); } -void -TotemAI::MoveInLineOfSight(Unit*) +void TotemAI::MoveInLineOfSight(Unit* /*who*/) { } @@ -51,10 +49,9 @@ void TotemAI::EnterEvadeMode() me->CombatStop(true); } -void -TotemAI::UpdateAI(const uint32 /*diff*/) +void TotemAI::UpdateAI(uint32 const /*diff*/) { - if (me->ToTotem()->GetTotemType() != TOTEM_ACTIVE) + if (me->ToTotem()->GetTotemType() != TOTEM_ACTIVE) return; if (!me->isAlive() || me->IsNonMeleeSpellCasted(false)) @@ -98,8 +95,7 @@ TotemAI::UpdateAI(const uint32 /*diff*/) i_victimGuid = 0; } -void -TotemAI::AttackStart(Unit*) +void TotemAI::AttackStart(Unit* /*victim*/) { // Sentry totem sends ping on attack if (me->GetEntry() == SENTRY_TOTEM_ENTRY && me->GetOwner()->GetTypeId() == TYPEID_PLAYER) diff --git a/src/server/game/AI/CoreAI/TotemAI.h b/src/server/game/AI/CoreAI/TotemAI.h index 0fa2920888f..f0d705345ef 100755 --- a/src/server/game/AI/CoreAI/TotemAI.h +++ b/src/server/game/AI/CoreAI/TotemAI.h @@ -31,12 +31,12 @@ class TotemAI : public CreatureAI explicit TotemAI(Creature* c); - void MoveInLineOfSight(Unit*); - void AttackStart(Unit*); + void MoveInLineOfSight(Unit* who); + void AttackStart(Unit* victim); void EnterEvadeMode(); - void UpdateAI(const uint32); - static int Permissible(const Creature*); + void UpdateAI(uint32 const diff); + static int Permissible(Creature const* creature); private: uint64 i_victimGuid; diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index b871a25835b..593f0d15e18 100755 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -223,7 +223,7 @@ class UnitAI targetList.reverse(); if (targetType == SELECT_TARGET_RANDOM) - Trinity::RandomResizeList(targetList, maxTargets); + Trinity::Containers::RandomResizeList(targetList, maxTargets); else targetList.resize(maxTargets); } diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index 423b00291e7..94ac452b9f3 100755 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -138,6 +138,12 @@ class CreatureAI : public UnitAI // Called at text emote receive from player virtual void ReceiveEmote(Player* /*player*/, uint32 /*emoteId*/) {} + // Called when owner takes damage + virtual void OwnerDamagedBy(Unit* /*attacker*/) {} + + // Called when owner attacks something + virtual void OwnerAttacked(Unit* /*target*/) {} + /// == Triggered Actions Requested ================== // Called when creature attack expected (if creature can and no have current victim) diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h index f568da80b49..d097adf38ec 100755 --- a/src/server/game/AI/CreatureAIImpl.h +++ b/src/server/game/AI/CreatureAIImpl.h @@ -326,11 +326,15 @@ class EventMap : private std::map<uint32, uint32> uint32 GetPhaseMask() const { return (_phase >> 24) & 0xFF; } + bool Empty() const { return empty(); } + // Sets event phase, must be in range 1 - 8 void SetPhase(uint32 phase) { if (phase && phase < 8) _phase = (1 << (phase + 24)); + else if (!phase) + _phase = 0; } // Creates new event entry in map with given id, time, group if given (1 - 8) and phase if given (1 - 8) @@ -604,6 +608,7 @@ inline void UnitAI::DoCast(Unit* victim, uint32 spellId, bool triggered) inline void UnitAI::DoCastVictim(uint32 spellId, bool triggered) { + // Why don't we check for casting unit_state and existing target as we do in DoCast(.. ? me->CastSpell(me->getVictim(), spellId, triggered); } diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index f64bb320542..1a0c6652e74 100755 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -82,7 +82,7 @@ namespace FactorySelector { const CreatureAICreator* factory = iter->second; const SelectableAI* p = dynamic_cast<const SelectableAI*>(factory); - ASSERT(p != NULL); + ASSERT(p); int val = p->Permit(creature); if (val > best_val) { @@ -102,7 +102,7 @@ namespace FactorySelector MovementGenerator* selectMovementGenerator(Creature* creature) { MovementGeneratorRegistry& mv_registry(*MovementGeneratorRepository::instance()); - ASSERT(creature->GetCreatureTemplate() != NULL); + ASSERT(creature->GetCreatureTemplate()); const MovementGeneratorCreator* mv_factory = mv_registry.GetRegistryItem(creature->GetDefaultMovementType()); /* if (mv_factory == NULL) @@ -133,6 +133,9 @@ namespace FactorySelector const GameObjectAICreator* ai_factory = NULL; GameObjectAIRegistry& ai_registry(*GameObjectAIRepository::instance()); + if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) + return scriptedAI; + ai_factory = ai_registry.GetRegistryItem(go->GetAIName()); //future goAI types go here diff --git a/src/server/game/AI/EventAI/CreatureEventAI.cpp b/src/server/game/AI/EventAI/CreatureEventAI.cpp index 7a2b83273c9..835705a0d7c 100755 --- a/src/server/game/AI/EventAI/CreatureEventAI.cpp +++ b/src/server/game/AI/EventAI/CreatureEventAI.cpp @@ -1107,7 +1107,7 @@ void CreatureEventAI::UpdateAI(const uint32 diff) break; case EVENT_T_RANGE: if (me->getVictim()) - if (me->IsInMap(me->getVictim())) + if (me->IsInMap(me->getVictim()) && me->InSamePhase(me->getVictim())) if (me->IsInRange(me->getVictim(), (float)(*i).Event.range.minDist, (float)(*i).Event.range.maxDist)) ProcessEvent(*i); break; diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index d80c71bfb35..6d27d251579 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -30,18 +30,6 @@ void SummonList::DoZoneInCombat(uint32 entry) } } -void SummonList::DoAction(uint32 entry, int32 info) -{ - for (iterator i = begin(); i != end();) - { - Creature* summon = Unit::GetCreature(*me, *i); - ++i; - if (summon && summon->IsAIEnabled - && (!entry || summon->GetEntry() == entry)) - summon->AI()->DoAction(info); - } -} - void SummonList::DespawnEntry(uint32 entry) { for (iterator i = begin(); i != end();) @@ -126,15 +114,7 @@ void ScriptedAI::UpdateAI(uint32 const /*diff*/) if (!UpdateVictim()) return; - if (me->isAttackReady()) - { - //If we are within range melee the target - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim()); - me->resetAttackTimer(); - } - } + DoMeleeAttackIfReady(); } void ScriptedAI::DoStartMovement(Unit* victim, float distance, float angle) @@ -189,11 +169,11 @@ SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mec { //No target so we can't cast if (!target) - return false; + return NULL; //Silenced so we can't cast if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) - return false; + return NULL; //Using the extended script system we first create a list of viable spells SpellInfo const* apSpell[CREATURE_MAX_SPELLS]; @@ -309,14 +289,13 @@ void ScriptedAI::DoTeleportTo(const float position[4]) void ScriptedAI::DoTeleportPlayer(Unit* unit, float x, float y, float z, float o) { - if (!unit || unit->GetTypeId() != TYPEID_PLAYER) - { - if (unit) - sLog->outError("TSCR: Creature " UI64FMTD " (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: " UI64FMTD ") to x: %f y:%f z: %f o: %f. Aborted.", me->GetGUID(), me->GetEntry(), unit->GetTypeId(), unit->GetGUID(), x, y, z, o); + if (!unit) return; - } - CAST_PLR(unit)->TeleportTo(unit->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT); + if (Player* player = unit->ToPlayer()) + player->TeleportTo(unit->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT); + else + sLog->outError("TSCR: Creature " UI64FMTD " (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: " UI64FMTD ") to x: %f y:%f z: %f o: %f. Aborted.", me->GetGUID(), me->GetEntry(), unit->GetTypeId(), unit->GetGUID(), x, y, z, o); } void ScriptedAI::DoTeleportAll(float x, float y, float z, float o) diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index a01c993cab6..4fac8b3cba5 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -38,7 +38,18 @@ class SummonList : public std::list<uint64> void Despawn(Creature* summon) { remove(summon->GetGUID()); } void DespawnEntry(uint32 entry); void DespawnAll(); - void DoAction(uint32 entry, int32 info); + + template <class Predicate> void DoAction(int32 info, Predicate& predicate, uint16 max = 0) + { + Trinity::Containers::RandomResizeList<uint64, Predicate>(*this, predicate, max); + for (iterator i = begin(); i != end(); ) + { + Creature* summon = Unit::GetCreature(*me, *i++); + if (summon && summon->IsAIEnabled) + summon->AI()->DoAction(info); + } + } + void DoZoneInCombat(uint32 entry = 0); void RemoveNotExisting(); bool HasEntry(uint32 entry); @@ -46,6 +57,22 @@ class SummonList : public std::list<uint64> Creature* me; }; +class EntryCheckPredicate +{ + public: + EntryCheckPredicate(uint32 entry) : _entry(entry) {} + bool operator()(uint64 guid) { return GUID_ENPART(guid) == _entry; } + + private: + uint32 _entry; +}; + +class DummyEntryCheckPredicate +{ + public: + bool operator()(uint64) { return true; } +}; + struct ScriptedAI : public CreatureAI { explicit ScriptedAI(Creature* creature); diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 4eb7f8a7f50..2a412bffb22 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -854,7 +854,7 @@ int SmartGameObjectAI::Permissible(const GameObject* g) return PERMIT_BASE_NO; } -void SmartGameObjectAI::UpdateAI(const uint32 diff) +void SmartGameObjectAI::UpdateAI(uint32 diff) { GetScript()->OnUpdate(diff); } diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 94e5e65cf8b..bfd1c7b9d41 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -239,7 +239,7 @@ public: SmartGameObjectAI(GameObject* g) : GameObjectAI(g), go(g) {} ~SmartGameObjectAI() {} - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); void InitializeAI(); void Reset(); SmartScript* GetScript() { return &mScript; } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index b2c4fd29868..893c8f4580e 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -108,8 +108,11 @@ void SmartScript::OnReset() ResetBaseObject(); for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i) { - InitTimer((*i)); - (*i).runOnce = false; + if (!((*i).event.event_flags & SMART_EVENT_FLAG_DONT_RESET)) + { + InitTimer((*i)); + (*i).runOnce = false; + } } ProcessEventsFor(SMART_EVENT_RESET); mLastInvoker = 0; @@ -1116,12 +1119,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { - if (!IsUnit(*itr)) - continue; - (*itr)->GetPosition(x, y, z, o); + x += e.target.x; + y += e.target.y; + z += e.target.z; + o += e.target.o; if (Creature* summon = GetBaseObject()->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration)) - if (unit && e.action.summonCreature.attackInvoker) + if (e.action.summonCreature.attackInvoker) summon->AI()->AttackStart((*itr)->ToUnit()); } @@ -1151,6 +1155,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u continue; (*itr)->GetPosition(x, y, z, o); + x += e.target.x; + y += e.target.y; + z += e.target.z; + o += e.target.o; GetBaseObject()->SummonGameObject(e.action.summonGO.entry, x, y, z, o, 0, 0, 0, 0, e.action.summonGO.despawnTime); } @@ -1862,19 +1870,26 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!targets) break; + ObjectList* storedTargets = GetTargetList(e.action.sendTargetToTarget.id); + if (!storedTargets) + { + delete targets; + return; + } + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { if (IsCreature(*itr)) { if (SmartAI* ai = CAST_AI(SmartAI, (*itr)->ToCreature()->AI())) - ai->GetScript()->StoreTargetList(GetTargetList(e.action.sendTargetToTarget.id), e.action.sendTargetToTarget.id); + ai->GetScript()->StoreTargetList(new ObjectList(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list else sLog->outErrorDb("SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartAI, skipping"); } else if (IsGameObject(*itr)) { if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, (*itr)->ToGameObject()->AI())) - ai->GetScript()->StoreTargetList(GetTargetList(e.action.sendTargetToTarget.id), e.action.sendTargetToTarget.id); + ai->GetScript()->StoreTargetList(new ObjectList(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list else sLog->outErrorDb("SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartGameObjectAI, skipping"); } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index e2cd75ee62c..8d3686a265d 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -1165,14 +1165,15 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] = enum SmartEventFlags { - SMART_EVENT_FLAG_NOT_REPEATABLE = 0x01, //Event can not repeat - SMART_EVENT_FLAG_DIFFICULTY_0 = 0x02, //Event only occurs in instance difficulty 0 - SMART_EVENT_FLAG_DIFFICULTY_1 = 0x04, //Event only occurs in instance difficulty 1 - SMART_EVENT_FLAG_DIFFICULTY_2 = 0x08, //Event only occurs in instance difficulty 2 - SMART_EVENT_FLAG_DIFFICULTY_3 = 0x10, //Event only occurs in instance difficulty 3 - SMART_EVENT_FLAG_RESERVED_5 = 0x20, - SMART_EVENT_FLAG_RESERVED_6 = 0x40, - SMART_EVENT_FLAG_DEBUG_ONLY = 0x80, //Event only occurs in debug build + SMART_EVENT_FLAG_NOT_REPEATABLE = 0x001, //Event can not repeat + SMART_EVENT_FLAG_DIFFICULTY_0 = 0x002, //Event only occurs in instance difficulty 0 + SMART_EVENT_FLAG_DIFFICULTY_1 = 0x004, //Event only occurs in instance difficulty 1 + SMART_EVENT_FLAG_DIFFICULTY_2 = 0x008, //Event only occurs in instance difficulty 2 + SMART_EVENT_FLAG_DIFFICULTY_3 = 0x010, //Event only occurs in instance difficulty 3 + SMART_EVENT_FLAG_RESERVED_5 = 0x020, + SMART_EVENT_FLAG_RESERVED_6 = 0x040, + SMART_EVENT_FLAG_DEBUG_ONLY = 0x080, //Event only occurs in debug build + SMART_EVENT_FLAG_DONT_RESET = 0x100, //Event will not reset in SmartScript::OnReset() SMART_EVENT_FLAG_DIFFICULTY_ALL = (SMART_EVENT_FLAG_DIFFICULTY_0|SMART_EVENT_FLAG_DIFFICULTY_1|SMART_EVENT_FLAG_DIFFICULTY_2|SMART_EVENT_FLAG_DIFFICULTY_3) }; diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index f3c393eaa36..44192a74123 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -144,6 +144,7 @@ Battleground::Battleground() m_Winner = 2; m_StartTime = 0; m_ResetStatTimer = 0; + m_ValidStartPositionTimer = 0; m_Events = 0; m_IsRated = false; m_BuffChange = false; @@ -177,6 +178,8 @@ Battleground::Battleground() m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0; m_ArenaTeamIds[BG_TEAM_HORDE] = 0; + m_StartMaxDist = 0.0f; + m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0; m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0; @@ -291,6 +294,7 @@ void Battleground::Update(uint32 diff) // Update start time and reset stats timer m_StartTime += diff; m_ResetStatTimer += diff; + m_ValidStartPositionTimer += diff; PostUpdateImpl(diff); } @@ -422,7 +426,7 @@ inline void Battleground::_ProcessJoin(uint32 diff) // ********************************************************* ModifyStartDelayTime(diff); - if (m_ResetStatTimer <= 5000) + if (m_ResetStatTimer > 5000) { m_ResetStatTimer = 0; for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) @@ -453,19 +457,19 @@ inline void Battleground::_ProcessJoin(uint32 diff) // First start warning - 2 or 1 minute SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL); } - // After 1 minute or 30 seconds, warning is signalled + // After 1 minute or 30 seconds, warning is signaled else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2)) { m_Events |= BG_STARTING_EVENT_2; SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL); } - // After 30 or 15 seconds, warning is signalled + // After 30 or 15 seconds, warning is signaled else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3)) { m_Events |= BG_STARTING_EVENT_3; SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL); } - // Delay expired (atfer 2 or 1 minute) + // Delay expired (after 2 or 1 minute) else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4)) { m_Events |= BG_STARTING_EVENT_4; @@ -526,6 +530,33 @@ inline void Battleground::_ProcessJoin(uint32 diff) sWorld->SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel()); } } + + // Find if the player left our start zone; if so, teleport it back + if (m_ValidStartPositionTimer > 1000) + { + m_ValidStartPositionTimer = 0; + float maxDist = GetStartMaxDist(); + if (maxDist > 0.0f) + { + for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) + { + if (Player *plr = ObjectAccessor::FindPlayer(itr->first)) + { + float x, y, z, o; + uint32 team = plr->GetBGTeam(); + GetTeamStartLoc(team, x, y, z, o); + + float dist = plr->GetDistance(x, y, z); + + if (dist >= maxDist) + { + sLog->outError("BATTLEGROUND: Sending %s back to start location (possible exploit)", plr->GetName()); + plr->TeleportTo(GetMapId(), x, y, z, o); + } + } + } + } + } } inline void Battleground::_ProcessLeave(uint32 diff) @@ -1459,9 +1490,8 @@ void Battleground::DoorClose(uint32 type) // If doors are open, close it if (obj->getLootState() == GO_ACTIVATED && obj->GetGoState() != GO_STATE_READY) { - // Change state to allow door to be closed obj->SetLootState(GO_READY); - obj->UseDoorOrButton(RESPAWN_ONE_DAY); + obj->SetGoState(GO_STATE_READY); } } else @@ -1473,9 +1503,8 @@ void Battleground::DoorOpen(uint32 type) { if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type])) { - // Change state to be sure they will be opened - obj->SetLootState(GO_READY); - obj->UseDoorOrButton(RESPAWN_ONE_DAY); + obj->SetLootState(GO_ACTIVATED); + obj->SetGoState(GO_STATE_ACTIVE); } else sLog->outError("Battleground::DoorOpen: door gameobject (type: %u, GUID: %u) not found for BG (map: %u, instance id: %u)!", diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 32f6ebc92de..01dfbb23033 100755 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -443,6 +443,8 @@ class Battleground Z = m_TeamStartLocZ[idx]; O = m_TeamStartLocO[idx]; } + void SetStartMaxDist(float startMaxDist) { m_StartMaxDist = startMaxDist; } + float GetStartMaxDist() const { return m_StartMaxDist; } // Packet Transfer // method that should fill worldpacket with actual world states (not yet implemented for all battlegrounds!) @@ -617,6 +619,7 @@ class Battleground uint32 m_ClientInstanceID; // the instance-id which is sent to the client and without any other internal use uint32 m_StartTime; uint32 m_ResetStatTimer; + uint32 m_ValidStartPositionTimer; int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself uint32 m_LastResurrectTime; BattlegroundBracketId m_BracketId; @@ -698,6 +701,7 @@ class Battleground float m_TeamStartLocY[BG_TEAMS_COUNT]; float m_TeamStartLocZ[BG_TEAMS_COUNT]; float m_TeamStartLocO[BG_TEAMS_COUNT]; + float m_StartMaxDist; uint32 ScriptId; }; #endif diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index e1b99cbdcb9..a106f11ae82 100755 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -660,6 +660,7 @@ uint32 BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data) bg->SetName(data.BattlegroundName); bg->SetTeamStartLoc(ALLIANCE, data.Team1StartLocX, data.Team1StartLocY, data.Team1StartLocZ, data.Team1StartLocO); bg->SetTeamStartLoc(HORDE, data.Team2StartLocX, data.Team2StartLocY, data.Team2StartLocZ, data.Team2StartLocO); + bg->SetStartMaxDist(data.StartMaxDist); bg->SetLevelRange(data.LevelMin, data.LevelMax); bg->SetScriptId(data.scriptId); @@ -677,8 +678,8 @@ void BattlegroundMgr::CreateInitialBattlegrounds() uint8 selectionWeight; BattlemasterListEntry const* bl; - // 0 1 2 3 4 5 6 7 8 9 10 - QueryResult result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, AllianceStartO, HordeStartLoc, HordeStartO, Weight, ScriptName FROM battleground_template"); + // 0 1 2 3 4 5 6 7 8 9 10 11 + QueryResult result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, AllianceStartO, HordeStartLoc, HordeStartO, StartMaxDist, Weight, ScriptName FROM battleground_template"); if (!result) { @@ -712,17 +713,20 @@ void BattlegroundMgr::CreateInitialBattlegrounds() data.MaxPlayersPerTeam = fields[2].GetUInt16(); data.LevelMin = fields[3].GetUInt8(); data.LevelMax = fields[4].GetUInt8(); - //check values from DB - if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam) + + // check values from DB + if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam) { - data.MinPlayersPerTeam = 0; // by default now expected strong full bg requirement - data.MaxPlayersPerTeam = 40; + sLog->outErrorDb("Table `battleground_template` for id %u has bad values for MinPlayersPerTeam (%u) and MaxPlayersPerTeam(%u)", + data.bgTypeId, data.MinPlayersPerTeam, data.MaxPlayersPerTeam); + continue; } + if (data.LevelMin == 0 || data.LevelMax == 0 || data.LevelMin > data.LevelMax) { - //TO-DO: FIX ME - data.LevelMin = 0;//bl->minlvl; - data.LevelMax = 80;//bl->maxlvl; + sLog->outErrorDb("Table `battleground_template` for id %u has bad values for LevelMin (%u) and LevelMax(%u)", + data.bgTypeId, data.LevelMin, data.LevelMax); + continue; } startId = fields[5].GetUInt32(); @@ -767,8 +771,10 @@ void BattlegroundMgr::CreateInitialBattlegrounds() continue; } - selectionWeight = fields[9].GetUInt8(); - data.scriptId = sObjectMgr->GetScriptId(fields[10].GetCString()); + data.StartMaxDist = fields[9].GetFloat(); + + selectionWeight = fields[10].GetUInt8(); + data.scriptId = sObjectMgr->GetScriptId(fields[11].GetCString()); data.BattlegroundName = bl->name[sWorld->GetDefaultDbcLocale()]; data.MapID = bl->mapid[0]; diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 88559d07993..7afb83da0a6 100755 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -50,6 +50,7 @@ struct CreateBattlegroundData float Team2StartLocY; float Team2StartLocZ; float Team2StartLocO; + float StartMaxDist; uint32 scriptId; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp index 8a11edf85e6..ccc6a2305b4 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp @@ -86,11 +86,8 @@ void BattlegroundDS::PostUpdateImpl(uint32 diff) setWaterFallTimer(BG_DS_WATERFALL_WARNING_DURATION); setWaterFallStatus(BG_DS_WATERFALL_STATUS_WARNING); } - else if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_WARNING) // Active collision and perform knockback + else if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_WARNING) // Active collision and start knockback timer { - if (Creature* waterSpout = GetBgMap()->GetCreature(BgCreatures[BG_DS_NPC_WATERFALL_KNOCKBACK])) - waterSpout->CastSpell(waterSpout, BG_DS_SPELL_WATER_SPOUT, true); - if (GameObject* gob = GetBgMap()->GetGameObject(BgObjects[BG_DS_OBJECT_WATER_1])) gob->SetGoState(GO_STATE_READY); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundDS.h b/src/server/game/Battlegrounds/Zones/BattlegroundDS.h index 12ed91fc922..aaf08ba1313 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundDS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundDS.h @@ -66,9 +66,9 @@ enum BattlegroundDSData { // These values are NOT blizzlike... need the correct data! BG_DS_WATERFALL_TIMER_MIN = 30000, BG_DS_WATERFALL_TIMER_MAX = 60000, - BG_DS_WATERFALL_WARNING_DURATION = 7000, - BG_DS_WATERFALL_DURATION = 10000, - BG_DS_WATERFALL_KNOCKBACK_TIMER = 500, + BG_DS_WATERFALL_WARNING_DURATION = 5000, + BG_DS_WATERFALL_DURATION = 30000, + BG_DS_WATERFALL_KNOCKBACK_TIMER = 1500, BG_DS_PIPE_KNOCKBACK_FIRST_DELAY = 5000, BG_DS_PIPE_KNOCKBACK_DELAY = 3000, @@ -118,7 +118,7 @@ class BattlegroundDS : public Battleground void setWaterFallStatus(uint8 status) { _waterfallStatus = status; }; uint32 getWaterFallTimer() { return _waterfallTimer; }; void setWaterFallTimer(uint32 timer) { _waterfallTimer = timer; }; - uint32 getWaterFallKnockbackTimer() { return _waterfallTimer; }; + uint32 getWaterFallKnockbackTimer() { return _waterfallKnockbackTimer; }; void setWaterFallKnockbackTimer(uint32 timer) { _waterfallKnockbackTimer = timer; }; uint8 getPipeKnockBackCount() { return _pipeKnockBackCount; }; void setPipeKnockBackCount(uint8 count) { _pipeKnockBackCount = count; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index f3d0f5520f0..45335ae7b8b 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -837,6 +837,7 @@ void BattlegroundIC::DestroyGate(Player* player, GameObject* go) { case GO_HORDE_GATE_1: lang_entry = LANG_BG_IC_NORTH_GATE_DESTROYED; + break; case GO_HORDE_GATE_2: case GO_ALLIANCE_GATE_1: lang_entry = LANG_BG_IC_WEST_GATE_DESTROYED; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index 6d784488aad..977897b8d48 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -534,16 +534,16 @@ void BattlegroundSA::EventPlayerDamagedGO(Player* /*player*/, GameObject* go, ui if (eventType == go->GetGOInfo()->building.damagedEvent) { - uint32 i = GetGateIDFromDestroyEventID(eventType); + uint32 i = getGateIdFromDamagedOrDestroyEventId(eventType); GateStatus[i] = BG_SA_GATE_DAMAGED; - uint32 uws = GetWorldStateFromGateID(i); + uint32 uws = getWorldStateFromGateId(i); if (uws) UpdateWorldState(uws, GateStatus[i]); } if (eventType == go->GetGOInfo()->building.destroyedEvent) { - if (go->GetGOInfo()->building.destroyedEvent == 19837) + if (go->GetGOInfo()->building.destroyedEvent == BG_SA_EVENT_ANCIENT_GATE_DESTROYED) SendWarningToAll(LANG_BG_SA_CHAMBER_BREACHED); else SendWarningToAll(LANG_BG_SA_WAS_DESTROYED, go->GetGOInfo()->name.c_str()); @@ -603,7 +603,7 @@ void BattlegroundSA::DemolisherStartState(bool start) void BattlegroundSA::DestroyGate(Player* player, GameObject* go) { - uint32 i = GetGateIDFromDestroyEventID(go->GetGOInfo()->building.destroyedEvent); + uint32 i = getGateIdFromDamagedOrDestroyEventId(go->GetGOInfo()->building.destroyedEvent); if (!GateStatus[i]) return; @@ -612,7 +612,7 @@ void BattlegroundSA::DestroyGate(Player* player, GameObject* go) if (g->GetGOValue()->Building.Health == 0) { GateStatus[i] = BG_SA_GATE_DESTROYED; - uint32 uws = GetWorldStateFromGateID(i); + uint32 uws = getWorldStateFromGateId(i); if (uws) UpdateWorldState(uws, GateStatus[i]); bool rewardHonor = true; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h index 76a772ff978..2ade101ce54 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -45,9 +45,30 @@ enum BG_SA_Status enum BG_SA_GateState { - BG_SA_GATE_OK = 1, - BG_SA_GATE_DAMAGED = 2, - BG_SA_GATE_DESTROYED = 3 + BG_SA_GATE_OK = 1, + BG_SA_GATE_DAMAGED = 2, + BG_SA_GATE_DESTROYED = 3 +}; + +enum BG_SA_EventIdGate +{ + BG_SA_EVENT_GREEN_GATE_DAMAGED = 19041, + BG_SA_EVENT_GREEN_GATE_DESTROYED = 19046, + + BG_SA_EVENT_BLUE_GATE_DAMAGED = 19040, + BG_SA_EVENT_BLUE_GATE_DESTROYED = 19045, + + BG_SA_EVENT_RED_GATE_DAMAGED = 19042, + BG_SA_EVENT_RED_GATE_DESTROYED = 19047, + + BG_SA_EVENT_PURPLE_GATE_DAMAGED = 19048, + BG_SA_EVENT_PURPLE_GATE_DESTROYED = 19043, + + BG_SA_EVENT_YELLOW_GATE_DAMAGED = 19049, + BG_SA_EVENT_YELLOW_GATE_DESTROYED = 19044, + + BG_SA_EVENT_ANCIENT_GATE_DAMAGED = 19836, + BG_SA_EVENT_ANCIENT_GATE_DESTROYED = 19837 }; enum BG_SA_Timers @@ -443,34 +464,60 @@ class BattlegroundSA : public Battleground /// Called when a player use a gamobject (relic) virtual void EventPlayerUsedGO(Player* Source, GameObject* object); /// Return gate id, relative to bg data, according to gameobject id - uint32 GetGateIDFromDestroyEventID(uint32 id) + uint32 getGateIdFromDamagedOrDestroyEventId(uint32 id) { - uint32 i = 0; switch (id) { - case 19046: i = BG_SA_GREEN_GATE; break; //Green gate destroyed - case 19045: i = BG_SA_BLUE_GATE; break; //blue gate - case 19047: i = BG_SA_RED_GATE; break; //red gate - case 19048: i = BG_SA_PURPLE_GATE; break; //purple gate - case 19049: i = BG_SA_YELLOW_GATE; break; //yellow gate - case 19837: i = BG_SA_ANCIENT_GATE; break; //ancient gate + // Green gate + case BG_SA_EVENT_GREEN_GATE_DAMAGED: + case BG_SA_EVENT_GREEN_GATE_DESTROYED: + return BG_SA_GREEN_GATE; + // Blue gate + case BG_SA_EVENT_BLUE_GATE_DAMAGED: + case BG_SA_EVENT_BLUE_GATE_DESTROYED: + return BG_SA_BLUE_GATE; + // Red gate + case BG_SA_EVENT_RED_GATE_DAMAGED: + case BG_SA_EVENT_RED_GATE_DESTROYED: + return BG_SA_RED_GATE; + // Purple gate + case BG_SA_EVENT_PURPLE_GATE_DAMAGED: + case BG_SA_EVENT_PURPLE_GATE_DESTROYED: + return BG_SA_PURPLE_GATE; + // Yellow gate + case BG_SA_EVENT_YELLOW_GATE_DAMAGED: + case BG_SA_EVENT_YELLOW_GATE_DESTROYED: + return BG_SA_YELLOW_GATE; + // Ancient gate + case BG_SA_EVENT_ANCIENT_GATE_DAMAGED: + case BG_SA_EVENT_ANCIENT_GATE_DESTROYED: + return BG_SA_ANCIENT_GATE; + default: + break; } - return i; + return 0; } /// Return worldstate id, according to door id - uint32 GetWorldStateFromGateID(uint32 id) + uint32 getWorldStateFromGateId(uint32 id) { - uint32 uws = 0; switch (id) { - case BG_SA_GREEN_GATE: uws = BG_SA_GREEN_GATEWS; break; - case BG_SA_YELLOW_GATE: uws = BG_SA_YELLOW_GATEWS; break; - case BG_SA_BLUE_GATE: uws = BG_SA_BLUE_GATEWS; break; - case BG_SA_RED_GATE: uws = BG_SA_RED_GATEWS; break; - case BG_SA_PURPLE_GATE: uws = BG_SA_PURPLE_GATEWS; break; - case BG_SA_ANCIENT_GATE: uws = BG_SA_ANCIENT_GATEWS; break; + case BG_SA_GREEN_GATE: + return BG_SA_GREEN_GATEWS; + case BG_SA_YELLOW_GATE: + return BG_SA_YELLOW_GATEWS; + case BG_SA_BLUE_GATE: + return BG_SA_BLUE_GATEWS; + case BG_SA_RED_GATE: + return BG_SA_RED_GATEWS; + case BG_SA_PURPLE_GATE: + return BG_SA_PURPLE_GATEWS; + case BG_SA_ANCIENT_GATE: + return BG_SA_ANCIENT_GATEWS; + default: + break; } - return uws; + return 0; } /// Called on battleground ending diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index 86ad749b8b7..d100dc645a2 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -179,20 +179,20 @@ void BattlegroundWS::StartingEventCloseDoors() void BattlegroundWS::StartingEventOpenDoors() { - for (uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; ++i) + for (uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_6; ++i) DoorOpen(i); - for (uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; ++i) + for (uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_4; ++i) DoorOpen(i); + for (uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY); SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY); SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY); SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY); - for (uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - - // players joining later are not egible + // players joining later are not eligibles StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, WS_EVENT_START_BATTLE); } @@ -476,7 +476,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* Source, GameObject* target } //Alliance flag on ground(not in base) (returned or picked up again from ground!) - if (GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10) && BgObjects[BG_WS_OBJECT_A_FLAG] == target_obj->GetGUID()) + if (GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10) && target_obj->GetGOInfo()->entry == BG_OBJECT_A_FLAG_GROUND_WS_ENTRY) { if (Source->GetTeam() == ALLIANCE) { @@ -510,7 +510,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* Source, GameObject* target } //Horde flag on ground(not in base) (returned or picked up again) - if (GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10) && BgObjects[BG_WS_OBJECT_H_FLAG] == target_obj->GetGUID()) + if (GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10) && target_obj->GetGOInfo()->entry == BG_OBJECT_H_FLAG_GROUND_WS_ENTRY) { if (Source->GetTeam() == HORDE) { diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 1f680f6e9b0..8b81a48c33b 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -107,7 +107,6 @@ set(game_STAT_SRCS include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/g3dlite/include - ${CMAKE_SOURCE_DIR}/dep/mersennetwister ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib ${CMAKE_SOURCE_DIR}/src/server/collision diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 92cf4d750a8..0e89601e987 100755 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -49,7 +49,6 @@ Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team) } else // it's custom channel { - channel_id = 0; m_flags |= CHANNEL_FLAG_CUSTOM; // If storing custom channels in the db is enabled either load or save the channel diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 48bb4c27ef8..cc64a8e22dd 100755 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -381,7 +381,6 @@ ChatCommand* ChatHandler::getCommandTable() { "linkgrave", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleLinkGraveCommand>, "", NULL }, { "neargrave", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleNearGraveCommand>, "", NULL }, { "explorecheat", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleExploreCheatCommand>, "", NULL }, - { "hover", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleHoverCommand>, "", NULL }, { "levelup", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleLevelUpCommand>, "", NULL }, { "showarea", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleShowAreaCommand>, "", NULL }, { "hidearea", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleHideAreaCommand>, "", NULL }, @@ -1334,7 +1333,7 @@ GameTele const* ChatHandler::extractGameTeleFromLink(char* text) // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r char* cId = extractKeyFromLink(text, "Htele"); if (!cId) - return false; + return NULL; // id case (explicit or from shift link) if (cId[0] >= '0' || cId[0] >= '9') @@ -1506,7 +1505,7 @@ char* ChatHandler::extractQuotedArg(char* args) { char* space = strtok(args, "\""); if (!space) - return false; + return NULL; return strtok(NULL, "\""); } } diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 0a39eb43ddb..e88914a2daf 100755 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -286,7 +286,6 @@ class ChatHandler bool HandleActivateObjectCommand(const char* args); bool HandleSpawnTransportCommand(const char* args); bool HandleExploreCheatCommand(const char* args); - bool HandleHoverCommand(const char* args); bool HandleWaterwalkCommand(const char* args); bool HandleLevelUpCommand(const char* args); bool HandleShowAreaCommand(const char* args); diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp index d3417705867..30562bb9662 100755 --- a/src/server/game/Chat/Commands/Level3.cpp +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -441,7 +441,7 @@ bool ChatHandler::HandleListItemCommand(const char *args) Field* fields = result->Fetch(); uint32 item_guid = fields[0].GetUInt32(); uint32 item_bag = fields[1].GetUInt32(); - uint32 item_slot = fields[2].GetUInt32(); + uint8 item_slot = fields[2].GetUInt8(); uint32 owner_guid = fields[3].GetUInt32(); uint32 owner_acc = fields[4].GetUInt32(); std::string owner_name = fields[5].GetString(); @@ -638,7 +638,7 @@ bool ChatHandler::HandleListObjectCommand(const char *args) uint32 obj_count = 0; result = WorldDatabase.PQuery("SELECT COUNT(guid) FROM gameobject WHERE id='%u'", go_id); if (result) - obj_count = (*result)[0].GetUInt32(); + obj_count = (*result)[0].GetUInt64(); if (m_session) { @@ -710,7 +710,7 @@ bool ChatHandler::HandleListCreatureCommand(const char *args) uint32 cr_count = 0; result = WorldDatabase.PQuery("SELECT COUNT(guid) FROM creature WHERE id='%u'", cr_id); if (result) - cr_count = (*result)[0].GetUInt32(); + cr_count = (*result)[0].GetUInt64(); if (m_session) { @@ -2158,25 +2158,6 @@ bool ChatHandler::HandleExploreCheatCommand(const char *args) return true; } -bool ChatHandler::HandleHoverCommand(const char *args) -{ - char* px = strtok((char*)args, " "); - uint32 flag; - if (!px) - flag = 1; - else - flag = atoi(px); - - m_session->GetPlayer()->SetHover(flag); - - if (flag) - SendSysMessage(LANG_HOVER_ENABLED); - else - SendSysMessage(LANG_HOVER_DISABLED); - - return true; -} - void ChatHandler::HandleCharacterLevel(Player* player, uint64 playerGuid, uint32 oldLevel, uint32 newLevel) { if (player) @@ -4593,40 +4574,38 @@ bool ChatHandler::HandleUnFreezeCommand(const char *args) { std::string name; Player* player; - char *TargetName = strtok((char*)args, " "); //get entered name - if (!TargetName) //if no name entered use target - { - player = getSelectedPlayer(); - if (player) //prevent crash with creature as target - name = player->GetName(); - } + char* targetName = strtok((char*)args, " "); // Get entered name - else // if name entered + if (targetName) { - name = TargetName; + name = targetName; normalizePlayerName(name); player = sObjectAccessor->FindPlayerByName(name.c_str()); } + else // If no name was entered - use target + { + player = getSelectedPlayer(); + if (player) + name = player->GetName(); + } - //effect if (player) { PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str()); - //Reset player faction + allow combat + allow duels + // Reset player faction + allow combat + allow duels player->setFactionForRace(player->getRace()); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - //allow movement and spells + // Remove Freeze spell (allowing movement and spells) player->RemoveAurasDueToSpell(9454); - //save player + // Save player player->SaveToDB(); } - - if (!player) + else { - if (TargetName) + if (targetName) { // Check for offline players PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_GUID_BY_NAME); @@ -4638,12 +4617,13 @@ bool ChatHandler::HandleUnFreezeCommand(const char *args) SendSysMessage(LANG_COMMAND_FREEZE_WRONG); return true; } - //if player found: delete his freeze aura - Field* fields=result->Fetch(); - uint64 pguid = fields[0].GetUInt64(); + + // If player found: delete his freeze aura + Field* fields = result->Fetch(); + uint32 lowGuid = fields[0].GetUInt32(); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_FROZEN); - stmt->setUInt32(0, pguid); + stmt->setUInt32(0, lowGuid); CharacterDatabase.Execute(stmt); PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str()); diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index d82e43ba83b..e604eaf9024 100755 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -75,7 +75,7 @@ bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellIn return false; // not in same map or phase - if (!hatedUnit->IsInMap(hatingUnit)) + if (!hatedUnit->IsInMap(hatingUnit) || !hatedUnit->InSamePhase(hatingUnit)) return false; // spell not causing threat @@ -182,6 +182,7 @@ void HostileReference::updateOnlineStatus() && (getTarget()->GetTypeId() != TYPEID_PLAYER || !getTarget()->ToPlayer()->isGameMaster()) && !getTarget()->HasUnitState(UNIT_STATE_IN_FLIGHT) && getTarget()->IsInMap(getSourceUnit()) + && getTarget()->InSamePhase(getSourceUnit()) ) { Creature* creature = getSourceUnit()->ToCreature(); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 3fcabea4c74..96f454fd3e2 100755 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -274,6 +274,12 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) condMeets = object->GetPhaseMask() & ConditionValue1; break; } + case CONDITION_TITLE: + { + if (Player* player = object->ToPlayer()) + condMeets = player->HasTitle(ConditionValue1); + break; + } default: condMeets = false; break; @@ -422,6 +428,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() case CONDITION_PHASEMASK: mask |= GRID_MAP_TYPE_MASK_ALL; break; + case CONDITION_TITLE: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; default: ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; @@ -1826,9 +1835,16 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog->outErrorDb("Phasemask condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_UNUSED_18: - sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_18 in `conditions` table - ignoring"); - return false; + case CONDITION_TITLE: + { + CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(cond->ConditionValue1); + if (!titleEntry) + { + sLog->outErrorDb("Title condition has non existing title in value1 (%u), skipped", cond->ConditionValue1); + return false; + } + break; + } case CONDITION_UNUSED_19: sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_19 in `conditions` table - ignoring"); return false; diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 2df79eab088..130a23a0cb0 100755 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -48,7 +48,7 @@ enum ConditionTypes CONDITION_CLASS = 15, // class 0 0 true if player's class is equal to class CONDITION_RACE = 16, // race 0 0 true if player's race is equal to race CONDITION_ACHIEVEMENT = 17, // achievement_id 0 0 true if achievement is complete - CONDITION_UNUSED_18 = 18, // + CONDITION_TITLE = 18, // title id 0 0 true if player has title CONDITION_UNUSED_19 = 19, // CONDITION_UNUSED_20 = 20, // CONDITION_UNUSED_21 = 21, // diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 38e8c957681..15792fd57da 100755 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1292,6 +1292,7 @@ struct MapEntry bool IsBattleground() const { return map_type == MAP_BATTLEGROUND; } bool IsBattleArena() const { return map_type == MAP_ARENA; } bool IsBattlegroundOrArena() const { return map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; } + bool IsWorldMap() const { return map_type == MAP_COMMON; } bool GetEntrancePos(int32 &mapid, float &x, float &y) const { diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index b936d32e13f..47c298d7467 100755 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -1023,7 +1023,7 @@ bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal) // Select a random dungeon from the compatible list // TODO - Select the dungeon based on group item Level, not just random // Create a new proposal - pProposal = new LfgProposal(SelectRandomContainerElement(compatibleDungeons)); + pProposal = new LfgProposal(Trinity::Containers::SelectRandomContainerElement(compatibleDungeons)); pProposal->cancelTime = time_t(time(NULL)) + LFG_TIME_PROPOSAL; pProposal->state = LFG_PROPOSAL_INITIATING; pProposal->queues = check; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 6a8ae07291a..ed89041ff66 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -357,8 +357,9 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData* data) m_regenHealth = cInfo->RegenHealth; - // creatures always have melee weapon ready if any - SetSheath(SHEATH_STATE_MELEE); + // creatures always have melee weapon ready if any unless specified otherwise + if (!GetCreatureAddon()) + SetSheath(SHEATH_STATE_MELEE); SelectLevel(GetCreatureTemplate()); if (team == HORDE) @@ -795,10 +796,12 @@ bool Creature::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, //! Need to be called after LoadCreaturesAddon - MOVEMENTFLAG_HOVER is set there if (HasUnitMovementFlag(MOVEMENTFLAG_HOVER)) + { z += GetFloatValue(UNIT_FIELD_HOVERHEIGHT); - //! Relocate again with updated Z coord - Relocate(x, y, z, ang); + //! Relocate again with updated Z coord + Relocate(x, y, z, ang); + } uint32 displayID = GetNativeDisplayId(); CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&displayID); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index f100d391698..f6d03ca38b2 100755 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -266,7 +266,6 @@ struct CreatureData // `creature_addon` table struct CreatureAddon { - uint32 guidOrEntry; uint32 path_id; uint32 mount; uint32 bytes1; @@ -508,7 +507,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature if (isPet()) return false; - return GetCreatureTemplate()->rank == CREATURE_ELITE_WORLDBOSS; + return GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_BOSS; } bool IsDungeonBoss() const; diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index a39bd8eddf7..836fbe8c7bf 100755 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -47,10 +47,7 @@ void GossipMenu::AddMenuItem(int32 menuItemId, uint8 icon, std::string const& me for (GossipMenuItemContainer::const_iterator itr = _menuItems.begin(); itr != _menuItems.end(); ++itr) { if (int32(itr->first) > menuItemId) - { - menuItemId = menuItemId; break; - } menuItemId = itr->first + 1; } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 1fe83023976..f58dd6b2e4d 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -135,10 +135,10 @@ void GameObject::AddToWorld() sObjectAccessor->AddObject(this); bool startOpen = (GetGoType() == GAMEOBJECT_TYPE_DOOR || GetGoType() == GAMEOBJECT_TYPE_BUTTON ? GetGOInfo()->door.startOpen : false); // The state can be changed after GameObject::Create but before GameObject::AddToWorld - bool toggledState = GetGoState() == GO_STATE_READY; + bool toggledState = GetGOData() ? GetGOData()->go_state == GO_STATE_READY : false; if (m_model) GetMap()->Insert(*m_model); - if ((startOpen && !toggledState) || (!startOpen && toggledState)) + if (startOpen ^ toggledState) EnableCollision(false); WorldObject::AddToWorld(); @@ -1432,7 +1432,7 @@ void GameObject::Use(Unit* user) if (info->summoningRitual.casterTargetSpell && info->summoningRitual.casterTargetSpell != 1) // No idea why this field is a bool in some cases for (uint32 i = 0; i < info->summoningRitual.casterTargetSpellTargets; i++) // m_unique_users can contain only player GUIDs - if (Player* target = ObjectAccessor::GetPlayer(*this, SelectRandomContainerElement(m_unique_users))) + if (Player* target = ObjectAccessor::GetPlayer(*this, Trinity::Containers::SelectRandomContainerElement(m_unique_users))) spellCaster->CastSpell(target, info->summoningRitual.casterTargetSpell, true); // finish owners spell @@ -1825,6 +1825,7 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* m_goValue->Building.Health = m_goValue->Building.MaxHealth; SetGoAnimProgress(255); } + EnableCollision(true); break; case GO_DESTRUCTIBLE_DAMAGED: { @@ -1881,6 +1882,7 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* m_goValue->Building.Health = 0; SetGoAnimProgress(0); } + EnableCollision(false); break; } case GO_DESTRUCTIBLE_REBUILDING: @@ -1900,6 +1902,7 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* m_goValue->Building.Health = m_goValue->Building.MaxHealth; SetGoAnimProgress(255); } + EnableCollision(true); break; } } diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index bc90e6f4484..f2b893896dc 100755 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -1089,9 +1089,9 @@ void Item::SaveRefundDataToDB() stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_REFUND_INSTANCE); stmt->setUInt32(0, GetGUIDLow()); - stmt->setUInt32(0, GetRefundRecipient()); - stmt->setUInt32(0, GetPaidMoney()); - stmt->setUInt16(0, uint16(GetPaidExtendedCost())); + stmt->setUInt32(1, GetRefundRecipient()); + stmt->setUInt32(2, GetPaidMoney()); + stmt->setUInt16(3, uint16(GetPaidExtendedCost())); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 69effaa016e..70b680c6ae0 100755 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1630,7 +1630,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const default: { float ground_z = GetBaseMap()->GetHeight(GetPhaseMask(), x, y, z, true); - if(ground_z > INVALID_HEIGHT) + if (ground_z > INVALID_HEIGHT) z = ground_z; break; } @@ -2741,6 +2741,14 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float pos.m_positionZ += 2.0f; destx = pos.m_positionX + dist * cos(angle); desty = pos.m_positionY + dist * sin(angle); + + // Prevent invalid coordinates here, position is unchanged + if (!Trinity::IsValidMapCoord(destx, desty)) + { + sLog->outCrash("WorldObject::MovePositionToFirstCollision invalid coordinates X: %f and Y: %f were passed!", destx, desty); + return; + } + ground = GetMap()->GetHeight(GetPhaseMask(), destx, desty, MAX_HEIGHT, true); floor = GetMap()->GetHeight(GetPhaseMask(), destx, desty, pos.m_positionZ, true); destz = fabs(ground - pos.m_positionZ) <= fabs(floor - pos.m_positionZ) ? ground : floor; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 6c77bf69a68..3693f683b24 100755 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -685,7 +685,7 @@ class WorldObject : public Object, public WorldLocation bool IsInMap(const WorldObject* obj) const { if (obj) - return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj); + return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()); return false; } bool IsWithinDist3d(float x, float y, float z, float dist) const @@ -703,7 +703,7 @@ class WorldObject : public Object, public WorldLocation } bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const { - return obj && IsInMap(obj) && _IsWithinDist(obj, dist2compare, is3D); + return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D); } bool IsWithinLOS(float x, float y, float z) const; bool IsWithinLOSInMap(const WorldObject* obj) const; @@ -878,20 +878,6 @@ class WorldObject : public Object, public WorldLocation namespace Trinity { - template<class T> - void RandomResizeList(std::list<T> &_list, uint32 _size) - { - size_t list_size = _list.size(); - - while (list_size > _size) - { - typename std::list<T>::iterator itr = _list.begin(); - std::advance(itr, urand(0, list_size - 1)); - _list.erase(itr); - --list_size; - } - } - // Binary predicate to sort WorldObjects based on the distance to a reference WorldObject class ObjectDistanceOrderPred { diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 0ee8381d54f..586f09bd79c 100755 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1041,6 +1041,13 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4))); break; } + case 28017: // Bloodworms + { + SetCreateHealth(4 * petlevel); + SetBonusDamage(int32(m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.006f)); + SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - 30 - (petlevel / 4))); + SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel - 30 + (petlevel / 4))); + } } break; } @@ -1745,7 +1752,7 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* online_pet /*= NULL*/) stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_LIST); stmt->setUInt32(0, owner->GetGUIDLow()); - stmt->setUInt32(0, except_petnumber); + stmt->setUInt32(1, except_petnumber); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 0a4363df323..7c70fe9358e 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -724,7 +724,6 @@ Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_rep for (uint8 i=0; i<MAX_TIMERS; i++) m_MirrorTimer[i] = DISABLED_MIRROR_TIMER; - _lastLiquid = NULL; m_MirrorTimerFlags = UNDERWATER_NONE; m_MirrorTimerFlagsLast = UNDERWATER_NONE; m_isInWater = false; @@ -932,7 +931,8 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) PlayerInfo const* info = sObjectMgr->GetPlayerInfo(createInfo->Race, createInfo->Class); if (!info) { - sLog->outError("Player (Name %s) has incorrect race/class pair. Can't be loaded.", m_name.c_str()); + sLog->outError("Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid race/class pair (%u/%u) - refusing to do so.", + GetSession()->GetAccountId(), m_name.c_str(), createInfo->Race, createInfo->Class); return false; } @@ -944,7 +944,8 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(createInfo->Class); if (!cEntry) { - sLog->outError("Class %u not found in DBC (Wrong DBC files?)", createInfo->Class); + sLog->outError("Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid character class (%u) - refusing to do so (wrong DBC-files?)", + GetSession()->GetAccountId(), m_name.c_str(), createInfo->Class); return false; } @@ -959,7 +960,8 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) if (!IsValidGender(createInfo->Gender)) { - sLog->outError("Player has invalid gender (%hu), can't be loaded.", createInfo->Gender); + sLog->outError("Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid gender (%hu) - refusing to do so", + GetSession()->GetAccountId(), m_name.c_str(), createInfo->Gender); return false; } @@ -2134,7 +2136,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (duel && GetMapId() != mapid && GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER))) DuelComplete(DUEL_FLED); - if ((GetMapId() == mapid && !m_transport) || (GetTransport() && GetMapId() == 628)) + if (GetMapId() == mapid) { //lets reset far teleport flag if it wasn't reset during chained teleports SetSemaphoreTeleportFar(false); @@ -2936,7 +2938,7 @@ void Player::GiveXP(uint32 xp, Unit* victim, float group_rate) if (xp < 1) return; - if (!isAlive()) + if (!isAlive() && !GetBattlegroundId()) return; if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_NO_XP_GAIN)) @@ -4819,16 +4821,16 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC { do { - Field* fields = resultMail->Fetch(); + Field* mailFields = resultMail->Fetch(); - uint32 mail_id = fields[0].GetUInt32(); - uint8 mailType = fields[1].GetUInt8(); - uint16 mailTemplateId= fields[2].GetUInt16(); - uint32 sender = fields[3].GetUInt32(); - std::string subject = fields[4].GetString(); - std::string body = fields[5].GetString(); - uint32 money = fields[6].GetUInt32(); - bool has_items = fields[7].GetBool(); + uint32 mail_id = mailFields[0].GetUInt32(); + uint8 mailType = mailFields[1].GetUInt8(); + uint16 mailTemplateId= mailFields[2].GetUInt16(); + uint32 sender = mailFields[3].GetUInt32(); + std::string subject = mailFields[4].GetString(); + std::string body = mailFields[5].GetString(); + uint32 money = mailFields[6].GetUInt32(); + bool has_items = mailFields[7].GetBool(); // We can return mail now // So firstly delete the old one @@ -4862,9 +4864,9 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC { do { - Field* fields2 = resultItems->Fetch(); - uint32 item_guidlow = fields2[11].GetUInt32(); - uint32 item_template = fields2[12].GetUInt32(); + Field* itemFields = resultItems->Fetch(); + uint32 item_guidlow = itemFields[11].GetUInt32(); + uint32 item_template = itemFields[12].GetUInt32(); ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_template); if (!itemProto) @@ -4876,7 +4878,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC } Item* pItem = NewItemOrBag(itemProto); - if (!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER), fields, item_template)) + if (!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER), itemFields, item_template)) { pItem->FSetState(ITEM_REMOVED); pItem->SaveToDB(trans); // it also deletes item object! @@ -6827,11 +6829,6 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation, bool t if (GetGroup()) SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION); - // code block for underwater state update - // Unit::UpdatePosition() checks for validity and updates our coordinates - // so we re-fetch them instead of using "raw" coordinates from function params - UpdateUnderwaterState(GetMap(), GetPositionX(), GetPositionY(), GetPositionZ()); - if (GetTrader() && !IsWithinDistInMap(GetTrader(), INTERACTION_DISTANCE)) GetSession()->SendCancelTrade(); @@ -8196,6 +8193,10 @@ void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackTy void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply) { + // don't apply mod if item is broken or cannot be used + if (item->IsBroken() || !CanUseAttackType(attackType)) + return; + // generic not weapon specific case processes in aura code if (aura->GetSpellInfo()->EquippedItemClass == -1) return; @@ -8209,13 +8210,13 @@ void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attac default: return; } - if (!item->IsBroken()&&item->IsFitToSpellRequirements(aura->GetSpellInfo())) + if (item->IsFitToSpellRequirements(aura->GetSpellInfo())) HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply); } void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply) { - //don't apply mod if item is broken + // don't apply mod if item is broken or cannot be used if (item->IsBroken() || !CanUseAttackType(attackType)) return; @@ -9216,6 +9217,9 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) case 4100: // The Culling of Stratholme NumberOfFields = 13; break; + case 4273: // Ulduar + NumberOfFields = 10; + break; default: NumberOfFields = 12; break; @@ -9760,6 +9764,16 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(3932) << uint32(0); // 13 WORLDSTATE_TIME_GUARDIAN_SHOW } break; + // Ulduar + case 4273: + if (instance && mapid == 603) + instance->FillInitialWorldStates(data); + else + { + data << uint32(4132) << uint32(0); // 9 WORLDSTATE_SHOW_CRATES + data << uint32(4131) << uint32(0); // 10 WORLDSTATE_CRATES_REVEALED + } + break; default: data << uint32(0x914) << uint32(0x0); // 7 data << uint32(0x913) << uint32(0x0); // 8 @@ -17650,7 +17664,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) ItemPosCountVec dest; err = CanStoreItem(itr->second->GetSlot(), slot, dest, item); if (err == EQUIP_ERR_OK) - itr->second->StoreItem(slot, item, true); + item = StoreItem(dest, item, true); } } @@ -18311,10 +18325,10 @@ void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficu CharacterDatabase.Execute(stmt); } - itr->second.save->RemovePlayer(this); // save can become invalid if (itr->second.perm) GetSession()->SendCalendarRaidLockout(itr->second.save, false); + itr->second.save->RemovePlayer(this); // save can become invalid m_boundInstances[difficulty].erase(itr++); } } @@ -19776,7 +19790,11 @@ void Player::SendResetInstanceSuccess(uint32 MapId) void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) { - // TODO: find what other fail reasons there are besides players in the instance + /*reasons for instance reset failure: + // 0: There are players inside the instance. + // 1: There are players offline in your party. + // 2>: There are players in your party attempting to zone into an instance. + */ WorldPacket data(SMSG_INSTANCE_RESET_FAILED, 4); data << uint32(reason); data << uint32(MapId); @@ -21144,10 +21162,10 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 } uint32 price = 0; - if(crItem->IsGoldRequired(pProto) && pProto->BuyPrice > 0) //Assume price cannot be negative (do not know why it is int32) + if (crItem->IsGoldRequired(pProto) && pProto->BuyPrice > 0) //Assume price cannot be negative (do not know why it is int32) { uint32 maxCount = MAX_MONEY_AMOUNT / pProto->BuyPrice; - if((uint32)count > maxCount) + if ((uint32)count > maxCount) { sLog->outError("Player %s tried to buy %u item id %u, causing overflow", GetName(), (uint32)count, pProto->ItemId); count = (uint8)maxCount; @@ -25546,3 +25564,27 @@ void Player::SendMovementSetCanTransitionBetweenSwimAndFly(bool apply) data << uint32(0); //! movement counter SendDirectMessage(&data); } + +void Player::SendMovementSetHover(bool apply) +{ + WorldPacket data(apply ? SMSG_MOVE_SET_HOVER : SMSG_MOVE_UNSET_HOVER, 12); + data.append(GetPackGUID()); + data << uint32(0); //! movement counter + SendDirectMessage(&data); +} + +void Player::SendMovementSetWaterWalking(bool apply) +{ + WorldPacket data(apply ? SMSG_MOVE_WATER_WALK : SMSG_MOVE_LAND_WALK, 12); + data.append(GetPackGUID()); + data << uint32(0); //! movement counter + SendDirectMessage(&data); +} + +void Player::SendMovementSetFeatherFall(bool apply) +{ + WorldPacket data(apply ? SMSG_MOVE_FEATHER_FALL : SMSG_MOVE_NORMAL_FALL, 12); + data.append(GetPackGUID()); + data << uint32(0); //! movement counter + SendDirectMessage(&data); +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 53b848a89b0..ed887994bca 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2486,6 +2486,9 @@ class Player : public Unit, public GridObject<Player> */ void SendMovementSetCanFly(bool apply); void SendMovementSetCanTransitionBetweenSwimAndFly(bool apply); + void SendMovementSetHover(bool apply); + void SendMovementSetWaterWalking(bool apply); + void SendMovementSetFeatherFall(bool apply); bool CanFly() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); } @@ -2822,7 +2825,6 @@ class Player : public Unit, public GridObject<Player> uint32 m_lastFallTime; float m_lastFallZ; - LiquidTypeEntry const* _lastLiquid; int32 m_MirrorTimer[MAX_TIMERS]; uint8 m_MirrorTimerFlags; uint8 m_MirrorTimerFlagsLast; diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 69771129ac9..2da1c1b88cb 100755 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -1068,6 +1068,7 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType) #define ENTRY_TREANT 1964 #define ENTRY_FIRE_ELEMENTAL 15438 #define ENTRY_GHOUL 26125 +#define ENTRY_BLOODWORM 28017 bool Guardian::UpdateStats(Stats stat) { @@ -1229,6 +1230,7 @@ void Guardian::UpdateMaxHealth() case ENTRY_SUCCUBUS: multiplicator = 9.1f; break; case ENTRY_FELHUNTER: multiplicator = 9.5f; break; case ENTRY_FELGUARD: multiplicator = 11.0f; break; + case ENTRY_BLOODWORM: multiplicator = 1.0f; break; default: multiplicator = 10.0f; break; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d71f8e8dfc3..fb91c3fc9f1 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -252,6 +252,7 @@ m_HostileRefManager(this) _focusSpell = NULL; _targetLocked = false; + _lastLiquid = NULL; } //////////////////////////////////////////////////////////// @@ -459,7 +460,7 @@ void Unit::resetAttackTimer(WeaponAttackType type) bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const { - if (!obj || !IsInMap(obj)) + if (!obj || !IsInMap(obj) || !InSamePhase(obj)) return false; float dx = GetPositionX() - obj->GetPositionX(); @@ -475,7 +476,7 @@ bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const bool Unit::IsWithinMeleeRange(const Unit* obj, float dist) const { - if (!obj || !IsInMap(obj)) + if (!obj || !IsInMap(obj) || !InSamePhase(obj)) return false; float dx = GetPositionX() - obj->GetPositionX(); @@ -572,6 +573,15 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam if (IsAIEnabled) GetAI()->DamageDealt(victim, damage, damagetype); + // Signal to pets that their owner was attacked + if (victim->GetTypeId() == TYPEID_PLAYER) + { + Pet* pet = victim->ToPlayer()->GetPet(); + + if (pet && pet->isAlive()) + pet->AI()->OwnerDamagedBy(this); + } + if (damagetype != NODAMAGE) { // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras) @@ -1485,7 +1495,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo } else { - if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*itr)->GetSpellInfo())) + if (ToPlayer()->HasItemFitToSpellRequirements((*itr)->GetSpellInfo())) bonusPct += (*itr)->GetAmount(); } } @@ -1495,6 +1505,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo maxArmorPen = float(400 + 85 * victim->getLevel()); else maxArmorPen = 400 + 85 * victim->getLevel() + 4.5f * 85 * (victim->getLevel() - 59); + // Cap armor penetration to this number maxArmorPen = std::min((armor + maxArmorPen) / 3, armor); // Figure out how much armor do we ignore @@ -1531,7 +1542,8 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype); // Magic damage, check for resists - if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) + // Ignore spells that cant be resisted + if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0 && (!spellInfo || (spellInfo->AttributesEx4 & SPELL_ATTR4_IGNORE_RESISTANCES) == 0)) { float victimResistance = float(victim->GetResistance(schoolMask)); victimResistance += float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask)); @@ -3078,6 +3090,48 @@ bool Unit::IsUnderWater() const return GetBaseMap()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ()); } +void Unit::UpdateUnderwaterState(Map* m, float x, float y, float z) +{ + if (!isPet() && !IsVehicle()) + return; + + LiquidData liquid_status; + ZLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status); + if (!res) + { + if (_lastLiquid && _lastLiquid->SpellId) + RemoveAurasDueToSpell(_lastLiquid->SpellId); + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER); + _lastLiquid = NULL; + return; + } + + if (uint32 liqEntry = liquid_status.entry) + { + LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry); + if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid->Id != liqEntry) + RemoveAurasDueToSpell(_lastLiquid->SpellId); + + if (liquid && liquid->SpellId) + { + if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER)) + CastSpell(this, liquid->SpellId, true); + else + RemoveAurasDueToSpell(liquid->SpellId); + } + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER); + _lastLiquid = liquid; + } + else if (_lastLiquid && _lastLiquid->SpellId) + { + RemoveAurasDueToSpell(_lastLiquid->SpellId); + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER); + _lastLiquid = NULL; + } +} + void Unit::DeMorph() { SetDisplayId(GetNativeDisplayId()); @@ -3597,8 +3651,9 @@ void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId { // final heal int32 healAmount = aurEff->GetAmount(); - int32 stack = dispelInfo.GetRemovedCharges(); - CastCustomSpell(this, 33778, &healAmount, &stack, NULL, true, NULL, NULL, aura->GetCasterGUID()); + if (Unit* caster = aura->GetCaster()) + healAmount = caster->SpellHealingBonus(this, aura->GetSpellInfo(), healAmount, HEAL, dispelInfo.GetRemovedCharges()); + CastCustomSpell(this, 33778, &healAmount, NULL, NULL, true, NULL, NULL, aura->GetCasterGUID()); // mana if (Unit* caster = aura->GetCaster()) @@ -4488,7 +4543,7 @@ float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_valu if (!sSpellMgr->AddSameEffectStackRuleSpellGroups((*i)->GetSpellInfo(), (*i)->GetAmount(), SameEffectSpellGroup)) AddPctN(multiplier, (*i)->GetAmount()); } - + for (std::map<SpellGroup, int32>::const_iterator itr = SameEffectSpellGroup.begin(); itr != SameEffectSpellGroup.end(); ++itr) AddPctN(multiplier, itr->second); @@ -4535,7 +4590,7 @@ int32 Unit::GetTotalAuraModifierByAffectMask(AuraType auratype, SpellInfo const* if (!sSpellMgr->AddSameEffectStackRuleSpellGroups((*i)->GetSpellInfo(), (*i)->GetAmount(), SameEffectSpellGroup)) modifier += (*i)->GetAmount(); } - + for (std::map<SpellGroup, int32>::const_iterator itr = SameEffectSpellGroup.begin(); itr != SameEffectSpellGroup.end(); ++itr) modifier += itr->second; @@ -5741,7 +5796,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Glyph of Polymorph case 56375: { - if(!target) + if (!target) return false; target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, 0, target->GetAura(32409)); // SW:D shall not be removed. target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); @@ -5800,7 +5855,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings) case 64411: { - if(!victim) + if (!victim) return false; basepoints0 = int32(CalculatePctN(damage, 15)); if (AuraEffect* aurEff = victim->GetAuraEffect(64413, 0, GetGUID())) @@ -5988,6 +6043,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Siphon Life case 63108: { + if (!damage) + break; // Glyph of Siphon Life if (HasAura(56216)) triggerAmount += triggerAmount / 4; @@ -6111,7 +6168,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Divine Aegis if (dummySpell->SpellIconID == 2820) { - if(!target) + if (!target) return false; // Multiple effects stack, so let's try to find this aura. @@ -6281,7 +6338,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Glyph of Shred case 54815: { - if(!target) + if (!target) return false; // try to find spell Rip on the target @@ -6587,7 +6644,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Explosive Shot if (procSpell->SpellFamilyFlags[2] & 0x200) { - if(!victim) + if (!victim) return false; if (AuraEffect const* pEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x0, 0x80000000, 0x0, GetGUID())) basepoints0 = pEff->GetSpellInfo()->CalcPowerCost(this, SpellSchoolMask(pEff->GetSpellInfo()->SchoolMask)) * 4/10/3; @@ -7342,20 +7399,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 63685; break; } - // Storm, Earth and Fire - if (dummySpell->SpellIconID == 3063) - { - // Earthbind Totem summon only - if (procSpell->Id != 2484) - return false; - - float chance = (float)triggerAmount; - if (!roll_chance_f(chance)) - return false; - - triggered_spell_id = 64695; - break; - } // Ancestral Awakening if (dummySpell->SpellIconID == 3065) { @@ -7384,8 +7427,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (GetTypeId() != TYPEID_PLAYER || !victim || !victim->isAlive() || !castItem || !castItem->IsEquipped()) return false; - Player* player = ToPlayer(); - WeaponAttackType attType = WeaponAttackType(player->GetAttackBySlot(castItem->GetSlot())); + WeaponAttackType attType = WeaponAttackType(Player::GetAttackBySlot(castItem->GetSlot())); if ((attType != BASE_ATTACK && attType != OFF_ATTACK) || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)) @@ -7973,11 +8015,7 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp for (uint8 i = 1; i < stack; ++i) dmg += mod * stack; if (Unit* caster = triggeredByAura->GetCaster()) - { caster->CastCustomSpell(70701, SPELLVALUE_BASE_POINT0, dmg); - if (Creature* creature = caster->ToCreature()) - creature->DespawnOrUnsummon(1); - } break; } // Ball of Flames Proc @@ -8188,6 +8226,16 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp CastCustomSpell(this, 70845, &basepoints0, NULL, NULL, true); break; } + // Recklessness + case 1719: + { + //! Possible hack alert + //! Don't drop charges on proc, they will be dropped on SpellMod removal + //! Before this change, it was dropping two charges per attack, one in ProcDamageAndSpellFor, and one in RemoveSpellMods. + //! The reason of this behaviour is Recklessness having three auras, 2 of them can not proc (isTriggeredAura array) but the other one can, making the whole spell proc. + *handled = true; + break; + } default: break; } @@ -8311,6 +8359,12 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg RemoveAuraFromStack(auraSpellInfo->Id); return false; } + if (auraSpellInfo->Id == 50720) + { + target = triggeredByAura->GetCaster(); + if (!target) + return false; + } break; case SPELLFAMILY_WARLOCK: { @@ -8663,6 +8717,26 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg } break; } + case SPELLFAMILY_ROGUE: + { + switch (auraSpellInfo->Id) + { + // Rogue T10 2P bonus, should only proc on caster + case 70805: + { + if (victim != this) + return false; + break; + } + // Rogue T10 4P bonus, should proc on victim + case 70803: + { + target = victim; + break; + } + } + break; + } default: break; } @@ -8827,7 +8901,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg } // Blade Barrier - if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 85) + if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 85 && procSpell) { Player* player = ToPlayer(); if (!player || player->getClass() != CLASS_DEATH_KNIGHT) @@ -9515,6 +9589,16 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) if (meleeAttack) SendMeleeAttackStart(victim); + // Let the pet know we've started attacking someting. Handles melee attacks only + // Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode + if (this->GetTypeId() == TYPEID_PLAYER) + { + Pet* playerPet = this->ToPlayer()->GetPet(); + + if (playerPet && playerPet->isAlive()) + playerPet->AI()->OwnerAttacked(victim); + } + return true; } @@ -12487,6 +12571,12 @@ bool Unit::IsAlwaysVisibleFor(WorldObject const* seer) const if (seer->GetGUID() == guid) return true; + if (Player const* seerPlayer = seer->ToPlayer()) + if (Unit* owner = GetOwner()) + if (Player* ownerPlayer = owner->ToPlayer()) + if (ownerPlayer->IsGroupVisibleFor(seerPlayer)) + return true; + return false; } @@ -14911,7 +15001,7 @@ Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const return NULL; // select random - return SelectRandomContainerElement(targets); + return Trinity::Containers::SelectRandomContainerElement(targets); } void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply) @@ -17208,6 +17298,9 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel else if (turn) UpdateOrientation(orientation); + // code block for underwater state update + UpdateUnderwaterState(GetMap(), x, y, z); + return (relocated || turn); } @@ -17512,7 +17605,7 @@ bool Unit::SetWalk(bool enable) return true; } -bool Unit::SetDisableGravity(bool disable) +bool Unit::SetDisableGravity(bool disable, bool /*packetOnly = false*/) { if (disable == IsLevitating()) return false; @@ -17553,26 +17646,35 @@ bool Unit::SetHover(bool enable) void Unit::SendMovementHover() { + if (GetTypeId() == TYPEID_PLAYER) + ToPlayer()->SendMovementSetHover(HasUnitMovementFlag(MOVEMENTFLAG_HOVER)); + WorldPacket data(MSG_MOVE_HOVER, 64); data.append(GetPackGUID()); BuildMovementPacket(&data); - SendMessageToSet(&data, true); + SendMessageToSet(&data, false); } void Unit::SendMovementWaterWalking() { + if (GetTypeId() == TYPEID_PLAYER) + ToPlayer()->SendMovementSetWaterWalking(HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING)); + WorldPacket data(MSG_MOVE_WATER_WALK, 64); data.append(GetPackGUID()); BuildMovementPacket(&data); - SendMessageToSet(&data, true); + SendMessageToSet(&data, false); } void Unit::SendMovementFeatherFall() { + if (GetTypeId() == TYPEID_PLAYER) + ToPlayer()->SendMovementSetFeatherFall(HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW)); + WorldPacket data(MSG_MOVE_FEATHER_FALL, 64); data.append(GetPackGUID()); BuildMovementPacket(&data); - SendMessageToSet(&data, true); + SendMessageToSet(&data, false); } void Unit::SendMovementGravityChange() @@ -17580,7 +17682,7 @@ void Unit::SendMovementGravityChange() WorldPacket data(MSG_MOVE_GRAVITY_CHNG, 64); data.append(GetPackGUID()); BuildMovementPacket(&data); - SendMessageToSet(&data, true); + SendMessageToSet(&data, false); } void Unit::SendMovementCanFlyChange() @@ -17605,5 +17707,5 @@ void Unit::SendMovementCanFlyChange() WorldPacket data(MSG_MOVE_UPDATE_CAN_FLY, 64); data.append(GetPackGUID()); BuildMovementPacket(&data); - SendMessageToSet(&data, true); + SendMessageToSet(&data, false); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index fcbe1afa389..5a6276d3b0c 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -707,6 +707,9 @@ enum MovementFlags MOVEMENTFLAG_MASK_TURNING = MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT, + MOVEMENTFLAG_MASK_MOVING_FLY = + MOVEMENTFLAG_FLYING | MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING, + //! TODO if needed: add more flags to this masks that are exclusive to players MOVEMENTFLAG_MASK_PLAYER_ONLY = MOVEMENTFLAG_FLYING, @@ -1577,6 +1580,7 @@ class Unit : public WorldObject virtual bool IsInWater() const; virtual bool IsUnderWater() const; + virtual void UpdateUnderwaterState(Map* m, float x, float y, float z); bool isInAccessiblePlaceFor(Creature const* c) const; void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false); @@ -1644,7 +1648,7 @@ class Unit : public WorldObject bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);} bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);} virtual bool SetWalk(bool enable); - virtual bool SetDisableGravity(bool disable); + virtual bool SetDisableGravity(bool disable, bool packetOnly = false); bool SetHover(bool enable); void SetInFront(Unit const* target); @@ -2316,6 +2320,7 @@ class Unit : public WorldObject Vehicle* m_vehicleKit; uint32 m_unitTypeMask; + LiquidTypeEntry const* _lastLiquid; bool IsAlwaysVisibleFor(WorldObject const* seer) const; bool IsAlwaysDetectableFor(WorldObject const* seer) const; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index f3d6e8abc79..4ce05ff40d3 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -453,11 +453,12 @@ void Vehicle::RelocatePassengers(float x, float y, float z, float ang) void Vehicle::Dismiss() { + if (GetBase()->GetTypeId() != TYPEID_UNIT) + return; + sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Dismiss Entry: %u, GuidLow %u", _creatureEntry, _me->GetGUIDLow()); Uninstall(); - _me->DestroyForNearbyPlayers(); - _me->CombatStop(); - _me->AddObjectToRemoveList(); + GetBase()->ToCreature()->DespawnOrUnsummon(); } void Vehicle::InitMovementInfoForBase() diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 0f2b2382007..f81e7f1f074 100755 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1025,15 +1025,6 @@ class ObjectMgr return &itr->second; } - bool IsGoOfSpecificEntrySpawned(uint32 entry) const - { - for (GameObjectDataContainer::const_iterator it = _gameObjectDataStore.begin(); it != _gameObjectDataStore.end(); ++it) - if (it->second.id == entry) - return true; - - return false; - } - GameObjectData const* GetGOData(uint32 guid) const { GameObjectDataContainer::const_iterator itr = _gameObjectDataStore.find(guid); diff --git a/src/server/game/Grids/GridStates.h b/src/server/game/Grids/GridStates.h index 08b66f6bb35..cf649f8d896 100755 --- a/src/server/game/Grids/GridStates.h +++ b/src/server/game/Grids/GridStates.h @@ -40,6 +40,7 @@ class GridState void setMagic() { i_Magic = MAGIC_TESTVAL; } unsigned int i_Magic; #endif + virtual ~GridState() {}; virtual void Update(Map &, NGridType&, GridInfo &, const uint32 t_diff) const = 0; }; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index bb2a9c5130b..e81822e72be 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -797,7 +797,7 @@ namespace Trinity if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isTotem()) return false; - if(!u->isTargetableForAttack(false)) + if (!u->isTargetableForAttack(false)) return false; return i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u); @@ -1287,7 +1287,7 @@ namespace Trinity AllWorldObjectsInRange(const WorldObject* object, float maxRange) : m_pObject(object), m_fRange(maxRange) {} bool operator() (WorldObject* go) { - return m_pObject->IsWithinDist(go, m_fRange, false); + return m_pObject->IsWithinDist(go, m_fRange, false) && m_pObject->InSamePhase(go); } private: const WorldObject* m_pObject; diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index 40b3863679b..e3cda4dd76d 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -251,9 +251,8 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m) return; for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); } template<class Check> @@ -263,9 +262,8 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(CreatureMapType &m) return; for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); } template<class Check> @@ -275,9 +273,8 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(CorpseMapType &m) return; for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); } template<class Check> @@ -287,9 +284,8 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(GameObjectMapType &m) return; for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); } template<class Check> @@ -299,9 +295,8 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType &m) return; for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); } // Gameobject searchers diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 768531b0aea..c7648bf1ccc 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -2136,7 +2136,7 @@ void Group::SetGroupMemberFlag(uint64 guid, bool apply, GroupMemberFlags flag) PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_FLAG); stmt->setUInt8(0, slot->flags); - stmt->setUInt32(0, GUID_LOPART(guid)); + stmt->setUInt32(1, GUID_LOPART(guid)); CharacterDatabase.Execute(stmt); diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 85694dba630..d537fc5b4aa 100755 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -1127,9 +1127,9 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GIFT); stmt->setUInt32(0, GUID_LOPART(item->GetOwnerGUID())); - stmt->setUInt32(0, item->GetGUIDLow()); - stmt->setUInt32(0, item->GetEntry()); - stmt->setUInt32(0, item->GetUInt32Value(ITEM_FIELD_FLAGS)); + stmt->setUInt32(1, item->GetGUIDLow()); + stmt->setUInt32(2, item->GetEntry()); + stmt->setUInt32(3, item->GetUInt32Value(ITEM_FIELD_FLAGS)); trans->Append(stmt); item->SetEntry(gift->GetEntry()); diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index aea7499aaa9..aa6d208ad3a 100755 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -525,9 +525,9 @@ void WorldSession::SendLfgBootPlayer(const LfgPlayerBoot* pBoot) ++agreeNum; } } - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_BOOT_PLAYER [" UI64FMTD "] inProgress: %u - didVote: %u - agree: %u - victim: [" UI64FMTD "] votes: %u - agrees: %u - left: %u - needed: %u - reason %s", + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_BOOT_PROPOSAL_UPDATE [" UI64FMTD "] inProgress: %u - didVote: %u - agree: %u - victim: [" UI64FMTD "] votes: %u - agrees: %u - left: %u - needed: %u - reason %s", guid, uint8(pBoot->inProgress), uint8(playerVote != LFG_ANSWER_PENDING), uint8(playerVote == LFG_ANSWER_AGREE), pBoot->victim, votesNum, agreeNum, secsleft, pBoot->votedNeeded, pBoot->reason.c_str()); - WorldPacket data(SMSG_LFG_BOOT_PLAYER, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + pBoot->reason.length()); + WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + pBoot->reason.length()); data << uint8(pBoot->inProgress); // Vote in progress data << uint8(playerVote != LFG_ANSWER_PENDING); // Did Vote data << uint8(playerVote == LFG_ANSWER_AGREE); // Agree diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 1fa6d9fc0ed..e54bee96b8b 100755 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -153,8 +153,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint16 spellid switch (spellid) { case COMMAND_STAY: //flat=1792 //STAY - pet->AttackStop(); - pet->InterruptNonMeleeSpells(false); pet->StopMoving(); pet->GetMotionMaster()->Clear(false); pet->GetMotionMaster()->MoveIdle(); diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp index 9c4eba67426..d6675188f6e 100755 --- a/src/server/game/Handlers/TicketHandler.cpp +++ b/src/server/game/Handlers/TicketHandler.cpp @@ -176,6 +176,8 @@ void WorldSession::HandleReportLag(WorldPacket& recv_data) stmt->setFloat (3, x); stmt->setFloat (4, y); stmt->setFloat (5, z); + stmt->setUInt32(6, GetLatency()); + stmt->setUInt32(7, time(NULL)); CharacterDatabase.Execute(stmt); } diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index c17c7edbf0d..8078a91d082 100755 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -581,17 +581,17 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_MAP_DIFF); stmt->setUInt16(0, uint16(mapid)); - stmt->setUInt8(0, uint8(difficulty)); + stmt->setUInt8(1, uint8(difficulty)); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_MAP_DIFF); stmt->setUInt16(0, uint16(mapid)); - stmt->setUInt8(0, uint8(difficulty)); + stmt->setUInt8(1, uint8(difficulty)); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INSTANCE_BY_MAP_DIFF); stmt->setUInt16(0, uint16(mapid)); - stmt->setUInt8(0, uint8(difficulty)); + stmt->setUInt8(1, uint8(difficulty)); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 1b349b11156..75065158ef6 100755 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -1526,7 +1526,7 @@ void LoadLootTemplates_Gameobject() { if (uint32 lootid = itr->second.GetLootId()) { - if (sObjectMgr->IsGoOfSpecificEntrySpawned(itr->second.entry) && lootIdSet.find(lootid) == lootIdSet.end()) + if (lootIdSet.find(lootid) == lootIdSet.end()) LootTemplates_Gameobject.ReportNotExistedId(lootid); else lootIdSetUsed.insert(lootid); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index f60a8f20c1c..a1b3d913c99 100755 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -787,20 +787,20 @@ void Map::RemoveCreatureFromMoveList(Creature* c) void Map::MoveAllCreaturesInMoveList() { _creatureToMoveLock = true; - for(std::vector<Creature*>::iterator itr = _creaturesToMove.begin(); itr != _creaturesToMove.end(); ++itr) + for (std::vector<Creature*>::iterator itr = _creaturesToMove.begin(); itr != _creaturesToMove.end(); ++itr) { Creature* c = *itr; - if(c->FindMap() != this) //pet is teleported to another map + if (c->FindMap() != this) //pet is teleported to another map continue; - if(c->_moveState != CREATURE_CELL_MOVE_ACTIVE) + if (c->_moveState != CREATURE_CELL_MOVE_ACTIVE) { c->_moveState = CREATURE_CELL_MOVE_NONE; continue; } c->_moveState = CREATURE_CELL_MOVE_NONE; - if(!c->IsInWorld()) + if (!c->IsInWorld()) continue; // do move or do move to respawn or remove creature if previous all fail diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 766e3d23f93..6ba08646f25 100755 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -228,7 +228,7 @@ enum LevelRequirementVsMode #define MAX_HEIGHT 100000.0f // can be use for find ground height at surface #define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE #define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT -#define DEFAULT_HEIGHT_SEARCH 10.0f // default search distance to find height at nearby locations +#define DEFAULT_HEIGHT_SEARCH 50.0f // default search distance to find height at nearby locations #define MIN_UNLOAD_DELAY 1 // immediate unload typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType; diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 0fb28008c1e..eb09538721d 100755 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -96,32 +96,32 @@ void MapManager::checkAndCorrectGridStatesArray() Map* MapManager::CreateBaseMap(uint32 id) { - Map* m = FindBaseMap(id); + Map* map = FindBaseMap(id); - if (m == NULL) + if (map == NULL) { TRINITY_GUARD(ACE_Thread_Mutex, Lock); const MapEntry* entry = sMapStore.LookupEntry(id); if (entry && entry->Instanceable()) { - m = new MapInstanced(id, i_gridCleanUpDelay); + map = new MapInstanced(id, i_gridCleanUpDelay); } else { - m = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); + map = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); } - i_maps[id] = m; + i_maps[id] = map; } - ASSERT(m != NULL); - return m; + ASSERT(map); + return map; } Map* MapManager::FindBaseNonInstanceMap(uint32 mapId) const { Map* map = FindBaseMap(mapId); - if(map && map->Instanceable()) + if (map && map->Instanceable()) return NULL; return map; } diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 547f1679b61..4b07d19bd7a 100755 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -522,8 +522,10 @@ enum TrinityStrings LANG_YOURS_EXPLORE_SET_ALL = 553, LANG_YOURS_EXPLORE_SET_NOTHING = 554, - LANG_HOVER_ENABLED = 555, - LANG_HOVER_DISABLED = 556, + //! Old ones now free: + // LANG_HOVER_ENABLED = 555, + // LANG_HOVER_DISABLED = 556, + LANG_YOURS_LEVEL_UP = 557, LANG_YOURS_LEVEL_DOWN = 558, LANG_YOURS_LEVEL_PROGRESS_RESET = 559, diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index bca896df38f..06aca10879d 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -269,7 +269,7 @@ enum SpellAttr0 SPELL_ATTR0_UNK0 = 0x00000001, // 0 SPELL_ATTR0_REQ_AMMO = 0x00000002, // 1 on next ranged SPELL_ATTR0_ON_NEXT_SWING = 0x00000004, // 2 - SPELL_ATTR0_UNK3 = 0x00000008, // 3 not set in 3.0.3 + SPELL_ATTR0_IS_REPLENISHMENT = 0x00000008, // 3 not set in 3.0.3 SPELL_ATTR0_ABILITY = 0x00000010, // 4 client puts 'ability' instead of 'spell' in game strings for these spells SPELL_ATTR0_TRADESPELL = 0x00000020, // 5 trade spells (recipes), will be added by client to a sublist of profession spell SPELL_ATTR0_PASSIVE = 0x00000040, // 6 Passive spell @@ -314,7 +314,7 @@ enum SpellAttr1 SPELL_ATTR1_MELEE_COMBAT_START = 0x00000200, // 9 player starts melee combat after this spell is cast SPELL_ATTR1_NO_THREAT = 0x00000400, // 10 no generates threat on cast 100% (old NO_INITIAL_AGGRO) SPELL_ATTR1_UNK11 = 0x00000800, // 11 aura - SPELL_ATTR1_UNK12 = 0x00001000, // 12 pickpoket + SPELL_ATTR1_IS_PICKPOCKET = 0x00001000, // 12 Pickpocket SPELL_ATTR1_FARSIGHT = 0x00002000, // 13 Client removes farsight on aura loss SPELL_ATTR1_CHANNEL_TRACK_TARGET = 0x00004000, // 14 Client automatically forces player to face target when channeling SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY = 0x00008000, // 15 remove auras on immunity @@ -326,7 +326,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 only fishing spells + SPELL_ATTR1_IS_FISHING = 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 melee spell? @@ -351,17 +351,17 @@ enum SpellAttr2 SPELL_ATTR2_UNK10 = 0x00000400, // 10 related to tame SPELL_ATTR2_HEALTH_FUNNEL = 0x00000800, // 11 SPELL_ATTR2_UNK12 = 0x00001000, // 12 Cleave, Heart Strike, Maul, Sunder Armor, Swipe - SPELL_ATTR2_UNK13 = 0x00002000, // 13 Items enchanted by spells with this flag preserve the enchant to arenas + SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA = 0x00002000, // 13 Items enchanted by spells with this flag preserve the enchant to arenas SPELL_ATTR2_UNK14 = 0x00004000, // 14 SPELL_ATTR2_UNK15 = 0x00008000, // 15 not set in 3.0.3 SPELL_ATTR2_TAME_BEAST = 0x00010000, // 16 SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS = 0x00020000, // 17 don't reset timers for melee autoattacks (swings) or ranged autoattacks (autoshoots) - SPELL_ATTR2_UNK18 = 0x00040000, // 18 Only Revive pet - possible req dead pet + SPELL_ATTR2_REQ_DEAD_PET = 0x00040000, // 18 Only Revive pet and Heart of the Pheonix SPELL_ATTR2_NOT_NEED_SHAPESHIFT = 0x00080000, // 19 does not necessarly need shapeshift SPELL_ATTR2_UNK20 = 0x00100000, // 20 SPELL_ATTR2_DAMAGE_REDUCED_SHIELD = 0x00200000, // 21 for ice blocks, pala immunity buffs, priest absorb shields, but used also for other spells -> not sure! SPELL_ATTR2_UNK22 = 0x00400000, // 22 Ambush, Backstab, Cheap Shot, Death Grip, Garrote, Judgements, Mutilate, Pounce, Ravage, Shiv, Shred - SPELL_ATTR2_UNK23 = 0x00800000, // 23 Only mage Arcane Concentration have this flag + SPELL_ATTR2_IS_ARCANE_CONCENTRATION = 0x00800000, // 23 Only mage Arcane Concentration have this flag SPELL_ATTR2_UNK24 = 0x01000000, // 24 SPELL_ATTR2_UNK25 = 0x02000000, // 25 SPELL_ATTR2_UNK26 = 0x04000000, // 26 unaffected by school immunity @@ -388,7 +388,7 @@ enum SpellAttr3 SPELL_ATTR3_BATTLEGROUND = 0x00000800, // 11 Can casted only on battleground SPELL_ATTR3_ONLY_TARGET_GHOSTS = 0x00001000, // 12 SPELL_ATTR3_UNK13 = 0x00002000, // 13 - SPELL_ATTR3_UNK14 = 0x00004000, // 14 "Honorless Target" only this spells have this flag + SPELL_ATTR3_IS_HONORLESS_TARGET = 0x00004000, // 14 "Honorless Target" only this spells have this flag SPELL_ATTR3_UNK15 = 0x00008000, // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag SPELL_ATTR3_CANT_TRIGGER_PROC = 0x00010000, // 16 confirmed with many patchnotes SPELL_ATTR3_NO_INITIAL_AGGRO = 0x00020000, // 17 Soothe Animal, 39758, Mind Soothe @@ -410,8 +410,8 @@ enum SpellAttr3 enum SpellAttr4 { - SPELL_ATTR4_UNK0 = 0x00000001, // 0 - SPELL_ATTR4_PROC_ONLY_ON_DUMMY = 0x00000002, // 1 proc only on SPELL_EFFECT_DUMMY? + SPELL_ATTR4_IGNORE_RESISTANCES = 0x00000001, // 0 spells with this attribute will completely ignore the target's resistance (these spells can't be resisted) + SPELL_ATTR4_PROC_ONLY_ON_CASTER = 0x00000002, // 1 proc only on effects with TARGET_UNIT_CASTER? SPELL_ATTR4_UNK2 = 0x00000004, // 2 SPELL_ATTR4_UNK3 = 0x00000008, // 3 SPELL_ATTR4_UNK4 = 0x00000010, // 4 This will no longer cause guards to attack on use?? @@ -432,16 +432,16 @@ enum SpellAttr4 SPELL_ATTR4_UNK19 = 0x00080000, // 19 proc dalayed, after damage or don't proc on absorb? SPELL_ATTR4_NOT_CHECK_SELFCAST_POWER = 0x00100000, // 20 supersedes message "More powerful spell applied" for self casts. SPELL_ATTR4_UNK21 = 0x00200000, // 21 Pally aura, dk presence, dudu form, warrior stance, shadowform, hunter track - SPELL_ATTR4_UNK22 = 0x00400000, // 22 + SPELL_ATTR4_UNK22 = 0x00400000, // 22 Seal of Command (42058,57770) and Gymer's Smash 55426 SPELL_ATTR4_UNK23 = 0x00800000, // 23 SPELL_ATTR4_UNK24 = 0x01000000, // 24 some shoot spell - SPELL_ATTR4_UNK25 = 0x02000000, // 25 pet scaling auras + SPELL_ATTR4_IS_PET_SCALING = 0x02000000, // 25 pet scaling auras SPELL_ATTR4_CAST_ONLY_IN_OUTLAND = 0x04000000, // 26 Can only be used in Outland. SPELL_ATTR4_UNK27 = 0x08000000, // 27 SPELL_ATTR4_UNK28 = 0x10000000, // 28 Aimed Shot SPELL_ATTR4_UNK29 = 0x20000000, // 29 SPELL_ATTR4_UNK30 = 0x40000000, // 30 - SPELL_ATTR4_UNK31 = 0x80000000 // 31 + SPELL_ATTR4_UNK31 = 0x80000000 // 31 Polymorph (chicken) 228 and Sonic Boom (38052,38488) }; enum SpellAttr5 @@ -461,7 +461,7 @@ enum SpellAttr5 SPELL_ATTR5_UNK12 = 0x00001000, // 12 Cleave related? SPELL_ATTR5_HASTE_AFFECT_DURATION = 0x00002000, // 13 haste effects decrease duration of this SPELL_ATTR5_UNK14 = 0x00004000, // 14 - SPELL_ATTR5_UNK15 = 0x00008000, // 15 + SPELL_ATTR5_UNK15 = 0x00008000, // 15 Inflits on multiple targets? SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK = 0x00010000, // 16 this allows spells with EquippedItemClass to affect spells from other items if the required item is equipped SPELL_ATTR5_USABLE_WHILE_FEARED = 0x00020000, // 17 usable while feared SPELL_ATTR5_USABLE_WHILE_CONFUSED = 0x00040000, // 18 usable while confused @@ -2566,7 +2566,7 @@ enum CreatureTypeFlags { CREATURE_TYPEFLAGS_TAMEABLE = 0x00000001, // Tameable by any hunter CREATURE_TYPEFLAGS_GHOST = 0x00000002, // Creature are also visible for not alive player. Allow gossip interaction if npcflag allow? - CREATURE_TYPEFLAGS_UNK2 = 0x00000004, + CREATURE_TYPEFLAGS_BOSS = 0x00000004, CREATURE_TYPEFLAGS_UNK3 = 0x00000008, CREATURE_TYPEFLAGS_UNK4 = 0x00000010, CREATURE_TYPEFLAGS_UNK5 = 0x00000020, @@ -3294,20 +3294,20 @@ enum BanReturn // indexes of BattlemasterList.dbc enum BattlegroundTypeId { - BATTLEGROUND_TYPE_NONE = 0, - BATTLEGROUND_AV = 1, - BATTLEGROUND_WS = 2, - BATTLEGROUND_AB = 3, - BATTLEGROUND_NA = 4, - BATTLEGROUND_BE = 5, - BATTLEGROUND_AA = 6, - BATTLEGROUND_EY = 7, - BATTLEGROUND_RL = 8, - BATTLEGROUND_SA = 9, - BATTLEGROUND_DS = 10, - BATTLEGROUND_RV = 11, - BATTLEGROUND_IC = 30, - BATTLEGROUND_RB = 32 + BATTLEGROUND_TYPE_NONE = 0, // None + BATTLEGROUND_AV = 1, // Alterac Valley + BATTLEGROUND_WS = 2, // Warsong Gulch + BATTLEGROUND_AB = 3, // Arathi Basin + BATTLEGROUND_NA = 4, // Nagrand Arena + BATTLEGROUND_BE = 5, // Blade's Edge Arena + BATTLEGROUND_AA = 6, // All Arenas + BATTLEGROUND_EY = 7, // Eye of the Storm + BATTLEGROUND_RL = 8, // Ruins of Lordaernon + BATTLEGROUND_SA = 9, // Strand of the Ancients + BATTLEGROUND_DS = 10, // Dalaran Sewers + BATTLEGROUND_RV = 11, // Ring of Valor + BATTLEGROUND_IC = 30, // Isle of Conquest + BATTLEGROUND_RB = 32 // Random Battleground }; #define MAX_BATTLEGROUND_TYPE_ID 33 diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index b8a7ee848ed..c0e1eb842ae 100755 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -114,6 +114,9 @@ void MotionMaster::UpdateMotion(uint32 diff) _cleanFlag &= ~MMCF_RESET; } + + // probably not the best place to pu this but im not really sure where else to put it. + _owner->UpdateUnderwaterState(_owner->GetMap(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); } void MotionMaster::DirectClean(bool reset) @@ -383,6 +386,12 @@ void MotionMaster::MoveFall(uint32 id/*=0*/) if (fabs(_owner->GetPositionZ() - tz) < 0.1f) return; + if (_owner->GetTypeId() == TYPEID_PLAYER) + { + _owner->AddUnitMovementFlag(MOVEMENTFLAG_FALLING); + _owner->m_movementInfo.SetFallTime(0); + } + Movement::MoveSplineInit init(*_owner); init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz); init.SetFall(); diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp index da830a9a49b..54a68f92c66 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp @@ -32,11 +32,10 @@ template<class T> void ConfusedMovementGenerator<T>::Initialize(T &unit) { - const float wander_distance=4; - float x,y,z; - x = unit.GetPositionX(); - y = unit.GetPositionY(); - z = unit.GetPositionZ(); + float const wander_distance = 4; + float x = unit.GetPositionX(); + float y = unit.GetPositionY(); + float z = unit.GetPositionZ(); Map const* map = unit.GetBaseMap(); @@ -47,31 +46,42 @@ void ConfusedMovementGenerator<T>::Initialize(T &unit) for (uint8 idx = 0; idx < MAX_CONF_WAYPOINTS + 1; ++idx) { - const float wanderX=wander_distance*(float)rand_norm() - wander_distance/2; - const float wanderY=wander_distance*(float)rand_norm() - wander_distance/2; - - i_waypoints[idx][0] = x + wanderX; - i_waypoints[idx][1] = y + wanderY; + float wanderX = x + (wander_distance * (float)rand_norm() - wander_distance/2); + float wanderY = y + (wander_distance * (float)rand_norm() - wander_distance/2); // prevent invalid coordinates generation - Trinity::NormalizeMapCoord(i_waypoints[idx][0]); - Trinity::NormalizeMapCoord(i_waypoints[idx][1]); + Trinity::NormalizeMapCoord(wanderX); + Trinity::NormalizeMapCoord(wanderY); - bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z); - // if generated wrong path just ignore - if ((is_water && !is_water_ok) || (!is_water && !is_land_ok)) + if (unit.IsWithinLOS(wanderX, wanderY, z)) + { + bool is_water = map->IsInWater(wanderX, wanderY, z); + + if ((is_water && !is_water_ok) || (!is_water && !is_land_ok)) + { + //! Cannot use coordinates outside our InhabitType. Use the current or previous position. + wanderX = idx > 0 ? i_waypoints[idx-1][0] : x; + wanderY = idx > 0 ? i_waypoints[idx-1][1] : y; + } + } + else { - i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x; - i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y; + //! Trying to access path outside line of sight. Skip this by using the current or previous position. + wanderX = idx > 0 ? i_waypoints[idx-1][0] : x; + wanderY = idx > 0 ? i_waypoints[idx-1][1] : y; } - unit.UpdateAllowedPositionZ(i_waypoints[idx][0], i_waypoints[idx][1], z); + unit.UpdateAllowedPositionZ(wanderX, wanderY, z); + + //! Positions are fine - apply them to this waypoint + i_waypoints[idx][0] = wanderX; + i_waypoints[idx][1] = wanderY; i_waypoints[idx][2] = z; } unit.StopMoving(); unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - unit.AddUnitState(UNIT_STATE_CONFUSED|UNIT_STATE_CONFUSED_MOVE); + unit.AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); } template<> @@ -94,7 +104,7 @@ void ConfusedMovementGenerator<T>::Reset(T &unit) i_nextMove = 1; i_nextMoveTime.Reset(0); unit.StopMoving(); - unit.AddUnitState(UNIT_STATE_CONFUSED|UNIT_STATE_CONFUSED_MOVE); + unit.AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); } template<class T> @@ -110,8 +120,8 @@ bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff) if (unit.movespline->Finalized()) { - i_nextMove = urand(1,MAX_CONF_WAYPOINTS); - i_nextMoveTime.Reset(urand(0, 1500-1)); // TODO: check the minimum reset time, should be probably higher + i_nextMove = urand(1, MAX_CONF_WAYPOINTS); + i_nextMoveTime.Reset(urand(500, 1200)); // Guessed } } else @@ -123,7 +133,7 @@ bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff) // start moving unit.AddUnitState(UNIT_STATE_CONFUSED_MOVE); - ASSERT( i_nextMove <= MAX_CONF_WAYPOINTS ); + ASSERT(i_nextMove <= MAX_CONF_WAYPOINTS); float x = i_waypoints[i_nextMove][0]; float y = i_waypoints[i_nextMove][1]; float z = i_waypoints[i_nextMove][2]; @@ -141,14 +151,14 @@ template<> void ConfusedMovementGenerator<Player>::Finalize(Player &unit) { unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - unit.ClearUnitState(UNIT_STATE_CONFUSED|UNIT_STATE_CONFUSED_MOVE); + unit.ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); } template<> void ConfusedMovementGenerator<Creature>::Finalize(Creature &unit) { unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - unit.ClearUnitState(UNIT_STATE_CONFUSED|UNIT_STATE_CONFUSED_MOVE); + unit.ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); if (unit.getVictim()) unit.SetTarget(unit.getVictim()->GetGUID()); } diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h index b9f96bb785d..7f2226ea069 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h @@ -22,11 +22,10 @@ #include "MovementGenerator.h" #include "Timer.h" -#define MAX_CONF_WAYPOINTS 24 +#define MAX_CONF_WAYPOINTS 24 //! Allows a twelve second confusion if i_nextMove always is the absolute minimum timer. template<class T> -class ConfusedMovementGenerator -: public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> > +class ConfusedMovementGenerator : public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> > { public: explicit ConfusedMovementGenerator() : i_nextMoveTime(0) {} diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index 7de5f1095c4..08e27abf050 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -28,8 +28,7 @@ #define MAX_QUIET_DISTANCE 43.0f template<class T> -void -FleeingMovementGenerator<T>::_setTargetLocation(T &owner) +void FleeingMovementGenerator<T>::_setTargetLocation(T &owner) { if (!&owner) return; @@ -53,8 +52,7 @@ FleeingMovementGenerator<T>::_setTargetLocation(T &owner) } template<class T> -bool -FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z) +bool FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z) { if (!&owner) return false; @@ -65,8 +63,8 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z) float temp_x, temp_y, angle; const Map* _map = owner.GetBaseMap(); - //primitive path-finding - for(uint8 i = 0; i < 18; ++i) + // primitive path-finding + for (uint8 i = 0; i < 18; ++i) { if (i_only_forward && i > 2) break; @@ -187,8 +185,7 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z) } template<class T> -bool -FleeingMovementGenerator<T>::_setMoveData(T &owner) +bool FleeingMovementGenerator<T>::_setMoveData(T &owner) { float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z); @@ -280,8 +277,7 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner) } template<class T> -void -FleeingMovementGenerator<T>::Initialize(T &owner) +void FleeingMovementGenerator<T>::Initialize(T &owner) { if (!&owner) return; @@ -312,8 +308,7 @@ FleeingMovementGenerator<T>::Initialize(T &owner) } template<> -void -FleeingMovementGenerator<Creature>::_Init(Creature &owner) +void FleeingMovementGenerator<Creature>::_Init(Creature &owner) { if (!&owner) return; @@ -324,8 +319,7 @@ FleeingMovementGenerator<Creature>::_Init(Creature &owner) } template<> -void -FleeingMovementGenerator<Player>::_Init(Player &) +void FleeingMovementGenerator<Player>::_Init(Player &) { is_water_ok = true; is_land_ok = true; @@ -354,8 +348,7 @@ void FleeingMovementGenerator<T>::Reset(T &owner) } template<class T> -bool -FleeingMovementGenerator<T>::Update(T &owner, const uint32 &time_diff) +bool FleeingMovementGenerator<T>::Update(T &owner, const uint32 &time_diff) { if (!&owner || !owner.isAlive()) return false; diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h index f795a002821..aec93ad3375 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h @@ -22,8 +22,7 @@ #include "MovementGenerator.h" template<class T> -class FleeingMovementGenerator -: public MovementGeneratorMedium< T, FleeingMovementGenerator<T> > +class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovementGenerator<T> > { public: FleeingMovementGenerator(uint64 fright) : i_frightGUID(fright), i_nextCheckTime(0) {} @@ -55,8 +54,7 @@ class FleeingMovementGenerator TimeTracker i_nextCheckTime; }; -class TimedFleeingMovementGenerator -: public FleeingMovementGenerator<Creature> +class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature> { public: TimedFleeingMovementGenerator(uint64 fright, uint32 time) : diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h index c724edc91ff..95eb05f281c 100755 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h @@ -27,8 +27,7 @@ template < class T > class HomeMovementGenerator; template <> -class HomeMovementGenerator<Creature> -: public MovementGeneratorMedium< Creature, HomeMovementGenerator<Creature> > +class HomeMovementGenerator<Creature> : public MovementGeneratorMedium< Creature, HomeMovementGenerator<Creature> > { public: diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 91b50344ccb..a922c937b5f 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -46,7 +46,7 @@ bool PointMovementGenerator<T>::Update(T &unit, const uint32 & /*diff*/) if (!&unit) return false; - if(unit.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (unit.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) { unit.ClearUnitState(UNIT_STATE_ROAMING_MOVE); return true; diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h index 82578da5f9b..13be9fee77b 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h @@ -23,8 +23,7 @@ #include "FollowerReference.h" template<class T> -class PointMovementGenerator -: public MovementGeneratorMedium< T, PointMovementGenerator<T> > +class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator<T> > { public: PointMovementGenerator(uint32 _id, float _x, float _y, float _z, float _speed = 0.0f) : id(_id), @@ -46,8 +45,7 @@ class PointMovementGenerator float speed; }; -class AssistanceMovementGenerator -: public PointMovementGenerator<Creature> +class AssistanceMovementGenerator : public PointMovementGenerator<Creature> { public: AssistanceMovementGenerator(float _x, float _y, float _z) : diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index e520253eb46..84cd9e88295 100755 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -127,8 +127,7 @@ void RandomMovementGenerator<Creature>::Initialize(Creature &creature) } template<> -void -RandomMovementGenerator<Creature>::Reset(Creature &creature) +void RandomMovementGenerator<Creature>::Reset(Creature &creature) { Initialize(creature); } @@ -141,8 +140,7 @@ void RandomMovementGenerator<Creature>::Finalize(Creature &creature) } template<> -bool -RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff) +bool RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff) { if (creature.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) { diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h index 67161b6fc29..07ec3647052 100755 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h @@ -22,8 +22,7 @@ #include "MovementGenerator.h" template<class T> -class RandomMovementGenerator -: public MovementGeneratorMedium< T, RandomMovementGenerator<T> > +class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovementGenerator<T> > { public: RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) {} diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index 6d507a3b694..fdff5a92564 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -78,7 +78,7 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner) //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE; - if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize ) + if ( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize ) return; */ @@ -135,7 +135,7 @@ bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_ } // prevent movement while casting spells with cast time or channel time - if (owner.IsNonMeleeSpellCasted(false, false, true)) + if (owner.HasUnitState(UNIT_STATE_CASTING)) { if (!owner.IsStopped()) owner.StopMoving(); diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h index b851dbc0e05..29fd73624e1 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h @@ -34,8 +34,7 @@ class TargetedMovementGeneratorBase }; template<class T, typename D> -class TargetedMovementGeneratorMedium -: public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase +class TargetedMovementGeneratorMedium : public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase { protected: TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) : diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index b5b43fcae64..0d8f047c83a 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -58,9 +58,8 @@ template<class T> class WaypointMovementGenerator; template<> -class WaypointMovementGenerator<Creature> -: public MovementGeneratorMedium< Creature, WaypointMovementGenerator<Creature> >, -public PathMovementBase<Creature, WaypointPath const*> +class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Creature, WaypointMovementGenerator<Creature> >, + public PathMovementBase<Creature, WaypointPath const*> { public: WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) @@ -110,9 +109,8 @@ public PathMovementBase<Creature, WaypointPath const*> /** FlightPathMovementGenerator generates movement of the player for the paths * and hence generates ground and activities for the player. */ -class FlightPathMovementGenerator -: public MovementGeneratorMedium< Player, FlightPathMovementGenerator >, -public PathMovementBase<Player, TaxiPathNodeList const*> +class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, FlightPathMovementGenerator >, + public PathMovementBase<Player, TaxiPathNodeList const*> { public: explicit FlightPathMovementGenerator(TaxiPathNodeList const& pathnodes, uint32 startNode = 0) diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp index 5d0344f9769..91b4ff08250 100644 --- a/src/server/game/Movement/Spline/MoveSpline.cpp +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -288,7 +288,7 @@ std::string MoveSpline::ToString() const str << "facing angle: " << facing.angle; else if (splineflags.final_target) str << "facing target: " << facing.target; - else if(splineflags.final_point) + else if (splineflags.final_point) str << "facing point: " << facing.f.x << " " << facing.f.y << " " << facing.f.z; str << std::endl; str << "time passed: " << time_passed << std::endl; diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp index e9031f95486..0260767dbe2 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -111,7 +111,7 @@ namespace Movement Vector3 middle = (real_path[0] + real_path[last_idx]) / 2.f; Vector3 offset; // first and last points already appended - for(uint32 i = 1; i < last_idx; ++i) + for (uint32 i = 1; i < last_idx; ++i) { offset = middle - real_path[i]; data.appendPackXYZ(offset.x, offset.y, offset.z); @@ -169,7 +169,7 @@ namespace Movement { data << move_spline.facing.target; } - else if(splineFlags.final_point) + else if (splineFlags.final_point) { data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z; } diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp index 5ebf78e484c..d8548b552d3 100755 --- a/src/server/game/Pools/PoolMgr.cpp +++ b/src/server/game/Pools/PoolMgr.cpp @@ -479,7 +479,7 @@ void PoolGroup<Quest>::SpawnObject(ActivePoolData& spawns, uint32 limit, uint32 { do { - uint32 questId = SelectRandomContainerElement(currentQuests); + uint32 questId = Trinity::Containers::SelectRandomContainerElement(currentQuests); newQuests.insert(questId); currentQuests.erase(questId); } while (newQuests.size() < limit && !currentQuests.empty()); // failsafe @@ -491,7 +491,7 @@ void PoolGroup<Quest>::SpawnObject(ActivePoolData& spawns, uint32 limit, uint32 // activate <limit> random quests do { - uint32 questId = SelectRandomContainerElement(newQuests); + uint32 questId = Trinity::Containers::SelectRandomContainerElement(newQuests); spawns.ActivateObject<Quest>(questId, poolId); PoolObject tempObj(questId, 0.0f); Spawn1Object(&tempObj); diff --git a/src/server/game/Reputation/ReputationMgr.h b/src/server/game/Reputation/ReputationMgr.h index 401503783b9..a073845ea73 100755 --- a/src/server/game/Reputation/ReputationMgr.h +++ b/src/server/game/Reputation/ReputationMgr.h @@ -132,6 +132,9 @@ class ReputationMgr void ApplyForceReaction(uint32 faction_id, ReputationRank rank, bool apply); + //! Public for chat command needs + bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental); + public: // senders void SendInitialReputations(); void SendForceReactions(); @@ -142,7 +145,6 @@ class ReputationMgr void Initialize(); uint32 GetDefaultStateFlags(FactionEntry const* factionEntry) const; bool SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental); - bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental); void SetVisible(FactionState* faction); void SetAtWar(FactionState* faction, bool atWar) const; void SetInactive(FactionState* faction, bool inactive) const; diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 8e95f1a05cd..f64d0953e86 100755 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -424,6 +424,7 @@ void AddSC_ulduar_teleporter(); void AddSC_boss_mimiron(); void AddSC_boss_hodir(); void AddSC_boss_freya(); +void AddSC_boss_algalon_the_observer(); void AddSC_instance_ulduar(); void AddSC_boss_keleseth(); //Utgarde Keep void AddSC_boss_skarvald_dalronn(); @@ -1127,6 +1128,7 @@ void AddNorthrendScripts() AddSC_boss_mimiron(); AddSC_boss_hodir(); AddSC_boss_freya(); + AddSC_boss_algalon_the_observer(); AddSC_instance_ulduar(); AddSC_boss_keleseth(); //Utgarde Keep AddSC_boss_skarvald_dalronn(); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 012910210a5..01d56cf8060 100755 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -582,7 +582,7 @@ void ScriptMgr::OnCreateMap(Map* map) { ASSERT(map); - SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnCreate(map); SCR_MAP_END; @@ -599,7 +599,7 @@ void ScriptMgr::OnDestroyMap(Map* map) { ASSERT(map); - SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnDestroy(map); SCR_MAP_END; @@ -617,7 +617,7 @@ void ScriptMgr::OnLoadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy) ASSERT(map); ASSERT(gmap); - SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnLoadGridMap(map, gmap, gx, gy); SCR_MAP_END; @@ -635,7 +635,7 @@ void ScriptMgr::OnUnloadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy) ASSERT(map); ASSERT(gmap); - SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnUnloadGridMap(map, gmap, gx, gy); SCR_MAP_END; @@ -653,7 +653,7 @@ void ScriptMgr::OnPlayerEnterMap(Map* map, Player* player) ASSERT(map); ASSERT(player); - SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnPlayerEnter(map, player); SCR_MAP_END; @@ -671,7 +671,7 @@ void ScriptMgr::OnPlayerLeaveMap(Map* map, Player* player) ASSERT(map); ASSERT(player); - SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnPlayerLeave(map, player); SCR_MAP_END; @@ -688,7 +688,7 @@ void ScriptMgr::OnMapUpdate(Map* map, uint32 diff) { ASSERT(map); - SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnUpdate(map, diff); SCR_MAP_END; @@ -954,6 +954,14 @@ bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effInd return tmpscript->OnDummyEffect(caster, spellId, effIndex, target); } +GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* go) +{ + ASSERT(go); + + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, NULL); + return tmpscript->GetAI(go); +} + bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger) { ASSERT(player); @@ -1415,7 +1423,7 @@ FormulaScript::FormulaScript(const char* name) WorldMapScript::WorldMapScript(const char* name, uint32 mapId) : ScriptObject(name), MapScript<Map>(mapId) { - if (GetEntry() && !GetEntry()->IsContinent()) + if (GetEntry() && !GetEntry()->IsWorldMap()) sLog->outError("WorldMapScript for map %u is invalid.", mapId); ScriptRegistry<WorldMapScript>::AddScript(this); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 3b65a5cf256..6fe058d336a 100755 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -39,6 +39,7 @@ class Creature; class CreatureAI; class DynamicObject; class GameObject; +class GameObjectAI; class Guild; class GridMap; class Group; @@ -471,6 +472,9 @@ class GameObjectScript : public ScriptObject, public UpdatableScript<GameObject> // Called when the game object is damaged (destructible buildings only). virtual void OnDamaged(GameObject* /*go*/, Player* /*player*/) { } + + // Called when a GameObjectAI object is needed for the gameobject. + virtual GameObjectAI* GetAI(GameObject* /*go*/) const { return NULL; } }; class AreaTriggerScript : public ScriptObject @@ -911,6 +915,7 @@ class ScriptMgr void OnGameObjectDestroyed(GameObject* go, Player* player); void OnGameObjectDamaged(GameObject* go, Player* player); void OnGameObjectUpdate(GameObject* go, uint32 diff); + GameObjectAI* GetGameObjectAI(GameObject* go); public: /* AreaTriggerScript */ diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index ab6ba7e7796..3c77ced6741 100755 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -911,7 +911,7 @@ enum Opcodes CMSG_LFG_SET_ROLES = 0x36A, CMSG_LFG_SET_NEEDS = 0x36B, CMSG_LFG_SET_BOOT_VOTE = 0x36C, - SMSG_LFG_BOOT_PLAYER = 0x36D, // uint8, uint8, uint8, uint64, uint32, uint32, uint32, uint32 + SMSG_LFG_BOOT_PROPOSAL_UPDATE = 0x36D, // uint8, uint8, uint8, uint64, uint32, uint32, uint32, uint32 CMSG_LFD_PLAYER_LOCK_INFO_REQUEST = 0x36E, SMSG_LFG_PLAYER_INFO = 0x36F, // uint8, for (uint8) { uint32, uint8, uint32, uint32, uint32, uint32, uint8, for (uint8) {uint32, uint32, uint32}}, uint32, for (uint32) {uint32, uint32} CMSG_LFG_TELEPORT = 0x370, diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index be6561c2633..88248b7bc55 100755 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -831,8 +831,8 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi) in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD. It will freeze clients that receive this player's movement info. */ - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT) && mi->HasMovementFlag(MOVEMENTFLAG_MASK_MOVING), - MOVEMENTFLAG_MASK_MOVING); + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT), + MOVEMENTFLAG_ROOT); //! Cannot hover without SPELL_AURA_HOVER REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !GetPlayer()->HasAuraType(SPELL_AURA_HOVER), diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 6383c7ff3ef..dbbd89c7533 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1231,12 +1231,11 @@ bool AuraEffect::IsPeriodicTickCrit(Unit* target, Unit const* caster) const if ((*itr)->IsAffectedOnSpell(m_spellInfo) && caster->isSpellCrit(target, m_spellInfo, m_spellInfo->GetSchoolMask())) return true; } + // Rupture - since 3.3.3 can crit - if (target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x100000, 0x0, 0x0, caster->GetGUID())) - { - if (caster->isSpellCrit(target, m_spellInfo, m_spellInfo->GetSchoolMask())) - return true; - } + if (m_spellInfo->SpellIconID == 500 && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) + return caster->isSpellCrit(target, m_spellInfo, m_spellInfo->GetSchoolMask()); + return false; } @@ -1475,6 +1474,23 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (spellInfo->Stances & (1<<(GetMiscValue()-1))) target->CastSpell(target, itr->first, true, NULL, this); } + + // Also do it for Glyphs + for (uint32 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) + { + if (uint32 glyphId = target->ToPlayer()->GetGlyph(i)) + { + if (GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId)) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(glyph->SpellId); + if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE))) + continue; + if (spellInfo->Stances & (1<<(GetMiscValue()-1))) + target->CastSpell(target, glyph->SpellId, true, NULL, this); + } + } + } + // Leader of the Pack if (target->ToPlayer()->HasSpell(17007)) { @@ -1584,10 +1600,25 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const } } + const Unit::AuraEffectList& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); + AuraEffect* newAura = NULL; + // Iterate through all the shapeshift auras that the target has, if there is another aura with SPELL_AURA_MOD_SHAPESHIFT, then this aura is being removed due to that one being applied + for (Unit::AuraEffectList::const_iterator itr = shapeshifts.begin(); itr != shapeshifts.end(); ++itr) + { + if ((*itr) != this) + { + newAura = *itr; + break; + } + } Unit::AuraApplicationMap& tAuras = target->GetAppliedAuras(); for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();) { - if (itr->second->GetBase()->IsRemovedOnShapeLost(target)) + // Use the new aura to see on what stance the target will be + uint32 newStance = (1<<((newAura ? newAura->GetMiscValue() : 0)-1)); + + // If the stances are not compatible with the spell, remove it + if (itr->second->GetBase()->IsRemovedOnShapeLost(target) && !(itr->second->GetBase()->GetSpellInfo()->Stances & newStance)) target->RemoveAura(itr); else ++itr; @@ -2856,9 +2887,8 @@ void AuraEffect::HandleAuraAllowFlight(AuraApplication const* aurApp, uint8 mode target->SetCanFly(apply); if (!apply) { - target->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING); - target->AddUnitMovementFlag(MOVEMENTFLAG_FALLING); - target->m_movementInfo.SetFallTime(0); + target->RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING_FLY); + target->GetMotionMaster()->MoveFall(); } Player* player = target->ToPlayer(); @@ -2889,10 +2919,7 @@ void AuraEffect::HandleAuraWaterWalk(AuraApplication const* aurApp, uint8 mode, if (apply) target->AddUnitMovementFlag(MOVEMENTFLAG_WATERWALKING); else - { target->RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING); - target->AddUnitMovementFlag(MOVEMENTFLAG_FALLING); - } target->SendMovementWaterWalking(); } @@ -4768,11 +4795,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use break; - case 49028: - if (caster) - if (AuraEffect* aurEff = caster->GetAuraEffect(63330, 0)) // glyph of Dancing Rune Weapon - GetBase()->SetDuration(GetBase()->GetDuration() + aurEff->GetAmount()); - break; case 52916: // Honor Among Thieves if (target->GetTypeId() == TYPEID_PLAYER) if (Unit* spellTarget = ObjectAccessor::GetUnit(*target, target->ToPlayer()->GetComboTarget())) @@ -4938,7 +4960,10 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool // final heal int32 stack = GetBase()->GetStackAmount(); - target->CastCustomSpell(target, 33778, &m_amount, &stack, NULL, true, NULL, this, GetCasterGUID()); + int32 heal = m_amount; + if (caster) + heal = caster->SpellHealingBonus(target, GetSpellInfo(), heal, HEAL, stack); + target->CastCustomSpell(target, 33778, &heal, &stack, NULL, true, NULL, this, GetCasterGUID()); // restore mana if (caster) @@ -5623,21 +5648,6 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const caster->CastCustomSpell(66153, SPELLVALUE_MAX_TARGETS, urand(1, 6), target, true); break; } - case 54798: // FLAMING Arrow Triggered Effect - { - if (!caster || !target || !target->ToCreature() || !caster->GetVehicle() || target->HasAura(54683)) - break; - - target->CastSpell(target, 54683, true); - - // Credit Frostworgs - if (target->GetEntry() == 29358) - caster->CastSpell(caster, 54896, true); - // Credit Frost Giants - else if (target->GetEntry() == 29351) - caster->CastSpell(caster, 54893, true); - break; - } case 62292: // Blaze (Pool of Tar) // should we use custom damage? target->CastSpell((Unit*)NULL, m_spellInfo->Effects[m_effIndex].TriggerSpell, true); @@ -5726,7 +5736,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const if (targets.empty()) return; - Unit* spellTarget = SelectRandomContainerElement(targets); + Unit* spellTarget = Trinity::Containers::SelectRandomContainerElement(targets); target->CastSpell(spellTarget, 57840, true); target->CastSpell(spellTarget, 57841, true); @@ -6272,7 +6282,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const { - if (!caster || !caster->isAlive() || !target->isAlive()) + if (!caster || !target->isAlive()) return; if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamage(GetSpellInfo())) @@ -6325,15 +6335,19 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist); if (damage) procVictim |= PROC_FLAG_TAKEN_DAMAGE; - caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo()); + if (caster->isAlive()) + caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo()); int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); - float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); + if (caster->isAlive()) + { + float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); - uint32 heal = uint32(caster->SpellHealingBonus(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetBase()->GetStackAmount())); + uint32 heal = uint32(caster->SpellHealingBonus(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetBase()->GetStackAmount())); - int32 gain = caster->HealBySpell(caster, GetSpellInfo(), heal); - caster->getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellInfo()); + int32 gain = caster->HealBySpell(caster, GetSpellInfo(), heal); + caster->getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellInfo()); + } } void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index b6cdc006d2d..0bf91b1b6c5 100755 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -2243,7 +2243,7 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellM } } -void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool & /*defaultPrevented*/) +void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool& defaultPrevented) { for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { @@ -2254,6 +2254,7 @@ void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication co if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount); } + defaultPrevented = (*scritr)->_IsDefaultActionPrevented(); (*scritr)->_FinishScriptCall(); } } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 942f9dc7e86..f055d669925 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1008,7 +1008,7 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar { case TARGET_OBJECT_TYPE_UNIT: if (Unit* unitTarget = target->ToUnit()) - AddUnitTarget(unitTarget, effMask, false); + AddUnitTarget(unitTarget, effMask, true, false); break; case TARGET_OBJECT_TYPE_GOBJ: if (GameObject* gobjTarget = target->ToGameObject()) @@ -1055,7 +1055,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge if ((*j)->IsAffectedOnSpell(m_spellInfo)) maxTargets += (*j)->GetAmount(); - Trinity::RandomResizeList(targets, maxTargets); + Trinity::Containers::RandomResizeList(targets, maxTargets); } // for compability with older code - add only unit and go targets @@ -1350,7 +1350,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge if (m_spellInfo->Id == 5246) //Intimidating Shout unitTargets.remove(m_targets.GetUnitTarget()); - Trinity::RandomResizeList(unitTargets, maxTargets); + Trinity::Containers::RandomResizeList(unitTargets, maxTargets); } CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex); @@ -1368,7 +1368,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge if ((*j)->IsAffectedOnSpell(m_spellInfo)) maxTargets += (*j)->GetAmount(); - Trinity::RandomResizeList(gObjTargets, maxTargets); + Trinity::Containers::RandomResizeList(gObjTargets, maxTargets); } for (std::list<GameObject*>::iterator itr = gObjTargets.begin(); itr != gObjTargets.end(); ++itr) AddGOTarget(*itr, effMask); @@ -1544,7 +1544,7 @@ void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImpli { ASSERT((m_targets.GetObjectTarget() || m_targets.GetItemTarget()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!"); if (Unit* unit = m_targets.GetUnitTarget()) - AddUnitTarget(unit, 1 << effIndex); + AddUnitTarget(unit, 1 << effIndex, true, false); else if (GameObject* gobj = m_targets.GetGOTarget()) AddGOTarget(gobj, 1 << effIndex); else @@ -2077,7 +2077,7 @@ void Spell::CleanupTargetList() m_delayMoment = 0; } -void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/) +void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/) { for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) if (!m_spellInfo->Effects[effIndex].IsEffect() || !CheckEffectTarget(target, effIndex)) @@ -2088,7 +2088,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= return; if (checkIfValid) - if (m_spellInfo->CheckTarget(m_caster, target, true) != SPELL_CAST_OK) + if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) return; // Check for effect immune skip if immuned @@ -2442,13 +2442,13 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) else procEx |= PROC_EX_NORMAL_HIT; - // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) - if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT) - caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell); - int32 gain = caster->HealBySpell(unitTarget, m_spellInfo, addhealth, crit); unitTarget->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo); m_healing = gain; + + // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) + if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT) + caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell); } // Do damage and triggers else if (m_damage > 0) @@ -2745,18 +2745,18 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask) if (!m_hitTriggerSpells.empty()) { int _duration = 0; - for (HitTriggerSpells::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i) + for (HitTriggerSpellList::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i) { - if (CanExecuteTriggersOnHit(effMask, i->first) && roll_chance_i(i->second)) + if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance)) { - m_caster->CastSpell(unit, i->first, true); - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first->Id); + m_caster->CastSpell(unit, i->triggeredSpell, true); + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->triggeredSpell->Id); // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration // set duration of current aura to the triggered spell - if (i->first->GetDuration() == -1) + if (i->triggeredSpell->GetDuration() == -1) { - if (Aura* triggeredAur = unit->GetAura(i->first->Id, m_caster->GetGUID())) + if (Aura* triggeredAur = unit->GetAura(i->triggeredSpell->Id, m_caster->GetGUID())) { // get duration from aura-only once if (!_duration) @@ -3101,11 +3101,20 @@ void Spell::cast(bool skipCheck) return; } - // now that we've done the basic check, now run the scripts - // should be done before the spell is actually executed if (Player* playerCaster = m_caster->ToPlayer()) + { + // now that we've done the basic check, now run the scripts + // should be done before the spell is actually executed sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck); + // As of 3.0.2 pets begin attacking their owner's target immediately + // Let any pets know we've attacked something. Check DmgClass for harmful spells only + // This prevents spells such as Hunter's Mark from triggering pet attack + if (this->GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE) + if (Pet* playerPet = playerCaster->GetPet()) + if (playerPet->isAlive() && playerPet->isControlled() && (m_targets.GetTargetMask() & TARGET_FLAG_UNIT)) + playerPet->AI()->OwnerAttacked(m_targets.GetObjectTarget()->ToUnit()); + } SetExecutedCurrently(true); if (m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.GetUnitTarget() && m_targets.GetUnitTarget() != m_caster) @@ -3418,36 +3427,6 @@ void Spell::_handle_immediate_phase() // process items for (std::list<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); - - if (!m_originalCaster) - return; - // Handle procs on cast - // TODO: finish new proc system:P - if (m_UniqueTargetInfo.empty()) - { - uint32 procAttacker = m_procAttacker; - if (!procAttacker) - { - bool positive = m_spellInfo->IsPositive(); - switch (m_spellInfo->DmgClass) - { - case SPELL_DAMAGE_CLASS_MAGIC: - if (positive) - procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS; - else - procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG; - break; - case SPELL_DAMAGE_CLASS_NONE: - if (positive) - procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS; - else - procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG; - break; - } - } - // Proc damage for spells which have only dest targets (2484 should proc 51486 for example) - m_originalCaster->ProcDamageAndSpell(NULL, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell); - } } void Spell::_handle_finish_phase() @@ -4331,10 +4310,9 @@ void Spell::TakePower() for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) if (ihit->targetGUID == targetGUID) { - if (ihit->missCondition != SPELL_MISS_NONE && ihit->missCondition != SPELL_MISS_MISS/* && ihit->targetGUID != m_caster->GetGUID()*/) - hit = false; if (ihit->missCondition != SPELL_MISS_NONE) { + hit = false; //lower spell cost on fail (by talent aura) if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost); @@ -5230,10 +5208,8 @@ SpellCastResult Spell::CheckCast(bool strict) case SPELL_EFFECT_SUMMON_DEAD_PET: { Creature* pet = m_caster->GetGuardianPet(); - if (!pet) - return SPELL_FAILED_NO_PET; - if (pet->isAlive()) + if (pet && pet->isAlive()) return SPELL_FAILED_ALREADY_HAVE_SUMMON; break; @@ -5283,7 +5259,6 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_caster->GetCharmGUID()) return SPELL_FAILED_ALREADY_HAVE_CHARM; - break; } case SPELL_EFFECT_SUMMON_PLAYER: @@ -7171,14 +7146,13 @@ void Spell::CallScriptAfterUnitTargetSelectHandlers(std::list<Unit*>& unitTarget } } -bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* spellInfo) const +bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura) const { - bool only_on_dummy = (spellInfo && (spellInfo->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_DUMMY)); - // If triggered spell has SPELL_ATTR4_PROC_ONLY_ON_DUMMY then it can only proc on a casted spell with SPELL_EFFECT_DUMMY - // If triggered spell doesn't have SPELL_ATTR4_PROC_ONLY_ON_DUMMY then it can NOT proc on SPELL_EFFECT_DUMMY (needs confirmation) + bool only_on_caster = (triggeredByAura && (triggeredByAura->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER)); + // If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a casted spell with TARGET_UNIT_CASTER for (uint8 i = 0;i < MAX_SPELL_EFFECTS; ++i) { - if ((effMask & (1 << i)) && (only_on_dummy == (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DUMMY))) + if ((effMask & (1 << i)) && (!only_on_caster || (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_CASTER))) return true; } return false; @@ -7230,9 +7204,14 @@ void Spell::PrepareTriggersExecutedOnHit() // calculate the chance using spell base amount, because aura amount is not updated on combo-points change // this possibly needs fixing int32 auraBaseAmount = (*i)->GetBaseAmount(); - int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount); // proc chance is stored in effect amount - m_hitTriggerSpells.push_back(std::make_pair(spellInfo, chance * (*i)->GetBase()->GetStackAmount())); + int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount); + // build trigger and add to the list + HitTriggerSpell spellTriggerInfo; + spellTriggerInfo.triggeredSpell = spellInfo; + spellTriggerInfo.triggeredByAura = auraSpellInfo; + spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount(); + m_hitTriggerSpells.push_back(spellTriggerInfo); } } } diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 37842433eb3..8f43b9b2290 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -596,7 +596,7 @@ class Spell SpellDestination m_destTargets[MAX_SPELL_EFFECTS]; - void AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid = true); + void AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid = true, bool implicit = true); void AddGOTarget(GameObject* target, uint32 effectMask); void AddItemTarget(Item* item, uint32 effectMask); void AddDestTarget(SpellDestination const& dest, uint32 effIndex); @@ -633,10 +633,18 @@ class Spell void CallScriptAfterUnitTargetSelectHandlers(std::list<Unit*>& unitTargets, SpellEffIndex effIndex); std::list<SpellScript*> m_loadedScripts; - bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* spellInfo = NULL) const; + struct HitTriggerSpell + { + SpellInfo const* triggeredSpell; + SpellInfo const* triggeredByAura; + // uint8 triggeredByEffIdx This might be needed at a later stage - No need known for now + int32 chance; + }; + + bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura = NULL) const; void PrepareTriggersExecutedOnHit(); - typedef std::list< std::pair<SpellInfo const*, int32> > HitTriggerSpells; - HitTriggerSpells m_hitTriggerSpells; + typedef std::list<HitTriggerSpell> HitTriggerSpellList; + HitTriggerSpellList m_hitTriggerSpells; // effect helpers void SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* properties, uint32 numSummons); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index ce64c2e9560..c72ccbacc3d 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -390,23 +390,6 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) if (!unitTarget->HasAura(27825)) return; break; - // Cataclysmic Bolt - case 38441: - { - damage = unitTarget->CountPctFromMaxHealth(50); - break; - } - case 20625: // Ritual of Doom Sacrifice - case 29142: // Eyesore Blaster - case 35139: // Throw Boom's Doom - case 42393: // Brewfest - Attack Keg - case 55269: // Deathly Stare - case 56578: // Rapid-Fire Harpoon - case 62775: // Tympanic Tantrum - { - damage = unitTarget->CountPctFromMaxHealth(damage); - break; - } // Gargoyle Strike case 51963: { @@ -666,19 +649,19 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) if (found) damage += m_spellInfo->Effects[EFFECT_1].CalcValue(); - if (m_caster->GetTypeId() == TYPEID_PLAYER) + if (Player* caster = m_caster->ToPlayer()) { // Add Ammo and Weapon damage plus RAP * 0.1 - Item* item = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK); - if (item) + if (Item* item = caster->GetWeaponForAttack(RANGED_ATTACK)) { - float dmg_min = item->GetTemplate()->Damage->DamageMin; - float dmg_max = item->GetTemplate()->Damage->DamageMax; + ItemTemplate const* weaponTemplate = item->GetTemplate(); + float dmg_min = weaponTemplate->Damage[0].DamageMin; + float dmg_max = weaponTemplate->Damage[0].DamageMax; if (dmg_max == 0.0f && dmg_min > dmg_max) damage += int32(dmg_min); else damage += irand(int32(dmg_min), int32(dmg_max)); - damage += int32(m_caster->ToPlayer()->GetAmmoDPS()*item->GetTemplate()->Delay*0.001f); + damage += int32(caster->GetAmmoDPS() * weaponTemplate->Delay * 0.001f); } } } @@ -774,7 +757,7 @@ void Spell::EffectDummy(SpellEffIndex effIndex) uint32 maxTargets = std::min<uint32>(3, attackers.size()); for (uint32 i = 0; i < maxTargets; ++i) { - Unit* attacker = SelectRandomContainerElement(attackers); + Unit* attacker = Trinity::Containers::SelectRandomContainerElement(attackers); AddUnitTarget(attacker, 1 << 1); attackers.erase(attacker); } @@ -1611,20 +1594,6 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/) } } } - // Lifebloom - final heal coef multiplied by original DoT stack - else if (m_spellInfo->Id == 33778) - addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL, m_spellValue->EffectBasePoints[1]); - // Riptide - increase healing done by Chain Heal - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x100) - { - addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); - if (AuraEffect* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, m_originalCasterGUID)) - { - addhealth = int32(addhealth * 1.25f); - // consume aura - unitTarget->RemoveAura(aurEff->GetBase()); - } - } // Death Pact - return pct of max health to caster else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL); @@ -2008,7 +1977,7 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) if (!avalibleElixirs.empty()) { // cast random elixir on target - m_caster->CastSpell(unitTarget, SelectRandomContainerElement(avalibleElixirs), true, m_CastItem); + m_caster->CastSpell(unitTarget, Trinity::Containers::SelectRandomContainerElement(avalibleElixirs), true, m_CastItem); } } } @@ -5726,7 +5695,7 @@ void Spell::EffectSummonDeadPet(SpellEffIndex /*effIndex*/) return; Pet* pet = player->GetPet(); - if (!pet || pet->isAlive()) + if (pet && pet->isAlive()) return; if (damage < 0) @@ -5734,8 +5703,16 @@ void Spell::EffectSummonDeadPet(SpellEffIndex /*effIndex*/) float x, y, z; player->GetPosition(x, y, z); + if (!pet) + { + player->SummonPet(0, x, y, z, player->GetOrientation(), SUMMON_PET, 0); + pet = player->GetPet(); + } + if (!pet) + return; + player->GetMap()->CreatureRelocation(pet, x, y, z, player->GetOrientation()); - + pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE); pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); pet->setDeathState(ALIVE); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index b95ee766f38..07ab71207f1 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -2177,12 +2177,12 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const switch (Id) { case 34700: // Allergic Reaction - case 61716: // Rabbit Costume - case 61734: // Noblegarden Bunny case 61987: // Avenging Wrath Marker case 61988: // Divine Shield exclude aura case 62532: // Conservator's Grip return false; + case 61716: // Rabbit Costume + case 61734: // Noblegarden Bunny case 30877: // Tag Murloc case 62344: // Fists of Stone return true; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 895dc9ab4b7..3de87790be9 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2094,7 +2094,7 @@ void SpellMgr::LoadEnchantCustomAttr() continue; // TODO: find a better check - if (!(spellInfo->AttributesEx2 & SPELL_ATTR2_UNK13) || !(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT)) + if (!(spellInfo->AttributesEx2 & SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT)) continue; for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) @@ -3238,6 +3238,10 @@ void SpellMgr::LoadDbcDataCorrections() spellInfo->EffectDieSides[0] = 0; // was 1, that should probably mean seat 0, but instead it's treated as spell 1 spellInfo->EffectBasePoints[0] = 52391; // Ride Vehicle (forces seat 0) break; + case 64745: // Item - Death Knight T8 Tank 4P Bonus + case 64936: // Item - Warrior T8 Protection 4P Bonus + spellInfo->EffectBasePoints[0] = 100; // 100% chance of procc'ing, not -10% (chance calculated in PrepareTriggersExecutedOnHit) + break; case 19970: // Entangling Roots (Rank 6) -- Nature's Grasp Proc case 19971: // Entangling Roots (Rank 5) -- Nature's Grasp Proc case 19972: // Entangling Roots (Rank 4) -- Nature's Grasp Proc @@ -3294,6 +3298,19 @@ void SpellMgr::LoadDbcDataCorrections() spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_NEARBY_ENTRY; spellInfo->EffectImplicitTargetB[2] = TARGET_UNIT_NEARBY_ENTRY; break; + case 62301: // Cosmic Smash (Algalon the Observer) + spellInfo->MaxAffectedTargets = 1; + break; + case 64598: // Cosmic Smash (Algalon the Observer) + spellInfo->MaxAffectedTargets = 3; + break; + case 62293: // Cosmic Smash (Algalon the Observer) + spellInfo->EffectImplicitTargetB[0] = TARGET_DEST_CASTER; + break; + case 62311: // Cosmic Smash (Algalon the Observer) + case 64596: // Cosmic Smash (Algalon the Observer) + spellInfo->rangeIndex = 6; // 100yd + break; // ENDOF ULDUAR SPELLS // // TRIAL OF THE CRUSADER SPELLS @@ -3343,9 +3360,9 @@ void SpellMgr::LoadDbcDataCorrections() case 70460: // Coldflame Jets (Traps after Saurfang) spellInfo->DurationIndex = 1; // 10 seconds break; - case 71413: // Green Ooze Summon (Professor Putricide) - case 71414: // Orange Ooze Summon (Professor Putricide) - spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; + case 71412: // Green Ooze Summon (Professor Putricide) + case 71415: // Orange Ooze Summon (Professor Putricide) + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; break; case 71159: // Awaken Plagued Zombies spellInfo->DurationIndex = 21; @@ -3406,10 +3423,7 @@ void SpellMgr::LoadDbcDataCorrections() spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_CASTER; break; case 69846: // Frost Bomb - spellInfo->speed = 10; - spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_TARGET_ANY; - spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ANY; - spellInfo->Effect[1] = 0; + spellInfo->speed = 0.0f; // This spell's summon happens instantly break; case 71614: // Ice Lock spellInfo->Mechanic = MECHANIC_STUN; @@ -3505,6 +3519,11 @@ void SpellMgr::LoadDbcDataCorrections() case 40166: // Introspection case 40167: // Introspection spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1; + break; + case 2378: // Minor Fortitude + spellInfo->manaCost = 0; + spellInfo->manaPerSecond = 0; + break; default: break; } diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 81f8bbd78c5..44a2dd4dedb 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -403,7 +403,7 @@ GameObject* SpellScript::GetHitGObj() return m_spell->gameObjTarget; } -WorldLocation const* SpellScript::GetHitDest() +WorldLocation* SpellScript::GetHitDest() { if (!IsInEffectHook()) { @@ -773,6 +773,7 @@ bool AuraScript::_IsDefaultActionPrevented() case AURA_SCRIPT_HOOK_EFFECT_APPLY: case AURA_SCRIPT_HOOK_EFFECT_REMOVE: case AURA_SCRIPT_HOOK_EFFECT_PERIODIC: + case AURA_SCRIPT_HOOK_EFFECT_ABSORB: return m_defaultActionPrevented; default: ASSERT(false && "AuraScript::_IsDefaultActionPrevented is called in a wrong place"); @@ -787,6 +788,7 @@ void AuraScript::PreventDefaultAction() case AURA_SCRIPT_HOOK_EFFECT_APPLY: case AURA_SCRIPT_HOOK_EFFECT_REMOVE: case AURA_SCRIPT_HOOK_EFFECT_PERIODIC: + case AURA_SCRIPT_HOOK_EFFECT_ABSORB: m_defaultActionPrevented = true; break; default: diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index e84a56c8dbb..26393040a1e 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -325,7 +325,7 @@ class SpellScript : public _SpellScript // returns: target of current effect if it was GameObject otherwise NULL GameObject* GetHitGObj(); // returns: destination of current effect - WorldLocation const* GetHitDest(); + WorldLocation* GetHitDest(); // setter/getter for for damage done by spell to target of spell hit // returns damage calculated before hit, and real dmg done after hit int32 GetHitDamage(); diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp index 68e28014319..f82c01adf31 100755 --- a/src/server/game/Tickets/TicketMgr.cpp +++ b/src/server/game/Tickets/TicketMgr.cpp @@ -37,7 +37,10 @@ GmTicket::GmTicket(Player* player, WorldPacket& recv_data) : _createTime(time(NU _playerName = player->GetName(); _playerGuid = player->GetGUID(); - recv_data >> _mapId; + uint32 mapId; + recv_data >> mapId; // Map is sent as UInt32! + _mapId = mapId; + recv_data >> _posX; recv_data >> _posY; recv_data >> _posZ; diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 8d5d16d22b9..476a19b6885 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -306,22 +306,28 @@ bool PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tabl switch (type) { case DTT_INVENTORY: - StoreGUID(result, 3, items); break; // item guid collection (character_inventory.item) + StoreGUID(result, 3, items); // item guid collection (character_inventory.item) + break; case DTT_PET: - StoreGUID(result, 0, pets); break; // pet petnumber collection (character_pet.id) + StoreGUID(result, 0, pets); // pet petnumber collection (character_pet.id) + break; case DTT_MAIL: - StoreGUID(result, 0, mails); // mail id collection (mail.id) + StoreGUID(result, 0, mails); // mail id collection (mail.id) + break; case DTT_MAIL_ITEM: - StoreGUID(result, 1, items); break; // item guid collection (mail_items.item_guid) + StoreGUID(result, 1, items); // item guid collection (mail_items.item_guid) + break; case DTT_CHARACTER: { - if (result->GetFieldCount() <= 67) // avoid crashes on next check - return true; - if (result->Fetch()[67].GetUInt32()) // characters.deleteInfos_Account - if filled error + if (result->GetFieldCount() <= 68) // avoid crashes on next check + sLog->outCrash("PlayerDumpWriter::DumpTable - Trying to access non-existing or wrong positioned field (`deleteInfos_Account`) in `characters` table."); + + if (result->Fetch()[68].GetUInt32()) // characters.deleteInfos_Account - if filled error return false; break; } - default: break; + default: + break; } dump += CreateDumpString(tableTo, result); diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp index fa30adde72a..0734e0a0f63 100644 --- a/src/server/game/Warden/Warden.cpp +++ b/src/server/game/Warden/Warden.cpp @@ -187,7 +187,9 @@ std::string Warden::Penalty(WardenCheck* check /*= NULL*/) duration << sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION) << "s"; std::string accountName; AccountMgr::GetName(_session->GetAccountId(), accountName); - sWorld->BanAccount(BAN_ACCOUNT, accountName, duration.str(), "Warden Anticheat violation","Server"); + std::stringstream banReason; + banReason << "Warden Anticheat Violation: " << check->Comment << " (CheckId: " << check->CheckId << ")"; + sWorld->BanAccount(BAN_ACCOUNT, accountName, duration.str(), banReason.str(),"Server"); return "Ban"; break; diff --git a/src/server/game/Warden/Warden.h b/src/server/game/Warden/Warden.h index e06ea7dca25..d16890b31b9 100644 --- a/src/server/game/Warden/Warden.h +++ b/src/server/game/Warden/Warden.h @@ -107,7 +107,7 @@ class Warden public: Warden(); - ~Warden(); + virtual ~Warden(); virtual void Init(WorldSession* session, BigNumber* k) = 0; virtual ClientWardenModule* GetModuleForClient() = 0; diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp index 90d1cfc0140..f4c7a5069cf 100644 --- a/src/server/game/Warden/WardenCheckMgr.cpp +++ b/src/server/game/Warden/WardenCheckMgr.cpp @@ -63,8 +63,8 @@ void WardenCheckMgr::LoadWardenChecks() CheckStore.resize(maxCheckId + 1); - // 0 1 2 3 4 5 6 - result = WorldDatabase.Query("SELECT id, type, data, result, address, length, str FROM warden_checks ORDER BY id ASC"); + // 0 1 2 3 4 5 6 7 + result = WorldDatabase.Query("SELECT id, type, data, result, address, length, str, comment FROM warden_checks ORDER BY id ASC"); uint32 count = 0; do @@ -78,9 +78,11 @@ void WardenCheckMgr::LoadWardenChecks() uint32 address = fields[4].GetUInt32(); uint8 length = fields[5].GetUInt8(); std::string str = fields[6].GetString(); + std::string comment = fields[7].GetString(); WardenCheck* wardenCheck = new WardenCheck(); wardenCheck->Type = checkType; + wardenCheck->CheckId = id; // Initialize action with default action from config wardenCheck->Action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION)); @@ -134,6 +136,11 @@ void WardenCheckMgr::LoadWardenChecks() CheckResultStore[id] = wr; } + if (comment.empty()) + wardenCheck->Comment = "Undocumented Check"; + else + wardenCheck->Comment = comment; + ++count; } while (result->NextRow()); diff --git a/src/server/game/Warden/WardenCheckMgr.h b/src/server/game/Warden/WardenCheckMgr.h index 45de18081c2..7a83d8f0c6d 100644 --- a/src/server/game/Warden/WardenCheckMgr.h +++ b/src/server/game/Warden/WardenCheckMgr.h @@ -36,6 +36,8 @@ struct WardenCheck uint32 Address; // PROC_CHECK, MEM_CHECK, PAGE_CHECK uint8 Length; // PROC_CHECK, MEM_CHECK, PAGE_CHECK std::string Str; // LUA, MPQ, DRIVER + std::string Comment; + uint16 CheckId; enum WardenActions Action; }; diff --git a/src/server/game/Warden/WardenMac.cpp b/src/server/game/Warden/WardenMac.cpp index f62aa11a339..a60ae765013 100644 --- a/src/server/game/Warden/WardenMac.cpp +++ b/src/server/game/Warden/WardenMac.cpp @@ -122,7 +122,7 @@ void WardenMac::HandleHashResult(ByteBuffer &buff) uint8 mod_seed[16] = { 0x4D, 0x80, 0x8D, 0x2C, 0x77, 0xD9, 0x05, 0xC4, 0x1A, 0x63, 0x80, 0xEC, 0x08, 0x58, 0x6A, 0xFE }; - for(int i = 0; i < 4; ++i) + for (int i = 0; i < 4; ++i) { keyIn[i] = *(int*)(&mod_seed[0] + i * 4); } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index ccc8bb2c3e7..6e32d33a7bb 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2602,7 +2602,7 @@ void World::SendAutoBroadcast() std::string msg; - msg = SelectRandomContainerElement(m_Autobroadcasts); + msg = Trinity::Containers::SelectRandomContainerElement(m_Autobroadcasts); uint32 abcenter = sWorld->getIntConfig(CONFIG_AUTOBROADCAST_CENTER); diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index 728d95a0851..792fdeb3e7b 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -53,7 +53,6 @@ include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT - ${CMAKE_SOURCE_DIR}/dep/mersennetwister ${CMAKE_SOURCE_DIR}/dep/zlib ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration @@ -120,6 +119,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Maps ${CMAKE_SOURCE_DIR}/src/server/game/Movement ${CMAKE_SOURCE_DIR}/src/server/game/Movement/MovementGenerators + ${CMAKE_SOURCE_DIR}/src/server/game/Movement/Spline ${CMAKE_SOURCE_DIR}/src/server/game/Movement/Waypoints ${CMAKE_SOURCE_DIR}/src/server/game/Opcodes ${CMAKE_SOURCE_DIR}/src/server/game/OutdoorPvP diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index f62c434e2e5..b6feccc10c6 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1241,7 +1241,7 @@ public: return false; } - target->GetReputationMgr().SetReputation(factionEntry, amount); + target->GetReputationMgr().SetOneFactionReputation(factionEntry, amount, false); handler->PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[handler->GetSessionDbcLocale()], factionId, handler->GetNameLink(target).c_str(), target->GetReputationMgr().GetReputation(factionEntry)); return true; diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 5f192ffceee..1c119fdef4c 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -424,7 +424,7 @@ public: continue; } - CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry); + CreatureTemplate* cInfo = const_cast<CreatureTemplate*>(sObjectMgr->GetCreatureTemplate(entry)); if (!cInfo) { handler->PSendSysMessage(LANG_COMMAND_CREATURESTORAGE_NOTFOUND, entry); @@ -435,90 +435,88 @@ public: Field* fields = result->Fetch(); - const_cast<CreatureTemplate*>(cInfo)->DifficultyEntry[0] = fields[0].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->DifficultyEntry[1] = fields[1].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->DifficultyEntry[2] = fields[2].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->KillCredit[0] = fields[3].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->KillCredit[1] = fields[4].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->Modelid1 = fields[5].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->Modelid2 = fields[6].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->Modelid3 = fields[7].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->Modelid4 = fields[8].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->Name = fields[9].GetString(); - const_cast<CreatureTemplate*>(cInfo)->SubName = fields[10].GetString(); - const_cast<CreatureTemplate*>(cInfo)->IconName = fields[11].GetString(); - const_cast<CreatureTemplate*>(cInfo)->GossipMenuId = fields[12].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->minlevel = fields[13].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->maxlevel = fields[14].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->expansion = fields[15].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->faction_A = fields[16].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->faction_H = fields[17].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->npcflag = fields[18].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->speed_walk = fields[19].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->speed_run = fields[20].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->scale = fields[21].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->rank = fields[22].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->mindmg = fields[23].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->maxdmg = fields[24].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->dmgschool = fields[25].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->attackpower = fields[26].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->dmg_multiplier = fields[27].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->baseattacktime = fields[28].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->rangeattacktime = fields[29].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->unit_class = fields[30].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->unit_flags = fields[31].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->dynamicflags = fields[32].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->family = fields[33].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->trainer_type = fields[34].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->trainer_spell = fields[35].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->trainer_class = fields[36].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->trainer_race = fields[37].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->minrangedmg = fields[38].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->maxrangedmg = fields[39].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->rangedattackpower = fields[40].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->type = fields[41].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->type_flags = fields[42].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->lootid = fields[43].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->pickpocketLootId = fields[44].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->SkinLootId = fields[45].GetUInt32(); + cInfo->DifficultyEntry[0] = fields[0].GetUInt32(); + cInfo->DifficultyEntry[1] = fields[1].GetUInt32(); + cInfo->DifficultyEntry[2] = fields[2].GetUInt32(); + cInfo->KillCredit[0] = fields[3].GetUInt32(); + cInfo->KillCredit[1] = fields[4].GetUInt32(); + cInfo->Modelid1 = fields[5].GetUInt32(); + cInfo->Modelid2 = fields[6].GetUInt32(); + cInfo->Modelid3 = fields[7].GetUInt32(); + cInfo->Modelid4 = fields[8].GetUInt32(); + cInfo->Name = fields[9].GetString(); + cInfo->SubName = fields[10].GetString(); + cInfo->IconName = fields[11].GetString(); + cInfo->GossipMenuId = fields[12].GetUInt32(); + cInfo->minlevel = fields[13].GetUInt8(); + cInfo->maxlevel = fields[14].GetUInt8(); + cInfo->expansion = fields[15].GetUInt16(); + cInfo->faction_A = fields[16].GetUInt16(); + cInfo->faction_H = fields[17].GetUInt16(); + cInfo->npcflag = fields[18].GetUInt32(); + cInfo->speed_walk = fields[19].GetFloat(); + cInfo->speed_run = fields[20].GetFloat(); + cInfo->scale = fields[21].GetFloat(); + cInfo->rank = fields[22].GetUInt8(); + cInfo->mindmg = fields[23].GetFloat(); + cInfo->maxdmg = fields[24].GetFloat(); + cInfo->dmgschool = fields[25].GetUInt8(); + cInfo->attackpower = fields[26].GetUInt32(); + cInfo->dmg_multiplier = fields[27].GetFloat(); + cInfo->baseattacktime = fields[28].GetUInt32(); + cInfo->rangeattacktime = fields[29].GetUInt32(); + cInfo->unit_class = fields[30].GetUInt8(); + cInfo->unit_flags = fields[31].GetUInt32(); + cInfo->dynamicflags = fields[32].GetUInt32(); + cInfo->family = fields[33].GetUInt8(); + cInfo->trainer_type = fields[34].GetUInt8(); + cInfo->trainer_spell = fields[35].GetUInt32(); + cInfo->trainer_class = fields[36].GetUInt8(); + cInfo->trainer_race = fields[37].GetUInt8(); + cInfo->minrangedmg = fields[38].GetFloat(); + cInfo->maxrangedmg = fields[39].GetFloat(); + cInfo->rangedattackpower = fields[40].GetUInt16(); + cInfo->type = fields[41].GetUInt8(); + cInfo->type_flags = fields[42].GetUInt32(); + cInfo->lootid = fields[43].GetUInt32(); + cInfo->pickpocketLootId = fields[44].GetUInt32(); + cInfo->SkinLootId = fields[45].GetUInt32(); for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - { - const_cast<CreatureTemplate*>(cInfo)->resistance[i] = fields[46 + i -1].GetUInt32(); - } - - const_cast<CreatureTemplate*>(cInfo)->spells[0] = fields[52].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->spells[1] = fields[53].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->spells[2] = fields[54].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->spells[3] = fields[55].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->spells[4] = fields[56].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->spells[5] = fields[57].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->spells[6] = fields[58].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->spells[7] = fields[59].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->PetSpellDataId = fields[60].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->VehicleId = fields[61].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->mingold = fields[62].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->maxgold = fields[63].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->AIName = fields[64].GetString(); - const_cast<CreatureTemplate*>(cInfo)->MovementType = fields[65].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->InhabitType = fields[66].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->HoverHeight = fields[67].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->ModHealth = fields[68].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->ModMana = fields[69].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->ModArmor = fields[70].GetFloat(); - const_cast<CreatureTemplate*>(cInfo)->RacialLeader = fields[71].GetBool(); - const_cast<CreatureTemplate*>(cInfo)->questItems[0] = fields[72].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->questItems[1] = fields[73].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->questItems[2] = fields[74].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->questItems[3] = fields[75].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->questItems[4] = fields[76].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->questItems[5] = fields[77].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->movementId = fields[78].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->RegenHealth = fields[79].GetBool(); - const_cast<CreatureTemplate*>(cInfo)->equipmentId = fields[80].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->MechanicImmuneMask = fields[81].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->flags_extra = fields[82].GetUInt32(); - const_cast<CreatureTemplate*>(cInfo)->ScriptID = sObjectMgr->GetScriptId(fields[83].GetCString()); + cInfo->resistance[i] = fields[46 + i -1].GetUInt16(); + + cInfo->spells[0] = fields[52].GetUInt32(); + cInfo->spells[1] = fields[53].GetUInt32(); + cInfo->spells[2] = fields[54].GetUInt32(); + cInfo->spells[3] = fields[55].GetUInt32(); + cInfo->spells[4] = fields[56].GetUInt32(); + cInfo->spells[5] = fields[57].GetUInt32(); + cInfo->spells[6] = fields[58].GetUInt32(); + cInfo->spells[7] = fields[59].GetUInt32(); + cInfo->PetSpellDataId = fields[60].GetUInt32(); + cInfo->VehicleId = fields[61].GetUInt32(); + cInfo->mingold = fields[62].GetUInt32(); + cInfo->maxgold = fields[63].GetUInt32(); + cInfo->AIName = fields[64].GetString(); + cInfo->MovementType = fields[65].GetUInt8(); + cInfo->InhabitType = fields[66].GetUInt8(); + cInfo->HoverHeight = fields[67].GetFloat(); + cInfo->ModHealth = fields[68].GetFloat(); + cInfo->ModMana = fields[69].GetFloat(); + cInfo->ModArmor = fields[70].GetFloat(); + cInfo->RacialLeader = fields[71].GetBool(); + cInfo->questItems[0] = fields[72].GetUInt32(); + cInfo->questItems[1] = fields[73].GetUInt32(); + cInfo->questItems[2] = fields[74].GetUInt32(); + cInfo->questItems[3] = fields[75].GetUInt32(); + cInfo->questItems[4] = fields[76].GetUInt32(); + cInfo->questItems[5] = fields[77].GetUInt32(); + cInfo->movementId = fields[78].GetUInt32(); + cInfo->RegenHealth = fields[79].GetBool(); + cInfo->equipmentId = fields[80].GetUInt32(); + cInfo->MechanicImmuneMask = fields[81].GetUInt32(); + cInfo->flags_extra = fields[82].GetUInt32(); + cInfo->ScriptID = sObjectMgr->GetScriptId(fields[83].GetCString()); sObjectMgr->CheckCreatureTemplate(cInfo); } diff --git a/src/server/scripts/Commands/cs_tele.cpp b/src/server/scripts/Commands/cs_tele.cpp index 89646c23ea0..ca7c3af7fde 100644 --- a/src/server/scripts/Commands/cs_tele.cpp +++ b/src/server/scripts/Commands/cs_tele.cpp @@ -138,8 +138,8 @@ public: if (resultDB) { Field* fieldsDB = resultDB->Fetch(); - uint32 mapId = fieldsDB[0].GetUInt32(); - uint32 zoneId = fieldsDB[1].GetUInt32(); + uint32 mapId = fieldsDB[0].GetUInt16(); + uint32 zoneId = fieldsDB[1].GetUInt16(); float posX = fieldsDB[2].GetFloat(); float posY = fieldsDB[3].GetFloat(); float posZ = fieldsDB[4].GetFloat(); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp index bbf87ac3e73..783ac6baad1 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp @@ -244,8 +244,8 @@ void boss_attumen::boss_attumenAI::UpdateAI(const uint32 diff) Midnight = 0; me->SetVisible(false); me->Kill(me); - } - } else ResetTimer -= diff; + } else ResetTimer -= diff; + } //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_sulfuron_harbinger.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_sulfuron_harbinger.cpp index 9f511c1394a..343298d29fe 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_sulfuron_harbinger.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_sulfuron_harbinger.cpp @@ -103,7 +103,7 @@ class boss_sulfuron : public CreatureScript { std::list<Creature*> healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE); if (!healers.empty()) - DoCast(SelectRandomContainerElement(healers), SPELL_INSPIRE); + DoCast(Trinity::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE); DoCast(me, SPELL_INSPIRE); events.ScheduleEvent(EVENT_INSPIRE, urand(20000, 26000)); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index ceab845f0a2..37808e2b924 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -809,11 +809,11 @@ public: { for (std::list<Creature*>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); ++itr) { - if (CAST_CRE(*itr)->GetOwner()->GetGUID() == me->GetOwner()->GetGUID()) + if ((*itr)->GetOwner()->GetGUID() == me->GetOwner()->GetGUID()) { - if (CAST_CRE(*itr)->isInCombat() && CAST_CRE(*itr)->getAttackerForHelper()) + if ((*itr)->isInCombat() && (*itr)->getAttackerForHelper()) { - AttackStart(CAST_CRE(*itr)->getAttackerForHelper()); + AttackStart((*itr)->getAttackerForHelper()); } } } @@ -826,10 +826,11 @@ public: { if (Unit* owner = me->GetOwner()) { - if (owner->GetTypeId() == TYPEID_PLAYER && CAST_PLR(owner)->isInCombat()) + Player* plrOwner = owner->ToPlayer(); + if (plrOwner && plrOwner->isInCombat()) { - if (CAST_PLR(owner)->getAttackerForHelper() && CAST_PLR(owner)->getAttackerForHelper()->GetEntry() == GHOSTS) - AttackStart(CAST_PLR(owner)->getAttackerForHelper()); + if (plrOwner->getAttackerForHelper() && plrOwner->getAttackerForHelper()->GetEntry() == GHOSTS) + AttackStart(plrOwner->getAttackerForHelper()); else FindMinions(owner); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp index a64636a4223..1989c318c84 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp @@ -66,9 +66,15 @@ public: Sleep_Timer = 30000; Dispel_Timer = 20000; PowerWordShield = false; + me->SetStandState(UNIT_STAND_STATE_DEAD); + me->SetUInt32Value(UNIT_FIELD_BYTES_1, 7); } - void EnterCombat(Unit* /*who*/) {} + void EnterCombat(Unit* /*who*/) + { + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + } void UpdateAI(const uint32 diff) { diff --git a/src/server/scripts/EasternKingdoms/eversong_woods.cpp b/src/server/scripts/EasternKingdoms/eversong_woods.cpp index 016dd60b39c..8ae72e142c8 100644 --- a/src/server/scripts/EasternKingdoms/eversong_woods.cpp +++ b/src/server/scripts/EasternKingdoms/eversong_woods.cpp @@ -490,14 +490,14 @@ public: { if (PlayerGUID) if (Player* player = Unit::GetPlayer(*me, PlayerGUID)) - CAST_PLR(player)->FailQuest(QUEST_UNEXPECTED_RESULT); + player->FailQuest(QUEST_UNEXPECTED_RESULT); } void UpdateAI(const uint32 /*diff*/) { if (KillCount >= 3 && PlayerGUID) if (Player* player = Unit::GetPlayer(*me, PlayerGUID)) - CAST_PLR(player)->CompleteQuest(QUEST_UNEXPECTED_RESULT); + player->CompleteQuest(QUEST_UNEXPECTED_RESULT); if (Summon) { diff --git a/src/server/scripts/EasternKingdoms/isle_of_queldanas.cpp b/src/server/scripts/EasternKingdoms/isle_of_queldanas.cpp index b0b09c0ec76..27d8ea3e51c 100644 --- a/src/server/scripts/EasternKingdoms/isle_of_queldanas.cpp +++ b/src/server/scripts/EasternKingdoms/isle_of_queldanas.cpp @@ -129,8 +129,8 @@ public: PlayerGUID = caster->GetGUID(); if (PlayerGUID) { - Unit* player = Unit::GetUnit(*me, PlayerGUID); - if (player && CAST_PLR(player)->GetQuestStatus(QUESTG) == QUEST_STATUS_INCOMPLETE) + Player* player = Unit::GetPlayer(*me, PlayerGUID); + if (player && player->GetQuestStatus(QUESTG) == QUEST_STATUS_INCOMPLETE) DoCast(player, 45110, true); } DoCast(me, ENRAGE); diff --git a/src/server/scripts/EasternKingdoms/undercity.cpp b/src/server/scripts/EasternKingdoms/undercity.cpp index 0522e214012..d5896812007 100644 --- a/src/server/scripts/EasternKingdoms/undercity.cpp +++ b/src/server/scripts/EasternKingdoms/undercity.cpp @@ -47,7 +47,15 @@ enum Sylvanas SPELL_HIGHBORNE_AURA = 37090, SPELL_SYLVANAS_CAST = 36568, - SPELL_RIBBON_OF_SOULS = 34432, //the real one to use might be 37099 + SPELL_RIBBON_OF_SOULS = 34432, // the real one to use might be 37099 + + // Combat spells + SPELL_BLACK_ARROW = 59712, + SPELL_FADE = 20672, + SPELL_FADE_BLINK = 29211, + SPELL_MULTI_SHOT = 59713, + SPELL_SHOT = 59710, + SPELL_SUMMON_SKELETON = 59711 }; float HighborneLoc[4][3]= @@ -90,15 +98,27 @@ public: { npc_lady_sylvanas_windrunnerAI(Creature* creature) : ScriptedAI(creature) {} - uint32 LamentEvent_Timer; + uint32 LamentEventTimer; bool LamentEvent; uint64 targetGUID; + uint32 FadeTimer; + uint32 SummonSkeletonTimer; + uint32 BlackArrowTimer; + uint32 ShotTimer; + uint32 MultiShotTimer; + void Reset() { - LamentEvent_Timer = 5000; + LamentEventTimer = 5000; LamentEvent = false; targetGUID = 0; + + FadeTimer = 30000; + SummonSkeletonTimer = 20000; + BlackArrowTimer = 15000; + ShotTimer = 8000; + MultiShotTimer = 10000; } void EnterCombat(Unit* /*who*/) {} @@ -123,23 +143,70 @@ public: { if (LamentEvent) { - if (LamentEvent_Timer <= diff) + if (LamentEventTimer <= diff) { DoSummon(ENTRY_HIGHBORNE_BUNNY, me, 10.0f, 3000, TEMPSUMMON_TIMED_DESPAWN); - LamentEvent_Timer = 2000; + LamentEventTimer = 2000; if (!me->HasAura(SPELL_SYLVANAS_CAST)) { DoScriptText(SAY_LAMENT_END, me); DoScriptText(EMOTE_LAMENT_END, me); LamentEvent = false; } - } else LamentEvent_Timer -= diff; + } else LamentEventTimer -= diff; } if (!UpdateVictim()) return; + // Combat spells + + if (FadeTimer <= diff) + { + DoCast(me, SPELL_FADE); + // add a blink to simulate a stealthed movement and reappearing elsewhere + DoCast(me, SPELL_FADE_BLINK); + FadeTimer = 30000 + rand()%5000; + // if the victim is out of melee range she cast multi shot + if (Unit* victim = me->getVictim()) + if (me->GetDistance(victim) > 10.0f) + DoCast(victim, SPELL_MULTI_SHOT); + } else FadeTimer -= diff; + + if (SummonSkeletonTimer <= diff) + { + DoCast(me, SPELL_SUMMON_SKELETON); + SummonSkeletonTimer = 20000 + rand()%10000; + } else SummonSkeletonTimer -= diff; + + if (BlackArrowTimer <= diff) + { + if (Unit* victim = me->getVictim()) + { + DoCast(me->getVictim(), SPELL_BLACK_ARROW); + BlackArrowTimer = 15000 + rand()%5000; + } + } else BlackArrowTimer -= diff; + + if (ShotTimer <= diff) + { + if (Unit* victim = me->getVictim()) + { + DoCast(me->getVictim(), SPELL_SHOT); + ShotTimer = 8000 + rand()%2000; + } + } else ShotTimer -= diff; + + if (MultiShotTimer <= diff) + { + if (Unit* victim = me->getVictim()) + { + DoCast(me->getVictim(), SPELL_MULTI_SHOT); + MultiShotTimer = 10000 + rand()%3000; + } + } else MultiShotTimer -= diff; + DoMeleeAttackIfReady(); } }; @@ -163,15 +230,15 @@ public: { npc_highborne_lamenterAI(Creature* creature) : ScriptedAI(creature) {} - uint32 EventMove_Timer; - uint32 EventCast_Timer; + uint32 EventMoveTimer; + uint32 EventCastTimer; bool EventMove; bool EventCast; void Reset() { - EventMove_Timer = 10000; - EventCast_Timer = 17500; + EventMoveTimer = 10000; + EventCastTimer = 17500; EventMove = true; EventCast = true; } @@ -182,21 +249,21 @@ public: { if (EventMove) { - if (EventMove_Timer <= diff) + if (EventMoveTimer <= diff) { me->SetDisableGravity(true); me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetDistance(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW) / (5000 * 0.001f)); me->SetPosition(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetOrientation()); EventMove = false; - } else EventMove_Timer -= diff; + } else EventMoveTimer -= diff; } if (EventCast) { - if (EventCast_Timer <= diff) + if (EventCastTimer <= diff) { DoCast(me, SPELL_HIGHBORNE_AURA); EventCast = false; - } else EventCast_Timer -= diff; + } else EventCastTimer -= diff; } } }; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp index 28457b3b461..22307468f14 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp @@ -226,7 +226,6 @@ public: player->SendNewItem(item, 1, true, false, true); } player->SEND_GOSSIP_MENU(907, creature->GetGUID()); - CAST_AI(hyjalAI, creature->AI()); } return true; } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/instance_dark_portal.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/instance_dark_portal.cpp index dabf3db13cb..2c8cd096644 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/instance_dark_portal.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/instance_dark_portal.cpp @@ -116,9 +116,9 @@ public: DoUpdateWorldState(WORLD_STATE_BM_RIFT, 0); } - bool IsEncounterInProgress() + bool IsEncounterInProgress() const { - if (GetData(TYPE_MEDIVH) == IN_PROGRESS) + if (const_cast<instance_dark_portal_InstanceMapScript*>(this)->GetData(TYPE_MEDIVH) == IN_PROGRESS) return true; return false; diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp index a290b07e60f..18a77519ba2 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp @@ -147,7 +147,7 @@ class boss_moam : public CreatureScript targetList.push_back((*itr)->getTarget()); } - Trinity::RandomResizeList(targetList, 5); + Trinity::Containers::RandomResizeList(targetList, 5); for (std::list<Unit*>::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) DoCast(*itr, SPELL_DRAIN_MANA); diff --git a/src/server/scripts/Kalimdor/silithus.cpp b/src/server/scripts/Kalimdor/silithus.cpp index 66986ebd5ae..2d91f32fe9d 100644 --- a/src/server/scripts/Kalimdor/silithus.cpp +++ b/src/server/scripts/Kalimdor/silithus.cpp @@ -373,8 +373,13 @@ static QuestCinematic EventAnim[]= {0, 0, 0} }; +struct Location +{ + float x, y, z, o; +}; + //Cordinates for Spawns -static const Position SpawnLocation[]= +static Location SpawnLocation[]= { {-8085.0f, 1528.0f, 2.61f, 3.141592f}, //Kaldorei Infantry {-8080.0f, 1526.0f, 2.61f, 3.141592f}, //Kaldorei Infantry @@ -485,9 +490,9 @@ class npc_anachronos_the_ancient : public CreatureScript public: npc_anachronos_the_ancient() : CreatureScript("npc_anachronos_the_ancient") { } - CreatureAI* GetAI(Creature* c) const + CreatureAI* GetAI(Creature* creature) const { - return new npc_anachronos_the_ancientAI(c); + return new npc_anachronos_the_ancientAI(creature); } struct npc_anachronos_the_ancientAI : public ScriptedAI @@ -813,9 +818,9 @@ class mob_qiraj_war_spawn : public CreatureScript public: mob_qiraj_war_spawn() : CreatureScript("mob_qiraj_war_spawn") { } - CreatureAI* GetAI(Creature* c) const + CreatureAI* GetAI(Creature* creature) const { - return new mob_qiraj_war_spawnAI(c); + return new mob_qiraj_war_spawnAI(creature); } struct mob_qiraj_war_spawnAI : public ScriptedAI @@ -928,9 +933,9 @@ class npc_anachronos_quest_trigger : public CreatureScript public: npc_anachronos_quest_trigger() : CreatureScript("npc_anachronos_quest_trigger") { } - CreatureAI* GetAI(Creature* c) const + CreatureAI* GetAI(Creature* creature) const { - return new npc_anachronos_quest_triggerAI(c); + return new npc_anachronos_quest_triggerAI(creature); } struct npc_anachronos_quest_triggerAI : public ScriptedAI @@ -967,16 +972,19 @@ public: void SummonNextWave() { - //uint8 count = WavesInfo[WaveCount].SpawnCount; uint8 locIndex = WavesInfo[WaveCount].UsedSpawnPoint; - //uint8 KaldoreiSoldierCount = 0; - //uint8 AnubisathConquerorCount = 0; - //uint8 QirajiWaspCount = 0; - for (uint8 i = 0; i < 67; ++i) + uint8 count = locIndex + WavesInfo[WaveCount].SpawnCount; + + for (uint8 i = locIndex; i <= count; ++i) { - if (Creature* spawn = me->SummonCreature(WavesInfo[WaveCount].CreatureId, SpawnLocation[locIndex + i], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, WavesInfo[WaveCount].DespTimer)) + float x = SpawnLocation[i].x; + float y = SpawnLocation[i].y; + float z = SpawnLocation[i].z; + float o = SpawnLocation[i].o; + uint32 desptimer = WavesInfo[WaveCount].DespTimer; + + if (Creature* spawn = me->SummonCreature(WavesInfo[WaveCount].CreatureId, x, y, z, o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, desptimer)) { - spawn->LoadCreaturesAddon(); if (spawn->GetEntry() == 15423) spawn->SetUInt32Value(UNIT_FIELD_DISPLAYID, 15427+rand()%4); if (i >= 30) WaveCount = 1; @@ -986,12 +994,15 @@ public: if (WaveCount < 5) //1-4 Wave { - mob_qiraj_war_spawn::mob_qiraj_war_spawnAI* spawnAI = CAST_AI(mob_qiraj_war_spawn::mob_qiraj_war_spawnAI, spawn->AI()); - spawnAI->MobGUID = me->GetGUID(); - spawnAI->PlayerGUID = PlayerGUID; + if (mob_qiraj_war_spawn::mob_qiraj_war_spawnAI* spawnAI = CAST_AI(mob_qiraj_war_spawn::mob_qiraj_war_spawnAI, spawn->AI())) + { + spawnAI->MobGUID = me->GetGUID(); + spawnAI->PlayerGUID = PlayerGUID; + } } } } + WaveTimer = WavesInfo[WaveCount].SpawnTimer; AnnounceTimer = WavesInfo[WaveCount].YellTimer; } @@ -1005,27 +1016,27 @@ public: if (Group* EventGroup = player->GetGroup()) { - Player* GroupMember; + Player* groupMember; uint8 GroupMemberCount = 0; uint8 DeadMemberCount = 0; uint8 FailedMemberCount = 0; - const Group::MemberSlotList members = EventGroup->GetMemberSlots(); + Group::MemberSlotList const members = EventGroup->GetMemberSlots(); for (Group::member_citerator itr = members.begin(); itr!= members.end(); ++itr) { - GroupMember = (Unit::GetPlayer(*me, itr->guid)); - if (!GroupMember) + groupMember = (Unit::GetPlayer(*me, itr->guid)); + if (!groupMember) continue; - if (!GroupMember->IsWithinDistInMap(me, EVENT_AREA_RADIUS) && GroupMember->GetQuestStatus(QUEST_A_PAWN_ON_THE_ETERNAL_BOARD) == QUEST_STATUS_INCOMPLETE) + if (!groupMember->IsWithinDistInMap(me, EVENT_AREA_RADIUS) && groupMember->GetQuestStatus(QUEST_A_PAWN_ON_THE_ETERNAL_BOARD) == QUEST_STATUS_INCOMPLETE) { - GroupMember->FailQuest(QUEST_A_PAWN_ON_THE_ETERNAL_BOARD); + groupMember->FailQuest(QUEST_A_PAWN_ON_THE_ETERNAL_BOARD); ++FailedMemberCount; } ++GroupMemberCount; - if (GroupMember->isDead()) + if (groupMember->isDead()) ++DeadMemberCount; } @@ -1069,8 +1080,13 @@ public: void mob_qiraj_war_spawn::mob_qiraj_war_spawnAI::JustDied(Unit* /*slayer*/) { me->RemoveCorpse(); - if (Creature* Mob = (Unit::GetCreature(*me, MobGUID))) - CAST_AI(npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI, Mob->AI())->LiveCounter(); + + if (!MobGUID) + return; + + if (Creature* mob = Unit::GetCreature(*me, MobGUID)) + if (npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI* triggerAI = CAST_AI(npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI, mob->AI())) + triggerAI->LiveCounter(); }; @@ -1087,15 +1103,13 @@ public: { if (quest->GetQuestId() == QUEST_A_PAWN_ON_THE_ETERNAL_BOARD) { - - if (Unit* Anachronos_Quest_Trigger = go->FindNearestCreature(15454, 100, player)) + if (Creature* trigger = go->FindNearestCreature(15454, 100, player)) { - - Unit* Merithra = Anachronos_Quest_Trigger->SummonCreature(15378, -8034.535f, 1535.14f, 2.61f, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); - Unit* Caelestrasz = Anachronos_Quest_Trigger->SummonCreature(15379, -8032.767f, 1533.148f, 2.61f, 1.5f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); - Unit* Arygos = Anachronos_Quest_Trigger->SummonCreature(15380, -8034.52f, 1537.843f, 2.61f, 5.7f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); - /* Unit* Fandral = */ Anachronos_Quest_Trigger->SummonCreature(15382, -8028.462f, 1535.843f, 2.61f, 3.141592f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); - Creature* Anachronos = Anachronos_Quest_Trigger->SummonCreature(15381, -8028.75f, 1538.795f, 2.61f, 4, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); + Unit* Merithra = trigger->SummonCreature(15378, -8034.535f, 1535.14f, 2.61f, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); + Unit* Caelestrasz = trigger->SummonCreature(15379, -8032.767f, 1533.148f, 2.61f, 1.5f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); + Unit* Arygos = trigger->SummonCreature(15380, -8034.52f, 1537.843f, 2.61f, 5.7f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); + /* Unit* Fandral = */ trigger->SummonCreature(15382, -8028.462f, 1535.843f, 2.61f, 3.141592f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); + Creature* Anachronos = trigger->SummonCreature(15381, -8028.75f, 1538.795f, 2.61f, 4, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 220000); if (Merithra) { @@ -1123,11 +1137,16 @@ public: if (Anachronos) { - CAST_AI(npc_anachronos_the_ancient::npc_anachronos_the_ancientAI, Anachronos->AI())->PlayerGUID = player->GetGUID(); - CAST_AI(npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI, CAST_CRE(Anachronos_Quest_Trigger)->AI())->Failed=false; - CAST_AI(npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI, CAST_CRE(Anachronos_Quest_Trigger)->AI())->PlayerGUID = player->GetGUID(); - CAST_AI(npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI, CAST_CRE(Anachronos_Quest_Trigger)->AI())->EventStarted=true; - CAST_AI(npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI, CAST_CRE(Anachronos_Quest_Trigger)->AI())->Announced=true; + if (npc_anachronos_the_ancient::npc_anachronos_the_ancientAI* anachronosAI = CAST_AI(npc_anachronos_the_ancient::npc_anachronos_the_ancientAI, Anachronos->AI())) + anachronosAI->PlayerGUID = player->GetGUID(); + + if (npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI* triggerAI = CAST_AI(npc_anachronos_quest_trigger::npc_anachronos_quest_triggerAI, trigger->AI())) + { + triggerAI->Failed = false; + triggerAI->PlayerGUID = player->GetGUID(); + triggerAI->EventStarted = true; + triggerAI->Announced = true; + } } } } diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index 31aa924365d..3502e7fb104 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -22,7 +22,7 @@ set(scripts_STAT_SRCS Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp Northrend/Ulduar/Ulduar/boss_thorim.cpp Northrend/Ulduar/Ulduar/boss_ignis.cpp - Northrend/Ulduar/Ulduar/boss_algalon.cpp + Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp Northrend/Ulduar/Ulduar/instance_ulduar.cpp Northrend/Ulduar/Ulduar/boss_auriaya.cpp Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp index 3407b42b2a7..4e5e01cc745 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp @@ -206,7 +206,7 @@ class spell_saviana_conflagration_init : public SpellScriptLoader unitList.remove_if (ConflagrationTargetSelector()); uint8 maxSize = uint8(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 6 : 3); if (unitList.size() > maxSize) - Trinity::RandomResizeList(unitList, maxSize); + Trinity::Containers::RandomResizeList(unitList, maxSize); } void HandleDummy(SpellEffIndex effIndex) diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index 37516e5e0df..c718c0cee5f 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -263,7 +263,8 @@ public: if (instance) instance->SetData(TYPE_ANUBARAK, IN_PROGRESS); //Despawn Scarab Swarms neutral - Summons.DoAction(NPC_SCARAB, ACTION_SCARAB_SUBMERGE); + EntryCheckPredicate pred(NPC_SCARAB); + Summons.DoAction(ACTION_SCARAB_SUBMERGE, pred); //Spawn Burrow for (int i=0; i < 4; i++) me->SummonCreature(NPC_BURROW, AnubarakLoc[i+2]); @@ -304,7 +305,8 @@ public: if (IsHeroic() && m_uiNerubianShadowStrikeTimer <= uiDiff) { - Summons.DoAction(NPC_BURROWER, ACTION_SHADOW_STRIKE); + EntryCheckPredicate pred(NPC_BURROWER); + Summons.DoAction(ACTION_SHADOW_STRIKE, pred); m_uiNerubianShadowStrikeTimer = 30*IN_MILLISECONDS; } else m_uiNerubianShadowStrikeTimer -= uiDiff; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp index 6f817a6d0eb..a7328b43826 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp @@ -515,36 +515,6 @@ public: }; -class spell_spinning_pain_spike : public SpellScriptLoader -{ - public: - spell_spinning_pain_spike() : SpellScriptLoader("spell_spinning_pain_spike") {} - - class spell_spinning_pain_spike_SpellScript : public SpellScript - { - PrepareSpellScript(spell_spinning_pain_spike_SpellScript); - - void HandleScript(SpellEffIndex /*eff*/) - { - Unit* target = GetHitUnit(); - if (!target) - return; - - if (target->isAlive()) - SetHitDamage(target->CountPctFromMaxHealth(50)); - } - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_spinning_pain_spike_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_spinning_pain_spike_SpellScript(); - } -}; - void AddSC_boss_jaraxxus() { new boss_jaraxxus(); @@ -553,5 +523,4 @@ void AddSC_boss_jaraxxus() new mob_fel_infernal(); new mob_nether_portal(); new mob_mistress_of_pain(); - new spell_spinning_pain_spike(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index 74b9c038482..241d6239f82 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -759,7 +759,7 @@ class spell_powering_up : public SpellScriptLoader uint32 spellId; - bool Validate(SpellEntry const* /*spellEntry*/) + bool Load() { spellId = sSpellMgr->GetSpellIdForDifficulty(SPELL_SURGE_OF_SPEED, GetCaster()); if (!sSpellMgr->GetSpellInfo(spellId)) 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 88e9bedcd07..8d015adf4a4 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp @@ -387,8 +387,7 @@ class player_overlord_brandAI : public PlayerAI void SetGUID(uint64 guid, int32 /*type*/) { tyrannus = ObjectAccessor::GetCreature(*me, guid); - if (!tyrannus) - me->IsAIEnabled = false; + me->IsAIEnabled = tyrannus != NULL; } void DamageDealt(Unit* /*victim*/, uint32& damage, DamageEffectType /*damageType*/) @@ -423,10 +422,9 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader return; oldAI = GetTarget()->GetAI(); + oldAIState = GetTarget()->IsAIEnabled; GetTarget()->SetAI(new player_overlord_brandAI(GetTarget()->ToPlayer())); GetTarget()->GetAI()->SetGUID(GetCasterGUID()); - oldAIState = GetTarget()->IsAIEnabled; - GetTarget()->IsAIEnabled = true; } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp index a91951ca25e..70d72e52e67 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp @@ -240,12 +240,13 @@ class mob_geist_ambusher : public CreatureScript _leapingFaceMaulCooldown = 9000; } - void MoveInLineOfSight(Unit* who) + void EnterCombat(Unit* who) { if (who->GetTypeId() != TYPEID_PLAYER) return; - if (me->IsWithinDistInMap(who, 30.0f)) + // the max range is determined by aggro range + if (me->GetDistance(who) > 5.0f) DoCast(who, SPELL_LEAPING_FACE_MAUL); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index de104a78e43..8090fc98101 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -103,6 +103,7 @@ enum Spells SPELL_UNSTABLE = 72059, SPELL_KINETIC_BOMB_VISUAL = 72054, SPELL_KINETIC_BOMB_EXPLOSION = 72052, + SPELL_KINETIC_BOMB_KNOCKBACK = 72087, // Shock Vortex SPELL_SHOCK_VORTEX_PERIODIC = 71945, @@ -443,20 +444,12 @@ class boss_prince_keleseth_icc : public CreatureScript { summons.Summon(summon); Position pos; - pos.Relocate(summon); + me->GetPosition(&pos); float maxRange = me->GetDistance2d(summon); float angle = me->GetAngle(summon); - // prevent spawning outside of room - while (!me->IsWithinLOS(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ())) - { - maxRange -= 5.0f; - if (maxRange < 5.0f) - break; - - summon->MovePosition(pos, float(rand_norm() * maxRange), angle); - } - + me->MovePositionToFirstCollision(pos, maxRange, angle); summon->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); + summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); } void DamageDealt(Unit* /*target*/, uint32& damage, DamageEffectType damageType) @@ -894,6 +887,7 @@ class boss_prince_valanar_icc : public CreatureScript summon->GetPosition(x, y, z); float ground_Z = summon->GetMap()->GetHeight(summon->GetPhaseMask(), x, y, z, true, 500.0f); summon->GetMotionMaster()->MovePoint(POINT_KINETIC_BOMB_IMPACT, x, y, ground_Z); + summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); break; } case NPC_SHOCK_VORTEX: @@ -1073,7 +1067,7 @@ class npc_blood_queen_lana_thel : public CreatureScript if (_introDone) return; - if (!me->IsWithinDistInMap(who, 35.0f)) + if (!me->IsWithinDistInMap(who, 35.0f, false)) return; _introDone = true; @@ -1232,12 +1226,12 @@ class npc_kinetic_bomb : public CreatureScript void Reset() { _events.Reset(); - me->SetDisplayId(DISPLAY_KINETIC_BOMB); + me->SetWalk(true); me->CastSpell(me, SPELL_UNSTABLE, true); me->CastSpell(me, SPELL_KINETIC_BOMB_VISUAL, true); me->SetReactState(REACT_PASSIVE); - me->SetSpeed(MOVE_FLIGHT, IsHeroic() ? 0.3f : 0.15f, true); me->GetPosition(_x, _y, _groundZ); + me->DespawnOrUnsummon(60000); _groundZ = me->GetMap()->GetHeight(me->GetPhaseMask(), _x, _y, _groundZ, true, 500.0f); } @@ -1247,9 +1241,9 @@ class npc_kinetic_bomb : public CreatureScript _events.ScheduleEvent(EVENT_BOMB_DESPAWN, 1000); else if (action == ACTION_KINETIC_BOMB_JUMP) { - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveJump(_x, _y, me->GetPositionZ() + 7.0f, 1.0f, 7.0f); - _events.ScheduleEvent(EVENT_CONTINUE_FALLING, 700); + if (!me->HasAura(SPELL_KINETIC_BOMB_KNOCKBACK)) + me->GetMotionMaster()->MoveCharge(_x, _y, me->GetPositionZ() + 100.0f, me->GetSpeed(MOVE_RUN), 0); + _events.RescheduleEvent(EVENT_CONTINUE_FALLING, 3000); } } @@ -1263,10 +1257,10 @@ class npc_kinetic_bomb : public CreatureScript { case EVENT_BOMB_DESPAWN: me->SetVisible(false); + me->DespawnOrUnsummon(5000); break; case EVENT_CONTINUE_FALLING: - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MovePoint(POINT_KINETIC_BOMB_IMPACT, _x, _y, _groundZ); + me->GetMotionMaster()->MoveCharge(_x, _y, _groundZ, me->GetSpeed(MOVE_WALK), POINT_KINETIC_BOMB_IMPACT); break; default: break; @@ -1329,17 +1323,16 @@ class npc_dark_nucleus : public CreatureScript void DamageTaken(Unit* attacker, uint32& /*damage*/) { - if (attacker == me) + if (attacker == me || attacker == me->getVictim()) return; - if (!_lockedTarget) - if (me->getVictim() == attacker) - _lockedTarget = true; + me->DeleteThreatList(); + me->AddThreat(attacker, 500000000.0f); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 const diff) { - if (!me->isInCombat()) + if (!UpdateVictim()) return; if (_targetAuraCheck <= diff) @@ -1355,23 +1348,6 @@ class npc_dark_nucleus : public CreatureScript } else _targetAuraCheck -= diff; - - if (!_lockedTarget) - { - if (Unit* victim = me->SelectVictim()) - { - if (me->getVictim() && me->getVictim() != victim) - { - me->getVictim()->RemoveAurasDueToSpell(SPELL_SHADOW_RESONANCE_RESIST, me->GetGUID()); - _lockedTarget = true; - } - - _lockedTarget = true; - AttackStart(victim); - DoCast(victim, SPELL_SHADOW_RESONANCE_RESIST); - me->ClearUnitState(UNIT_STATE_CASTING); - } - } } private: @@ -1525,6 +1501,7 @@ class spell_valanar_kinetic_bomb : public SpellScriptLoader Position offset = {0.0f, 0.0f, 20.0f, 0.0f}; summonPos.RelocateOffset(offset); SetTargetDest(summonPos); + GetHitDest()->RelocateOffset(offset); } void Register() @@ -1586,7 +1563,7 @@ class spell_valanar_kinetic_bomb_knockback : public SpellScriptLoader void Register() { - AfterHit += SpellHitFn(spell_valanar_kinetic_bomb_knockback_SpellScript::KnockIntoAir); + BeforeHit += SpellHitFn(spell_valanar_kinetic_bomb_knockback_SpellScript::KnockIntoAir); } }; @@ -1663,7 +1640,7 @@ class spell_blood_council_shadow_prison_damage : public SpellScriptLoader void AddExtraDamage() { if (Aura* aur = GetHitUnit()->GetAura(GetSpellInfo()->Id)) - if (AuraEffect const* eff = aur->GetEffect(1)) + if (AuraEffect const* eff = aur->GetEffect(EFFECT_1)) SetHitDamage(GetHitDamage() + eff->GetAmount()); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp index 784cda8f595..b6544fd9a2a 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp @@ -386,7 +386,7 @@ class boss_blood_queen_lana_thel : public CreatureScript ++targetCount; if (Is25ManRaid()) ++targetCount; - Trinity::RandomResizeList<Player*>(targets, targetCount); + Trinity::Containers::RandomResizeList<Player*>(targets, targetCount); if (targets.size() > 1) { Talk(SAY_PACT_OF_THE_DARKFALLEN); @@ -409,7 +409,7 @@ class boss_blood_queen_lana_thel : public CreatureScript { std::list<Player*> targets; SelectRandomTarget(false, &targets); - Trinity::RandomResizeList<Player*>(targets, uint32(Is25ManRaid() ? 4 : 2)); + Trinity::Containers::RandomResizeList<Player*>(targets, uint32(Is25ManRaid() ? 4 : 2)); for (std::list<Player*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) DoCast(*itr, SPELL_TWILIGHT_BLOODBOLT); DoCast(me, SPELL_TWILIGHT_BLOODBOLT_TARGET); @@ -481,7 +481,7 @@ class boss_blood_queen_lana_thel : public CreatureScript return tempTargets.front(); } - return SelectRandomContainerElement(tempTargets); + return Trinity::Containers::SelectRandomContainerElement(tempTargets); } std::set<uint64> _vampires; @@ -658,7 +658,7 @@ class spell_blood_queen_bloodbolt : public SpellScriptLoader { uint32 targetCount = (targets.size() + 2) / 3; targets.remove_if (BloodboltHitCheck(static_cast<LanaThelAI*>(GetCaster()->GetAI()))); - Trinity::RandomResizeList(targets, targetCount); + Trinity::Containers::RandomResizeList(targets, targetCount); // mark targets now, effect hook has missile travel time delay (might cast next in that time) for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) GetCaster()->GetAI()->SetGUID((*itr)->GetGUID(), GUID_BLOODBOLT); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 3ce62d939d3..249eed01643 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -1272,7 +1272,7 @@ class spell_deathbringer_boiling_blood : public SpellScriptLoader if (unitList.empty()) return; - Unit* target = SelectRandomContainerElement(unitList); + Unit* target = Trinity::Containers::SelectRandomContainerElement(unitList); unitList.clear(); unitList.push_back(target); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index ea2f73e788f..e2f9faf6a97 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -605,7 +605,7 @@ class boss_lady_deathwhisper : public CreatureScript return; // select random cultist - Creature* cultist = SelectRandomContainerElement(temp); + Creature* cultist = Trinity::Containers::SelectRandomContainerElement(temp); DoCast(cultist, cultist->GetEntry() == NPC_CULT_FANATIC ? SPELL_DARK_TRANSFORMATION_T : SPELL_DARK_EMPOWERMENT_T, true); Talk(uint8(cultist->GetEntry() == NPC_CULT_FANATIC ? SAY_DARK_TRANSFORMATION : SAY_DARK_EMPOWERMENT)); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 44bc40d08bd..c043cb27c7c 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -64,6 +64,9 @@ enum Spells SPELL_MALLEABLE_GOO = 70852, SPELL_UNSTABLE_EXPERIMENT = 70351, SPELL_TEAR_GAS = 71617, // phase transition + SPELL_TEAR_GAS_CREATURE = 71618, + SPELL_TEAR_GAS_CANCEL = 71620, + SPELL_TEAR_GAS_PERIODIC_TRIGGER = 73170, SPELL_CREATE_CONCOCTION = 71621, SPELL_GUZZLE_POTIONS = 71893, SPELL_OOZE_TANK_PROTECTION = 71770, // protects the tank @@ -86,6 +89,7 @@ enum Spells SPELL_GASEOUS_BLOAT_PROC = 70215, SPELL_GASEOUS_BLOAT = 70672, SPELL_GASEOUS_BLOAT_PROTECTION = 70812, + SPELL_EXPUNGED_GAS = 70701, // Volatile Ooze SPELL_OOZE_ERUPTION = 70492, @@ -167,6 +171,33 @@ enum PutricideData #define EXPERIMENT_STATE_OOZE false #define EXPERIMENT_STATE_GAS true +class AbominationDespawner +{ + public: + explicit AbominationDespawner(Unit* owner) : _owner(owner) { } + + bool operator()(uint64 guid) + { + if (Unit* summon = ObjectAccessor::GetUnit(*_owner, guid)) + { + if (summon->GetEntry() == NPC_MUTATED_ABOMINATION_10 || summon->GetEntry() == NPC_MUTATED_ABOMINATION_25) + { + if (Vehicle* veh = summon->GetVehicleKit()) + veh->RemoveAllPassengers(); // also despawns the vehicle + + return true; + } + + return false; + } + + return true; + } + + private: + Unit* _owner; +}; + class boss_professor_putricide : public CreatureScript { public: @@ -477,8 +508,7 @@ class boss_professor_putricide : public CreatureScript SetPhase(PHASE_COMBAT_3); events.ScheduleEvent(EVENT_MUTATED_PLAGUE, 25000); events.CancelEvent(EVENT_UNSTABLE_EXPERIMENT); - summons.DespawnEntry(NPC_MUTATED_ABOMINATION_10); - summons.DespawnEntry(NPC_MUTATED_ABOMINATION_25); + summons.remove_if(AbominationDespawner(me)); break; default: break; @@ -514,7 +544,7 @@ class boss_professor_putricide : public CreatureScript void UpdateAI(uint32 const diff) { - if ((!UpdateVictim() && !(events.GetPhaseMask() & PHASE_MASK_NOT_SELF)) || !CheckInRoom()) + if ((!(events.GetPhaseMask() & PHASE_MASK_NOT_SELF) && !UpdateVictim()) || !CheckInRoom()) return; events.Update(diff); @@ -569,13 +599,15 @@ class boss_professor_putricide : public CreatureScript break; case EVENT_TEAR_GAS: me->GetMotionMaster()->MovePoint(POINT_TABLE, tablePos); + DoCast(me, SPELL_TEAR_GAS_PERIODIC_TRIGGER, true); break; case EVENT_RESUME_ATTACK: me->SetReactState(REACT_DEFENSIVE); AttackStart(me->getVictim()); // remove Tear Gas + me->RemoveAurasDueToSpell(SPELL_TEAR_GAS_PERIODIC_TRIGGER); instance->DoRemoveAurasDueToSpellOnPlayers(71615); - instance->DoRemoveAurasDueToSpellOnPlayers(71618); + DoCastAOE(SPELL_TEAR_GAS_CANCEL); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAS_VARIABLE); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_OOZE_VARIABLE); break; @@ -673,27 +705,36 @@ class npc_volatile_ooze : public CreatureScript public: npc_volatile_ooze() : CreatureScript("npc_volatile_ooze") { } - struct npc_volatile_oozeAI : public ScriptedAI + struct npc_putricide_oozeAI : public ScriptedAI { - npc_volatile_oozeAI(Creature* creature) : ScriptedAI(creature) + npc_putricide_oozeAI(Creature* creature) : ScriptedAI(creature) { _newTargetSelectTimer = 0; } void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) { - if (!_newTargetSelectTimer && sSpellMgr->GetSpellDifficultyId(spell->Id) == sSpellMgr->GetSpellDifficultyId(SPELL_OOZE_ERUPTION)) + if (!_newTargetSelectTimer && spell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_OOZE_ERUPTION, me)) + _newTargetSelectTimer = 1000; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_TEAR_GAS_CREATURE) _newTargetSelectTimer = 1000; } void UpdateAI(uint32 const diff) { - if (!UpdateVictim()) + if (!UpdateVictim() && !_newTargetSelectTimer) return; if (!_newTargetSelectTimer) return; + if (me->HasAura(SPELL_TEAR_GAS_CREATURE)) + return; + if (_newTargetSelectTimer <= diff) { _newTargetSelectTimer = 0; @@ -704,13 +745,68 @@ class npc_volatile_ooze : public CreatureScript } private: - // no need to use EventMap for just one event uint32 _newTargetSelectTimer; }; CreatureAI* GetAI(Creature* creature) const { - return GetIcecrownCitadelAI<npc_volatile_oozeAI>(creature); + return GetIcecrownCitadelAI<npc_putricide_oozeAI>(creature); + } +}; + +class npc_gas_cloud : public CreatureScript +{ + public: + npc_gas_cloud() : CreatureScript("npc_gas_cloud") { } + + struct npc_gas_cloudAI : public ScriptedAI + { + npc_gas_cloudAI(Creature* creature) : ScriptedAI(creature) + { + _newTargetSelectTimer = 0; + } + + void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) + { + if (!_newTargetSelectTimer && spell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_EXPUNGED_GAS, me)) + _newTargetSelectTimer = 1000; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_TEAR_GAS_CREATURE) + _newTargetSelectTimer = 1000; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() && !_newTargetSelectTimer) + return; + + DoMeleeAttackIfReady(); + + if (!_newTargetSelectTimer) + return; + + if (me->HasAura(SPELL_TEAR_GAS_CREATURE)) + return; + + if (_newTargetSelectTimer <= diff) + { + _newTargetSelectTimer = 0; + me->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, me, false); + } + else + _newTargetSelectTimer -= diff; + } + + private: + uint32 _newTargetSelectTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_gas_cloudAI>(creature); } }; @@ -729,8 +825,8 @@ class spell_putricide_gaseous_bloat : public SpellScriptLoader if (Unit* caster = GetCaster()) { target->RemoveAuraFromStack(GetSpellInfo()->Id, GetCasterGUID()); - if (!target->HasAura(GetId())&& caster->GetTypeId() == TYPEID_UNIT) - caster->ToCreature()->DespawnOrUnsummon(); + if (!target->HasAura(GetId())) + caster->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, caster, false); } } @@ -781,7 +877,7 @@ class spell_putricide_ooze_channel : public SpellScriptLoader return; } - Unit* target = SelectRandomContainerElement(targetList); + Unit* target = Trinity::Containers::SelectRandomContainerElement(targetList); targetList.clear(); targetList.push_back(target); _target = target; @@ -797,7 +893,19 @@ class spell_putricide_ooze_channel : public SpellScriptLoader void StartAttack() { GetCaster()->ClearUnitState(UNIT_STATE_CASTING); + GetCaster()->DeleteThreatList(); GetCaster()->ToCreature()->AI()->AttackStart(GetHitUnit()); + GetCaster()->AddThreat(GetHitUnit(), 500000000.0f); // value seen in sniff + } + + // temporary, until SelectTarget are not called on empty lists + void CheckTarget() + { + if (_target) + return; + + FinishCast(SPELL_FAILED_NO_VALID_TARGETS); + GetCaster()->ToCreature()->DespawnOrUnsummon(1); // despawn next update } void Register() @@ -806,6 +914,7 @@ class spell_putricide_ooze_channel : public SpellScriptLoader OnUnitTargetSelect += SpellUnitTargetFn(spell_putricide_ooze_channel_SpellScript::SetTarget, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); OnUnitTargetSelect += SpellUnitTargetFn(spell_putricide_ooze_channel_SpellScript::SetTarget, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY); AfterHit += SpellHitFn(spell_putricide_ooze_channel_SpellScript::StartAttack); + OnCast += SpellCastFn(spell_putricide_ooze_channel_SpellScript::CheckTarget); } Unit* _target; @@ -905,13 +1014,13 @@ class spell_putricide_unstable_experiment : public SpellScriptLoader uint32 stage = GetCaster()->ToCreature()->AI()->GetData(DATA_EXPERIMENT_STAGE); Creature* target = NULL; std::list<Creature*> creList; - GetCreatureListWithEntryInGrid(creList, GetCaster(), NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 100.0f); + GetCreatureListWithEntryInGrid(creList, GetCaster(), NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 200.0f); // 2 of them are spawned at green place - weird trick blizz for (std::list<Creature*>::iterator itr = creList.begin(); itr != creList.end(); ++itr) { target = *itr; std::list<Creature*> tmp; - GetCreatureListWithEntryInGrid(tmp, target, NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 1.0f); + GetCreatureListWithEntryInGrid(tmp, target, NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 10.0f); if ((!stage && tmp.size() > 1) || (stage && tmp.size() == 1)) break; } @@ -931,42 +1040,6 @@ class spell_putricide_unstable_experiment : public SpellScriptLoader } }; -class spell_putricide_ooze_summon : public SpellScriptLoader -{ - public: - spell_putricide_ooze_summon() : SpellScriptLoader("spell_putricide_ooze_summon") { } - - class spell_putricide_ooze_summon_AuraScript : public AuraScript - { - PrepareAuraScript(spell_putricide_ooze_summon_AuraScript); - - void HandleTriggerSpell(AuraEffect const* aurEff) - { - PreventDefaultAction(); - if (Unit* caster = GetCaster()) - { - uint32 triggerSpellId = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - float x, y, z; - GetTarget()->GetPosition(x, y, z); - z = GetTarget()->GetMap()->GetHeight(GetTarget()->GetPhaseMask(), x, y, z, true, 25.0f); - x += 10.0f * cosf(caster->GetOrientation()); - y += 10.0f * sinf(caster->GetOrientation()); - caster->CastSpell(x, y, z, triggerSpellId, true, NULL, NULL, GetCasterGUID()); - } - } - - void Register() - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_putricide_ooze_summon_AuraScript::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_putricide_ooze_summon_AuraScript(); - } -}; - class spell_putricide_ooze_eruption_searcher : public SpellScriptLoader { public: @@ -1429,14 +1502,15 @@ class spell_putricide_regurgitated_ooze : public SpellScriptLoader } }; -class spell_putricide_clear_mutated_plague : public SpellScriptLoader +// Removes aura with id stored in effect value +class spell_putricide_clear_aura_effect_value : public SpellScriptLoader { public: - spell_putricide_clear_mutated_plague() : SpellScriptLoader("spell_putricide_clear_mutated_plague") { } + spell_putricide_clear_aura_effect_value() : SpellScriptLoader("spell_putricide_clear_aura_effect_value") { } - class spell_putricide_clear_mutated_plague_SpellScript : public SpellScript + class spell_putricide_clear_aura_effect_value_SpellScript : public SpellScript { - PrepareSpellScript(spell_putricide_clear_mutated_plague_SpellScript); + PrepareSpellScript(spell_putricide_clear_aura_effect_value_SpellScript); void HandleScript(SpellEffIndex effIndex) { @@ -1447,13 +1521,13 @@ class spell_putricide_clear_mutated_plague : public SpellScriptLoader void Register() { - OnEffectHitTarget += SpellEffectFn(spell_putricide_clear_mutated_plague_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + OnEffectHitTarget += SpellEffectFn(spell_putricide_clear_aura_effect_value_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; SpellScript* GetSpellScript() const { - return new spell_putricide_clear_mutated_plague_SpellScript(); + return new spell_putricide_clear_aura_effect_value_SpellScript(); } }; @@ -1492,12 +1566,12 @@ void AddSC_boss_professor_putricide() { new boss_professor_putricide(); new npc_volatile_ooze(); + new npc_gas_cloud(); new spell_putricide_gaseous_bloat(); new spell_putricide_ooze_channel(); new spell_putricide_slime_puddle(); new spell_putricide_slime_puddle_aura(); new spell_putricide_unstable_experiment(); - new spell_putricide_ooze_summon(); new spell_putricide_ooze_eruption_searcher(); new spell_putricide_choking_gas_bomb(); new spell_putricide_unbound_plague(); @@ -1508,6 +1582,6 @@ void AddSC_boss_professor_putricide() new spell_putricide_mutated_transformation(); new spell_putricide_mutated_transformation_dmg(); new spell_putricide_regurgitated_ooze(); - new spell_putricide_clear_mutated_plague(); + new spell_putricide_clear_aura_effect_value(); new spell_stinky_precious_decimate(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp index 09707b2d9ab..85de6789784 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp @@ -498,7 +498,7 @@ class spell_rotface_mutated_infection : public SpellScriptLoader if (targets.empty()) return; - Unit* target = SelectRandomContainerElement(targets); + Unit* target = Trinity::Containers::SelectRandomContainerElement(targets); targets.clear(); targets.push_back(target); _target = target; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index c88b3aa8b37..ebf9ae02a95 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -61,6 +61,7 @@ enum Spells SPELL_ASPHYXIATION = 71665, SPELL_FROST_BOMB_TRIGGER = 69846, SPELL_FROST_BOMB_VISUAL = 70022, + SPELL_BIRTH_NO_VISUAL = 40031, SPELL_FROST_BOMB = 69845, SPELL_MYSTIC_BUFFET = 70128, @@ -98,6 +99,8 @@ enum Events EVENT_LAND = 12, EVENT_AIR_MOVEMENT = 21, EVENT_THIRD_PHASE_CHECK = 22, + EVENT_AIR_MOVEMENT_FAR = 23, + EVENT_LAND_GROUND = 24, // Spinestalker EVENT_BELLOWING_ROAR = 13, @@ -133,6 +136,8 @@ enum MovementPoints POINT_AIR_PHASE = 3, POINT_TAKEOFF = 4, POINT_LAND = 5, + POINT_AIR_PHASE_FAR = 6, + POINT_LAND_GROUND = 7, }; enum Shadowmourne @@ -152,6 +157,8 @@ Position const SindragosaSpawnPos = {4818.700f, 2483.710f, 287.0650f, 3.089233f Position const SindragosaFlyPos = {4475.190f, 2484.570f, 234.8510f, 3.141593f}; Position const SindragosaLandPos = {4419.190f, 2484.570f, 203.3848f, 3.141593f}; Position const SindragosaAirPos = {4475.990f, 2484.430f, 247.9340f, 3.141593f}; +Position const SindragosaAirPosFar = {4525.600f, 2485.150f, 245.0820f, 3.141593f}; +Position const SindragosaFlyInPos = {4419.190f, 2484.360f, 232.5150f, 3.141593f}; class FrostwyrmLandEvent : public BasicEvent { @@ -169,6 +176,23 @@ class FrostwyrmLandEvent : public BasicEvent Position const& _dest; }; +class FrostBombExplosion : public BasicEvent +{ + public: + FrostBombExplosion(Creature* owner, uint64 sindragosaGUID) : _owner(owner), _sindragosaGUID(sindragosaGUID) { } + + bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) + { + _owner->CastSpell((Unit*)NULL, SPELL_FROST_BOMB, true, NULL, NULL, _sindragosaGUID); + _owner->RemoveAurasDueToSpell(SPELL_FROST_BOMB_VISUAL); + return true; + } + + private: + Creature* _owner; + uint64 _sindragosaGUID; +}; + class boss_sindragosa : public CreatureScript { public: @@ -293,20 +317,31 @@ class boss_sindragosa : public CreatureScript break; case POINT_AIR_PHASE: me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL); - events.ScheduleEvent(EVENT_FROST_BOMB, 8000); + me->SetFacingTo(float(M_PI)); + events.ScheduleEvent(EVENT_AIR_MOVEMENT_FAR, 1); + events.ScheduleEvent(EVENT_FROST_BOMB, 9000); + break; + case POINT_AIR_PHASE_FAR: + me->SetFacingTo(float(M_PI)); + events.ScheduleEvent(EVENT_LAND, 30000); break; case POINT_LAND: + events.ScheduleEvent(EVENT_LAND_GROUND, 1); + break; + case POINT_LAND_GROUND: + { me->SetCanFly(false); me->SetDisableGravity(false); me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); me->SetReactState(REACT_DEFENSIVE); if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); - DoStartMovement(me->getVictim()); _isInAirPhase = false; // trigger Asphyxiation - summons.DoAction(NPC_ICE_TOMB, ACTION_TRIGGER_ASPHYXIATION); + EntryCheckPredicate pred(NPC_ICE_TOMB); + summons.DoAction(ACTION_TRIGGER_ASPHYXIATION, pred); break; + } default: break; } @@ -325,6 +360,12 @@ class boss_sindragosa : public CreatureScript void JustSummoned(Creature* summon) { summons.Summon(summon); + if (summon->GetEntry() == NPC_FROST_BOMB) + { + summon->CastSpell(summon, SPELL_FROST_BOMB_VISUAL, true); + summon->CastSpell(summon, SPELL_BIRTH_NO_VISUAL, true); + summon->m_Events.AddEvent(new FrostBombExplosion(summon, me->GetGUID()), summon->m_Events.CalculateTime(5500)); + } } void SummonedCreatureDespawn(Creature* summon) @@ -337,18 +378,25 @@ class boss_sindragosa : public CreatureScript void SpellHitTarget(Unit* target, SpellInfo const* spell) { if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(70127, me)) + { if (spellId == spell->Id) + { if (Aura const* mysticBuffet = target->GetAura(spell->Id)) _mysticBuffetStack = std::max<uint8>(_mysticBuffetStack, mysticBuffet->GetStackAmount()); + return; + } + } + // Frost Infusion if (Player* player = target->ToPlayer()) { if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(_isThirdPhase ? SPELL_FROST_BREATH_P2 : SPELL_FROST_BREATH_P1, me)) { - if (player->GetQuestStatus(QUEST_FROST_INFUSION) == QUEST_STATUS_INCOMPLETE && spellId == spell->Id) + if (spellId == spell->Id) { - if (Item* shadowsEdge = player->GetWeaponForAttack(BASE_ATTACK, true)) + Item* shadowsEdge = player->GetWeaponForAttack(BASE_ATTACK, true); + if (player->GetQuestStatus(QUEST_FROST_INFUSION) == QUEST_STATUS_INCOMPLETE && shadowsEdge) { if (!player->HasAura(SPELL_FROST_IMBUED_BLADE) && shadowsEdge->GetEntry() == ITEM_SHADOW_S_EDGE) { @@ -366,15 +414,11 @@ class boss_sindragosa : public CreatureScript player->CastSpell(player, SPELL_FROST_INFUSION, true); } } + + return; } } } - - if (spell->Id == SPELL_FROST_BOMB_TRIGGER) - { - target->CastSpell(target, SPELL_FROST_BOMB, true); - target->RemoveAurasDueToSpell(SPELL_FROST_BOMB_VISUAL); - } } void UpdateAI(uint32 const diff) @@ -415,7 +459,6 @@ class boss_sindragosa : public CreatureScript break; case EVENT_ICY_GRIP: DoCast(me, SPELL_ICY_GRIP); - events.ScheduleEvent(EVENT_ICY_GRIP, urand(70000, 75000), EVENT_GROUP_LAND_PHASE); events.ScheduleEvent(EVENT_BLISTERING_COLD, 1000, EVENT_GROUP_LAND_PHASE); break; case EVENT_BLISTERING_COLD: @@ -434,19 +477,21 @@ class boss_sindragosa : public CreatureScript me->SetDisableGravity(true); me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); me->SetReactState(REACT_PASSIVE); + me->AttackStop(); Position pos; pos.Relocate(me); pos.m_positionZ += 17.0f; me->GetMotionMaster()->MoveTakeoff(POINT_TAKEOFF, pos, 8.30078125f); - events.DelayEvents(45000, EVENT_GROUP_LAND_PHASE); + events.CancelEventGroup(EVENT_GROUP_LAND_PHASE); events.ScheduleEvent(EVENT_AIR_PHASE, 110000); - events.RescheduleEvent(EVENT_UNCHAINED_MAGIC, urand(55000, 60000), EVENT_GROUP_LAND_PHASE); - events.ScheduleEvent(EVENT_LAND, 45000); break; } case EVENT_AIR_MOVEMENT: me->GetMotionMaster()->MovePoint(POINT_AIR_PHASE, SindragosaAirPos); break; + case EVENT_AIR_MOVEMENT_FAR: + me->GetMotionMaster()->MovePoint(POINT_AIR_PHASE_FAR, SindragosaAirPosFar); + break; case EVENT_ICE_TOMB: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_ICE_TOMB_UNTARGETABLE)) { @@ -458,30 +503,28 @@ class boss_sindragosa : public CreatureScript case EVENT_FROST_BOMB: { float destX, destY, destZ; - destX = float(rand_norm()) * 117.25f + 4339.25f; - if (destX > 4371.5f && destX < 4432.0f) - destY = float(rand_norm()) * 111.0f + 2429.0f; - else - destY = float(rand_norm()) * 31.23f + 2454.64f; + destX = float(rand_norm()) * 75.0f + 4350.0f; + destY = float(rand_norm()) * 75.0f + 2450.0f; destZ = 205.0f; // random number close to ground, get exact in next call me->UpdateGroundPositionZ(destX, destY, destZ); - Position pos; - pos.Relocate(destX, destY, destZ, 0.0f); - if (TempSummon* summ = me->SummonCreature(NPC_FROST_BOMB, pos, TEMPSUMMON_TIMED_DESPAWN, 40000)) - { - summ->CastSpell(summ, SPELL_FROST_BOMB_VISUAL, true); - DoCast(summ, SPELL_FROST_BOMB_TRIGGER); - //me->CastSpell(destX, destY, destZ, SPELL_FROST_BOMB_TRIGGER, false); - } - events.ScheduleEvent(EVENT_FROST_BOMB, urand(5000, 10000)); + me->CastSpell(destX, destY, destZ, SPELL_FROST_BOMB_TRIGGER, false); + events.ScheduleEvent(EVENT_FROST_BOMB, urand(6000, 8000)); break; } case EVENT_LAND: { events.CancelEvent(EVENT_FROST_BOMB); - me->GetMotionMaster()->MovePoint(POINT_LAND, SindragosaLandPos); + me->GetMotionMaster()->MovePoint(POINT_LAND, SindragosaFlyInPos); break; } + case EVENT_LAND_GROUND: + events.ScheduleEvent(EVENT_CLEAVE, urand(13000, 15000), EVENT_GROUP_LAND_PHASE); + events.ScheduleEvent(EVENT_TAIL_SMASH, urand(19000, 23000), EVENT_GROUP_LAND_PHASE); + events.ScheduleEvent(EVENT_FROST_BREATH, urand(10000, 15000), EVENT_GROUP_LAND_PHASE); + events.ScheduleEvent(EVENT_UNCHAINED_MAGIC, urand(12000, 17000), EVENT_GROUP_LAND_PHASE); + events.ScheduleEvent(EVENT_ICY_GRIP, urand(35000, 40000), EVENT_GROUP_LAND_PHASE); + me->GetMotionMaster()->MoveLand(POINT_LAND_GROUND, SindragosaLandPos, 0.0f); + break; case EVENT_THIRD_PHASE_CHECK: { if (!_isInAirPhase) @@ -670,6 +713,7 @@ class npc_spinestalker : public CreatureScript me->SetDisableGravity(false); me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); me->SetHomePosition(SpinestalkerLandPos); + me->SetFacingTo(SpinestalkerLandPos.GetOrientation()); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } @@ -796,6 +840,7 @@ class npc_rimefang : public CreatureScript me->SetDisableGravity(false); me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); me->SetHomePosition(RimefangLandPos); + me->SetFacingTo(RimefangLandPos.GetOrientation()); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); } @@ -1054,10 +1099,10 @@ class spell_sindragosa_unchained_magic : public SpellScriptLoader void FilterTargets(std::list<Unit*>& unitList) { - unitList.remove_if (UnchainedMagicTargetSelector()); - uint32 maxSize = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 5 : 2); + unitList.remove_if(UnchainedMagicTargetSelector()); + uint32 maxSize = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 6 : 2); if (unitList.size() > maxSize) - Trinity::RandomResizeList(unitList, maxSize); + Trinity::Containers::RandomResizeList(unitList, maxSize); } void Register() @@ -1240,6 +1285,46 @@ class spell_sindragosa_icy_grip : public SpellScriptLoader } }; +class MysticBuffetTargetFilter +{ + public: + explicit MysticBuffetTargetFilter(Unit* caster) : _caster(caster) { } + + bool operator()(Unit* unit) + { + return !unit->IsWithinLOSInMap(_caster); + } + + private: + Unit* _caster; +}; + +class spell_sindragosa_mystic_buffet : public SpellScriptLoader +{ + public: + spell_sindragosa_mystic_buffet() : SpellScriptLoader("spell_sindragosa_mystic_buffet") { } + + class spell_sindragosa_mystic_buffet_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sindragosa_mystic_buffet_SpellScript); + + void FilterTargets(std::list<Unit*>& unitList) + { + unitList.remove_if(MysticBuffetTargetFilter(GetCaster())); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_sindragosa_mystic_buffet_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_sindragosa_mystic_buffet_SpellScript(); + } +}; + class spell_rimefang_icy_blast : public SpellScriptLoader { public: @@ -1321,7 +1406,7 @@ class spell_frostwarden_handler_order_whelp : public SpellScriptLoader if (unitList.empty()) return; - Unit* target = SelectRandomContainerElement(unitList); + Unit* target = Trinity::Containers::SelectRandomContainerElement(unitList); unitList.clear(); unitList.push_back(target); } @@ -1338,7 +1423,7 @@ class spell_frostwarden_handler_order_whelp : public SpellScriptLoader if (unitList.empty()) return; - SelectRandomContainerElement(unitList)->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); + Trinity::Containers::SelectRandomContainerElement(unitList)->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); } void Register() @@ -1465,6 +1550,7 @@ void AddSC_boss_sindragosa() new spell_sindragosa_frost_beacon(); new spell_sindragosa_ice_tomb(); new spell_sindragosa_icy_grip(); + new spell_sindragosa_mystic_buffet(); new spell_rimefang_icy_blast(); new spell_frostwarden_handler_order_whelp(); new spell_frostwarden_handler_focus_fire(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 90ee6e1af71..2eb894a5153 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -554,7 +554,8 @@ class boss_the_lich_king : public CreatureScript if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) tirion->AI()->EnterEvadeMode(); DoCastAOE(SPELL_KILL_FROSTMOURNE_PLAYERS); - summons.DoAction(NPC_STRANGULATE_VEHICLE, ACTION_TELEPORT_BACK); + EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE); + summons.DoAction(ACTION_TELEPORT_BACK, pred); } void KilledUnit(Unit* victim) @@ -595,12 +596,15 @@ class boss_the_lich_king : public CreatureScript events.ScheduleEvent(EVENT_OUTRO_TALK_8, 17000, 0, PHASE_OUTRO); break; case ACTION_TELEPORT_BACK: - summons.DoAction(NPC_STRANGULATE_VEHICLE, ACTION_TELEPORT_BACK); + { + EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE); + summons.DoAction(ACTION_TELEPORT_BACK, pred); if (!IsHeroic()) Talk(SAY_LK_FROSTMOURNE_ESCAPE); else DoCastAOE(SPELL_TRIGGER_VILE_SPIRIT_HEROIC); break; + } default: break; } @@ -2550,7 +2554,7 @@ class spell_the_lich_king_valkyr_target_search : public SpellScriptLoader if (unitList.empty()) return; - _target = SelectRandomContainerElement(unitList); + _target = Trinity::Containers::SelectRandomContainerElement(unitList); unitList.clear(); unitList.push_back(_target); GetCaster()->GetAI()->SetGUID(_target->GetGUID()); @@ -2758,7 +2762,7 @@ class spell_the_lich_king_vile_spirit_move_target_search : public SpellScriptLoa if (targets.empty()) return; - _target = SelectRandomContainerElement(targets); + _target = Trinity::Containers::SelectRandomContainerElement(targets); } void HandleScript(SpellEffIndex effIndex) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index af2eb57b7c3..ed1ca4d20fb 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -1196,7 +1196,7 @@ class spell_dreamwalker_summoner : public SpellScriptLoader if (targets.empty()) return; - Unit* target = SelectRandomContainerElement(targets); + Unit* target = Trinity::Containers::SelectRandomContainerElement(targets); targets.clear(); targets.push_back(target); } @@ -1242,7 +1242,7 @@ class spell_dreamwalker_summon_suppresser : public SpellScriptLoader std::list<Creature*> summoners; GetCreatureListWithEntryInGrid(summoners, caster, NPC_WORLD_TRIGGER, 100.0f); summoners.remove_if (Trinity::UnitAuraCheck(true, SPELL_RECENTLY_SPAWNED)); - Trinity::RandomResizeList(summoners, 2); + Trinity::Containers::RandomResizeList(summoners, 2); if (summoners.empty()) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 5720ce0e423..8d562a23f67 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -796,7 +796,8 @@ class boss_sister_svalna : public CreatureScript { _JustReachedHome(); me->SetReactState(REACT_PASSIVE); - me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetHover(false); } void DoAction(int32 const action) @@ -838,13 +839,14 @@ class boss_sister_svalna : public CreatureScript void MovementInform(uint32 type, uint32 id) { - if (type != POINT_MOTION_TYPE || id != POINT_LAND) + if (type != EFFECT_MOTION_TYPE || id != POINT_LAND) return; _isEventInProgress = false; me->setActive(false); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); - me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetHover(false); } void SpellHitTarget(Unit* target, SpellInfo const* spell) @@ -1368,7 +1370,7 @@ class npc_captain_arnath : public CreatureScript case EVENT_ARNATH_PW_SHIELD: { std::list<Creature*> targets = DoFindFriendlyMissingBuff(40.0f, SPELL_POWER_WORD_SHIELD); - DoCast(SelectRandomContainerElement(targets), SPELL_POWER_WORD_SHIELD); + DoCast(Trinity::Containers::SelectRandomContainerElement(targets), SPELL_POWER_WORD_SHIELD); Events.ScheduleEvent(EVENT_ARNATH_PW_SHIELD, urand(15000, 20000)); break; } @@ -1822,7 +1824,7 @@ class spell_frost_giant_death_plague : public SpellScriptLoader unitList.remove_if (DeathPlagueTargetSelector(GetCaster())); if (!unitList.empty()) { - Unit* target = SelectRandomContainerElement(unitList); + Unit* target = Trinity::Containers::SelectRandomContainerElement(unitList); unitList.clear(); unitList.push_back(target); } @@ -1909,7 +1911,7 @@ class spell_svalna_revive_champion : public SpellScriptLoader void RemoveAliveTarget(std::list<Unit*>& unitList) { unitList.remove_if(AliveCheck()); - Trinity::RandomResizeList(unitList, 2); + Trinity::Containers::RandomResizeList(unitList, 2); } void Land(SpellEffIndex /*effIndex*/) @@ -1921,10 +1923,10 @@ class spell_svalna_revive_champion : public SpellScriptLoader Position pos; caster->GetPosition(&pos); caster->GetNearPosition(pos, 5.0f, 0.0f); - pos.m_positionZ = caster->GetBaseMap()->GetHeight(caster->GetPhaseMask(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 20.0f); - pos.m_positionZ += 0.05f; + //pos.m_positionZ = caster->GetBaseMap()->GetHeight(caster->GetPhaseMask(), pos.GetPositionX(), pos.GetPositionY(), caster->GetPositionZ(), true, 50.0f); + //pos.m_positionZ += 0.05f; caster->SetHomePosition(pos); - caster->GetMotionMaster()->MovePoint(POINT_LAND, pos); + caster->GetMotionMaster()->MoveLand(POINT_LAND, pos, caster->GetSpeed(MOVE_FLIGHT)); } void Register() diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp index 132ecdafa5a..8d23de5427c 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp @@ -424,7 +424,8 @@ class boss_gothik : public CreatureScript { if (instance) instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE); - summons.DoAction(0, 0); + DummyEntryCheckPredicate pred; + summons.DoAction(0, pred); //! Magic numbers fail summons.DoZoneInCombat(); mergedSides = true; } @@ -447,7 +448,8 @@ class boss_gothik : public CreatureScript DoScriptText(SAY_TELEPORT, me); DoTeleportTo(PosGroundLiveSide); me->SetReactState(REACT_AGGRESSIVE); - summons.DoAction(0, 0); + DummyEntryCheckPredicate pred; + summons.DoAction(0, pred); //! Magic numbers fail summons.DoZoneInCombat(); events.ScheduleEvent(EVENT_BOLT, 1000); events.ScheduleEvent(EVENT_HARVEST, urand(3000, 15000)); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon.cpp deleted file mode 100644 index 2dd13e7ce07..00000000000 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "ulduar.h" - -#define GAMEOBJECT_GIVE_OF_THE_OBSERVER 194821 - -enum Spells -{ - SPELL_ASCEND = 64487, - SPELL_BERSERK = 47008, - SPELL_BIG_BANG = 64443, - H_SPELL_BIG_BANG = 64584, - SPELL_COSMIC_SMASH = 62301, - H_SPELL_COSMIC_SMASH = 64598, - SPELL_PHASE_PUNCH = 64412, - SPELL_QUANTUM_STRIKE = 64395, - H_SPELL_QUANTUM_STRIKE = 64592, - SPELL_BLACK_HOLE_EXPLOSION = 64122, - SPELL_ARCANE_BARAGE = 64599, - H_SPELL_ARCANE_BARAGE = 64607 -}; - -enum Creatures -{ - CREATURE_COLLAPSING_STAR = 32955, - CREATURE_BLACK_HOLE = 32953, - CREATURE_LIVING_CONSTELLATION = 33052, - CREATURE_DARK_MATTER = 33089 -}; - -enum Yells -{ - SAY_AGGRO = -1603000, - SAY_SLAY_1 = -1603001, - SAY_SLAY_2 = -1603002, - SAY_ENGADED_FOR_FIRTS_TIME = -1603003, - SAY_PHASE_2 = -1603004, - SAY_SUMMON_COLLAPSING_STAR = -1603005, - SAY_DEATH_1 = -1603006, - SAY_DEATH_2 = -1603007, - SAY_DEATH_3 = -1603008, - SAY_DEATH_4 = -1603009, - SAY_DEATH_5 = -1603010, - SAY_BERSERK = -1603011, - SAY_BIG_BANG_1 = -1603012, - SAY_BIG_BANG_2 = -1603013, - SAY_TIMER_1 = -1603014, - SAY_TIMER_2 = -1603015, - SAY_TIMER_3 = -1603016, - SAY_SUMMON_1 = -1603017, - SAY_SUMMON_2 = -1603018, - SAY_SUMMON_3 = -1603019, -}; - -class boss_algalon : public CreatureScript -{ -public: - boss_algalon() : CreatureScript("boss_algalon") { } - - CreatureAI* GetAI(Creature* creature) const - { - return GetUlduarAI<boss_algalonAI>(creature); - } - - struct boss_algalonAI : public ScriptedAI - { - boss_algalonAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - Summon = false; // not in reset. intro speech done only once. - } - - InstanceScript* instance; - - std::list<uint64> m_lCollapsingStarGUIDList; - - uint32 Phase; - uint32 Ascend_Timer; - uint32 Berserk_Timer; - uint32 BigBang_Timer; - uint32 CosmicSmash_Timer; - uint32 PhasePunch_Timer; - uint32 QuantumStrike_Timer; - uint32 CollapsingStar_Timer; - uint32 uiPhase_timer; - uint32 uiStep; - - uint64 BlackHoleGUID; - - bool Enrage; - bool Summon; - - void EnterCombat(Unit* who) - { - if (Summon) - { - DoScriptText(SAY_AGGRO, me); - me->InterruptSpell(CURRENT_CHANNELED_SPELL); - DoZoneInCombat(who->ToCreature()); - } - else - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_PASSIVE); - uiStep = 1; - } - - if (instance) - instance->SetData(BOSS_ALGALON, IN_PROGRESS); - } - - void KilledUnit(Unit* /*victim*/) - { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me); - } - - void Reset() - { - Phase = 1; - - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if (instance) - instance->SetData(BOSS_ALGALON, NOT_STARTED); - - BlackHoleGUID = 0; - - uiPhase_timer = 0; - Ascend_Timer = 480000; //8 minutes - QuantumStrike_Timer = urand(4000, 14000); - Berserk_Timer = 360000; //6 minutes - CollapsingStar_Timer = urand(15000, 20000); //Spawns between 15 to 20 seconds - BigBang_Timer = 90000; - PhasePunch_Timer = 8000; - CosmicSmash_Timer = urand(30000, 60000); - Enrage = false; - } - - void JumpToNextStep(uint32 uiTimer) - { - uiPhase_timer = uiTimer; - ++uiStep; - } - - void DespawnCollapsingStar() - { - if (m_lCollapsingStarGUIDList.empty()) - return; - - for (std::list<uint64>::const_iterator itr = m_lCollapsingStarGUIDList.begin(); itr != m_lCollapsingStarGUIDList.end(); ++itr) - { - if (Creature* temp = Unit::GetCreature(*me, *itr)) - { - if (temp->isAlive()) - temp->DespawnOrUnsummon(); - } - } - m_lCollapsingStarGUIDList.clear(); - } - - void JustSummoned(Creature* summoned) - { - if (summoned->GetEntry() == CREATURE_COLLAPSING_STAR) - { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (me->getVictim()) - summoned->AI()->AttackStart(target ? target : me->getVictim()); - m_lCollapsingStarGUIDList.push_back(summoned->GetGUID()); - } - } - - void SummonCollapsingStar(Unit* target) - { - DoScriptText(SAY_SUMMON_COLLAPSING_STAR, me); - me->SummonCreature(CREATURE_COLLAPSING_STAR, target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 100000); - me->SummonCreature(CREATURE_BLACK_HOLE, target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 27000); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (Phase == 1 && HealthBelowPct(20)) - { - Phase = 2; - DoScriptText(SAY_PHASE_2, me); - } - - if (HealthBelowPct(2)) - { - me->SummonGameObject(GAMEOBJECT_GIVE_OF_THE_OBSERVER, 1634.258667f, -295.101166f, 417.321381f, 0, 0, 0, 0, 0, 0); - - // All of them. or random? - DoScriptText(SAY_DEATH_1, me); - DoScriptText(SAY_DEATH_2, me); - DoScriptText(SAY_DEATH_3, me); - DoScriptText(SAY_DEATH_4, me); - DoScriptText(SAY_DEATH_5, me); - - me->DisappearAndDie(); - - if (instance) - instance->SetData(BOSS_ALGALON, DONE); - - return; - } - - if (Phase == 1) - { - if (!Summon) - { - if (uiPhase_timer <= diff) - { - switch (uiStep) - { - case 1: - DoScriptText(SAY_SUMMON_1, me); - JumpToNextStep(3000); - break; - case 2: - DoScriptText(SAY_SUMMON_2, me); - JumpToNextStep(3000); - break; - case 3: - DoScriptText(SAY_SUMMON_3, me); - JumpToNextStep(3000); - break; - case 4: - DoScriptText(SAY_ENGADED_FOR_FIRTS_TIME, me); - JumpToNextStep(3000); - break; - case 5: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_AGGRESSIVE); - Summon = true; - break; - } - } else uiPhase_timer -= diff; - - return; - } - - if (QuantumStrike_Timer <= diff) - { - DoCast(me->getVictim(), RAID_MODE(SPELL_QUANTUM_STRIKE, H_SPELL_QUANTUM_STRIKE), true); - - QuantumStrike_Timer = urand(4000, 14000); - } else QuantumStrike_Timer -= diff; - - if (BigBang_Timer <= diff) - { - DoScriptText(RAND(SAY_BIG_BANG_1, SAY_BIG_BANG_2), me); - DoCast(me->getVictim(), RAID_MODE(SPELL_BIG_BANG, H_SPELL_BIG_BANG), true); - - BigBang_Timer = 90000; - } else BigBang_Timer -= diff; - - if (Ascend_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_ASCEND, true); - - Ascend_Timer = 480000; - } else Ascend_Timer -= diff; - - if (PhasePunch_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_PHASE_PUNCH, true); - - PhasePunch_Timer = 8000; - } else PhasePunch_Timer -= diff; - - if (CosmicSmash_Timer <= diff) - { - DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), RAID_MODE(SPELL_COSMIC_SMASH, H_SPELL_COSMIC_SMASH), true); - - CosmicSmash_Timer = urand(30000, 60000); - } else CosmicSmash_Timer -= diff; - - if (Berserk_Timer <= diff) - { - DoScriptText(SAY_BERSERK, me); - DoCast(me->getVictim(), SPELL_BERSERK, true); - - Berserk_Timer = 360000; - } else Berserk_Timer -= diff; - - DoMeleeAttackIfReady(); - - EnterEvadeIfOutOfCombatArea(diff); - } - - if (Phase == 2) - { - if (Enrage) - { - if (Ascend_Timer <= diff) - { - DoCast(me, SPELL_ASCEND); - DoScriptText(SAY_BERSERK, me); - Ascend_Timer = urand(360000, 365000); - Enrage = false; - } else Ascend_Timer -= diff; - } - } - - DoMeleeAttackIfReady(); - } - }; - -}; - -//Collapsing Star -class mob_collapsing_star : public CreatureScript -{ -public: - mob_collapsing_star() : CreatureScript("mob_collapsing_star") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new mob_collapsing_starAI(creature); - } - - struct mob_collapsing_starAI : public ScriptedAI - { - mob_collapsing_starAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 BlackHoleExplosion_Timer; - - void Reset() - { - BlackHoleExplosion_Timer = 0; - } - - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim()) - return; - - if (BlackHoleExplosion_Timer <= diff) - { - me->CastSpell(me, SPELL_BLACK_HOLE_EXPLOSION, false); - BlackHoleExplosion_Timer = 0; - } else BlackHoleExplosion_Timer -= diff; - } - }; - -}; - -void AddSC_boss_Algalon() -{ - new boss_algalon(); - new mob_collapsing_star(); -} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp new file mode 100644 index 00000000000..6f87d7fcd2a --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -0,0 +1,1374 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "PassiveAI.h" +#include "GameObjectAI.h" +#include "MapManager.h" +#include "MoveSplineInit.h" +#include "ulduar.h" + +enum Texts +{ + SAY_BRANN_ALGALON_INTRO_1 = 0, + SAY_BRANN_ALGALON_INTRO_2 = 1, + SAY_BRANN_ALGALON_OUTRO = 2, + + SAY_ALGALON_INTRO_1 = 0, + SAY_ALGALON_INTRO_2 = 1, + SAY_ALGALON_INTRO_3 = 2, + SAY_ALGALON_START_TIMER = 3, + SAY_ALGALON_AGGRO = 4, + SAY_ALGALON_COLLAPSING_STAR = 5, + EMOTE_ALGALON_COLLAPSING_STAR = 6, + SAY_ALGALON_BIG_BANG = 7, + EMOTE_ALGALON_BIG_BANG = 8, + SAY_ALGALON_ASCEND = 9, + EMOTE_ALGALON_COSMIC_SMASH = 10, + SAY_ALGALON_PHASE_TWO = 11, + SAY_ALGALON_OUTRO_1 = 12, + SAY_ALGALON_OUTRO_2 = 13, + SAY_ALGALON_OUTRO_3 = 14, + SAY_ALGALON_OUTRO_4 = 15, + SAY_ALGALON_OUTRO_5 = 16, + SAY_ALGALON_DESPAWN_1 = 17, + SAY_ALGALON_DESPAWN_2 = 18, + SAY_ALGALON_DESPAWN_3 = 19, + SAY_ALGALON_KILL = 20, +}; + +enum Spells +{ + // Algalon the Observer + SPELL_ARRIVAL = 64997, + SPELL_RIDE_THE_LIGHTNING = 64986, + SPELL_SUMMON_AZEROTH = 64994, + SPELL_REORIGINATION = 64996, + SPELL_SUPERMASSIVE_FAIL = 65311, + SPELL_QUANTUM_STRIKE = 64395, + SPELL_PHASE_PUNCH = 64412, + SPELL_BIG_BANG = 64443, + SPELL_ASCEND_TO_THE_HEAVENS = 64487, + SPELL_COSMIC_SMASH = 62301, + SPELL_COSMIC_SMASH_TRIGGERED = 62304, + SPELL_COSMIC_SMASH_VISUAL_STATE = 62300, + SPELL_SELF_STUN = 65256, + SPELL_KILL_CREDIT = 65184, + SPELL_TELEPORT = 62940, + + // Algalon Stalker + SPELL_TRIGGER_3_ADDS = 62266, // Triggers Living Constellation + + // Living Constellation + SPELL_ARCANE_BARRAGE = 64599, + + // Collapsing Star + SPELL_COLLAPSE = 62018, + SPELL_BLACK_HOLE_SPAWN_VISUAL = 62003, + SPELL_SUMMON_BLACK_HOLE = 62189, + + // Black Hole + SPELL_BLACK_HOLE_TRIGGER = 62185, + SPELL_CONSTELLATION_PHASE_TRIGGER = 65508, + SPELL_CONSTELLATION_PHASE_EFFECT = 65509, + SPELL_BLACK_HOLE_EXPLOSION = 64122, + SPELL_SUMMON_VOID_ZONE_VISUAL = 64470, + SPELL_VOID_ZONE_VISUAL = 64469, + SPELL_BLACK_HOLE_CREDIT = 65312, + + // Worm Hole + SPELL_WORM_HOLE_TRIGGER = 65251, + SPELL_SUMMON_UNLEASHED_DARK_MATTER = 64450, +}; + +uint32 const PhasePunchAlphaId[5] = {64435, 64434, 64428, 64421, 64417}; + +enum Events +{ + // Celestial Planetarium Access + EVENT_DESPAWN_CONSOLE = 1, + + // Brann Bronzebeard + EVENT_BRANN_MOVE_INTRO = 2, + EVENT_SUMMON_ALGALON = 3, + EVENT_BRANN_OUTRO_1 = 4, + EVENT_BRANN_OUTRO_2 = 5, + + // Algalon the Observer + EVENT_INTRO_1 = 6, + EVENT_INTRO_2 = 7, + EVENT_INTRO_3 = 8, + EVENT_INTRO_FINISH = 9, + EVENT_START_COMBAT = 10, + EVENT_INTRO_TIMER_DONE = 11, + EVENT_QUANTUM_STRIKE = 12, + EVENT_PHASE_PUNCH = 13, + EVENT_SUMMON_COLLAPSING_STAR = 14, + EVENT_BIG_BANG = 15, + EVENT_RESUME_UPDATING = 16, + EVENT_ASCEND_TO_THE_HEAVENS = 17, + EVENT_EVADE = 18, + EVENT_COSMIC_SMASH = 19, + EVENT_UNLOCK_YELL = 20, + EVENT_OUTRO_START = 21, + EVENT_OUTRO_1 = 22, + EVENT_OUTRO_2 = 23, + EVENT_OUTRO_3 = 24, + EVENT_OUTRO_4 = 25, + EVENT_OUTRO_5 = 26, + EVENT_OUTRO_6 = 27, + EVENT_OUTRO_7 = 28, + EVENT_OUTRO_8 = 29, + EVENT_OUTRO_9 = 30, + EVENT_OUTRO_10 = 31, + EVENT_OUTRO_11 = 32, + EVENT_OUTRO_12 = 33, + EVENT_OUTRO_13 = 34, + EVENT_OUTRO_14 = 35, + EVENT_DESPAWN_ALGALON_1 = 36, + EVENT_DESPAWN_ALGALON_2 = 37, + EVENT_DESPAWN_ALGALON_3 = 38, + + // Living Constellation + EVENT_ARCANE_BARRAGE = 39, +}; + +enum Actions +{ + ACTION_START_INTRO = 0, + ACTION_FINISH_INTRO = 1, + ACTION_ACTIVATE_STAR = 2, + ACTION_BIG_BANG = 3, + ACTION_ASCEND = 4, + ACTION_OUTRO = 5, +}; + +enum Points +{ + POINT_BRANN_INTRO = 0, + MAX_BRANN_WAYPOINTS_INTRO = 10, + POINT_BRANN_OUTRO = 10, + POINT_BRANN_OUTRO_END = 11, + + POINT_ALGALON_LAND = 1, + POINT_ALGALON_OUTRO = 2, +}; + +enum EncounterPhases +{ + PHASE_NORMAL = 0, + PHASE_ROLE_PLAY = 1, + PHASE_BIG_BANG = 2, + + PHASE_MASK_NO_UPDATE = (1 << PHASE_ROLE_PLAY) | (1 << PHASE_BIG_BANG), + PHASE_MASK_NO_CAST_CHECK = 1 << PHASE_ROLE_PLAY, +}; + +enum AchievmentInfo +{ + EVENT_ID_SUPERMASSIVE_START = 21697, + DATA_HAS_FED_ON_TEARS = 30043005, +}; + + +Position const BrannIntroSpawnPos = {1676.277f, -162.5308f, 427.3326f, 3.235537f}; +Position const BrannIntroWaypoint[MAX_BRANN_WAYPOINTS_INTRO] = +{ + {1642.482f, -164.0812f, 427.2602f, 0.0f}, + {1635.000f, -169.5145f, 427.2523f, 0.0f}, + {1632.814f, -173.9334f, 427.2621f, 0.0f}, + {1632.676f, -190.5927f, 425.8831f, 0.0f}, + {1631.497f, -214.2221f, 418.1152f, 0.0f}, + {1624.717f, -224.6876f, 418.1152f, 0.0f}, + {1631.497f, -214.2221f, 418.1152f, 0.0f}, + {1632.676f, -190.5927f, 425.8831f, 0.0f}, + {1632.814f, -173.9334f, 427.2621f, 0.0f}, + {1635.000f, -169.5145f, 427.2523f, 0.0f}, +}; +Position const AlgalonSummonPos = {1632.531f, -304.8516f, 450.1123f, 1.530165f}; +Position const AlgalonLandPos = {1632.668f, -302.7656f, 417.3211f, 1.530165f}; + +#define LIVING_CONSTELLATION_COUNT 11 +Position const ConstellationPos[LIVING_CONSTELLATION_COUNT] = +{ + {1625.208f, -267.2771f, 446.4296f, 5.044002f}, + {1658.279f, -262.5490f, 441.9073f, 4.188790f}, + {1678.677f, -276.3280f, 427.7531f, 3.979351f}, + {1593.389f, -299.4325f, 432.4636f, 6.073746f}, + {1685.613f, -300.1219f, 443.2366f, 3.385939f}, + {1591.706f, -263.8201f, 441.4153f, 5.253441f}, + {1668.317f, -324.7676f, 457.9394f, 3.211406f}, + {1592.242f, -325.5323f, 446.9508f, 0.226893f}, + {1635.821f, -363.3442f, 424.3459f, 1.466077f}, + {1672.188f, -357.2484f, 436.7337f, 2.338741f}, + {1615.800f, -348.0065f, 442.9586f, 1.134464f}, +}; + +#define COLLAPSING_STAR_COUNT 4 +Position const CollapsingStarPos[COLLAPSING_STAR_COUNT] = +{ + {1649.438f, -319.8127f, 418.3941f, 1.082104f}, + {1647.005f, -288.6790f, 417.3955f, 3.490659f}, + {1622.451f, -321.1563f, 417.6188f, 4.677482f}, + {1615.060f, -291.6816f, 417.7796f, 3.490659f}, +}; +Position const AlgalonOutroPos = {1633.64f, -317.78f, 417.3211f, 0.0f}; +Position const BrannOutroPos[3] = +{ + {1632.023f, -243.7434f, 417.9118f, 0.0f}, + {1631.986f, -297.7831f, 417.3210f, 0.0f}, + {1633.832f, -216.2948f, 417.0463f, 0.0f}, +}; + +class ActivateLivingConstellation : public BasicEvent +{ + public: + ActivateLivingConstellation(Unit* owner) : _owner(owner), _instance(owner->GetInstanceScript()) + { + } + + bool Execute(uint64 execTime, uint32 /*diff*/) + { + if (!_instance || _instance->GetBossState(BOSS_ALGALON) != IN_PROGRESS) + return true; // delete event + + _owner->CastSpell((Unit*)NULL, SPELL_TRIGGER_3_ADDS, TRIGGERED_FULL_MASK); + _owner->m_Events.AddEvent(this, execTime + urand(45000, 50000)); + return false; + } + + private: + Unit* _owner; + InstanceScript* _instance; +}; + +class CosmicSmashDamageEvent : public BasicEvent +{ + public: + CosmicSmashDamageEvent(Unit* caster) : _caster(caster) + { + } + + bool Execute(uint64 /*execTime*/, uint32 /*diff*/) + { + _caster->CastSpell((Unit*)NULL, SPELL_COSMIC_SMASH_TRIGGERED, TRIGGERED_FULL_MASK); + return true; + } + + private: + Unit* _caster; +}; + +class SummonUnleashedDarkMatter : public BasicEvent +{ + public: + SummonUnleashedDarkMatter(Unit* caster) : _caster(caster) + { + } + + bool Execute(uint64 execTime, uint32 /*diff*/) + { + _caster->CastSpell((Unit*)NULL, SPELL_SUMMON_UNLEASHED_DARK_MATTER, TRIGGERED_FULL_MASK); + _caster->m_Events.AddEvent(this, execTime + 30000); + return false; + } + + private: + Unit* _caster; +}; + +class boss_algalon_the_observer : public CreatureScript +{ + public: + boss_algalon_the_observer() : CreatureScript("boss_algalon_the_observer") {} + + struct boss_algalon_the_observerAI : public BossAI + { + boss_algalon_the_observerAI(Creature* creature) : BossAI(creature, BOSS_ALGALON) + { + _firstPull = true; + _fedOnTears = false; + } + + void Reset() + { + _Reset(); + me->SetReactState(REACT_PASSIVE); + _phaseTwo = false; + _fightWon = false; + _hasYelled = false; + } + + void KilledUnit(Unit* victim) + { + if (victim->GetTypeId() == TYPEID_UNIT) + { + _fedOnTears = true; + if (!_hasYelled) + { + _hasYelled = true; + events.ScheduleEvent(EVENT_UNLOCK_YELL, 1000); + Talk(SAY_ALGALON_KILL); + } + } + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_START_INTRO: + { + me->SetFlag(UNIT_FIELD_FLAGS_2, 0x20); + me->SetDisableGravity(true); + DoCast(me, SPELL_ARRIVAL, true); + DoCast(me, SPELL_RIDE_THE_LIGHTNING, true); + me->GetMotionMaster()->MovePoint(POINT_ALGALON_LAND, AlgalonLandPos); + me->SetHomePosition(AlgalonLandPos); + Movement::MoveSplineInit init(*me); + init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ()); + init.SetOrientationFixed(true); + init.Launch(); + events.Reset(); + events.SetPhase(PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_INTRO_1, 5000, 0, PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_INTRO_2, 15000, 0, PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_INTRO_3, 23000, 0, PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_INTRO_FINISH, 36000, 0, PHASE_ROLE_PLAY); + break; + } + case ACTION_ASCEND: + events.SetPhase(PHASE_BIG_BANG); + events.CancelEvent(EVENT_RESUME_UPDATING); + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1500); + break; + case EVENT_DESPAWN_ALGALON: + events.Reset(); + events.SetPhase(PHASE_ROLE_PLAY); + if (me->isInCombat()) + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_1, 5000); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_2, 17000); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_3, 26000); + me->DespawnOrUnsummon(34000); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_NPC); + break; + case ACTION_INIT_ALGALON: + _firstPull = false; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + break;; + } + } + + uint32 GetData(uint32 type) + { + return type == DATA_HAS_FED_ON_TEARS ? _fedOnTears : 1; + } + + void EnterCombat(Unit* /*target*/) + { + uint32 introDelay = 0; + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_NPC); + events.Reset(); + events.SetPhase(PHASE_ROLE_PLAY); + + if (!_firstPull) + { + Talk(SAY_ALGALON_AGGRO); + _EnterCombat(); + introDelay = 8000; + } + else + { + _firstPull = false; + Talk(SAY_ALGALON_START_TIMER); + if (Creature* brann = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BRANN_BRONZEBEARD_ALG))) + brann->AI()->DoAction(ACTION_FINISH_INTRO); + + me->setActive(true); + DoZoneInCombat(); + introDelay = 26000; + summons.DespawnEntry(NPC_AZEROTH); + instance->SetData(EVENT_DESPAWN_ALGALON, 0); + events.ScheduleEvent(EVENT_START_COMBAT, 18000); + } + + events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay); + events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500 + introDelay); + events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500 + introDelay); + events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 18000 + introDelay); + events.ScheduleEvent(EVENT_BIG_BANG, 90000 + introDelay); + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360000 + introDelay); + events.ScheduleEvent(EVENT_COSMIC_SMASH, 25000 + introDelay); + + std::list<Creature*> stalkers; + me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); + for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr) + (*itr)->m_Events.KillAllEvents(true); + } + + void MovementInform(uint32 movementType, uint32 pointId) + { + if (movementType != POINT_MOTION_TYPE) + return; + + if (pointId == POINT_ALGALON_LAND) + me->SetDisableGravity(false); + else if (pointId == POINT_ALGALON_OUTRO) + { + me->SetFacingTo(1.605703f); + events.ScheduleEvent(EVENT_OUTRO_3, 1200); + events.ScheduleEvent(EVENT_OUTRO_4, 2400); + events.ScheduleEvent(EVENT_OUTRO_5, 8500); + events.ScheduleEvent(EVENT_OUTRO_6, 15500); + events.ScheduleEvent(EVENT_OUTRO_7, 55500); + events.ScheduleEvent(EVENT_OUTRO_8, 73500); + events.ScheduleEvent(EVENT_OUTRO_9, 85500); + events.ScheduleEvent(EVENT_OUTRO_10, 108500); + events.ScheduleEvent(EVENT_OUTRO_11, 123500); + } + } + + void JustSummoned(Creature* summon) + { + summons.Summon(summon); + switch (summon->GetEntry()) + { + case NPC_AZEROTH: + DoCastAOE(SPELL_REORIGINATION, true); + break; + case NPC_COLLAPSING_STAR: + summon->SetReactState(REACT_PASSIVE); + summon->GetMotionMaster()->MoveRandom(20.0f); + summon->CastSpell(summon, SPELL_COLLAPSE, TRIGGERED_FULL_MASK); + break; + case NPC_BLACK_HOLE: + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell((Unit*)NULL, SPELL_BLACK_HOLE_TRIGGER, TRIGGERED_FULL_MASK); + summon->CastSpell(summon, SPELL_CONSTELLATION_PHASE_TRIGGER, TRIGGERED_FULL_MASK); + summon->CastSpell((Unit*)NULL, SPELL_BLACK_HOLE_EXPLOSION); + summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); + break; + case NPC_ALGALON_VOID_ZONE_VISUAL_STALKER: + summon->CastSpell(summon, SPELL_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); + break; + case NPC_ALGALON_STALKER_ASTEROID_TARGET_01: + summon->CastSpell(summon, SPELL_COSMIC_SMASH_VISUAL_STATE, TRIGGERED_FULL_MASK); + break; + case NPC_ALGALON_STALKER_ASTEROID_TARGET_02: + summon->m_Events.AddEvent(new CosmicSmashDamageEvent(summon), summon->m_Events.CalculateTime(3250)); + break; + case NPC_WORM_HOLE: + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_WORM_HOLE_TRIGGER, TRIGGERED_FULL_MASK); + summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); + break; + case NPC_UNLEASHED_DARK_MATTER: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + if (summon->Attack(target, true)) + summon->GetMotionMaster()->MoveChase(target); + break; + } + } + + void EnterEvadeMode() + { + instance->SetBossState(BOSS_ALGALON, FAIL); + BossAI::EnterEvadeMode(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + me->SetSheath(SHEATH_STATE_UNARMED); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (_fightWon) + { + damage = 0; + return; + } + + if (!_phaseTwo && me->HealthBelowPctDamaged(20, damage)) + { + _phaseTwo = true; + Talk(SAY_ALGALON_PHASE_TWO); + summons.DespawnEntry(NPC_LIVING_CONSTELLATION); + summons.DespawnEntry(NPC_COLLAPSING_STAR); + summons.DespawnEntry(NPC_BLACK_HOLE); + summons.DespawnEntry(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER); + events.CancelEvent(EVENT_SUMMON_COLLAPSING_STAR); + std::list<Creature*> stalkers; + me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); + for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr) + (*itr)->m_Events.KillAllEvents(true); + for (uint32 i = 0; i < COLLAPSING_STAR_COUNT; ++i) + if (Creature* wormHole = DoSummon(NPC_WORM_HOLE, CollapsingStarPos[i], TEMPSUMMON_MANUAL_DESPAWN)) + wormHole->m_Events.AddEvent(new SummonUnleashedDarkMatter(wormHole), wormHole->m_Events.CalculateTime(i >= 2 ? 8000 : 6000)); + } + else if ((int32(me->GetHealth()) - int32(damage)) < CalculatePctF<int32>(int32(me->GetMaxHealth()), 2.5f) && !_fightWon) + { + _fightWon = true; + damage = 0; + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->setFaction(35); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_SELF_STUN); + events.Reset(); + summons.DespawnAll(); + events.SetPhase(PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_OUTRO_START, 1500); + events.ScheduleEvent(EVENT_OUTRO_1, 7200); + events.ScheduleEvent(EVENT_OUTRO_2, 8700); + } + } + + void UpdateAI(uint32 const diff) + { + if ((!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim()) || !CheckInRoom()) + return; + + events.Update(diff); + + if (!(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK)) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_1: + me->RemoveAurasDueToSpell(SPELL_RIDE_THE_LIGHTNING); + Talk(SAY_ALGALON_INTRO_1); + break; + case EVENT_INTRO_2: + DoCastAOE(SPELL_SUMMON_AZEROTH, true); + Talk(SAY_ALGALON_INTRO_2); + break; + case EVENT_INTRO_3: + Talk(SAY_ALGALON_INTRO_3); + break; + case EVENT_INTRO_FINISH: + events.Reset(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + break; + case EVENT_START_COMBAT: + instance->SetBossState(BOSS_ALGALON, IN_PROGRESS); + break; + case EVENT_INTRO_TIMER_DONE: + { + events.SetPhase(PHASE_NORMAL); + me->SetSheath(SHEATH_STATE_MELEE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_NPC); + me->SetReactState(REACT_DEFENSIVE); + DoCastAOE(SPELL_SUPERMASSIVE_FAIL, true); + //! Workaround for Creature::_IsTargetAcceptable returning false + //! for creatures that start combat in REACT_PASSIVE and UNIT_FLAG_NOT_SELECTABLE + //! causing them to immediately evade + if (!me->getThreatManager().isThreatListEmpty()) + AttackStart(me->getThreatManager().getHostilTarget()); + for (uint32 i = 0; i < LIVING_CONSTELLATION_COUNT; ++i) + if (Creature* summon = DoSummon(NPC_LIVING_CONSTELLATION, ConstellationPos[i], 0, TEMPSUMMON_DEAD_DESPAWN)) + summon->SetReactState(REACT_PASSIVE); + + std::list<Creature*> stalkers; + me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); + if (!stalkers.empty()) + { + Unit* stalker = Trinity::Containers::SelectRandomContainerElement(stalkers); + stalker->m_Events.AddEvent(new ActivateLivingConstellation(stalker), stalker->m_Events.CalculateTime(urand(45000, 50000))); + } + break; + } + case EVENT_QUANTUM_STRIKE: + DoCastVictim(SPELL_QUANTUM_STRIKE); + events.ScheduleEvent(EVENT_QUANTUM_STRIKE, urand(3000, 5000)); + break; + case EVENT_PHASE_PUNCH: + DoCastVictim(SPELL_PHASE_PUNCH); + events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500); + break; + case EVENT_SUMMON_COLLAPSING_STAR: + Talk(SAY_ALGALON_COLLAPSING_STAR); + Talk(EMOTE_ALGALON_COLLAPSING_STAR); + for (uint32 i = 0; i < COLLAPSING_STAR_COUNT; ++i) + me->SummonCreature(NPC_COLLAPSING_STAR, CollapsingStarPos[i], TEMPSUMMON_CORPSE_DESPAWN); + events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 60000); + break; + case EVENT_BIG_BANG: + { + Talk(SAY_ALGALON_BIG_BANG); + Talk(EMOTE_ALGALON_BIG_BANG); + events.SetPhase(PHASE_BIG_BANG); + std::list<Creature*> constellations; + me->GetCreatureListWithEntryInGrid(constellations, NPC_LIVING_CONSTELLATION, 200.0f); + for (std::list<Creature*>::iterator itr = constellations.begin(); itr != constellations.end(); ++itr) + (*itr)->AI()->DoAction(ACTION_BIG_BANG); + DoCastAOE(SPELL_BIG_BANG); + events.ScheduleEvent(EVENT_BIG_BANG, 90500); + events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500); + break; + } + case EVENT_RESUME_UPDATING: + events.SetPhase(0); + break; + case EVENT_ASCEND_TO_THE_HEAVENS: + Talk(SAY_ALGALON_ASCEND); + DoCastAOE(SPELL_ASCEND_TO_THE_HEAVENS); + events.ScheduleEvent(EVENT_EVADE, 2500); + break; + case EVENT_EVADE: + EnterEvadeMode(); + break; + case EVENT_COSMIC_SMASH: + Talk(EMOTE_ALGALON_COSMIC_SMASH); + DoCastAOE(SPELL_COSMIC_SMASH); + events.ScheduleEvent(EVENT_COSMIC_SMASH, 25500); + break; + case EVENT_UNLOCK_YELL: + _hasYelled = false; + break; + case EVENT_OUTRO_START: + instance->SetBossState(BOSS_ALGALON, DONE); + break; + case EVENT_OUTRO_1: + me->RemoveAllAuras(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_RENAME); + break; + case EVENT_OUTRO_2: + _EnterEvadeMode(); + me->AddUnitState(UNIT_STATE_EVADE); + me->GetMotionMaster()->MovePoint(POINT_ALGALON_OUTRO, AlgalonOutroPos); + break; + case EVENT_OUTRO_3: + DoCastAOE(SPELL_KILL_CREDIT); + break; + case EVENT_OUTRO_4: + DoCastAOE(SPELL_SUPERMASSIVE_FAIL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + break; + case EVENT_OUTRO_5: + if (Creature* brann = DoSummon(NPC_BRANN_BRONZBEARD_ALG, BrannOutroPos[0], 131500, TEMPSUMMON_TIMED_DESPAWN)) + brann->AI()->DoAction(ACTION_OUTRO); + break; + case EVENT_OUTRO_6: + Talk(SAY_ALGALON_OUTRO_1); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + case EVENT_OUTRO_7: + Talk(SAY_ALGALON_OUTRO_2); + break; + case EVENT_OUTRO_8: + Talk(SAY_ALGALON_OUTRO_3); + break; + case EVENT_OUTRO_9: + Talk(SAY_ALGALON_OUTRO_4); + break; + case EVENT_OUTRO_10: + Talk(SAY_ALGALON_OUTRO_5); + break; + case EVENT_OUTRO_11: + me->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(me, SPELL_TELEPORT); + me->DespawnOrUnsummon(1500); + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + bool _firstPull; + bool _fedOnTears; + bool _phaseTwo; + bool _fightWon; + bool _hasYelled; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<boss_algalon_the_observerAI>(creature); + } +}; + +class npc_living_constellation : public CreatureScript +{ + public: + npc_living_constellation() : CreatureScript("npc_living_constellation") { } + + struct npc_living_constellationAI : public CreatureAI + { + npc_living_constellationAI(Creature* creature) : CreatureAI(creature) + { + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500); + _isActive = false; + } + + uint32 GetData(uint32 /*type*/) + { + return _isActive ? 1 : 0; + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_ACTIVATE_STAR: + if (Creature* algalon = me->FindNearestCreature(NPC_ALGALON, 200.0f)) + { + if (Unit* target = algalon->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(algalon))) + { + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + AttackStart(target); + DoZoneInCombat(); + _isActive = true; + } + } + break; + case ACTION_BIG_BANG: + _events.SetPhase(PHASE_BIG_BANG); + _events.DelayEvents(9500); + _events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500); + break; + } + } + + void SpellHit(Unit* caster, SpellInfo const* spell) + { + if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || caster->GetTypeId() != TYPEID_UNIT) + return; + + me->DespawnOrUnsummon(1); + if (InstanceScript* instance = me->GetInstanceScript()) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_ID_SUPERMASSIVE_START); + caster->CastSpell((Unit*)NULL, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK); + caster->ToCreature()->DespawnOrUnsummon(1); + } + + void UpdateAI(uint32 const diff) + { + if (!(_events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARCANE_BARRAGE: + DoCastAOE(SPELL_ARCANE_BARRAGE); + _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500); + break; + case EVENT_RESUME_UPDATING: + _events.SetPhase(0); + break; + } + } + } + + private: + EventMap _events; + bool _isActive; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_living_constellationAI>(creature); + } +}; + +class npc_collapsing_star : public CreatureScript +{ + public: + npc_collapsing_star() : CreatureScript("npc_collapsing_star") { } + + struct npc_collapsing_starAI : public PassiveAI + { + npc_collapsing_starAI(Creature* creature) : PassiveAI(creature) + { + _dying = false; + } + + void JustSummoned(Creature* summon) + { + if (summon->GetEntry() != NPC_BLACK_HOLE) + return; + + if (TempSummon* summ = me->ToTempSummon()) + if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID())) + algalon->AI()->JustSummoned(summon); + + me->DespawnOrUnsummon(1); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (_dying) + { + damage = 0; + return; + } + + if (damage >= me->GetHealth()) + { + _dying = true; + damage = 0; + DoCast(me, SPELL_BLACK_HOLE_SPAWN_VISUAL, true); + DoCast(me, SPELL_SUMMON_BLACK_HOLE, true); + } + } + + bool _dying; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_collapsing_starAI>(creature); + } +}; + +class npc_brann_bronzebeard_algalon : public CreatureScript +{ + public: + npc_brann_bronzebeard_algalon() : CreatureScript("npc_brann_bronzebeard_algalon") { } + + struct npc_brann_bronzebeard_algalonAI : public CreatureAI + { + npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature) + { + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_START_INTRO: + _currentPoint = 0; + _events.Reset(); + me->SetWalk(false); + _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1); + break; + case ACTION_FINISH_INTRO: + Talk(SAY_BRANN_ALGALON_INTRO_2); + _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1); + break; + case ACTION_OUTRO: + me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO, BrannOutroPos[1]); + _events.ScheduleEvent(EVENT_BRANN_OUTRO_1, 89500); + _events.ScheduleEvent(EVENT_BRANN_OUTRO_2, 116500); + break; + } + } + + void MovementInform(uint32 movementType, uint32 pointId) + { + if (movementType != POINT_MOTION_TYPE) + return; + + uint32 delay = 1; + _currentPoint = pointId + 1; + switch (pointId) + { + case 2: + delay = 8000; + me->SetWalk(true); + break; + case 5: + me->SetWalk(false); + Talk(SAY_BRANN_ALGALON_INTRO_1); + _events.ScheduleEvent(EVENT_SUMMON_ALGALON, 7500); + return; + case 9: + me->DespawnOrUnsummon(1); + return; + case POINT_BRANN_OUTRO: + case POINT_BRANN_OUTRO_END: + return; + } + + _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay); + } + + void UpdateAI(uint32 const diff) + { + UpdateVictim(); + + if (_events.Empty()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BRANN_MOVE_INTRO: + if (_currentPoint < MAX_BRANN_WAYPOINTS_INTRO) + me->GetMotionMaster()->MovePoint(_currentPoint, BrannIntroWaypoint[_currentPoint]); + break; + case EVENT_SUMMON_ALGALON: + if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos)) + algalon->AI()->DoAction(ACTION_START_INTRO); + break; + case EVENT_BRANN_OUTRO_1: + Talk(SAY_BRANN_ALGALON_OUTRO); + break; + case EVENT_BRANN_OUTRO_2: + me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO_END, BrannOutroPos[2]); + break; + } + } + } + + private: + EventMap _events; + uint32 _currentPoint; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_brann_bronzebeard_algalonAI>(creature); + } +}; + +class go_celestial_planetarium_access : public GameObjectScript +{ + public: + go_celestial_planetarium_access() : GameObjectScript("go_celestial_planetarium_access") {} + + struct go_celestial_planetarium_accessAI : public GameObjectAI + { + go_celestial_planetarium_accessAI(GameObject* go) : GameObjectAI(go) + { + } + + bool GossipHello(Player* player) + { + bool hasKey = true; + if (LockEntry const* lock = sLockStore.LookupEntry(go->GetGOInfo()->goober.lockId)) + { + hasKey = false; + for (uint32 i = 0; i < MAX_LOCK_CASE; ++i) + { + if (!lock->Index[i]) + continue; + + if (player->HasItemCount(lock->Index[i], 1)) + { + hasKey = true; + break; + } + } + } + + if (!hasKey) + return false; + + // Start Algalon event + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + _events.ScheduleEvent(EVENT_DESPAWN_CONSOLE, 5000); + if (Creature* brann = go->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannIntroSpawnPos)) + brann->AI()->DoAction(ACTION_START_INTRO); + + if (InstanceScript* instance = go->GetInstanceScript()) + { + instance->SetData(DATA_ALGALON_SUMMON_STATE, 1); + if (GameObject* sigil = ObjectAccessor::GetGameObject(*go, instance->GetData64(DATA_SIGILDOOR_01))) + sigil->SetGoState(GO_STATE_ACTIVE); + + if (GameObject* sigil = ObjectAccessor::GetGameObject(*go, instance->GetData64(DATA_SIGILDOOR_02))) + sigil->SetGoState(GO_STATE_ACTIVE); + } + + return false; + } + + void UpdateAI(uint32 diff) + { + if (_events.Empty()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DESPAWN_CONSOLE: + go->Delete(); + break; + } + } + } + + EventMap _events; + }; + + GameObjectAI* GetAI(GameObject* go) const + { + return GetUlduarAI<go_celestial_planetarium_accessAI>(go); + } +}; + +class spell_algalon_phase_punch : public SpellScriptLoader +{ + public: + spell_algalon_phase_punch() : SpellScriptLoader("spell_algalon_phase_punch") { } + + class spell_algalon_phase_punch_AuraScript : public AuraScript + { + PrepareAuraScript(spell_algalon_phase_punch_AuraScript); + + void HandlePeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + if (GetStackAmount() != 1) + GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 2]); + GetTarget()->CastSpell(GetTarget(), PhasePunchAlphaId[GetStackAmount() - 1], TRIGGERED_FULL_MASK); + if (GetStackAmount() == 5) + Remove(AURA_REMOVE_BY_DEFAULT); + } + + void OnRemove(AuraEffect const*, AuraEffectHandleModes) + { + if (GetStackAmount() != 5) + GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 1]); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_phase_punch_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + OnEffectRemove += AuraEffectRemoveFn(spell_algalon_phase_punch_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_algalon_phase_punch_AuraScript(); + } +}; + +class NotVictimFilter +{ + public: + NotVictimFilter(Unit* caster) : _victim(caster->getVictim()) + { + } + + bool operator()(Unit* target) + { + return target != _victim; + } + + private: + Unit* _victim; +}; + +class spell_algalon_arcane_barrage : public SpellScriptLoader +{ + public: + spell_algalon_arcane_barrage() : SpellScriptLoader("spell_algalon_arcane_barrage") { } + + class spell_algalon_arcane_barrage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_arcane_barrage_SpellScript); + + void SelectTarget(std::list<Unit*>& targets) + { + targets.remove_if(NotVictimFilter(GetCaster())); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_algalon_arcane_barrage_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_algalon_arcane_barrage_SpellScript(); + } +}; + +class ActiveConstellationFilter +{ + public: + bool operator()(Unit* target) const + { + return target->GetAI()->GetData(0); + } +}; + +class spell_algalon_trigger_3_adds : public SpellScriptLoader +{ + public: + spell_algalon_trigger_3_adds() : SpellScriptLoader("spell_algalon_trigger_3_adds") { } + + class spell_algalon_trigger_3_adds_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_trigger_3_adds_SpellScript); + + void SelectTarget(std::list<Unit*>& targets) + { + targets.remove_if(ActiveConstellationFilter()); + } + + void HandleDummy(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + Creature* target = GetHitCreature(); + if (!target) + return; + + target->AI()->DoAction(ACTION_ACTIVATE_STAR); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_algalon_trigger_3_adds_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_algalon_trigger_3_adds_SpellScript(); + } +}; + +class spell_algalon_collapse : public SpellScriptLoader +{ + public: + spell_algalon_collapse() : SpellScriptLoader("spell_algalon_collapse") { } + + class spell_algalon_collapse_AuraScript : public AuraScript + { + PrepareAuraScript(spell_algalon_collapse_AuraScript); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + GetTarget()->DealDamage(GetTarget(), GetTarget()->CountPctFromMaxHealth(1), NULL, NODAMAGE); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_collapse_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_algalon_collapse_AuraScript(); + } +}; + +class spell_algalon_big_bang : public SpellScriptLoader +{ + public: + spell_algalon_big_bang() : SpellScriptLoader("spell_algalon_big_bang") { } + + class spell_algalon_big_bang_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_big_bang_SpellScript); + + bool Load() + { + _targetCount = 0; + return true; + } + + void CountTargets(std::list<Unit*>& targets) + { + _targetCount = targets.size(); + } + + void CheckTargets() + { + if (!_targetCount) + GetCaster()->GetAI()->DoAction(ACTION_ASCEND); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_algalon_big_bang_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + AfterCast += SpellCastFn(spell_algalon_big_bang_SpellScript::CheckTargets); + } + + uint32 _targetCount; + }; + + SpellScript* GetSpellScript() const + { + return new spell_algalon_big_bang_SpellScript(); + } +}; + +class spell_algalon_remove_phase : public SpellScriptLoader +{ + public: + spell_algalon_remove_phase() : SpellScriptLoader("spell_algalon_remove_phase") { } + + class spell_algalon_remove_phase_AuraScript : public AuraScript + { + PrepareAuraScript(spell_algalon_remove_phase_AuraScript); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + GetTarget()->RemoveAurasByType(SPELL_AURA_PHASE); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_remove_phase_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_algalon_remove_phase_AuraScript(); + } +}; + +class spell_algalon_cosmic_smash : public SpellScriptLoader +{ + public: + spell_algalon_cosmic_smash() : SpellScriptLoader("spell_algalon_cosmic_smash") { } + + class spell_algalon_cosmic_smash_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_cosmic_smash_SpellScript); + + void ModDestHeight(SpellEffIndex /*effIndex*/) + { + Position offset = {0.0f, 0.0f, 65.0f, 0.0f}; + const_cast<WorldLocation*>(GetTargetDest())->RelocateOffset(offset); + GetHitDest()->RelocateOffset(offset); + } + + void Register() + { + OnEffectLaunch += SpellEffectFn(spell_algalon_cosmic_smash_SpellScript::ModDestHeight, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_algalon_cosmic_smash_SpellScript(); + } +}; + +class spell_algalon_cosmic_smash_damage : public SpellScriptLoader +{ + public: + spell_algalon_cosmic_smash_damage() : SpellScriptLoader("spell_algalon_cosmic_smash_damage") { } + + class spell_algalon_cosmic_smash_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_cosmic_smash_damage_SpellScript); + + void RecalculateDamage() + { + if (!GetTargetDest() || !GetHitUnit()) + return; + + float distance = GetHitUnit()->GetDistance2d(GetTargetDest()->GetPositionX(), GetTargetDest()->GetPositionY()); + if (distance > 6.0f) + SetHitDamage(int32(float(GetHitDamage()) / distance) * 2); + } + + void Register() + { + OnHit += SpellHitFn(spell_algalon_cosmic_smash_damage_SpellScript::RecalculateDamage); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_algalon_cosmic_smash_damage_SpellScript(); + } +}; + +class spell_algalon_supermassive_fail : public SpellScriptLoader +{ + public: + spell_algalon_supermassive_fail() : SpellScriptLoader("spell_algalon_supermassive_fail") { } + + class spell_algalon_supermassive_fail_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_supermassive_fail_SpellScript); + + void RecalculateDamage() + { + if (!GetHitPlayer()) + return; + + GetHitPlayer()->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT, GetSpellInfo()->Id, true); + } + + void Register() + { + OnHit += SpellHitFn(spell_algalon_supermassive_fail_SpellScript::RecalculateDamage); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_algalon_supermassive_fail_SpellScript(); + } +}; + +class achievement_he_feeds_on_your_tears : public AchievementCriteriaScript +{ + public: + achievement_he_feeds_on_your_tears() : AchievementCriteriaScript("achievement_he_feeds_on_your_tears") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + return !target->GetAI()->GetData(DATA_HAS_FED_ON_TEARS); + } +}; + +void AddSC_boss_algalon_the_observer() +{ + new boss_algalon_the_observer(); + new npc_living_constellation(); + new npc_collapsing_star(); + new npc_brann_bronzebeard_algalon(); + new go_celestial_planetarium_access(); + new spell_algalon_phase_punch(); + new spell_algalon_arcane_barrage(); + new spell_algalon_trigger_3_adds(); + new spell_algalon_collapse(); + new spell_algalon_big_bang(); + new spell_algalon_remove_phase(); + new spell_algalon_cosmic_smash(); + new spell_algalon_cosmic_smash_damage(); + new spell_algalon_supermassive_fail(); + new achievement_he_feeds_on_your_tears(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 5d68da4e75a..462c767f599 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -1273,7 +1273,7 @@ class go_ulduar_tower : public GameObjectScript public: go_ulduar_tower() : GameObjectScript("go_ulduar_tower") { } - void OnDestroyed(GameObject* go, Player* /*player*/, uint32 /*value*/) + void OnDestroyed(GameObject* go, Player* /*player*/) { InstanceScript* instance = go->GetInstanceScript(); if (!instance) @@ -1678,7 +1678,7 @@ class spell_pursue : public SpellScriptLoader else { //! In the end, only one target should be selected - _target = SelectRandomContainerElement(targets); + _target = Trinity::Containers::SelectRandomContainerElement(targets); FilterTargetsSubsequently(targets); } } 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 61f82d898b9..3556bf188de 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -290,7 +290,7 @@ class boss_general_vezax : public CreatureScript if (size < playersMin) return NULL; - return SelectRandomContainerElement(PlayerList); + return Trinity::Containers::SelectRandomContainerElement(PlayerList); } return NULL; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index 727f40aef81..c7091b42c5a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -947,13 +947,19 @@ class spell_xt002_tympanic_tantrum : public SpellScriptLoader void FilterTargets(std::list<Unit*>& unitList) { - unitList.remove_if (PlayerOrPetCheck()); + unitList.remove_if(PlayerOrPetCheck()); + } + + void RecalculateDamage() + { + SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(GetHitDamage())); } void Register() { OnUnitTargetSelect += SpellUnitTargetFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); OnUnitTargetSelect += SpellUnitTargetFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnHit += SpellHitFn(spell_xt002_tympanic_tantrum_SpellScript::RecalculateDamage); } }; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index e12393f047f..654d763ddbc 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -22,9 +22,14 @@ static DoorData const doorData[] = { - { GO_LEVIATHAN_DOOR, BOSS_LEVIATHAN, DOOR_TYPE_ROOM, BOUNDARY_S }, - { GO_XT_002_DOOR, BOSS_XT002, DOOR_TYPE_ROOM, BOUNDARY_S }, - { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }, + {GO_LEVIATHAN_DOOR, BOSS_LEVIATHAN, DOOR_TYPE_ROOM, BOUNDARY_S }, + {GO_XT_002_DOOR, BOSS_XT002, DOOR_TYPE_ROOM, BOUNDARY_S }, + {GO_DOODAD_UL_SIGILDOOR_03, BOSS_ALGALON, DOOR_TYPE_ROOM, BOUNDARY_W }, + {GO_DOODAD_UL_UNIVERSEFLOOR_01, BOSS_ALGALON, DOOR_TYPE_ROOM, BOUNDARY_NONE }, + {GO_DOODAD_UL_UNIVERSEFLOOR_02, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, + {GO_DOODAD_UL_UNIVERSEGLOBE01, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, + {GO_DOODAD_UL_ULDUAR_TRAPDOOR_03, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, + {0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }, }; class instance_ulduar : public InstanceMapScript @@ -36,7 +41,6 @@ class instance_ulduar : public InstanceMapScript { instance_ulduar_InstanceMapScript(InstanceMap* map) : InstanceScript(map) { } - uint32 Encounter[MAX_ENCOUNTER]; std::string m_strInstData; // Creatures @@ -72,6 +76,12 @@ class instance_ulduar : public InstanceMapScript uint64 HodirDoorGUID; uint64 HodirIceDoorGUID; uint64 ArchivumDoorGUID; + uint64 AlgalonSigilDoorGUID[3]; + uint64 AlgalonFloorGUID[2]; + uint64 AlgalonUniverseGUID; + uint64 AlgalonTrapdoorGUID; + uint64 BrannBronzebeardAlgGUID; + uint64 GiftOfTheObserverGUID; // Miscellaneous uint32 TeamInInstance; @@ -111,35 +121,49 @@ class instance_ulduar : public InstanceMapScript HodirDoorGUID = 0; HodirIceDoorGUID = 0; ArchivumDoorGUID = 0; + AlgalonUniverseGUID = 0; + AlgalonTrapdoorGUID = 0; + BrannBronzebeardAlgGUID = 0; + GiftOfTheObserverGUID = 0; + _algalonTimer = 61; + _maxArmorItemLevel = 0; + _maxWeaponItemLevel = 0; TeamInInstance = 0; HodirRareCacheData = 0; ColossusData = 0; elderCount = 0; conSpeedAtory = false; Unbroken = true; + _summonAlgalon = false; - memset(Encounter, 0, sizeof(Encounter)); + memset(AlgalonSigilDoorGUID, 0, sizeof(AlgalonSigilDoorGUID)); + memset(AlgalonFloorGUID, 0, sizeof(AlgalonFloorGUID)); memset(XTToyPileGUIDs, 0, sizeof(XTToyPileGUIDs)); memset(AssemblyGUIDs, 0, sizeof(AssemblyGUIDs)); memset(RazorHarpoonGUIDs, 0, sizeof(RazorHarpoonGUIDs)); memset(KeeperGUIDs, 0, sizeof(KeeperGUIDs)); } - bool IsEncounterInProgress() const + void FillInitialWorldStates(WorldPacket& packet) { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - if (Encounter[i] == IN_PROGRESS) - return true; - } - - return false; + packet << uint32(WORLD_STATE_ALGALON_TIMER_ENABLED) << uint32(_algalonTimer && _algalonTimer <= 60); + packet << uint32(WORLD_STATE_ALGALON_DESPAWN_TIMER) << uint32(std::min<uint32>(_algalonTimer, 60)); } void OnPlayerEnter(Player* player) { if (!TeamInInstance) TeamInInstance = player->GetTeam(); + + if (_summonAlgalon) + { + _summonAlgalon = false; + TempSummon* algalon = instance->SummonCreature(NPC_ALGALON, AlgalonLandPos); + if (_algalonTimer && _algalonTimer <= 60) + algalon->AI()->DoAction(ACTION_INIT_ALGALON); + else + algalon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + } } void OnCreatureCreate(Creature* creature) @@ -234,7 +258,6 @@ class instance_ulduar : public InstanceMapScript case NPC_ALGALON: AlgalonGUID = creature->GetGUID(); break; - // Hodir's Helper NPCs case NPC_EIVI_NIGHTFEATHER: if (TeamInInstance == HORDE) @@ -268,9 +291,32 @@ class instance_ulduar : public InstanceMapScript if (TeamInInstance == HORDE) creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA, HORDE); break; + case NPC_BRANN_BRONZBEARD_ALG: + BrannBronzebeardAlgGUID = creature->GetGUID(); + break; + //! These creatures are summoned by something else than Algalon + //! but need to be controlled/despawned by him - so they need to be + //! registered in his summon list + case NPC_ALGALON_VOID_ZONE_VISUAL_STALKER: + case NPC_ALGALON_STALKER_ASTEROID_TARGET_01: + case NPC_ALGALON_STALKER_ASTEROID_TARGET_02: + case NPC_UNLEASHED_DARK_MATTER: + if (Creature* algalon = instance->GetCreature(AlgalonGUID)) + algalon->AI()->JustSummoned(creature); + break; } + } - } + void OnCreatureRemove(Creature* creature) + { + switch (creature->GetEntry()) + { + case NPC_BRANN_BRONZBEARD_ALG: + if (BrannBronzebeardAlgGUID == creature->GetGUID()) + BrannBronzebeardAlgGUID = 0; + break; + } + } void OnGameObjectCreate(GameObject* gameObject) { @@ -341,6 +387,45 @@ class instance_ulduar : public InstanceMapScript if (GetBossState(BOSS_ASSEMBLY_OF_IRON) != DONE) HandleGameObject(ArchivumDoorGUID, false); break; + case GO_CELESTIAL_PLANETARIUM_ACCESS_10: + case GO_CELESTIAL_PLANETARIUM_ACCESS_25: + if (_algalonSummoned) + gameObject->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + break; + case GO_DOODAD_UL_SIGILDOOR_01: + AlgalonSigilDoorGUID[0] = gameObject->GetGUID(); + if (_algalonSummoned) + gameObject->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOODAD_UL_SIGILDOOR_02: + AlgalonSigilDoorGUID[1] = gameObject->GetGUID(); + if (_algalonSummoned) + gameObject->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOODAD_UL_SIGILDOOR_03: + AlgalonSigilDoorGUID[2] = gameObject->GetGUID(); + AddDoor(gameObject, true); + break; + case GO_DOODAD_UL_UNIVERSEFLOOR_01: + AlgalonFloorGUID[0] = gameObject->GetGUID(); + AddDoor(gameObject, true); + break; + case GO_DOODAD_UL_UNIVERSEFLOOR_02: + AlgalonFloorGUID[1] = gameObject->GetGUID(); + AddDoor(gameObject, true); + break; + case GO_DOODAD_UL_UNIVERSEGLOBE01: + AlgalonUniverseGUID = gameObject->GetGUID(); + AddDoor(gameObject, true); + break; + case GO_DOODAD_UL_ULDUAR_TRAPDOOR_03: + AlgalonTrapdoorGUID = gameObject->GetGUID(); + AddDoor(gameObject, true); + break; + case GO_GIFT_OF_THE_OBSERVER_10: + case GO_GIFT_OF_THE_OBSERVER_25: + GiftOfTheObserverGUID = gameObject->GetGUID(); + break; } } @@ -349,10 +434,14 @@ class instance_ulduar : public InstanceMapScript switch (gameObject->GetEntry()) { case GO_LEVIATHAN_DOOR: - AddDoor(gameObject, false); - break; case GO_XT_002_DOOR: + case GO_DOODAD_UL_SIGILDOOR_03: + case GO_DOODAD_UL_UNIVERSEFLOOR_01: + case GO_DOODAD_UL_UNIVERSEFLOOR_02: + case GO_DOODAD_UL_UNIVERSEGLOBE01: + case GO_DOODAD_UL_ULDUAR_TRAPDOOR_03: AddDoor(gameObject, false); + break; default: break; } @@ -390,6 +479,7 @@ class instance_ulduar : public InstanceMapScript // Flame Leviathan's Tower Event triggers Creature* FlameLeviathan = instance->GetCreature(LeviathanGUID); if (FlameLeviathan && FlameLeviathan->isAlive()) // No leviathan, no event triggering ;) + { switch (eventId) { case EVENT_TOWER_OF_STORM_DESTROYED: @@ -405,6 +495,7 @@ class instance_ulduar : public InstanceMapScript FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_LIFE_DESTROYED); break; } + } } @@ -465,6 +556,52 @@ class instance_ulduar : public InstanceMapScript if (GameObject* gameObject = instance->GetGameObject(ThorimChestGUID)) gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); break; + case BOSS_ALGALON: + if (state == DONE) + { + _events.CancelEvent(EVENT_UPDATE_ALGALON_TIMER); + _events.CancelEvent(EVENT_DESPAWN_ALGALON); + DoUpdateWorldState(WORLD_STATE_ALGALON_TIMER_ENABLED, 0); + _algalonTimer = 61; + if (GameObject* gameObject = instance->GetGameObject(GiftOfTheObserverGUID)) + gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); + // get item level (recheck weapons) + Map::PlayerList const& players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->getSource()) + for (uint8 slot = EQUIPMENT_SLOT_MAINHAND; slot <= EQUIPMENT_SLOT_RANGED; ++slot) + if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + if (item->GetTemplate()->ItemLevel > _maxWeaponItemLevel) + _maxWeaponItemLevel = item->GetTemplate()->ItemLevel; + } + else if (state == IN_PROGRESS) + { + // get item level (armor cannot be swapped in combat) + Map::PlayerList const& players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* player = itr->getSource()) + { + for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) + { + if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY) + continue; + + if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + { + if (slot >= EQUIPMENT_SLOT_MAINHAND && slot <= EQUIPMENT_SLOT_RANGED) + { + if (item->GetTemplate()->ItemLevel > _maxWeaponItemLevel) + _maxWeaponItemLevel = item->GetTemplate()->ItemLevel; + } + else if (item->GetTemplate()->ItemLevel > _maxArmorItemLevel) + _maxArmorItemLevel = item->GetTemplate()->ItemLevel; + } + } + } + } + } + break; } return true; @@ -497,6 +634,16 @@ class instance_ulduar : public InstanceMapScript case DATA_UNBROKEN: Unbroken = bool(data); break; + case EVENT_DESPAWN_ALGALON: + DoUpdateWorldState(WORLD_STATE_ALGALON_TIMER_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_ALGALON_DESPAWN_TIMER, 60); + _algalonTimer = 60; + _events.ScheduleEvent(EVENT_DESPAWN_ALGALON, 3600000); + _events.ScheduleEvent(EVENT_UPDATE_ALGALON_TIMER, 60000); + break; + case DATA_ALGALON_SUMMON_STATE: + _algalonSummoned = true; + break; default: break; } @@ -571,6 +718,22 @@ class instance_ulduar : public InstanceMapScript return KeeperGUIDs[1]; case BOSS_STONEBARK: return KeeperGUIDs[2]; + case DATA_SIGILDOOR_01: + return AlgalonSigilDoorGUID[0]; + case DATA_SIGILDOOR_02: + return AlgalonSigilDoorGUID[1]; + case DATA_SIGILDOOR_03: + return AlgalonSigilDoorGUID[2]; + case DATA_UNIVERSE_FLOOR_01: + return AlgalonFloorGUID[0]; + case DATA_UNIVERSE_FLOOR_02: + return AlgalonFloorGUID[1]; + case DATA_UNIVERSE_GLOBE: + return AlgalonUniverseGUID; + case DATA_ALGALON_TRAPDOOR: + return AlgalonTrapdoorGUID; + case DATA_BRANN_BRONZEBEARD_ALG: + return BrannBronzebeardAlgGUID; } return 0; @@ -593,12 +756,23 @@ class instance_ulduar : public InstanceMapScript return 0; } + bool CheckAchievementCriteriaMeet(uint32 criteriaId, Player const* , Unit const* /* = NULL */, uint32 /* = 0 */) + { + switch (criteriaId) + { + case CRITERIA_HERALD_OF_TITANS: + return _maxArmorItemLevel <= MAX_HERALD_ARMOR_ITEMLEVEL && _maxWeaponItemLevel <= MAX_HERALD_WEAPON_ITEMLEVEL; + } + + return false; + } + std::string GetSaveData() { OUT_SAVE_INST_DATA; std::ostringstream saveStream; - saveStream << "U U " << GetBossSaveData() << GetData(DATA_COLOSSUS); + saveStream << "U U " << GetBossSaveData() << GetData(DATA_COLOSSUS) << ' ' << _algalonTimer << ' ' << (_algalonSummoned ? 1 : 0); OUT_SAVE_INST_DATA_COMPLETE; return saveStream.str(); @@ -628,15 +802,68 @@ class instance_ulduar : public InstanceMapScript if (tmpState == IN_PROGRESS || tmpState > SPECIAL) tmpState = NOT_STARTED; - if (i == DATA_COLOSSUS) - SetData(i, tmpState); - else - SetBossState(i, EncounterState(tmpState)); + SetBossState(i, EncounterState(tmpState)); + } + + uint32 tempState; + loadStream >> tempState; + if (tempState == IN_PROGRESS || tempState > SPECIAL) + tempState = NOT_STARTED; + SetData(DATA_COLOSSUS, tempState); + + loadStream >> _algalonTimer; + loadStream >> tempState; + _algalonSummoned = tempState != 0; + if (_algalonSummoned && GetBossState(BOSS_ALGALON) != DONE) + { + _summonAlgalon = true; + if (_algalonTimer && _algalonTimer <= 60) + { + _events.ScheduleEvent(EVENT_UPDATE_ALGALON_TIMER, 60000); + DoUpdateWorldState(WORLD_STATE_ALGALON_TIMER_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_ALGALON_DESPAWN_TIMER, _algalonTimer); + } } } OUT_LOAD_INST_DATA_COMPLETE; } + + void Update(uint32 diff) + { + if (_events.Empty()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_UPDATE_ALGALON_TIMER: + SaveToDB(); + DoUpdateWorldState(WORLD_STATE_ALGALON_DESPAWN_TIMER, --_algalonTimer); + if (_algalonTimer) + _events.ScheduleEvent(EVENT_UPDATE_ALGALON_TIMER, 60000); + else + { + DoUpdateWorldState(WORLD_STATE_ALGALON_TIMER_ENABLED, 0); + _events.CancelEvent(EVENT_UPDATE_ALGALON_TIMER); + if (Creature* algalon = instance->GetCreature(AlgalonGUID)) + algalon->AI()->DoAction(EVENT_DESPAWN_ALGALON); + } + break; + } + } + } + + private: + EventMap _events; + uint32 _algalonTimer; + bool _summonAlgalon; + bool _algalonSummoned; + uint32 _maxArmorItemLevel; + uint32 _maxWeaponItemLevel; }; InstanceScript* GetInstanceScript(InstanceMap* map) const diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index a31954b8a16..d35f0559080 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -21,6 +21,8 @@ #include "ObjectMgr.h" #define UlduarScriptName "instance_ulduar" +extern Position const AlgalonLandPos; + enum UlduarBosses { MAX_ENCOUNTER = 20, @@ -50,98 +52,124 @@ enum UlduarBosses enum UlduarNPCs { // General - NPC_LEVIATHAN = 33113, - NPC_SALVAGED_DEMOLISHER = 33109, - NPC_SALVAGED_SIEGE_ENGINE = 33060, - NPC_IGNIS = 33118, - NPC_RAZORSCALE = 33186, - NPC_RAZORSCALE_CONTROLLER = 33233, - NPC_STEELFORGED_DEFFENDER = 33236, - NPC_EXPEDITION_COMMANDER = 33210, - NPC_XT002 = 33293, - NPC_XT_TOY_PILE = 33337, - NPC_STEELBREAKER = 32867, - NPC_MOLGEIM = 32927, - NPC_BRUNDIR = 32857, - NPC_KOLOGARN = 32930, - NPC_FOCUSED_EYEBEAM = 33632, - NPC_FOCUSED_EYEBEAM_RIGHT = 33802, - NPC_LEFT_ARM = 32933, - NPC_RIGHT_ARM = 32934, - NPC_RUBBLE = 33768, - NPC_AURIAYA = 33515, - NPC_MIMIRON = 33350, - NPC_HODIR = 32845, - NPC_THORIM = 32865, - NPC_FREYA = 32906, - NPC_VEZAX = 33271, - NPC_YOGGSARON = 33288, - NPC_ALGALON = 32871, + NPC_LEVIATHAN = 33113, + NPC_SALVAGED_DEMOLISHER = 33109, + NPC_SALVAGED_SIEGE_ENGINE = 33060, + NPC_IGNIS = 33118, + NPC_RAZORSCALE = 33186, + NPC_RAZORSCALE_CONTROLLER = 33233, + NPC_STEELFORGED_DEFFENDER = 33236, + NPC_EXPEDITION_COMMANDER = 33210, + NPC_XT002 = 33293, + NPC_XT_TOY_PILE = 33337, + NPC_STEELBREAKER = 32867, + NPC_MOLGEIM = 32927, + NPC_BRUNDIR = 32857, + NPC_KOLOGARN = 32930, + NPC_FOCUSED_EYEBEAM = 33632, + NPC_FOCUSED_EYEBEAM_RIGHT = 33802, + NPC_LEFT_ARM = 32933, + NPC_RIGHT_ARM = 32934, + NPC_RUBBLE = 33768, + NPC_AURIAYA = 33515, + NPC_MIMIRON = 33350, + NPC_HODIR = 32845, + NPC_THORIM = 32865, + NPC_FREYA = 32906, + NPC_VEZAX = 33271, + NPC_YOGGSARON = 33288, + NPC_ALGALON = 32871, // Mimiron - NPC_LEVIATHAN_MKII = 33432, - NPC_VX_001 = 33651, - NPC_AERIAL_COMMAND_UNIT = 33670, + NPC_LEVIATHAN_MKII = 33432, + NPC_VX_001 = 33651, + NPC_AERIAL_COMMAND_UNIT = 33670, // Freya's Keepers - NPC_IRONBRANCH = 32913, - NPC_BRIGHTLEAF = 32915, - NPC_STONEBARK = 32914, + NPC_IRONBRANCH = 32913, + NPC_BRIGHTLEAF = 32915, + NPC_STONEBARK = 32914, // Hodir's Helper NPCs - NPC_TOR_GREYCLOUD = 32941, - NPC_KAR_GREYCLOUD = 33333, - NPC_EIVI_NIGHTFEATHER = 33325, - NPC_ELLIE_NIGHTFEATHER = 32901, - NPC_SPIRITWALKER_TARA = 33332, - NPC_SPIRITWALKER_YONA = 32950, - NPC_ELEMENTALIST_MAHFUUN = 33328, - NPC_ELEMENTALIST_AVUUN = 32900, - NPC_AMIRA_BLAZEWEAVER = 33331, - NPC_VEESHA_BLAZEWEAVER = 32946, - NPC_MISSY_FLAMECUFFS = 32893, - NPC_SISSY_FLAMECUFFS = 33327, - NPC_BATTLE_PRIEST_ELIZA = 32948, - NPC_BATTLE_PRIEST_GINA = 33330, - NPC_FIELD_MEDIC_PENNY = 32897, - NPC_FIELD_MEDIC_JESSI = 33326, + NPC_TOR_GREYCLOUD = 32941, + NPC_KAR_GREYCLOUD = 33333, + NPC_EIVI_NIGHTFEATHER = 33325, + NPC_ELLIE_NIGHTFEATHER = 32901, + NPC_SPIRITWALKER_TARA = 33332, + NPC_SPIRITWALKER_YONA = 32950, + NPC_ELEMENTALIST_MAHFUUN = 33328, + NPC_ELEMENTALIST_AVUUN = 32900, + NPC_AMIRA_BLAZEWEAVER = 33331, + NPC_VEESHA_BLAZEWEAVER = 32946, + NPC_MISSY_FLAMECUFFS = 32893, + NPC_SISSY_FLAMECUFFS = 33327, + NPC_BATTLE_PRIEST_ELIZA = 32948, + NPC_BATTLE_PRIEST_GINA = 33330, + NPC_FIELD_MEDIC_PENNY = 32897, + NPC_FIELD_MEDIC_JESSI = 33326, // Freya's trash NPCs - NPC_CORRUPTED_SERVITOR = 33354, - NPC_MISGUIDED_NYMPH = 33355, - NPC_GUARDIAN_LASHER = 33430, - NPC_FOREST_SWARMER = 33431, - NPC_MANGROVE_ENT = 33525, - NPC_IRONROOT_LASHER = 33526, - NPC_NATURES_BLADE = 33527, - NPC_GUARDIAN_OF_LIFE = 33528, + NPC_CORRUPTED_SERVITOR = 33354, + NPC_MISGUIDED_NYMPH = 33355, + NPC_GUARDIAN_LASHER = 33430, + NPC_FOREST_SWARMER = 33431, + NPC_MANGROVE_ENT = 33525, + NPC_IRONROOT_LASHER = 33526, + NPC_NATURES_BLADE = 33527, + NPC_GUARDIAN_OF_LIFE = 33528, + + // Algalon the Observer + NPC_BRANN_BRONZBEARD_ALG = 34064, + NPC_AZEROTH = 34246, + NPC_LIVING_CONSTELLATION = 33052, + NPC_ALGALON_STALKER = 33086, + NPC_COLLAPSING_STAR = 32955, + NPC_BLACK_HOLE = 32953, + NPC_WORM_HOLE = 34099, + NPC_ALGALON_VOID_ZONE_VISUAL_STALKER = 34100, + NPC_ALGALON_STALKER_ASTEROID_TARGET_01 = 33104, + NPC_ALGALON_STALKER_ASTEROID_TARGET_02 = 33105, + NPC_UNLEASHED_DARK_MATTER = 34097, }; enum UlduarGameObjects { - GO_KOLOGARN_CHEST_HERO = 195047, - GO_KOLOGARN_CHEST = 195046, - GO_KOLOGARN_BRIDGE = 194232, - GO_KOLOGARN_DOOR = 194553, - GO_THORIM_CHEST_HERO = 194315, - GO_THORIM_CHEST = 194314, - GO_HODIR_RARE_CACHE_OF_WINTER = 194200, - GO_HODIR_RARE_CACHE_OF_WINTER_HERO = 194201, - GO_HODIR_CHEST_HERO = 194308, - GO_HODIR_CHEST = 194307, - GO_LEVIATHAN_DOOR = 194905, - GO_LEVIATHAN_GATE = 194630, - GO_XT_002_DOOR = 194631, - GO_VEZAX_DOOR = 194750, - GO_MOLE_MACHINE = 194316, - GO_RAZOR_HARPOON_1 = 194542, - GO_RAZOR_HARPOON_2 = 194541, - GO_RAZOR_HARPOON_3 = 194543, - GO_RAZOR_HARPOON_4 = 194519, - GO_RAZOR_BROKEN_HARPOON = 194565, - GO_HODIR_DOOR = 194634, - GO_HODIR_ICE_DOOR = 194441, - GO_ARCHIVUM_DOOR = 194556, + GO_KOLOGARN_CHEST_HERO = 195047, + GO_KOLOGARN_CHEST = 195046, + GO_KOLOGARN_BRIDGE = 194232, + GO_KOLOGARN_DOOR = 194553, + GO_THORIM_CHEST_HERO = 194315, + GO_THORIM_CHEST = 194314, + GO_HODIR_RARE_CACHE_OF_WINTER = 194200, + GO_HODIR_RARE_CACHE_OF_WINTER_HERO = 194201, + GO_HODIR_CHEST_HERO = 194308, + GO_HODIR_CHEST = 194307, + GO_LEVIATHAN_DOOR = 194905, + GO_LEVIATHAN_GATE = 194630, + GO_XT_002_DOOR = 194631, + GO_VEZAX_DOOR = 194750, + GO_MOLE_MACHINE = 194316, + GO_RAZOR_HARPOON_1 = 194542, + GO_RAZOR_HARPOON_2 = 194541, + GO_RAZOR_HARPOON_3 = 194543, + GO_RAZOR_HARPOON_4 = 194519, + GO_RAZOR_BROKEN_HARPOON = 194565, + GO_HODIR_DOOR = 194634, + GO_HODIR_ICE_DOOR = 194441, + GO_ARCHIVUM_DOOR = 194556, + + // Algalon the Observer + GO_CELESTIAL_PLANETARIUM_ACCESS_10 = 194628, + GO_CELESTIAL_PLANETARIUM_ACCESS_25 = 194752, + GO_DOODAD_UL_SIGILDOOR_01 = 194767, + GO_DOODAD_UL_SIGILDOOR_02 = 194911, + GO_DOODAD_UL_SIGILDOOR_03 = 194910, + GO_DOODAD_UL_UNIVERSEFLOOR_01 = 194715, + GO_DOODAD_UL_UNIVERSEFLOOR_02 = 194716, + GO_DOODAD_UL_UNIVERSEGLOBE01 = 194148, + GO_DOODAD_UL_ULDUAR_TRAPDOOR_03 = 194253, + GO_GIFT_OF_THE_OBSERVER_10 = 194821, + GO_GIFT_OF_THE_OBSERVER_25 = 194822, }; enum LeviathanData @@ -161,6 +189,7 @@ enum UlduarAchievementCriteriaIds { CRITERIA_CON_SPEED_ATORY = 21597, CRITERIA_DISARMED = 21687, + CRITERIA_HERALD_OF_TITANS = 10678, }; enum UlduarData @@ -180,12 +209,38 @@ enum UlduarData // Hodir DATA_HODIR_RARE_CACHE, + + // Algalon the Observer + DATA_ALGALON_SUMMON_STATE, + DATA_SIGILDOOR_01, + DATA_SIGILDOOR_02, + DATA_SIGILDOOR_03, + DATA_UNIVERSE_FLOOR_01, + DATA_UNIVERSE_FLOOR_02, + DATA_UNIVERSE_GLOBE, + DATA_ALGALON_TRAPDOOR, + DATA_BRANN_BRONZEBEARD_ALG, +}; + +enum UlduarWorldStates +{ + WORLD_STATE_ALGALON_DESPAWN_TIMER = 4131, + WORLD_STATE_ALGALON_TIMER_ENABLED = 4132, }; enum UlduarAchievementData { // FL Achievement boolean DATA_UNBROKEN = 29052906, // 2905, 2906 are achievement IDs, + MAX_HERALD_ARMOR_ITEMLEVEL = 226, + MAX_HERALD_WEAPON_ITEMLEVEL = 232, +}; + +enum UlduarEvents +{ + EVENT_DESPAWN_ALGALON = 1, + EVENT_UPDATE_ALGALON_TIMER = 2, + ACTION_INIT_ALGALON = 6, }; template<class AI> @@ -199,6 +254,17 @@ CreatureAI* GetUlduarAI(Creature* creature) return NULL; } +template<class AI> +GameObjectAI* GetUlduarAI(GameObject* go) +{ + if (InstanceMap* instance = go->GetMap()->ToInstanceMap()) + if (instance->GetInstanceScript()) + if (instance->GetScriptId() == sObjectMgr->GetScriptId(UlduarScriptName)) + return new AI(go); + + return NULL; +} + class PlayerOrPetCheck { public: diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_emalon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_emalon.cpp index dc58e51a5a1..4980ed36ec3 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_emalon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_emalon.cpp @@ -139,7 +139,7 @@ class boss_emalon : public CreatureScript case EVENT_OVERCHARGE: if (!summons.empty()) { - Creature* minion = Unit::GetCreature(*me, SelectRandomContainerElement(summons)); + Creature* minion = Unit::GetCreature(*me, Trinity::Containers::SelectRandomContainerElement(summons)); if (minion && minion->isAlive()) { minion->CastSpell(me, SPELL_OVERCHARGED, true); diff --git a/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp b/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp index 0dd1d37116c..ce1732433c8 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp @@ -134,7 +134,8 @@ public: if (!phase || phase == PHASE_CHASE) { phase = PHASE_STRIKE; - summons.DoAction(EVENT_VOLCANO, 0); + DummyEntryCheckPredicate pred; + summons.DoAction(EVENT_VOLCANO, pred); events.ScheduleEvent(EVENT_HATEFUL_STRIKE, 5000, GCD_CAST, PHASE_STRIKE); me->SetSpeed(MOVE_RUN, 1.2f); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); diff --git a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp index 147d2d60359..a213713ae1a 100644 --- a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp +++ b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp @@ -31,15 +31,15 @@ enum Texts enum Spells { - SPELL_SHADOWVOLLEY = 32963, + SPELL_SHADOW_VOLLEY = 32963, SPELL_CLEAVE = 31779, SPELL_THUNDERCLAP = 36706, - SPELL_VOIDBOLT = 39329, - SPELL_MARKOFKAZZAK = 32960, - SPELL_MARKOFKAZZAK_DAMAGE = 32961, + SPELL_VOID_BOLT = 39329, + SPELL_MARK_OF_KAZZAK = 32960, SPELL_ENRAGE = 32964, - SPELL_CAPTURESOUL = 32966, - SPELL_TWISTEDREFLECTION = 21063 + SPELL_CAPTURE_SOUL = 32966, + SPELL_TWISTED_REFLECTION = 21063, + SPELL_BERSERK = 32965, }; enum Events @@ -47,10 +47,11 @@ enum Events EVENT_SHADOW_VOLLEY = 1, EVENT_CLEAVE = 2, EVENT_THUNDERCLAP = 3, - EVENT_VOIDBOLT = 4, + EVENT_VOID_BOLT = 4, EVENT_MARK_OF_KAZZAK = 5, EVENT_ENRAGE = 6, - EVENT_TWISTED_REFLECTION = 7 + EVENT_TWISTED_REFLECTION = 7, + EVENT_BERSERK = 8 }; class boss_doomlord_kazzak : public CreatureScript @@ -70,10 +71,11 @@ class boss_doomlord_kazzak : public CreatureScript _events.ScheduleEvent(EVENT_SHADOW_VOLLEY, urand(6000, 10000)); _events.ScheduleEvent(EVENT_CLEAVE, 7000); _events.ScheduleEvent(EVENT_THUNDERCLAP, urand(14000, 18000)); - _events.ScheduleEvent(EVENT_VOIDBOLT, 30000); + _events.ScheduleEvent(EVENT_VOID_BOLT, 30000); _events.ScheduleEvent(EVENT_MARK_OF_KAZZAK, 25000); _events.ScheduleEvent(EVENT_ENRAGE, 60000); _events.ScheduleEvent(EVENT_TWISTED_REFLECTION, 33000); + _events.ScheduleEvent(EVENT_BERSERK, 180000); } void JustRespawned() @@ -92,7 +94,7 @@ class boss_doomlord_kazzak : public CreatureScript if (victim->GetTypeId() != TYPEID_PLAYER) return; - DoCast(me, SPELL_CAPTURESOUL); + DoCast(me, SPELL_CAPTURE_SOUL); Talk(SAY_KILL); } @@ -118,7 +120,7 @@ class boss_doomlord_kazzak : public CreatureScript switch (eventId) { case EVENT_SHADOW_VOLLEY: - DoCastVictim(SPELL_SHADOWVOLLEY); + DoCastVictim(SPELL_SHADOW_VOLLEY); _events.ScheduleEvent(EVENT_SHADOW_VOLLEY, urand(4000, 6000)); break; case EVENT_CLEAVE: @@ -129,13 +131,13 @@ class boss_doomlord_kazzak : public CreatureScript DoCastVictim(SPELL_THUNDERCLAP); _events.ScheduleEvent(EVENT_THUNDERCLAP, urand(10000, 14000)); break; - case EVENT_VOIDBOLT: - DoCastVictim(SPELL_VOIDBOLT); - _events.ScheduleEvent(EVENT_VOIDBOLT, urand(15000, 18000)); + case EVENT_VOID_BOLT: + DoCastVictim(SPELL_VOID_BOLT); + _events.ScheduleEvent(EVENT_VOID_BOLT, urand(15000, 18000)); break; case EVENT_MARK_OF_KAZZAK: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - DoCast(target, SPELL_MARKOFKAZZAK); + DoCast(target, SPELL_MARK_OF_KAZZAK); _events.ScheduleEvent(EVENT_MARK_OF_KAZZAK, 20000); break; case EVENT_ENRAGE: @@ -145,9 +147,12 @@ class boss_doomlord_kazzak : public CreatureScript break; case EVENT_TWISTED_REFLECTION: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - DoCast(target, SPELL_TWISTEDREFLECTION); + DoCast(target, SPELL_TWISTED_REFLECTION); _events.ScheduleEvent(EVENT_TWISTED_REFLECTION, 15000); break; + case EVENT_BERSERK: + DoCast(me, SPELL_BERSERK); + break; default: break; } diff --git a/src/server/scripts/Outland/netherstorm.cpp b/src/server/scripts/Outland/netherstorm.cpp index 4fdaebeacae..388d18697b9 100644 --- a/src/server/scripts/Outland/netherstorm.cpp +++ b/src/server/scripts/Outland/netherstorm.cpp @@ -812,7 +812,7 @@ public: } if (!UnitsWithMana.empty()) { - DoCast(SelectRandomContainerElement(UnitsWithMana), SPELL_MANA_BURN); + DoCast(Trinity::Containers::SelectRandomContainerElement(UnitsWithMana), SPELL_MANA_BURN); ManaBurnTimer = 8000 + (rand() % 10 * 1000); // 8-18 sec cd } else diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 4c440f18bd9..380cac4e5ee 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -250,7 +250,7 @@ class spell_dru_t10_restoration_4p_bonus : public SpellScriptLoader return; } - Unit* target = SelectRandomContainerElement(tempTargets); + Unit* target = Trinity::Containers::SelectRandomContainerElement(tempTargets); unitList.clear(); unitList.push_back(target); } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 41d1c24c517..2d431331691 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -2601,7 +2601,7 @@ class spell_gen_wg_water : public SpellScriptLoader SpellCastResult CheckCast() { - if (!GetSpellInfo()->CheckTargetCreatureType(GetTargetUnit())) + if (!GetSpellInfo()->CheckTargetCreatureType(GetCaster())) return SPELL_FAILED_DONT_REPORT; return SPELL_CAST_OK; } @@ -2618,6 +2618,44 @@ class spell_gen_wg_water : public SpellScriptLoader } }; +class spell_gen_count_pct_from_max_hp : public SpellScriptLoader +{ + public: + spell_gen_count_pct_from_max_hp(char const* name, int32 damagePct = 0) : SpellScriptLoader(name), _damagePct(damagePct) { } + + class spell_gen_count_pct_from_max_hp_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_count_pct_from_max_hp_SpellScript) + + public: + spell_gen_count_pct_from_max_hp_SpellScript(int32 damagePct) : SpellScript(), _damagePct(damagePct) { } + + void RecalculateDamage() + { + if (!_damagePct) + _damagePct = GetHitDamage(); + + SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(_damagePct)); + } + + void Register() + { + OnHit += SpellHitFn(spell_gen_count_pct_from_max_hp_SpellScript::RecalculateDamage); + } + + private: + int32 _damagePct; + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_count_pct_from_max_hp_SpellScript(_damagePct); + } + + private: + int32 _damagePct; +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -2669,4 +2707,6 @@ void AddSC_generic_spell_scripts() new spell_gen_chaos_blast(); new spell_gen_ds_flush_knockback(); new spell_gen_wg_water(); + new spell_gen_count_pct_from_max_hp("spell_gen_default_count_pct_from_max_hp"); + new spell_gen_count_pct_from_max_hp("spell_gen_50pct_count_pct_from_max_hp", 50); } diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 666477e68e7..3c5d6438275 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -1744,6 +1744,7 @@ class spell_item_rocket_boots : public SpellScriptLoader if (Battleground* bg = caster->GetBattleground()) bg->EventPlayerDroppedFlag(caster); + caster->RemoveSpellCooldown(SPELL_ROCKET_BOOTS_PROC); caster->CastSpell(caster, SPELL_ROCKET_BOOTS_PROC, true, NULL); } @@ -2020,6 +2021,37 @@ class spell_item_muisek_vessel : public SpellScriptLoader } }; +enum GreatmothersSoulcather +{ + SPELL_FORCE_CAST_SUMMON_GNOME_SOUL = 46486, +}; +class spell_item_greatmothers_soulcatcher : public SpellScriptLoader +{ +public: + spell_item_greatmothers_soulcatcher() : SpellScriptLoader("spell_item_greatmothers_soulcatcher") { } + + class spell_item_greatmothers_soulcatcher_SpellScript : public SpellScript + { + PrepareSpellScript(spell_item_greatmothers_soulcatcher_SpellScript); + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + GetCaster()->CastSpell(GetCaster(),SPELL_FORCE_CAST_SUMMON_GNOME_SOUL); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_item_greatmothers_soulcatcher_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_item_greatmothers_soulcatcher_SpellScript(); + } +}; + void AddSC_item_spell_scripts() { // 23074 Arcanite Dragonling diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index b746c37a090..050741ffaba 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -250,9 +250,11 @@ class spell_mage_frost_warding_trigger : public SpellScriptLoader if (roll_chance_i(chance)) { - absorbAmount = dmgInfo.GetDamage(); - int32 bp = absorbAmount; + int32 bp = dmgInfo.GetDamage(); + dmgInfo.AbsorbDamage(bp); target->CastCustomSpell(target, SPELL_MAGE_FROST_WARDING_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); + absorbAmount = 0; + PreventDefaultAction(); } } } diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index d823c629d4b..9f7f7d847e1 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -285,9 +285,20 @@ class spell_pal_holy_shock : public SpellScriptLoader } } + SpellCastResult CheckCast() + { + Player* caster = GetCaster()->ToPlayer(); + if (GetTargetUnit()) + if (Player* target = GetTargetUnit()->ToPlayer()) + if (caster->GetTeam() != target->GetTeam() && !caster->IsValidAttackTarget(target)) + return SPELL_FAILED_BAD_TARGETS; + return SPELL_CAST_OK; + } + void Register() { // add dummy effect spell handler to Holy Shock + OnCheckCast += SpellCheckCastFn(spell_pal_holy_shock_SpellScript::CheckCast); OnEffectHitTarget += SpellEffectFn(spell_pal_holy_shock_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 278abcc0c0b..48faf83cd2f 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -636,6 +636,10 @@ class spell_q12851_going_bearback : public SpellScriptLoader if (Unit* caster = GetCaster()) { Unit* target = GetTarget(); + // Already in fire + if (target->HasAura(SPELL_ABLAZE)) + return; + if (Player* player = caster->GetCharmerOrOwnerPlayerOrPlayerItself()) { switch (target->GetEntry()) diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 96ee7a18429..f16f663ae2d 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -35,6 +35,9 @@ enum ShamanSpells SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1 = 8349, SHAMAN_SPELL_SATED = 57724, SHAMAN_SPELL_EXHAUSTION = 57723, + + SHAMAN_SPELL_STORM_EARTH_AND_FIRE = 51483, + EARTHBIND_TOTEM_SPELL_EARTHGRAB = 64695, // For Earthen Power SHAMAN_TOTEM_SPELL_EARTHBIND_TOTEM = 6474, @@ -212,18 +215,33 @@ class spell_sha_earthbind_totem : public SpellScriptLoader void HandleEffectPeriodic(AuraEffect const* aurEff) { - if (Unit* target = GetTarget()) - if (Unit* caster = aurEff->GetBase()->GetCaster()) - if (TempSummon* summon = caster->ToTempSummon()) - if (Unit* owner = summon->GetOwner()) - if (AuraEffect* aur = owner->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, 2289, 0)) - if (roll_chance_i(aur->GetBaseAmount()) && target->HasAuraWithMechanic(1 << MECHANIC_SNARE)) - caster->CastSpell(caster, SHAMAN_TOTEM_SPELL_EARTHEN_POWER, true, NULL, aurEff); + if (!GetCaster()) + return; + if (Player* owner = GetCaster()->GetCharmerOrOwnerPlayerOrPlayerItself()) + if (AuraEffect* aur = owner->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, 2289, 0)) + if (roll_chance_i(aur->GetBaseAmount())) + GetTarget()->CastSpell((Unit*)NULL, SHAMAN_TOTEM_SPELL_EARTHEN_POWER, true); + } + + void Apply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (!GetCaster()) + return; + Player* owner = GetCaster()->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!owner) + return; + // Storm, Earth and Fire + if (AuraEffect* aurEff = owner->GetAuraEffectOfRankedSpell(SHAMAN_SPELL_STORM_EARTH_AND_FIRE, EFFECT_1)) + { + if (roll_chance_i(aurEff->GetAmount())) + GetCaster()->CastSpell(GetCaster(), EARTHBIND_TOTEM_SPELL_EARTHGRAB, false); + } } void Register() { OnEffectPeriodic += AuraEffectPeriodicFn(spell_sha_earthbind_totem_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + OnEffectApply += AuraEffectApplyFn(spell_sha_earthbind_totem_AuraScript::Apply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); } }; @@ -233,6 +251,46 @@ class spell_sha_earthbind_totem : public SpellScriptLoader } }; +class EarthenPowerTargetSelector +{ + public: + EarthenPowerTargetSelector() { } + + bool operator() (Unit* target) + { + if (!target->HasAuraWithMechanic(1 << MECHANIC_SNARE)) + return true; + + return false; + } +}; + +class spell_sha_earthen_power : public SpellScriptLoader +{ + public: + spell_sha_earthen_power() : SpellScriptLoader("spell_sha_earthen_power") { } + + class spell_sha_earthen_power_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sha_earthen_power_SpellScript); + + void FilterTargets(std::list<Unit*>& unitList) + { + unitList.remove_if(EarthenPowerTargetSelector()); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_sha_earthen_power_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_sha_earthen_power_SpellScript(); + } +}; + class spell_sha_bloodlust : public SpellScriptLoader { public: @@ -251,7 +309,7 @@ class spell_sha_bloodlust : public SpellScriptLoader void RemoveInvalidTargets(std::list<Unit*>& targets) { - targets.remove_if (Trinity::UnitAuraCheck(true, SHAMAN_SPELL_SATED)); + targets.remove_if(Trinity::UnitAuraCheck(true, SHAMAN_SPELL_SATED)); } void ApplyDebuff() @@ -542,6 +600,55 @@ class spell_sha_lava_lash : public SpellScriptLoader } }; +// 1064 Chain Heal +class spell_sha_chain_heal : public SpellScriptLoader +{ + public: + spell_sha_chain_heal() : SpellScriptLoader("spell_sha_chain_heal") { } + + class spell_sha_chain_heal_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sha_chain_heal_SpellScript); + + bool Load() + { + firstHeal = true; + riptide = false; + return true; + } + + void HandleHeal(SpellEffIndex /*effIndex*/) + { + if (firstHeal) + { + // Check if the target has Riptide + if (AuraEffect* aurEff = GetHitUnit()->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, GetCaster()->GetGUID())) + { + riptide = true; + // Consume it + GetHitUnit()->RemoveAura(aurEff->GetBase()); + } + firstHeal = false; + } + // Riptide increases the Chain Heal effect by 25% + if (riptide) + SetHitHeal(GetHitHeal() * 1.25f); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_sha_chain_heal_SpellScript::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL); + } + + bool firstHeal; + bool riptide; + }; + + SpellScript* GetSpellScript() const + { + return new spell_sha_chain_heal_SpellScript(); + } +}; void AddSC_shaman_spell_scripts() { @@ -549,6 +656,7 @@ void AddSC_shaman_spell_scripts() new spell_sha_fire_nova(); new spell_sha_mana_tide_totem(); new spell_sha_earthbind_totem(); + new spell_sha_earthen_power(); new spell_sha_bloodlust(); new spell_sha_heroism(); new spell_sha_ancestral_awakening_proc(); @@ -556,4 +664,5 @@ void AddSC_shaman_spell_scripts() new spell_sha_healing_stream_totem(); new spell_sha_mana_spring_totem(); new spell_sha_lava_lash(); + new spell_sha_chain_heal(); } diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 29a52406279..1f7e8171e46 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -172,6 +172,19 @@ class spell_warl_create_healthstone : public SpellScriptLoader return true; } + SpellCastResult CheckCast() + { + if (Player* caster = GetCaster()->ToPlayer()) + { + uint8 spellRank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); + ItemPosCountVec dest; + InventoryResult msg = caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, iTypes[spellRank - 1][0], 1, NULL); + if (msg != EQUIP_ERR_OK) + return SPELL_FAILED_TOO_MANY_OF_ITEM; + } + return SPELL_CAST_OK; + } + void HandleScriptEffect(SpellEffIndex effIndex) { if (Unit* unitTarget = GetHitUnit()) @@ -198,6 +211,7 @@ class spell_warl_create_healthstone : public SpellScriptLoader void Register() { OnEffectHitTarget += SpellEffectFn(spell_warl_create_healthstone_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + OnCheckCast += SpellCheckCastFn(spell_warl_create_healthstone_SpellScript::CheckCast); } }; diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 1084398c37d..3e4c043ae47 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -365,7 +365,7 @@ class spell_warr_concussion_blow : public SpellScriptLoader void HandleDummy(SpellEffIndex /* effIndex */) { - SetHitDamage(GetHitDamage() + CalculatePctF(GetHitDamage(),GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK))); + SetHitDamage(CalculatePctN(GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK), GetEffectValue())); } void Register() @@ -413,6 +413,51 @@ class spell_warr_bloodthirst : public SpellScriptLoader } }; +enum Overpower +{ + SPELL_UNRELENTING_ASSAULT_RANK_1 = 46859, + SPELL_UNRELENTING_ASSAULT_RANK_2 = 46860, + SPELL_UNRELENTING_ASSAULT_TRIGGER_1 = 64849, + SPELL_UNRELENTING_ASSAULT_TRIGGER_2 = 64850, +}; + +class spell_warr_overpower : public SpellScriptLoader +{ +public: + spell_warr_overpower() : SpellScriptLoader("spell_warr_overpower") { } + + class spell_warr_overpower_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warr_overpower_SpellScript); + + void HandleEffect(SpellEffIndex /* effIndex */) + { + uint32 spellId = 0; + if (GetCaster()->HasAura(SPELL_UNRELENTING_ASSAULT_RANK_1)) + spellId = SPELL_UNRELENTING_ASSAULT_TRIGGER_1; + else if (GetCaster()->HasAura(SPELL_UNRELENTING_ASSAULT_RANK_2)) + spellId = SPELL_UNRELENTING_ASSAULT_TRIGGER_2; + + if (!spellId) + return; + + if (Player* target = GetHitPlayer()) + if (target->HasUnitState(UNIT_STATE_CASTING)) + target->CastSpell(target, spellId, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_warr_overpower_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_ANY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_warr_overpower_SpellScript(); + } +}; + void AddSC_warrior_spell_scripts() { new spell_warr_last_stand(); @@ -424,4 +469,5 @@ void AddSC_warrior_spell_scripts() new spell_warr_execute(); new spell_warr_concussion_blow(); new spell_warr_bloodthirst(); + new spell_warr_overpower(); } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 6858827ed8e..e1cfd077444 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -2400,6 +2400,9 @@ enum eLockSmith QUEST_HOTTER_THAN_HELL_H = 10764, QUEST_RETURN_TO_KHAGDAR = 9837, QUEST_CONTAINMENT = 13159, + QUEST_ETERNAL_VIGILANCE = 11011, + QUEST_KEY_TO_THE_FOCUSING_IRIS = 13372, + QUEST_HC_KEY_TO_THE_FOCUSING_IRIS = 13375, ITEM_ARCATRAZ_KEY = 31084, ITEM_SHADOWFORGE_KEY = 11000, @@ -2407,21 +2410,28 @@ enum eLockSmith ITEM_SHATTERED_HALLS_KEY = 28395, ITEM_THE_MASTERS_KEY = 24490, ITEM_VIOLET_HOLD_KEY = 42482, + ITEM_ESSENCE_INFUSED_MOONSTONE = 32449, + ITEM_KEY_TO_THE_FOCUSING_IRIS = 44582, + ITEM_HC_KEY_TO_THE_FOCUSING_IRIS = 44581, SPELL_ARCATRAZ_KEY = 54881, SPELL_SHADOWFORGE_KEY = 54882, SPELL_SKELETON_KEY = 54883, SPELL_SHATTERED_HALLS_KEY = 54884, SPELL_THE_MASTERS_KEY = 54885, - SPELL_VIOLET_HOLD_KEY = 67253 + SPELL_VIOLET_HOLD_KEY = 67253, + SPELL_ESSENCE_INFUSED_MOONSTONE = 40173, }; -#define GOSSIP_LOST_ARCATRAZ_KEY "I've lost my key to the Arcatraz." -#define GOSSIP_LOST_SHADOWFORGE_KEY "I've lost my key to the Blackrock Depths." -#define GOSSIP_LOST_SKELETON_KEY "I've lost my key to the Scholomance." -#define GOSSIP_LOST_SHATTERED_HALLS_KEY "I've lost my key to the Shattered Halls." -#define GOSSIP_LOST_THE_MASTERS_KEY "I've lost my key to the Karazhan." -#define GOSSIP_LOST_VIOLET_HOLD_KEY "I've lost my key to the Violet Hold." +#define GOSSIP_LOST_ARCATRAZ_KEY "I've lost my key to the Arcatraz." +#define GOSSIP_LOST_SHADOWFORGE_KEY "I've lost my key to the Blackrock Depths." +#define GOSSIP_LOST_SKELETON_KEY "I've lost my key to the Scholomance." +#define GOSSIP_LOST_SHATTERED_HALLS_KEY "I've lost my key to the Shattered Halls." +#define GOSSIP_LOST_THE_MASTERS_KEY "I've lost my key to the Karazhan." +#define GOSSIP_LOST_VIOLET_HOLD_KEY "I've lost my key to the Violet Hold." +#define GOSSIP_LOST_ESSENCE_INFUSED_MOONSTONE "I've lost my Essence-Infused Moonstone." +#define GOSSIP_LOST_KEY_TO_THE_FOCUSING_IRIS "I've lost my Key to the Focusing Iris." +#define GOSSIP_LOST_HC_KEY_TO_THE_FOCUSING_IRIS "I've lost my Heroic Key to the Focusing Iris." class npc_locksmith : public CreatureScript { @@ -2456,6 +2466,18 @@ public: if (player->GetQuestRewardStatus(QUEST_CONTAINMENT) && !player->HasItemCount(ITEM_VIOLET_HOLD_KEY, 1, true)) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_VIOLET_HOLD_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + // Essence-Infused Moonstone + if (player->GetQuestRewardStatus(QUEST_ETERNAL_VIGILANCE) && !player->HasItemCount(ITEM_ESSENCE_INFUSED_MOONSTONE, 1, true)) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_ESSENCE_INFUSED_MOONSTONE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + + // Key to the Focusing Iris + if (player->GetQuestRewardStatus(QUEST_KEY_TO_THE_FOCUSING_IRIS) && !player->HasItemCount(ITEM_KEY_TO_THE_FOCUSING_IRIS, 1, true)) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_KEY_TO_THE_FOCUSING_IRIS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + + // Heroic Key to the Focusing Iris + if (player->GetQuestRewardStatus(QUEST_HC_KEY_TO_THE_FOCUSING_IRIS) && !player->HasItemCount(ITEM_HC_KEY_TO_THE_FOCUSING_IRIS, 1, true)) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_HC_KEY_TO_THE_FOCUSING_IRIS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); return true; @@ -2490,171 +2512,17 @@ public: player->CLOSE_GOSSIP_MENU(); player->CastSpell(player, SPELL_VIOLET_HOLD_KEY, false); break; - } - return true; - } -}; - -/*###### -## npc_tabard_vendor -######*/ - -enum -{ - QUEST_TRUE_MASTERS_OF_LIGHT = 9737, - QUEST_THE_UNWRITTEN_PROPHECY = 9762, - QUEST_INTO_THE_BREACH = 10259, - QUEST_BATTLE_OF_THE_CRIMSON_WATCH = 10781, - QUEST_SHARDS_OF_AHUNE = 11972, - - ACHIEVEMENT_EXPLORE_NORTHREND = 45, - ACHIEVEMENT_TWENTYFIVE_TABARDS = 1021, - ACHIEVEMENT_THE_LOREMASTER_A = 1681, - ACHIEVEMENT_THE_LOREMASTER_H = 1682, - - ITEM_TABARD_OF_THE_HAND = 24344, - ITEM_TABARD_OF_THE_BLOOD_KNIGHT = 25549, - ITEM_TABARD_OF_THE_PROTECTOR = 28788, - ITEM_OFFERING_OF_THE_SHATAR = 31408, - ITEM_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI = 31404, - ITEM_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI = 31405, - ITEM_TABARD_OF_THE_SUMMER_SKIES = 35279, - ITEM_TABARD_OF_THE_SUMMER_FLAMES = 35280, - ITEM_TABARD_OF_THE_ACHIEVER = 40643, - ITEM_LOREMASTERS_COLORS = 43300, - ITEM_TABARD_OF_THE_EXPLORER = 43348, - - SPELL_TABARD_OF_THE_BLOOD_KNIGHT = 54974, - SPELL_TABARD_OF_THE_HAND = 54976, - SPELL_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI = 54977, - SPELL_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI = 54982, - SPELL_TABARD_OF_THE_ACHIEVER = 55006, - SPELL_TABARD_OF_THE_PROTECTOR = 55008, - SPELL_LOREMASTERS_COLORS = 58194, - SPELL_TABARD_OF_THE_EXPLORER = 58224, - SPELL_TABARD_OF_SUMMER_SKIES = 62768, - SPELL_TABARD_OF_SUMMER_FLAMES = 62769 -}; - -#define GOSSIP_LOST_TABARD_OF_BLOOD_KNIGHT "I've lost my Tabard of Blood Knight." -#define GOSSIP_LOST_TABARD_OF_THE_HAND "I've lost my Tabard of the Hand." -#define GOSSIP_LOST_TABARD_OF_THE_PROTECTOR "I've lost my Tabard of the Protector." -#define GOSSIP_LOST_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI "I've lost my Green Trophy Tabard of the Illidari." -#define GOSSIP_LOST_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI "I've lost my Purple Trophy Tabard of the Illidari." -#define GOSSIP_LOST_TABARD_OF_SUMMER_SKIES "I've lost my Tabard of Summer Skies." -#define GOSSIP_LOST_TABARD_OF_SUMMER_FLAMES "I've lost my Tabard of Summer Flames." -#define GOSSIP_LOST_LOREMASTERS_COLORS "I've lost my Loremaster's Colors." -#define GOSSIP_LOST_TABARD_OF_THE_EXPLORER "I've lost my Tabard of the Explorer." -#define GOSSIP_LOST_TABARD_OF_THE_ACHIEVER "I've lost my Tabard of the Achiever." - -class npc_tabard_vendor : public CreatureScript -{ -public: - npc_tabard_vendor() : CreatureScript("npc_tabard_vendor") { } - - bool OnGossipHello(Player* player, Creature* creature) - { - bool lostBloodKnight = false; - bool lostHand = false; - bool lostProtector = false; - bool lostIllidari = false; - bool lostSummer = false; - - //Tabard of the Blood Knight - if (player->GetQuestRewardStatus(QUEST_TRUE_MASTERS_OF_LIGHT) && !player->HasItemCount(ITEM_TABARD_OF_THE_BLOOD_KNIGHT, 1, true)) - lostBloodKnight = true; - - //Tabard of the Hand - if (player->GetQuestRewardStatus(QUEST_THE_UNWRITTEN_PROPHECY) && !player->HasItemCount(ITEM_TABARD_OF_THE_HAND, 1, true)) - lostHand = true; - - //Tabard of the Protector - if (player->GetQuestRewardStatus(QUEST_INTO_THE_BREACH) && !player->HasItemCount(ITEM_TABARD_OF_THE_PROTECTOR, 1, true)) - lostProtector = true; - - //Green Trophy Tabard of the Illidari - //Purple Trophy Tabard of the Illidari - if (player->GetQuestRewardStatus(QUEST_BATTLE_OF_THE_CRIMSON_WATCH) && - (!player->HasItemCount(ITEM_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI, 1, true) && - !player->HasItemCount(ITEM_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI, 1, true) && - !player->HasItemCount(ITEM_OFFERING_OF_THE_SHATAR, 1, true))) - lostIllidari = true; - - //Tabard of Summer Skies - //Tabard of Summer Flames - if (player->GetQuestRewardStatus(QUEST_SHARDS_OF_AHUNE) && - !player->HasItemCount(ITEM_TABARD_OF_THE_SUMMER_SKIES, 1, true) && - !player->HasItemCount(ITEM_TABARD_OF_THE_SUMMER_FLAMES, 1, true)) - lostSummer = true; - - if (lostBloodKnight || lostHand || lostProtector || lostIllidari || lostSummer) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - if (lostBloodKnight) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_BLOOD_KNIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if (lostHand) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_THE_HAND, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - if (lostProtector) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_THE_PROTECTOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - - if (lostIllidari) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - } - - if (lostSummer) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_SUMMER_SKIES, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_SUMMER_FLAMES, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - } - - player->SEND_GOSSIP_MENU(13583, creature->GetGUID()); - } - else - player->GetSession()->SendListInventory(creature->GetGUID()); - - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_TRADE: - player->GetSession()->SendListInventory(creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 1: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TABARD_OF_THE_BLOOD_KNIGHT, false); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TABARD_OF_THE_HAND, false); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TABARD_OF_THE_PROTECTOR, false); - break; - case GOSSIP_ACTION_INFO_DEF + 4: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI, false); - break; - case GOSSIP_ACTION_INFO_DEF + 5: + case GOSSIP_ACTION_INFO_DEF + 7: player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI, false); + player->CastSpell(player, SPELL_ESSENCE_INFUSED_MOONSTONE, false); break; - case GOSSIP_ACTION_INFO_DEF + 6: + case GOSSIP_ACTION_INFO_DEF + 8: player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TABARD_OF_SUMMER_SKIES, false); + player->AddItem(ITEM_KEY_TO_THE_FOCUSING_IRIS,1); break; - case GOSSIP_ACTION_INFO_DEF + 7: + case GOSSIP_ACTION_INFO_DEF + 9: player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TABARD_OF_SUMMER_FLAMES, false); + player->AddItem(ITEM_HC_KEY_TO_THE_FOCUSING_IRIS,1); break; } return true; @@ -3124,7 +2992,6 @@ void AddSC_npcs_special() new npc_wormhole(); new npc_pet_trainer(); new npc_locksmith(); - new npc_tabard_vendor(); new npc_experience(); new npc_fire_elemental(); new npc_earth_elemental(); diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index 3ec35b5394a..de998442419 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -53,7 +53,6 @@ set(shared_STAT_SRCS include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/SFMT - ${CMAKE_SOURCE_DIR}/dep/mersennetwister ${CMAKE_SOURCE_DIR}/dep/sockets/include ${CMAKE_SOURCE_DIR}/dep/utf8cpp ${CMAKE_SOURCE_DIR}/src/server diff --git a/src/server/shared/Containers.h b/src/server/shared/Containers.h new file mode 100644 index 00000000000..f0242cbff0e --- /dev/null +++ b/src/server/shared/Containers.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_CONTAINERS_H +#define TRINITY_CONTAINERS_H + +#include <list> + +//! Because circular includes are bad +extern uint32 urand(uint32 min, uint32 max); + +namespace Trinity +{ + namespace Containers + { + template<class T> + void RandomResizeList(std::list<T> &list, uint32 size) + { + size_t list_size = list.size(); + + while (list_size > size) + { + typename std::list<T>::iterator itr = list.begin(); + std::advance(itr, urand(0, list_size - 1)); + list.erase(itr); + --list_size; + } + } + + template<class T, class Predicate> + void RandomResizeList(std::list<T> &list, Predicate& predicate, uint32 size) + { + //! First use predicate filter + std::list<T> listCopy; + for (typename std::list<T>::iterator itr = list.begin(); itr != list.end(); ++itr) + if (predicate(*itr)) + listCopy.push_back(*itr); + + if (size) + RandomResizeList(listCopy, size); + + list = listCopy; + } + + /* Select a random element from a container. Note: make sure you explicitly empty check the container */ + template <class C> typename C::value_type const& SelectRandomContainerElement(C const& container) + { + typename C::const_iterator it = container.begin(); + std::advance(it, urand(0, container.size() - 1)); + return *it; + } + }; + //! namespace Containers +}; +//! namespace Trinity + +#endif //! #ifdef TRINITY_CONTAINERS_H
\ No newline at end of file diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index 5fe31006bb2..314d196cc06 100755 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -102,7 +102,7 @@ class DatabaseWorkerPool //! Shuts down delaythreads for this connection pool by underlying deactivate(). //! The next dequeue attempt in the worker thread tasks will result in an error, - //! ultimately ending the worker thread task. + //! ultimately ending the worker thread task. _queue->queue()->close(); for (uint8 i = 0; i < _connectionCount[IDX_ASYNC]; ++i) @@ -114,7 +114,7 @@ class DatabaseWorkerPool t->Close(); //! Closes the actualy MySQL connection. } - sLog->outSQLDriver("Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.", + sLog->outSQLDriver("Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.", GetDatabaseName()); //! Shut down the synchronous connections @@ -239,7 +239,7 @@ class DatabaseWorkerPool va_list ap; char szQuery[MAX_QUERY_LEN]; - va_start(ap, sql); + va_start(ap, conn); vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap); va_end(ap); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 97207410159..772a52b62cf 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -27,9 +27,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_DEL_EXPIRED_BANS, "UPDATE character_banned SET active = 0 WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_SEL_GUID_BY_NAME, "SELECT guid FROM characters WHERE name = ?", CONNECTION_BOTH); - PREPARE_STATEMENT(CHAR_SEL_CHECK_NAME, "SELECT 1 FROM characters WHERE name = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_SEL_CHECK_NAME, "SELECT 1 FROM characters WHERE name = ?", CONNECTION_BOTH); PREPARE_STATEMENT(CHAR_SEL_CHECK_GUID, "SELECT 1 FROM characters WHERE guid = ?", CONNECTION_SYNCH); - PREPARE_STATEMENT(CHAR_SEL_SUM_CHARS, "SELECT COUNT(guid) FROM characters WHERE account = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_SEL_SUM_CHARS, "SELECT COUNT(guid) FROM characters WHERE account = ?", CONNECTION_BOTH); PREPARE_STATEMENT(CHAR_SEL_CHAR_CREATE_INFO, "SELECT level, race, class FROM characters WHERE account = ? LIMIT 0, ?", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_INS_CHARACTER_BAN, "INSERT INTO character_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_UPD_CHARACTER_BAN, "UPDATE character_banned SET active = 0 WHERE guid = ? AND active != 0", CONNECTION_ASYNC) @@ -335,7 +335,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() // GM Survey/subsurvey/lag report PREPARE_STATEMENT(CHAR_INS_GM_SURVEY, "INSERT INTO gm_surveys (guid, surveyId, mainSurvey, overallComment, createTime) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(NOW()))", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_INS_GM_SUBSURVEY, "INSERT INTO gm_subsurveys (surveyId, subsurveyId, rank, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC) - PREPARE_STATEMENT(CHAR_INS_LAG_REPORT, "INSERT INTO lag_reports (guid, lagType, mapId, posX, posY, posZ) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_INS_LAG_REPORT, "INSERT INTO lag_reports (guid, lagType, mapId, posX, posY, posZ, latency, createTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC) // For loading and deleting expired auctions at startup PREPARE_STATEMENT(CHAR_SEL_EXPIRED_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid WHERE ah.time <= ?", CONNECTION_SYNCH) diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index 63648f66e29..febc5ef3573 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -195,7 +195,23 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) case VER_PLATFORM_WIN32_NT: // Test for the specific product family. if (osvi.dwMajorVersion == 6) - _tcsncat(szVersion, _T("Windows Vista or Windows Server 2008 "), cntMax); + { + #if WINVER < 0x0500 + if (osvi.wReserved[1] == VER_NT_WORKSTATION) + #else + if (osvi.wProductType == VER_NT_WORKSTATION) + #endif // WINVER < 0x0500 + { + if (osvi.dwMinorVersion == 1) + _tcsncat(szVersion, _T("Windows 7 "), cntMax); + else + _tcsncat(szVersion, _T("Windows Vista "), cntMax); + } + else if (osvi.dwMinorVersion == 1) + _tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax); + else + _tcsncat(szVersion, _T("Windows Server 2008 "), cntMax); + } if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) _tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax); if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) diff --git a/src/server/shared/Dynamic/TypeContainerFunctionsPtr.h b/src/server/shared/Dynamic/TypeContainerFunctionsPtr.h deleted file mode 100755 index 2c065d96d4a..00000000000 --- a/src/server/shared/Dynamic/TypeContainerFunctionsPtr.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef TYPECONTAINER_FUNCTIONS_PTR_H -#define TYPECONTAINER_FUNCTIONS_PTR_H - -/* - * Here you'll find a list of helper functions to make - * the TypeContainer usefull. Without it, its hard - * to access or mutate the container. - */ - -#include "Platform/Define.h" -#include "Utilities/TypeList.h" -#include <map> - -namespace Trinity -{ - /* ContainerMapList Helpers */ - // count functions - // template<class SPECIFIC_TYPE> size_t Count(const ContainerMapList<SPECIFIC_TYPE> &elements, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - // { - // return elements._element.size(); - // }; - // - // template<class SPECIFIC_TYPE> size_t Count(const ContainerMapList<TypeNull> &elements, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - // { - // return 0; - // } - // - // template<class SPECIFIC_TYPE, class T> size_t Count(const ContainerMapList<T> &elements, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - // { - // return 0; - // } - // - // template<class SPECIFIC_TYPE, class T> size_t Count(const ContainerMapList<TypeList<SPECIFIC_TYPE, T> >&elements, SPECIFIC_TYPE* fake) - // { - // return Count(elements._elements, fake); - // } - // - // template<class SPECIFIC_TYPE, class H, class T> size_t Count(const ContainerMapList<TypeList<H, T> >&elements, SPECIFIC_TYPE* fake) - // { - // return Count(elements._TailElements, fake); - // } - - // non-const find functions - template<class SPECIFIC_TYPE> CountedPtr<SPECIFIC_TYPE>& Find(ContainerMapList<SPECIFIC_TYPE> &elements, OBJECT_HANDLE hdl, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - { - typename std::map<OBJECT_HANDLE, CountedPtr<SPECIFIC_TYPE> >::iterator iter = elements._element.find(hdl); - return (iter == elements._element.end() ? NullPtr<SPECIFIC_TYPE>((SPECIFIC_TYPE*)NULL) : iter->second); - }; - - template<class SPECIFIC_TYPE> CountedPtr<SPECIFIC_TYPE>& Find(ContainerMapList<TypeNull> &elements, OBJECT_HANDLE hdl, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - { - return NullPtr<SPECIFIC_TYPE>((SPECIFIC_TYPE*)NULL);// terminate recursion - } - - template<class SPECIFIC_TYPE, class T> CountedPtr<SPECIFIC_TYPE>& Find(ContainerMapList<T> &elements, OBJECT_HANDLE hdl, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - { - return NullPtr<SPECIFIC_TYPE>((SPECIFIC_TYPE*)NULL);// this is a missed - } - - template<class SPECIFIC_TYPE, class H, class T> CountedPtr<SPECIFIC_TYPE>& Find(ContainerMapList<TypeList<H, T> >&elements, OBJECT_HANDLE hdl, CountedPtr<SPECIFIC_TYPE>* fake) - { - CountedPtr<SPECIFIC_TYPE> &t = Find(elements._elements, hdl, fake); - return (!t ? Find(elements._TailElements, hdl, fake) : t); - } - - // const find functions - template<class SPECIFIC_TYPE> const CountedPtr<SPECIFIC_TYPE>& Find(const ContainerMapList<SPECIFIC_TYPE> &elements, OBJECT_HANDLE hdl, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - { - typename CountedPtr<SPECIFIC_TYPE>::iterator iter = elements._element.find(hdl); - return (iter == elements._element.end() ? NullPtr<SPECIFIC_TYPE>((SPECIFIC_TYPE*)NULL) : iter->second); - }; - - template<class SPECIFIC_TYPE> const CountedPtr<SPECIFIC_TYPE>& Find(const ContainerMapList<TypeNull> &elements, OBJECT_HANDLE hdl, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - { - return NullPtr<SPECIFIC_TYPE>((SPECIFIC_TYPE*)NULL); - } - - template<class SPECIFIC_TYPE, class T> const CountedPtr<SPECIFIC_TYPE>& Find(const ContainerMapList<T> &elements, OBJECT_HANDLE hdl, CountedPtr<SPECIFIC_TYPE>* /*fake*/) - { - return NullPtr<SPECIFIC_TYPE>((SPECIFIC_TYPE*)NULL); - } - - template<class SPECIFIC_TYPE, class H, class T> CountedPtr<SPECIFIC_TYPE>& Find(const ContainerMapList<TypeList<H, T> >&elements, OBJECT_HANDLE hdl, CountedPtr<SPECIFIC_TYPE>* fake) - { - CountedPtr<SPECIFIC_TYPE> &t = Find(elements._elements, hdl, fake); - if (!t) - t = Find(elements._TailElement, hdl, fake); - - return t; - } - - // non-const insert functions - template<class SPECIFIC_TYPE> CountedPtr<SPECIFIC_TYPE>& Insert(ContainerMapList<SPECIFIC_TYPE> &elements, CountedPtr<SPECIFIC_TYPE> &obj, OBJECT_HANDLE hdl) - { - elements._element[hdl] = obj; - return obj; - }; - - template<class SPECIFIC_TYPE> CountedPtr<SPECIFIC_TYPE>& Insert(ContainerMapList<TypeNull> &elements, CountedPtr<SPECIFIC_TYPE> &obj, OBJECT_HANDLE hdl) - { - return NullPtr<SPECIFIC_TYPE>((SPECIFIC_TYPE*)NULL); - } - - // this is a missed - template<class SPECIFIC_TYPE, class T> CountedPtr<SPECIFIC_TYPE>& Insert(ContainerMapList<T> &elements, CountedPtr<SPECIFIC_TYPE> &obj, OBJECT_HANDLE hdl) - { - return NullPtr<SPECIFIC_TYPE>((SPECIFIC_TYPE*)NULL);// a missed - } - - // Recursion - template<class SPECIFIC_TYPE, class H, class T> CountedPtr<SPECIFIC_TYPE>& Insert(ContainerMapList<TypeList<H, T> >&elements, CountedPtr<SPECIFIC_TYPE> &obj, OBJECT_HANDLE hdl) - { - CountedPtr<SPECIFIC_TYPE> &t= Insert(elements._elements, obj, hdl); - return (!t ? Insert(elements._TailElements, obj, hdl) : t); - } - - // non-const remove method - template<class SPECIFIC_TYPE> bool Remove(ContainerMapList<SPECIFIC_TYPE> &elements, CountedPtr<SPECIFIC_TYPE> &obj, OBJECT_HANDLE hdl) - { - typename std::map<OBJECT_HANDLE, CountedPtr<SPECIFIC_TYPE> >::iterator iter = elements._element.find(hdl); - if ( iter != elements._element.end() ) - { - elements._element.erase(iter); - return true; - } - - return false; // found... terminate the search - } - - template<class SPECIFIC_TYPE> bool Remove(ContainerMapList<TypeNull> &elements, CountedPtr<SPECIFIC_TYPE> &obj, OBJECT_HANDLE hdl) - { - return false; - } - - // this is a missed - template<class SPECIFIC_TYPE, class T> bool Remove(ContainerMapList<T> &elements, CountedPtr<SPECIFIC_TYPE> &obj, OBJECT_HANDLE hdl) - { - return false; - } - - template<class SPECIFIC_TYPE, class T, class H> bool Remove(ContainerMapList<TypeList<H, T> > &elements, CountedPtr<SPECIFIC_TYPE> &obj, OBJECT_HANDLE hdl) - { - // The head element is bad - bool t = Remove(elements._elements, obj, hdl); - return ( !t ? Remove(elements._TailElements, obj, hdl) : t ); - } - -} -#endif - diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index 4c2c1936993..196882dc2a0 100755 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -20,7 +20,7 @@ #define _UTIL_H #include "Common.h" - +#include "Containers.h" #include <string> #include <vector> @@ -73,7 +73,7 @@ inline uint32 secsToTimeBitFields(time_t secs) double rand_norm(void); /* Return a random double from 0.0 to 99.9999999999999. Floats support only 7 valid decimal digits. - * A double supports up to 15 valid decimal digits and is used internaly (RAND32_MAX has 10 digits). + * A double supports up to 15 valid decimal digits and is used internally (RAND32_MAX has 10 digits). * With an FPU, there is usually no difference in performance between float and double. */ double rand_chance(void); @@ -653,12 +653,4 @@ public: }; }; -/* Select a random element from a container. Note: make sure you explicitly empty check the container */ -template <class C> typename C::value_type const& SelectRandomContainerElement(C const& container) -{ - typename C::const_iterator it = container.begin(); - std::advance(it, urand(0, container.size() - 1)); - return *it; -} - #endif diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index d1419cb0fcb..0d51f30449e 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -48,7 +48,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/gsoap ${CMAKE_SOURCE_DIR}/dep/sockets/include ${CMAKE_SOURCE_DIR}/dep/SFMT - ${CMAKE_SOURCE_DIR}/dep/mersennetwister ${CMAKE_SOURCE_DIR}/src/server/collision ${CMAKE_SOURCE_DIR}/src/server/collision/Management ${CMAKE_SOURCE_DIR}/src/server/collision/Models diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index bbde9f4675e..cf2f2188a70 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -71,7 +71,7 @@ float CONF_flat_height_delta_limit = 0.005f; // If max - min less this value - s float CONF_flat_liquid_delta_limit = 0.001f; // If max - min less this value - liquid surface is flat // List MPQ for extract from -char *CONF_mpq_list[]={ +const char *CONF_mpq_list[]={ "common.MPQ", "common-2.MPQ", "lichking.MPQ", @@ -83,7 +83,7 @@ char *CONF_mpq_list[]={ "patch-5.MPQ", }; -static char* const langs[] = {"enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" }; +static const char* const langs[] = {"enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" }; #define LANG_COUNT 12 void CreateDir( const std::string& Path ) |