diff options
Diffstat (limited to 'src')
73 files changed, 2497 insertions, 1165 deletions
diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h index 98b0afdefc9..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) 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/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 209eb38e13a..893c8f4580e 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1119,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()); } @@ -1154,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); } 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/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..c18806490f2 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -30,8 +30,8 @@ class BattlegroundSAScore : public BattlegroundScore uint8 gates_destroyed; }; -#define BG_SA_FLAG_AMOUNT 3 -#define BG_SA_DEMOLISHER_AMOUNT 4 +#define BG_SA_FLAG_AMOUNT 3 +#define BG_SA_DEMOLISHER_AMOUNT 4 enum BG_SA_Status { @@ -45,45 +45,66 @@ 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_BLUE_GATE_DAMAGED = 19040, + BG_SA_EVENT_BLUE_GATE_DESTROYED = 19045, + + BG_SA_EVENT_GREEN_GATE_DAMAGED = 19041, + BG_SA_EVENT_GREEN_GATE_DESTROYED = 19046, + + BG_SA_EVENT_RED_GATE_DAMAGED = 19042, + BG_SA_EVENT_RED_GATE_DESTROYED = 19047, + + BG_SA_EVENT_PURPLE_GATE_DAMAGED = 19043, + BG_SA_EVENT_PURPLE_GATE_DESTROYED = 19048, + + BG_SA_EVENT_YELLOW_GATE_DAMAGED = 19044, + BG_SA_EVENT_YELLOW_GATE_DESTROYED = 19049, + + BG_SA_EVENT_ANCIENT_GATE_DAMAGED = 19836, + BG_SA_EVENT_ANCIENT_GATE_DESTROYED = 19837 }; enum BG_SA_Timers { - BG_SA_BOAT_START = 60*IN_MILLISECONDS, - BG_SA_WARMUPLENGTH = 120*IN_MILLISECONDS, - BG_SA_ROUNDLENGTH = 600*IN_MILLISECONDS + BG_SA_BOAT_START = 60 * IN_MILLISECONDS, + BG_SA_WARMUPLENGTH = 120 * IN_MILLISECONDS, + BG_SA_ROUNDLENGTH = 600 * IN_MILLISECONDS }; enum BG_SA_WorldStates { - BG_SA_TIMER_MINS = 3559, - BG_SA_TIMER_SEC_TENS = 3560, - BG_SA_TIMER_SEC_DECS = 3561, - BG_SA_ALLY_ATTACKS = 4352, - BG_SA_HORDE_ATTACKS = 4353, - BG_SA_PURPLE_GATEWS = 3614, - BG_SA_RED_GATEWS = 3617, - BG_SA_BLUE_GATEWS = 3620, - BG_SA_GREEN_GATEWS = 3623, - BG_SA_YELLOW_GATEWS = 3638, - BG_SA_ANCIENT_GATEWS = 3849, - BG_SA_LEFT_GY_ALLIANCE = 3635, - BG_SA_RIGHT_GY_ALLIANCE = 3636, - BG_SA_CENTER_GY_ALLIANCE = 3637, - BG_SA_RIGHT_ATT_TOKEN_ALL = 3627, - BG_SA_LEFT_ATT_TOKEN_ALL = 3626, - BG_SA_LEFT_ATT_TOKEN_HRD = 3629, - BG_SA_RIGHT_ATT_TOKEN_HRD = 3628, - BG_SA_HORDE_DEFENCE_TOKEN = 3631, - BG_SA_ALLIANCE_DEFENCE_TOKEN = 3630, - BG_SA_RIGHT_GY_HORDE = 3632, - BG_SA_LEFT_GY_HORDE = 3633, - BG_SA_CENTER_GY_HORDE = 3634, - BG_SA_BONUS_TIMER = 0xdf3, - BG_SA_ENABLE_TIMER = 3564, + BG_SA_TIMER_MINS = 3559, + BG_SA_TIMER_SEC_TENS = 3560, + BG_SA_TIMER_SEC_DECS = 3561, + BG_SA_ALLY_ATTACKS = 4352, + BG_SA_HORDE_ATTACKS = 4353, + BG_SA_PURPLE_GATEWS = 3614, + BG_SA_RED_GATEWS = 3617, + BG_SA_BLUE_GATEWS = 3620, + BG_SA_GREEN_GATEWS = 3623, + BG_SA_YELLOW_GATEWS = 3638, + BG_SA_ANCIENT_GATEWS = 3849, + BG_SA_LEFT_GY_ALLIANCE = 3635, + BG_SA_RIGHT_GY_ALLIANCE = 3636, + BG_SA_CENTER_GY_ALLIANCE = 3637, + BG_SA_RIGHT_ATT_TOKEN_ALL = 3627, + BG_SA_LEFT_ATT_TOKEN_ALL = 3626, + BG_SA_LEFT_ATT_TOKEN_HRD = 3629, + BG_SA_RIGHT_ATT_TOKEN_HRD = 3628, + BG_SA_HORDE_DEFENCE_TOKEN = 3631, + BG_SA_ALLIANCE_DEFENCE_TOKEN = 3630, + BG_SA_RIGHT_GY_HORDE = 3632, + BG_SA_LEFT_GY_HORDE = 3633, + BG_SA_CENTER_GY_HORDE = 3634, + BG_SA_BONUS_TIMER = 0xdf3, + BG_SA_ENABLE_TIMER = 3564, }; enum npc @@ -122,14 +143,14 @@ enum BG_SA_NPCs enum BG_SA_Boat { - BG_SA_BOAT_ONE_A =193182, - BG_SA_BOAT_TWO_H =193183, - BG_SA_BOAT_ONE_H =193184, - BG_SA_BOAT_TWO_A =193185, + BG_SA_BOAT_ONE_A = 193182, + BG_SA_BOAT_TWO_H = 193183, + BG_SA_BOAT_ONE_H = 193184, + BG_SA_BOAT_TWO_A = 193185, }; -const uint32 BG_SA_NpcEntries[BG_SA_MAXNPC] = - { +uint32 const BG_SA_NpcEntries[BG_SA_MAXNPC] = +{ NPC_ANTI_PERSONNAL_CANNON, NPC_ANTI_PERSONNAL_CANNON, NPC_ANTI_PERSONNAL_CANNON, @@ -140,25 +161,25 @@ const uint32 BG_SA_NpcEntries[BG_SA_MAXNPC] = NPC_ANTI_PERSONNAL_CANNON, NPC_ANTI_PERSONNAL_CANNON, NPC_ANTI_PERSONNAL_CANNON, - //4 beach demolishers + // 4 beach demolishers NPC_DEMOLISHER_SA, NPC_DEMOLISHER_SA, NPC_DEMOLISHER_SA, NPC_DEMOLISHER_SA, - //Triggers + // Triggers 23472, 23472, 23472, 23472, 23472, - //Used Demolisher Salesman + // Used Demolisher Salesman NPC_RIGGER_SPARKLIGHT, NPC_GORGRIL_RIGSPARK - }; +}; -const float BG_SA_NpcSpawnlocs[BG_SA_MAXNPC + BG_SA_DEMOLISHER_AMOUNT][4] = +float const BG_SA_NpcSpawnlocs[BG_SA_MAXNPC + BG_SA_DEMOLISHER_AMOUNT][4] = { - //Cannons + // Cannons { 1436.429f, 110.05f, 41.407f, 5.4f }, { 1404.9023f, 84.758f, 41.183f, 5.46f }, { 1068.693f, -86.951f, 93.81f, 0.02f }, @@ -169,21 +190,21 @@ const float BG_SA_NpcSpawnlocs[BG_SA_MAXNPC + BG_SA_DEMOLISHER_AMOUNT][4] = { 1249.634f, -224.189f, 66.72f, 0.635f }, { 1236.213f, 92.287f, 64.965f, 5.751f }, { 1215.11f, 57.772f, 64.739f, 5.78f }, - //Demolishers + // Demolishers { 1611.597656f, -117.270073f, 8.719355f, 2.513274f}, { 1575.562500f, -158.421875f, 5.024450f, 2.129302f}, { 1618.047729f, 61.424641f, 7.248210f, 3.979351f}, { 1575.103149f, 98.873344f, 2.830360f, 3.752458f}, - //trigger + // Triggers { 1453.49f, -250.453f, 30.896f, 4.2883f}, { 1377.05f, 97.036f, 30.8605f, 2.46539f}, { 1186.05f, 58.8048f, 56.5491f, 2.75992f}, { 1042.83f, -72.839f, 84.8145f, 3.58615f}, { 1233.62f, -250.49f, 55.4036f, 3.7016f}, - //Npcs + // Npcs { 1348.644165f, -298.786469f, 31.080130f, 1.710423f}, { 1358.191040f, 195.527786f, 31.018187f, 4.171337f}, - //Demolishers2 + // Demolishers 2 { 1371.055786f, -317.071136f, 35.007359f, 1.947460f}, { 1424.034912f, -260.195190f, 31.084425f, 2.820013f}, { 1353.139893f, 223.745438f, 35.265411f, 4.343684f}, @@ -221,7 +242,7 @@ enum BG_SA_Objects BG_SA_MAXOBJ = BG_SA_BOMB+68 }; -const float BG_SA_ObjSpawnlocs[BG_SA_MAXOBJ][4] = +float const BG_SA_ObjSpawnlocs[BG_SA_MAXOBJ][4] = { { 1411.57f, 108.163f, 28.692f, 5.441f }, { 1055.452f, -108.1f, 82.134f, 0.034f }, @@ -230,30 +251,30 @@ const float BG_SA_ObjSpawnlocs[BG_SA_MAXOBJ][4] = { 1214.681f, 81.21f, 53.413f, 5.745f }, { 878.555f, -108.2f, 117.845f, 0.0f }, { 836.5f, -108.8f, 120.219f, 0.0f }, - //Ships + // Ships { 2679.696777f, -826.891235f, 3.712860f, 5.78367f}, //rot2 1 rot3 0.0002f { 2574.003662f, 981.261475f, 2.603424f, 0.807696f}, - //Sigils + // Sigils { 1414.054f, 106.72f, 41.442f, 5.441f }, { 1060.63f, -107.8f, 94.7f, 0.034f }, { 1433.383f, -216.4f, 43.642f, 0.9736f }, { 1230.75f, -210.724f, 67.611f, 0.5023f }, { 1217.8f, 79.532f, 66.58f, 5.745f }, - //Flagpoles + // Flagpoles { 1215.114258f, -65.711861f, 70.084267f, -3.124123f}, {1338.863892f, -153.336533f, 30.895121f, -2.530723f}, {1309.124268f, 9.410645f, 30.893402f, -1.623156f}, - //Flags + // Flags { 1215.108032f, -65.715767f, 70.084267f, -3.124123f}, { 1338.859253f, -153.327316f, 30.895077f, -2.530723f}, { 1309.192017f, 9.416233f, 30.893402f, 1.518436f}, - //Portal + // Portal {1468.380005f, -225.798996f, 30.896200f, 0.0f}, //blue {1394.270020f, 72.551399f, 31.054300f, 0.0f}, //green {1065.260010f, -89.79501f, 81.073402f, 0.0f}, //yellow {1216.069946f, 47.904301f, 54.278198f, 0.0f}, //purple {1255.569946f, -233.548996f, 56.43699f, 0.0f}, //red - //Bombs + // Bombs {1333.45f, 211.354f, 31.0538f, 5.03666f}, {1334.29f, 209.582f, 31.0532f, 1.28088f}, {1332.72f, 210.049f, 31.0532f, 1.28088f}, @@ -337,7 +358,7 @@ const float BG_SA_ObjSpawnlocs[BG_SA_MAXOBJ][4] = * to get horde ones. */ -const uint32 BG_SA_ObjEntries[BG_SA_MAXOBJ + BG_SA_FLAG_AMOUNT] = +uint32 const BG_SA_ObjEntries[BG_SA_MAXOBJ + BG_SA_FLAG_AMOUNT] = { 190722, 190727, @@ -367,7 +388,7 @@ const uint32 BG_SA_ObjEntries[BG_SA_MAXOBJ + BG_SA_FLAG_AMOUNT] = 190753 }; -const uint32 BG_SA_Factions[2] = +uint32 const BG_SA_Factions[2] = { 1732, 1735, @@ -392,13 +413,13 @@ const uint32 BG_SA_GYEntries[BG_SA_MAX_GY] = 1348, }; -const float BG_SA_GYOrientation[BG_SA_MAX_GY] = +float const BG_SA_GYOrientation[BG_SA_MAX_GY] = { 6.202f, - 1.926f, //right capturable GY - 3.917f, //left capturable GY - 3.104f, //center, capturable - 6.148f, //defender last GY + 1.926f, // right capturable GY + 3.917f, // left capturable GY + 3.104f, // center, capturable + 6.148f, // defender last GY }; struct BG_SA_RoundScore @@ -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 495178f18dd..d100dc645a2 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -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/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 042f16be3cc..cc64a8e22dd 100755 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -359,7 +359,6 @@ ChatCommand* ChatHandler::getCommandTable() { "summon", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleSummonCommand>, "", NULL }, { "groupsummon", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGroupSummonCommand>, "", NULL }, { "commands", SEC_PLAYER, true, OldHandler<&ChatHandler::HandleCommandsCommand>, "", NULL }, - { "demorph", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleDeMorphCommand>, "", NULL }, { "die", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleDieCommand>, "", NULL }, { "revive", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleReviveCommand>, "", NULL }, { "dismount", SEC_PLAYER, false, OldHandler<&ChatHandler::HandleDismountCommand>, "", NULL }, diff --git a/src/server/game/Chat/Commands/Level2.cpp b/src/server/game/Chat/Commands/Level2.cpp index cc638193b5a..52bdcd15163 100755 --- a/src/server/game/Chat/Commands/Level2.cpp +++ b/src/server/game/Chat/Commands/Level2.cpp @@ -205,22 +205,6 @@ bool ChatHandler::HandleItemMoveCommand(const char* args) return true; } -//demorph player or unit -bool ChatHandler::HandleDeMorphCommand(const char* /*args*/) -{ - Unit* target = getSelectedUnit(); - if (!target) - target = m_session->GetPlayer(); - - // check online security - else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) - return false; - - target->DeMorph(); - - return true; -} - //kick player bool ChatHandler::HandleKickPlayerCommand(const char *args) { 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/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 6a8ae07291a..fde85feb8d9 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -135,7 +135,7 @@ CreatureBaseStats const* CreatureBaseStats::GetBaseStats(uint8 level, uint8 unit bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) { - m_owner.ForcedDespawn(); + m_owner.DespawnOrUnsummon(); // since we are here, we are not TempSummon as object type cannot change during runtime return true; } @@ -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 4b5b07fd8a5..f6021a7d7ec 100755 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -507,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; @@ -635,7 +635,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature void RemoveCorpse(bool setSpawnTime = true); - void ForcedDespawn(uint32 timeMSToDespawn = 0); void DespawnOrUnsummon(uint32 msTimeToDespawn = 0); time_t const& GetRespawnTime() const { return m_respawnTime; } @@ -763,6 +762,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature bool IsInvisibleDueToDespawn() const; bool CanAlwaysSee(WorldObject const* obj) const; private: + void ForcedDespawn(uint32 timeMSToDespawn = 0); + //WaypointMovementGenerator vars uint32 m_waypointID; uint32 m_path_id; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index d96c9052b7a..f58dd6b2e4d 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -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/Object/Object.h b/src/server/game/Entities/Object/Object.h index 39be4d4f529..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; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 141902fbbdc..7c70fe9358e 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9217,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; @@ -9761,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 diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index da23a7ba010..fb91c3fc9f1 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -460,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(); @@ -476,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(); diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 4ce05ff40d3..c297ce1e792 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -285,9 +285,6 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 typ // return; // Something went wrong in the spellsystem //} - // This is not good, we have to send update twice - accessory->SendMovementFlagUpdate(); - if (GetBase()->GetTypeId() == TYPEID_UNIT) sScriptMgr->OnInstallAccessory(this, accessory); } @@ -352,6 +349,7 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) unit->m_movementInfo.t_pos.m_orientation = 0; unit->m_movementInfo.t_time = 0; // 1 for player unit->m_movementInfo.t_seat = seat->first; + unit->m_movementInfo.t_guid = _me->GetGUID(); if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index ec79db769da..e81822e72be 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -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/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index f1217e58b3f..b3d663e1850 100755 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -46,7 +46,7 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->SetSemaphoreTeleportFar(false); // get the teleport destination - WorldLocation &loc = GetPlayer()->GetTeleportDest(); + WorldLocation const loc = GetPlayer()->GetTeleportDest(); // possible errors in the coordinate validity check if (!MapManager::IsValidMapCoord(loc)) 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/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 0386e6b4214..06aca10879d 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -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, diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 76c3f1c073c..f64d0953e86 100755 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -61,7 +61,6 @@ void AddSC_reload_commandscript(); void AddSC_tele_commandscript(); void AddSC_titles_commandscript(); void AddSC_wp_commandscript(); -void AddSC_gps_commandscript(); #ifdef SCRIPTS //world @@ -425,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(); @@ -663,7 +663,6 @@ void AddCommandScripts() AddSC_tele_commandscript(); AddSC_titles_commandscript(); AddSC_wp_commandscript(); - AddSC_gps_commandscript(); } void AddWorldScripts() @@ -1129,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/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index dbbd89c7533..31a8e57825c 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1616,7 +1616,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const { // 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); @@ -6473,7 +6473,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const // damage caster for heal amount if (target != caster && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL) { - uint32 funnelDamage = GetSpellInfo()->Effects[EFFECT_0].CalcValue(); // damage is not affected by spell power + uint32 funnelDamage = GetSpellInfo()->ManaPerSecond; // damage is not affected by spell power if ((int32)funnelDamage > gain) funnelDamage = gain; uint32 funnelAbsorb = 0; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index df2b9c35320..f055d669925 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3107,13 +3107,13 @@ void Spell::cast(bool skipCheck) // should be done before the spell is actually executed sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck); - // Let any pets know we've attacked something. As of 3.0.2 pets begin - // attacking their owner's target immediately - if (Pet* playerPet = playerCaster->GetPet()) - { - if (playerPet->isAlive() && playerPet->isControlled() && (m_targets.GetTargetMask() & TARGET_FLAG_UNIT)) - playerPet->AI()->OwnerAttacked(m_targets.GetObjectTarget()->ToUnit()); - } + // 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); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 5078391348f..d3566c24a48 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); } } } @@ -1102,10 +1085,6 @@ void Spell::EffectForceCast(SpellEffIndex effIndex) case 52349: // Overtake unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID); return; - case 72378: // Blood Nova - case 73058: // Blood Nova - m_caster->CastSpell(unitTarget, damage, true); // additional spell cast - break; } } @@ -5727,9 +5706,9 @@ void Spell::EffectSummonDeadPet(SpellEffIndex /*effIndex*/) } 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/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 05431ef0a16..64e1527b8d3 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3298,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 @@ -3333,13 +3346,22 @@ void SpellMgr::LoadDbcDataCorrections() case 70835: // Bone Storm (Lord Marrowgar) case 70836: // Bone Storm (Lord Marrowgar) case 72864: // Death Plague (Rotting Frost Giant) - case 72378: // Blood Nova (Deathbringer Saurfang) - case 73058: // Blood Nova (Deathbringer Saurfang) case 71160: // Plague Stench (Stinky) case 71161: // Plague Stench (Stinky) case 71123: // Decimate (Stinky & Precious) spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd break; + case 72378: // Blood Nova (Deathbringer Saurfang) + case 73058: // Blood Nova (Deathbringer Saurfang) + spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; + spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; + break; + case 72769: // Scent of Blood (Deathbringer Saurfang) + spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; + // no break + case 72771: // Scent of Blood (Deathbringer Saurfang) + spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; + break; case 72723: // Resistant Skin (Deathbringer Saurfang adds) // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client spellInfo->Effect[2] = 0; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index df1640df1b7..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()) { 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/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index f0136b065e8..792fdeb3e7b 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -119,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/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt index d14e71aac4a..86fe984e197 100644 --- a/src/server/scripts/Commands/CMakeLists.txt +++ b/src/server/scripts/Commands/CMakeLists.txt @@ -17,7 +17,6 @@ set(scripts_STAT_SRCS Commands/cs_gm.cpp Commands/cs_go.cpp Commands/cs_gobject.cpp - Commands/cs_gps.cpp Commands/cs_honor.cpp Commands/cs_learn.cpp Commands/cs_misc.cpp diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 679bb450800..c7bcde01e9b 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -95,6 +95,7 @@ public: static ChatCommand commandTable[] = { { "debug", SEC_MODERATOR, true, NULL, "", debugCommandTable }, + { "wpgps", SEC_ADMINISTRATOR, false, &HandleWPGPSCommand, "", NULL }, { NULL, SEC_PLAYER, false, NULL, "", NULL } }; return commandTable; @@ -1319,6 +1320,16 @@ public: return true; } + + static bool HandleWPGPSCommand(ChatHandler* handler, char const* /*args*/) + { + Player* player = handler->GetSession()->GetPlayer(); + + sLog->outSQLDev("(@PATH, XX, %.3f, %.3f, %.5f, 0,0, 0,100, 0),", player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); + + handler->PSendSysMessage("Waypoint SQL written to SQL Developer log"); + return true; + } }; void AddSC_debug_commandscript() diff --git a/src/server/scripts/Commands/cs_gps.cpp b/src/server/scripts/Commands/cs_gps.cpp deleted file mode 100644 index 59e2ec90905..00000000000 --- a/src/server/scripts/Commands/cs_gps.cpp +++ /dev/null @@ -1,144 +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/>. - */ - -/* ScriptData -Name: gps_commandscript -%Complete: 100 -Comment: GPS/WPGPS commands -Category: commandscripts -EndScriptData */ - -#include "ObjectAccessor.h" -#include "ScriptMgr.h" -#include "Chat.h" -#include "CellImpl.h" - -class gps_commandscript : public CommandScript -{ -public: - gps_commandscript() : CommandScript("gps_commandscript") { } - - ChatCommand* GetCommands() const - { - static ChatCommand commandTable[] = - { - { "gps", SEC_ADMINISTRATOR, false, &HandleGPSCommand, "", NULL }, - { "wpgps", SEC_ADMINISTRATOR, false, &HandleWPGPSCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } - }; - return commandTable; - } - - static bool HandleGPSCommand(ChatHandler* handler, char const* args) - { - WorldObject* object = NULL; - if (*args) - { - uint64 guid = handler->extractGuidFromLink((char*)args); - if (guid) - object = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*handler->GetSession()->GetPlayer(), guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT); - - if (!object) - { - handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); - handler->SetSentErrorMessage(true); - return false; - } - } - else - { - object = handler->getSelectedUnit(); - - if (!object) - { - handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - handler->SetSentErrorMessage(true); - return false; - } - } - - CellCoord cellCoord = Trinity::ComputeCellCoord(object->GetPositionX(), object->GetPositionY()); - Cell cell(cellCoord); - - uint32 zoneId, areaId; - object->GetZoneAndAreaId(zoneId, areaId); - - MapEntry const* mapEntry = sMapStore.LookupEntry(object->GetMapId()); - AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zoneId); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId); - - float zoneX = object->GetPositionX(); - float zoneY = object->GetPositionY(); - - Map2ZoneCoordinates(zoneX, zoneY, zoneId); - - Map const* map = object->GetMap(); - float groundZ = map->GetHeight(object->GetPhaseMask(), object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT); - float floorZ = map->GetHeight(object->GetPhaseMask(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ()); - - GridCoord gridCoord = Trinity::ComputeGridCoord(object->GetPositionX(), object->GetPositionY()); - - // 63? WHY? - int gridX = 63 - gridCoord.x_coord; - int gridY = 63 - gridCoord.y_coord; - - uint32 haveMap = Map::ExistMap(object->GetMapId(), gridX, gridY) ? 1 : 0; - uint32 haveVMap = Map::ExistVMap(object->GetMapId(), gridX, gridY) ? 1 : 0; - - if (haveVMap) - { - if (map->IsOutdoors(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ())) - handler->PSendSysMessage("You are outdoors"); - else - handler->PSendSysMessage("You are indoors"); - } - else - handler->PSendSysMessage("no VMAP available for area info"); - - handler->PSendSysMessage(LANG_MAP_POSITION, - object->GetMapId(), (mapEntry ? mapEntry->name[handler->GetSessionDbcLocale()] : "<unknown>"), - zoneId, (zoneEntry ? zoneEntry->area_name[handler->GetSessionDbcLocale()] : "<unknown>"), - areaId, (areaEntry ? areaEntry->area_name[handler->GetSessionDbcLocale()] : "<unknown>"), - object->GetPhaseMask(), - object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation(), - cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(), - zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap); - - LiquidData liquidStatus; - ZLiquidStatus status = map->getLiquidStatus(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus); - - if (status) - handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status); - - return true; - } - - static bool HandleWPGPSCommand(ChatHandler* handler, char const* /*args*/) - { - Player* player = handler->GetSession()->GetPlayer(); - - sLog->outSQLDev("(@PATH, XX, %.3f, %.3f, %.5f, 0,0, 0,100, 0),", player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); - - handler->PSendSysMessage("Waypoint SQL written to SQL Developer log"); - return true; - } -}; - -void AddSC_gps_commandscript() -{ - new gps_commandscript(); -} diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 5f0434e5c55..7c431566f52 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -17,6 +17,9 @@ #include "ScriptPCH.h"
#include "Chat.h"
+#include "ObjectAccessor.h"
+#include "ScriptMgr.h"
+#include "CellImpl.h"
class misc_commandscript : public CommandScript
{
@@ -27,7 +30,8 @@ public: {
static ChatCommand commandTable[] =
{
- { "dev", SEC_ADMINISTRATOR, false, &HandleDevCommand, "", NULL },
+ { "dev", SEC_ADMINISTRATOR, false, &HandleDevCommand, "", NULL },
+ { "gps", SEC_ADMINISTRATOR, false, &HandleGPSCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
return commandTable;
@@ -64,6 +68,90 @@ public: handler->SetSentErrorMessage(true);
return false;
}
+
+ static bool HandleGPSCommand(ChatHandler* handler, char const* args)
+ {
+ WorldObject* object = NULL;
+ if (*args)
+ {
+ uint64 guid = handler->extractGuidFromLink((char*)args);
+ if (guid)
+ object = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*handler->GetSession()->GetPlayer(), guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT);
+
+ if (!object)
+ {
+ handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ else
+ {
+ object = handler->getSelectedUnit();
+
+ if (!object)
+ {
+ handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ CellCoord cellCoord = Trinity::ComputeCellCoord(object->GetPositionX(), object->GetPositionY());
+ Cell cell(cellCoord);
+
+ uint32 zoneId, areaId;
+ object->GetZoneAndAreaId(zoneId, areaId);
+
+ MapEntry const* mapEntry = sMapStore.LookupEntry(object->GetMapId());
+ AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zoneId);
+ AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId);
+
+ float zoneX = object->GetPositionX();
+ float zoneY = object->GetPositionY();
+
+ Map2ZoneCoordinates(zoneX, zoneY, zoneId);
+
+ Map const* map = object->GetMap();
+ float groundZ = map->GetHeight(object->GetPhaseMask(), object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
+ float floorZ = map->GetHeight(object->GetPhaseMask(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
+
+ GridCoord gridCoord = Trinity::ComputeGridCoord(object->GetPositionX(), object->GetPositionY());
+
+ // 63? WHY?
+ int gridX = 63 - gridCoord.x_coord;
+ int gridY = 63 - gridCoord.y_coord;
+
+ uint32 haveMap = Map::ExistMap(object->GetMapId(), gridX, gridY) ? 1 : 0;
+ uint32 haveVMap = Map::ExistVMap(object->GetMapId(), gridX, gridY) ? 1 : 0;
+
+ if (haveVMap)
+ {
+ if (map->IsOutdoors(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ()))
+ handler->PSendSysMessage("You are outdoors");
+ else
+ handler->PSendSysMessage("You are indoors");
+ }
+ else
+ handler->PSendSysMessage("no VMAP available for area info");
+
+ handler->PSendSysMessage(LANG_MAP_POSITION,
+ object->GetMapId(), (mapEntry ? mapEntry->name[handler->GetSessionDbcLocale()] : "<unknown>"),
+ zoneId, (zoneEntry ? zoneEntry->area_name[handler->GetSessionDbcLocale()] : "<unknown>"),
+ areaId, (areaEntry ? areaEntry->area_name[handler->GetSessionDbcLocale()] : "<unknown>"),
+ object->GetPhaseMask(),
+ object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation(),
+ cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
+ zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap);
+
+ LiquidData liquidStatus;
+ ZLiquidStatus status = map->getLiquidStatus(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus);
+
+ if (status)
+ handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status);
+
+ return true;
+ }
};
void AddSC_misc_commandscript()
diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index bb3a4d65b76..b6feccc10c6 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -33,6 +33,16 @@ public: ChatCommand* GetCommands() const { + static ChatCommand modifyspeedCommandTable[] = + { + { "fly", SEC_MODERATOR, false, &HandleModifyFlyCommand, "", NULL }, + { "all", SEC_MODERATOR, false, &HandleModifyASpeedCommand, "", NULL }, + { "walk", SEC_MODERATOR, false, &HandleModifySpeedCommand, "", NULL }, + { "backwalk", SEC_MODERATOR, false, &HandleModifyBWalkCommand, "", NULL }, + { "swim", SEC_MODERATOR, false, &HandleModifySwimCommand, "", NULL }, + { "", SEC_MODERATOR, false, &HandleModifyASpeedCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; static ChatCommand modifyCommandTable[] = { { "hp", SEC_MODERATOR, false, &HandleModifyHPCommand, "", NULL }, @@ -41,29 +51,26 @@ public: { "runicpower", SEC_MODERATOR, false, &HandleModifyRunicPowerCommand, "", NULL }, { "energy", SEC_MODERATOR, false, &HandleModifyEnergyCommand, "", NULL }, { "money", SEC_MODERATOR, false, &HandleModifyMoneyCommand, "", NULL }, - { "speed", SEC_MODERATOR, false, &HandleModifySpeedCommand, "", NULL }, - { "swim", SEC_MODERATOR, false, &HandleModifySwimCommand, "", NULL }, { "scale", SEC_MODERATOR, false, &HandleModifyScaleCommand, "", NULL }, { "bit", SEC_MODERATOR, false, &HandleModifyBitCommand, "", NULL }, - { "bwalk", SEC_MODERATOR, false, &HandleModifyBWalkCommand, "", NULL }, - { "fly", SEC_MODERATOR, false, &HandleModifyFlyCommand, "", NULL }, - { "aspeed", SEC_MODERATOR, false, &HandleModifyASpeedCommand, "", NULL }, { "faction", SEC_MODERATOR, false, &HandleModifyFactionCommand, "", NULL }, { "spell", SEC_MODERATOR, false, &HandleModifySpellCommand, "", NULL }, - { "tp", SEC_MODERATOR, false, &HandleModifyTalentCommand, "", NULL }, + { "talentpoints", SEC_MODERATOR, false, &HandleModifyTalentCommand, "", NULL }, { "mount", SEC_MODERATOR, false, &HandleModifyMountCommand, "", NULL }, { "honor", SEC_MODERATOR, false, &HandleModifyHonorCommand, "", NULL }, - { "rep", SEC_GAMEMASTER, false, &HandleModifyRepCommand, "", NULL }, - { "arena", SEC_MODERATOR, false, &HandleModifyArenaCommand, "", NULL }, + { "reputation", SEC_GAMEMASTER, false, &HandleModifyRepCommand, "", NULL }, + { "arenapoints", SEC_MODERATOR, false, &HandleModifyArenaCommand, "", NULL }, { "drunk", SEC_MODERATOR, false, &HandleModifyDrunkCommand, "", NULL }, { "standstate", SEC_GAMEMASTER, false, &HandleModifyStandStateCommand, "", NULL }, - { "morph", SEC_GAMEMASTER, false, &HandleModifyMorphCommand, "", NULL }, { "phase", SEC_ADMINISTRATOR, false, &HandleModifyPhaseCommand, "", NULL }, { "gender", SEC_GAMEMASTER, false, &HandleModifyGenderCommand, "", NULL }, + { "speed", SEC_MODERATOR, false, NULL, "", modifyspeedCommandTable }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand commandTable[] = { + { "morph", SEC_GAMEMASTER, false, &HandleModifyMorphCommand, "", NULL }, + { "demorph", SEC_GAMEMASTER, false, &HandleDeMorphCommand, "", NULL }, { "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable }, { NULL, 0, false, NULL, "", NULL } }; @@ -1376,6 +1383,21 @@ public: return true; } +//demorph player or unit + static bool HandleDeMorphCommand(ChatHandler* handler, const char* /*args*/) + { + Unit* target = handler->getSelectedUnit(); + if (!target) + target = handler->GetSession()->GetPlayer(); + + // check online security + else if (target->GetTypeId() == TYPEID_PLAYER && handler->HasLowerSecurity(target->ToPlayer(), 0)) + return false; + + target->DeMorph(); + + return true; + } }; void AddSC_modify_commandscript() diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 37808e2b924..bf887bec164 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -664,7 +664,7 @@ public: { CAST_PLR(charmer)->GroupEventHappens(12687, me); charmer->RemoveAurasDueToSpell(SPELL_EFFECT_OVERTAKE); - CAST_CRE(who)->ForcedDespawn(); + CAST_CRE(who)->DespawnOrUnsummon(); //CAST_CRE(who)->Respawn(true); } @@ -767,7 +767,7 @@ public: //Todo: Creatures must not be removed, but, must instead // stand next to Gothik and be commanded into the pit // and dig into the ground. - CAST_CRE(who)->ForcedDespawn(); + CAST_CRE(who)->DespawnOrUnsummon(); if (CAST_PLR(owner)->GetQuestStatus(12698) == QUEST_STATUS_COMPLETE) owner->RemoveAllMinionsByEntry(GHOULS); diff --git a/src/server/scripts/Kalimdor/bloodmyst_isle.cpp b/src/server/scripts/Kalimdor/bloodmyst_isle.cpp index ffc2fb3fb61..6c692a6738b 100644 --- a/src/server/scripts/Kalimdor/bloodmyst_isle.cpp +++ b/src/server/scripts/Kalimdor/bloodmyst_isle.cpp @@ -193,7 +193,7 @@ public: if (type == POINT_MOTION_TYPE && id == 1) { DoScriptText(SAY_DIRECTION, me); - me->ForcedDespawn(); + me->DespawnOrUnsummon(); } } }; diff --git a/src/server/scripts/Kalimdor/durotar.cpp b/src/server/scripts/Kalimdor/durotar.cpp index 88bc3352ea1..fe5bedf4c98 100644 --- a/src/server/scripts/Kalimdor/durotar.cpp +++ b/src/server/scripts/Kalimdor/durotar.cpp @@ -264,7 +264,7 @@ class npc_tiger_matriarch : public CreatureScript vehSummoner->RemoveAurasDueToSpell(SPELL_SPIRIT_OF_THE_TIGER_RIDER); vehSummoner->RemoveAurasDueToSpell(SPELL_SUMMON_ZENTABRA_TRIGGER); } - me->ForcedDespawn(); + me->DespawnOrUnsummon(); } void DamageTaken(Unit* attacker, uint32& damage) @@ -287,7 +287,7 @@ class npc_tiger_matriarch : public CreatureScript vehSummoner->RemoveAurasDueToSpell(SPELL_SUMMON_ZENTABRA_TRIGGER); } - me->ForcedDespawn(); + me->DespawnOrUnsummon(); } } diff --git a/src/server/scripts/Kalimdor/dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/dustwallow_marsh.cpp index 4a1b67ba477..cbacc4fdf66 100644 --- a/src/server/scripts/Kalimdor/dustwallow_marsh.cpp +++ b/src/server/scripts/Kalimdor/dustwallow_marsh.cpp @@ -847,7 +847,7 @@ public: player->KilledMonsterCredit(NPC_THERAMORE_PRISONER, 0); prisoner->AI()->Talk(SAY_FREE); // We also emote cry here (handled in creature_text.emote) - prisoner->ForcedDespawn(6000); + prisoner->DespawnOrUnsummon(6000); } return 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/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index c718c0cee5f..f329b940e1f 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -104,7 +104,7 @@ enum BossSpells SPELL_SPIKE_TELE = 66170, }; -#define SPELL_PERMAFROST_HELPER RAID_MODE<uint32>(66193, 67856, 67855, 67857) +#define SPELL_PERMAFROST_HELPER RAID_MODE<uint32>(66193, 67855, 67856, 67857) enum SummonActions { 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/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/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_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 249eed01643..afc7c503bee 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -39,6 +39,7 @@ enum ScriptTexts SAY_FRENZY = 11, SAY_BERSERK = 12, SAY_DEATH = 13, + EMOTE_SCENT_OF_BLOOD = 14, // High Overlord Saurfang SAY_INTRO_HORDE_1 = 0, @@ -145,6 +146,7 @@ enum EventTypes EVENT_BOILING_BLOOD = 20, EVENT_BLOOD_NOVA = 21, EVENT_RUNE_OF_BLOOD = 22, + EVENT_SCENT_OF_BLOOD = 52, EVENT_OUTRO_ALLIANCE_1 = 23, EVENT_OUTRO_ALLIANCE_2 = 24, @@ -297,7 +299,7 @@ class boss_deathbringer_saurfang : public CreatureScript Talk(SAY_AGGRO); events.ScheduleEvent(EVENT_SUMMON_BLOOD_BEAST, 30000, 0, PHASE_COMBAT); - events.ScheduleEvent(EVENT_BERSERK, 480000, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_BERSERK, IsHeroic() ? 360000 : 480000, 0, PHASE_COMBAT); events.ScheduleEvent(EVENT_BOILING_BLOOD, 15500, 0, PHASE_COMBAT); events.ScheduleEvent(EVENT_BLOOD_NOVA, 17000, 0, PHASE_COMBAT); events.ScheduleEvent(EVENT_RUNE_OF_BLOOD, 20000, 0, PHASE_COMBAT); @@ -374,16 +376,13 @@ class boss_deathbringer_saurfang : public CreatureScript if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true)) summon->AI()->AttackStart(target); - if (IsHeroic()) - DoCast(summon, SPELL_SCENT_OF_BLOOD); - - summon->AI()->DoCast(summon, SPELL_BLOOD_LINK_BEAST, true); - summon->AI()->DoCast(summon, SPELL_RESISTANT_SKIN, true); + summon->CastSpell(summon, SPELL_BLOOD_LINK_BEAST, true); + summon->CastSpell(summon, SPELL_RESISTANT_SKIN, true); summons.Summon(summon); DoZoneInCombat(summon); } - void SummonedCreatureDespawn(Creature* summon) + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) { summons.Despawn(summon); } @@ -463,18 +462,13 @@ class boss_deathbringer_saurfang : public CreatureScript DoCast(me, SPELL_SUMMON_BLOOD_BEAST_25_MAN+i25); Talk(SAY_BLOOD_BEASTS); events.ScheduleEvent(EVENT_SUMMON_BLOOD_BEAST, 40000, 0, PHASE_COMBAT); + if (IsHeroic()) + events.ScheduleEvent(EVENT_SCENT_OF_BLOOD, 10000, 0, PHASE_COMBAT); break; case EVENT_BLOOD_NOVA: - { - // select at range only - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, -10.0f, true); - if (!target) - target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true); // noone? select melee - if (target) - DoCast(target, SPELL_BLOOD_NOVA_TRIGGER); + DoCastAOE(SPELL_BLOOD_NOVA_TRIGGER); events.ScheduleEvent(EVENT_BLOOD_NOVA, urand(20000, 25000), 0, PHASE_COMBAT); break; - } case EVENT_RUNE_OF_BLOOD: DoCastVictim(SPELL_RUNE_OF_BLOOD); events.ScheduleEvent(EVENT_RUNE_OF_BLOOD, urand(20000, 25000), 0, PHASE_COMBAT); @@ -487,6 +481,13 @@ class boss_deathbringer_saurfang : public CreatureScript DoCast(me, SPELL_BERSERK); Talk(SAY_BERSERK); break; + case EVENT_SCENT_OF_BLOOD: + if (!summons.empty()) + { + Talk(EMOTE_SCENT_OF_BLOOD); + DoCastAOE(SPELL_SCENT_OF_BLOOD); + } + break; default: break; } @@ -1237,10 +1238,16 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader unitList.push_back(target); } + void HandleForceCast(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), TRIGGERED_FULL_MASK); + } + void Register() { OnUnitTargetSelect += SpellUnitTargetFn(spell_deathbringer_blood_nova_targeting_SpellScript::FilterTargetsInitial, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); OnUnitTargetSelect += SpellUnitTargetFn(spell_deathbringer_blood_nova_targeting_SpellScript::FilterTargetsSubsequent, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_deathbringer_blood_nova_targeting_SpellScript::HandleForceCast, EFFECT_0, SPELL_EFFECT_FORCE_CAST); } Unit* target; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 273f2a20b4b..c043cb27c7c 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -544,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); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index ab924d1b543..ebf9ae02a95 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -713,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); } @@ -839,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); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index ed1ca4d20fb..c40a521c794 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -262,7 +262,7 @@ class ValithriaDespawner : public BasicEvent if (CreatureData const* data = creature->GetCreatureData()) creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation); - creature->ForcedDespawn(); + creature->DespawnOrUnsummon(); creature->SetCorpseDelay(corpseDelay); creature->SetRespawnDelay(respawnDelay); @@ -1087,7 +1087,7 @@ class npc_dream_cloud : public CreatureScript me->GetMotionMaster()->MoveIdle(); // must use originalCaster the same for all clouds to allow stacking me->CastSpell(me, EMERALD_VIGOR, false, NULL, NULL, _instance->GetData64(DATA_VALITHRIA_DREAMWALKER)); - me->ForcedDespawn(100); + me->DespawnOrUnsummon(100); break; default: break; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index c99fde1739c..5b208768b0c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -346,7 +346,7 @@ class FrostwingGauntletRespawner if (CreatureData const* data = creature->GetCreatureData()) creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation); - creature->ForcedDespawn(); + creature->DespawnOrUnsummon(); creature->SetCorpseDelay(corpseDelay); creature->SetRespawnDelay(respawnDelay); @@ -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) @@ -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/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_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp index 6c2c08f07a0..472ff153d73 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp @@ -298,14 +298,14 @@ class npc_auriaya_seeping_trigger : public CreatureScript void Reset() { - me->ForcedDespawn(600000); + me->DespawnOrUnsummon(600000); DoCast(me, SPELL_SEEPING_ESSENCE); } void UpdateAI(uint32 const /*diff*/) { if (instance->GetBossState(BOSS_AURIAYA) != IN_PROGRESS) - me->ForcedDespawn(); + me->DespawnOrUnsummon(); } private: diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index 4ea38a7642d..a3c9cb847e5 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -507,7 +507,7 @@ class boss_freya : public CreatureScript for (uint8 n = 0; n < 3; ++n) { summons.remove(Elemental[n][i]->GetGUID()); - Elemental[n][i]->ForcedDespawn(5000); + Elemental[n][i]->DespawnOrUnsummon(5000); trioDefeated[i] = true; Elemental[n][i]->CastSpell(me, SPELL_REMOVE_10STACK, true); } @@ -664,12 +664,12 @@ class boss_freya : public CreatureScript case NPC_DETONATING_LASHER: summoned->CastSpell(me, SPELL_REMOVE_2STACK, true); summoned->CastSpell(who, SPELL_DETONATE, true); - summoned->ForcedDespawn(5000); + summoned->DespawnOrUnsummon(5000); summons.remove(summoned->GetGUID()); break; case NPC_ANCIENT_CONSERVATOR: summoned->CastSpell(me, SPELL_REMOVE_25STACK, true); - summoned->ForcedDespawn(5000); + summoned->DespawnOrUnsummon(5000); summons.remove(summoned->GetGUID()); break; } @@ -1385,7 +1385,7 @@ class npc_healthy_spore : public CreatureScript if (lifeTimer <= diff) { me->RemoveAurasDueToSpell(SPELL_GROW); - me->ForcedDespawn(2200); + me->DespawnOrUnsummon(2200); lifeTimer = urand(22000, 30000); } else @@ -1423,7 +1423,7 @@ class npc_eonars_gift : public CreatureScript { me->RemoveAurasDueToSpell(SPELL_GROW); DoCast(SPELL_LIFEBINDERS_GIFT); - me->ForcedDespawn(2500); + me->DespawnOrUnsummon(2500); lifeBindersGiftTimer = 12000; } else 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 22858cf69e5..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) @@ -267,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) { @@ -340,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; } } @@ -348,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; } @@ -389,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: @@ -404,6 +495,7 @@ class instance_ulduar : public InstanceMapScript FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_LIFE_DESTROYED); break; } + } } @@ -464,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; @@ -496,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; } @@ -570,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; @@ -592,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(); @@ -627,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/borean_tundra.cpp b/src/server/scripts/Northrend/borean_tundra.cpp index f83538b344c..8b51618eedd 100644 --- a/src/server/scripts/Northrend/borean_tundra.cpp +++ b/src/server/scripts/Northrend/borean_tundra.cpp @@ -186,7 +186,7 @@ public: if (owner->GetTypeId() == TYPEID_PLAYER) { owner->CastSpell(owner, 46231, true); - CAST_CRE(who)->ForcedDespawn(); + CAST_CRE(who)->DespawnOrUnsummon(); } } } diff --git a/src/server/scripts/Northrend/storm_peaks.cpp b/src/server/scripts/Northrend/storm_peaks.cpp index 251bdb8278a..15239e9f836 100644 --- a/src/server/scripts/Northrend/storm_peaks.cpp +++ b/src/server/scripts/Northrend/storm_peaks.cpp @@ -550,7 +550,7 @@ public: // drake unsummoned, passengers dropped if (!me->IsOnVehicle(drake) && !hasEmptySeats) - me->ForcedDespawn(3000); + me->DespawnOrUnsummon(3000); if (enter_timer <= 0) return; @@ -605,7 +605,7 @@ public: me->ExitVehicle(); me->CastSpell(me, SPELL_SUMMON_LIBERATED, true); - me->ForcedDespawn(500); + me->DespawnOrUnsummon(500); // drake is empty now, deliver credit for drake and despawn him if (drake->GetVehicleKit()->HasEmptySeat(1) && @@ -616,7 +616,7 @@ public: if (rider->ToPlayer()) rider->ToPlayer()->KilledMonsterCredit(29709, 0); - drake->ForcedDespawn(0); + drake->DespawnOrUnsummon(0); } } } diff --git a/src/server/scripts/Outland/blades_edge_mountains.cpp b/src/server/scripts/Outland/blades_edge_mountains.cpp index 7a371170d7d..cf0955ed89c 100644 --- a/src/server/scripts/Outland/blades_edge_mountains.cpp +++ b/src/server/scripts/Outland/blades_edge_mountains.cpp @@ -855,7 +855,7 @@ class npc_simon_bunny : public CreatureScript if (GameObject* relic = me->FindNearestGameObject(large ? GO_APEXIS_MONUMENT : GO_APEXIS_RELIC, searchDistance)) relic->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - me->ForcedDespawn(1000); + me->DespawnOrUnsummon(1000); } /* 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/nagrand.cpp b/src/server/scripts/Outland/nagrand.cpp index 8080a1402af..871a2f200bb 100644 --- a/src/server/scripts/Outland/nagrand.cpp +++ b/src/server/scripts/Outland/nagrand.cpp @@ -450,7 +450,7 @@ public: { if (Say_Timer <= diff) { - me->ForcedDespawn(); + me->DespawnOrUnsummon(); ReleasedFromCage = false; } else @@ -689,7 +689,7 @@ class go_warmaul_prison : public GameObjectScript player->KilledMonsterCredit(NPC_MAGHAR_PRISONER, 0); prisoner->AI()->Talk(SAY_FREE, player->GetGUID()); - prisoner->ForcedDespawn(6000); + prisoner->DespawnOrUnsummon(6000); } return true; } diff --git a/src/server/scripts/Outland/netherstorm.cpp b/src/server/scripts/Outland/netherstorm.cpp index 388d18697b9..afc18c71b92 100644 --- a/src/server/scripts/Outland/netherstorm.cpp +++ b/src/server/scripts/Outland/netherstorm.cpp @@ -1057,7 +1057,7 @@ class go_captain_tyralius_prison : public GameObjectScript player->KilledMonsterCredit(NPC_CAPTAIN_TYRALIUS, 0); tyralius->AI()->Talk(SAY_FREE); - tyralius->ForcedDespawn(8000); + tyralius->DespawnOrUnsummon(8000); } return true; } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 035f9ec98b2..7fd37ede316 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -169,7 +169,7 @@ class spell_gen_burn_brutallus : public SpellScriptLoader } }; -enum eCannibalizeSpells +enum CannibalizeSpells { SPELL_CANNIBALIZE_TRIGGERED = 20578, }; @@ -224,7 +224,7 @@ class spell_gen_cannibalize : public SpellScriptLoader }; // 45472 Parachute -enum eParachuteSpells +enum ParachuteSpells { SPELL_PARACHUTE = 45472, SPELL_PARACHUTE_BUFF = 44795, @@ -365,7 +365,7 @@ class spell_gen_remove_flight_auras : public SpellScriptLoader }; // 66118 Leeching Swarm -enum eLeechingSwarmSpells +enum LeechingSwarmSpells { SPELL_LEECHING_SWARM_DMG = 66240, SPELL_LEECHING_SWARM_HEAL = 66125, @@ -481,7 +481,7 @@ class spell_gen_elune_candle : public SpellScriptLoader }; // 24750 Trick -enum eTrickSpells +enum TrickSpells { SPELL_PIRATE_COSTUME_MALE = 24708, SPELL_PIRATE_COSTUME_FEMALE = 24709, @@ -557,7 +557,7 @@ class spell_gen_trick : public SpellScriptLoader }; // 24751 Trick or Treat -enum eTrickOrTreatSpells +enum TrickOrTreatSpells { SPELL_TRICK = 24714, SPELL_TREAT = 24715, @@ -2618,6 +2618,76 @@ 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; +}; + +class spell_gen_despawn_self : public SpellScriptLoader +{ +public: + spell_gen_despawn_self() : SpellScriptLoader("spell_gen_despawn_self") { } + + class spell_gen_despawn_self_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_despawn_self_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleDummy(SpellEffIndex effIndex) + { + if (GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_DUMMY || GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_SCRIPT_EFFECT) + GetCaster()->ToCreature()->DespawnOrUnsummon(); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_gen_despawn_self_SpellScript::HandleDummy, EFFECT_ALL, SPELL_EFFECT_ANY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_despawn_self_SpellScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -2669,4 +2739,7 @@ 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); + new spell_gen_despawn_self(); } diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 666477e68e7..eb2d3187636 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); } @@ -2005,7 +2006,7 @@ class spell_item_muisek_vessel : public SpellScriptLoader { if (Creature* target = GetHitCreature()) if (target->isDead()) - target->ForcedDespawn(); + target->DespawnOrUnsummon(); } void Register() @@ -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 @@ -2072,4 +2104,5 @@ void AddSC_item_spell_scripts() new spell_item_uded(); new spell_item_chicken_cover(); new spell_item_muisek_vessel(); + new spell_item_greatmothers_soulcatcher(); } diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index d823c629d4b..c8c563d3d5d 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 (Unit* target = GetTargetUnit()) + if (!caster->IsFriendlyTo(target) && !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_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index d2bba2b8bc3..47cec6ce516 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -228,8 +228,8 @@ class spell_pri_penance : public SpellScriptLoader { Player* caster = GetCaster()->ToPlayer(); if (GetTargetUnit()) - if (Player* target = GetTargetUnit()->ToPlayer()) - if (caster->GetTeam() != target->GetTeam() && !caster->IsValidAttackTarget(target)) + if (Unit* target = GetTargetUnit()) + if (!caster->IsFriendlyTo(target) && !caster->IsValidAttackTarget(target)) return SPELL_FAILED_BAD_TARGETS; return SPELL_CAST_OK; } @@ -291,12 +291,53 @@ class spell_pri_reflective_shield_trigger : public SpellScriptLoader } }; +enum PrayerOfMending +{ + SPELL_T9_HEALING_2_PIECE = 67201, +}; +// Prayer of Mending Heal +class spell_pri_prayer_of_mending_heal : public SpellScriptLoader +{ +public: + spell_pri_prayer_of_mending_heal() : SpellScriptLoader("spell_pri_prayer_of_mending_heal") { } + + class spell_pri_prayer_of_mending_heal_SpellScript : public SpellScript + { + PrepareSpellScript(spell_pri_prayer_of_mending_heal_SpellScript); + + void HandleHeal(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetOriginalCaster()) + { + if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_T9_HEALING_2_PIECE,EFFECT_0)) + { + int32 heal = GetHitHeal(); + AddPctN(heal, aurEff->GetAmount()); + SetHitHeal(heal); + } + } + + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_pri_prayer_of_mending_heal_SpellScript::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_pri_prayer_of_mending_heal_SpellScript(); + } +}; + void AddSC_priest_spell_scripts() { new spell_pri_guardian_spirit(); - new spell_pri_mana_burn; - new spell_pri_pain_and_suffering_proc; - new spell_pri_penance; + new spell_pri_mana_burn(); + new spell_pri_pain_and_suffering_proc(); + new spell_pri_penance(); new spell_pri_reflective_shield_trigger(); new spell_pri_mind_sear(); + new spell_pri_prayer_of_mending_heal(); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 48faf83cd2f..06678407b93 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -837,7 +837,7 @@ class spell_q12659_ahunaes_knife : public SpellScriptLoader Player* caster = GetCaster()->ToPlayer(); if (Creature* target = GetHitCreature()) { - target->ForcedDespawn(); + target->DespawnOrUnsummon(); caster->KilledMonsterCredit(NPC_SCALPS_KC_BUNNY, 0); } } diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 84e3bd8d604..f16f663ae2d 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -215,13 +215,12 @@ 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*/) @@ -252,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: @@ -270,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() @@ -617,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(); diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 3e4c043ae47..3b683eb5795 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -397,8 +397,7 @@ class spell_warr_bloodthirst : public SpellScriptLoader void HandleDummy(SpellEffIndex /* effIndex */) { int32 damage = GetEffectValue(); - if (GetHitUnit()) - GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_BLOODTHIRST, &damage, NULL, NULL, true, NULL); + GetCaster()->CastCustomSpell(GetCaster(), SPELL_BLOODTHIRST, &damage, NULL, NULL, true, NULL); } void Register() diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 60ddf8990a7..790a9d0f814 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -1174,7 +1174,7 @@ class go_gjalerbron_cage : public GameObjectScript player->KilledMonsterCredit(NPC_GJALERBRON_PRISONER, 0); prisoner->AI()->Talk(SAY_FREE); - prisoner->ForcedDespawn(6000); + prisoner->DespawnOrUnsummon(6000); } } return true; @@ -1201,7 +1201,7 @@ class go_large_gjalerbron_cage : public GameObjectScript { go->UseDoorOrButton(); player->KilledMonsterCredit(NPC_GJALERBRON_PRISONER, (*itr)->GetGUID()); - (*itr)->ForcedDespawn(6000); + (*itr)->DespawnOrUnsummon(6000); (*itr)->AI()->Talk(SAY_FREE); } } @@ -1235,7 +1235,7 @@ class go_veil_skith_cage : public GameObjectScript { go->UseDoorOrButton(); player->KilledMonsterCredit(NPC_CAPTIVE_CHILD, (*itr)->GetGUID()); - (*itr)->ForcedDespawn(5000); + (*itr)->DespawnOrUnsummon(5000); (*itr)->GetMotionMaster()->MovePoint(1, go->GetPositionX()+5, go->GetPositionY(), go->GetPositionZ()); (*itr)->AI()->Talk(SAY_FREE_0); (*itr)->GetMotionMaster()->Clear(); diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 61b997bba35..e1cfd077444 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -2530,172 +2530,6 @@ public: }; /*###### -## 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: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI, false); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TABARD_OF_SUMMER_SKIES, false); - break; - case GOSSIP_ACTION_INFO_DEF + 7: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TABARD_OF_SUMMER_FLAMES, false); - break; - } - return true; - } -}; - -/*###### ## npc_experience ######*/ @@ -3158,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/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) |