aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp4
-rw-r--r--src/server/game/Battlefield/Battlefield.cpp4
-rw-r--r--src/server/game/Battlefield/Zones/BattlefieldWG.cpp12
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundAV.cpp2
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundAV.h6
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundBE.cpp2
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp3
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundIC.cpp13
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundNA.cpp2
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundRL.cpp2
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundRV.cpp2
-rw-r--r--src/server/game/DataStores/DBCStructure.h4
-rwxr-xr-xsrc/server/game/DataStores/DBCfmt.h2
-rwxr-xr-xsrc/server/game/DungeonFinding/LFGMgr.cpp89
-rwxr-xr-xsrc/server/game/DungeonFinding/LFGMgr.h13
-rw-r--r--src/server/game/DungeonFinding/LFGScripts.cpp4
-rwxr-xr-xsrc/server/game/Entities/GameObject/GameObject.cpp7
-rw-r--r--src/server/game/Entities/Player/Player.cpp31
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp3
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h20
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp2
-rwxr-xr-xsrc/server/game/Handlers/LFGHandler.cpp16
-rwxr-xr-xsrc/server/game/Handlers/SpellHandler.cpp3
-rwxr-xr-xsrc/server/game/Maps/Map.cpp2
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp1
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp1
-rwxr-xr-xsrc/server/game/Movement/Waypoints/WaypointManager.h2
-rwxr-xr-xsrc/server/game/Scripting/ScriptLoader.cpp2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp3
-rw-r--r--src/server/game/Spells/SpellMgr.cpp85
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.h2
-rwxr-xr-xsrc/server/game/Spells/SpellScript.h2
-rw-r--r--src/server/game/World/World.cpp3
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp8
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp8
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp16
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp294
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp6
-rw-r--r--src/server/scripts/Northrend/CMakeLists.txt1
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp4
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp1740
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp138
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h53
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp45
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp9
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp83
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp299
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/oculus.h13
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp21
-rw-r--r--src/server/scripts/Northrend/wintergrasp.cpp39
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp22
-rw-r--r--src/server/scripts/World/go_scripts.cpp168
-rwxr-xr-xsrc/server/shared/Utilities/Util.cpp5
-rwxr-xr-xsrc/server/shared/Utilities/Util.h2
54 files changed, 2881 insertions, 442 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 32b9f8b5903..f37ae4fa60e 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -130,12 +130,10 @@ void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint3
if (eventType == e/* && (!(*i).event.event_phase_mask || IsInPhase((*i).event.event_phase_mask)) && !((*i).event.event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE && (*i).runOnce)*/)
{
- bool meets = true;
ConditionList conds = sConditionMgr->GetConditionsForSmartEvent((*i).entryOrGuid, (*i).event_id, (*i).source_type);
ConditionSourceInfo info = ConditionSourceInfo(unit, GetBaseObject());
- meets = sConditionMgr->IsObjectMeetToConditions(info, conds);
- if (meets)
+ if (sConditionMgr->IsObjectMeetToConditions(info, conds))
ProcessEvent(*i, unit, var0, var1, bvar, spell, gob);
}
}
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp
index cbaab482b01..b7572c6f2b0 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -1001,7 +1001,7 @@ bool BfCapturePoint::Update(uint32 diff)
// get the difference of numbers
float fact_diff = ((float) m_activePlayers[0].size() - (float) m_activePlayers[1].size()) * diff / BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL;
- if (!fact_diff)
+ if (G3D::fuzzyEq(fact_diff, 0.0f))
return false;
uint32 Challenger = 0;
@@ -1071,7 +1071,7 @@ bool BfCapturePoint::Update(uint32 diff)
m_team = TEAM_NEUTRAL;
}
- if (m_value != oldValue)
+ if (G3D::fuzzyNe(m_value, oldValue))
SendChangePhase();
if (m_OldState != m_State)
diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
index de1ee1785d8..119880bae8d 100644
--- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
+++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
@@ -528,12 +528,12 @@ void BattlefieldWG::OnCreatureCreate(Creature* creature)
case NPC_WINTERGRASP_CATAPULT:
case NPC_WINTERGRASP_DEMOLISHER:
{
- if (!creature->ToTempSummon()->GetSummonerGUID() || !sObjectAccessor->FindPlayer(creature->ToTempSummon()->GetSummonerGUID()))
+ if (!creature->ToTempSummon() || !creature->ToTempSummon()->GetSummonerGUID() || !sObjectAccessor->FindPlayer(creature->ToTempSummon()->GetSummonerGUID()))
{
- creature->setDeathState(DEAD);
- creature->RemoveFromWorld();
+ creature->DespawnOrUnsummon();
return;
}
+
Player* creator = sObjectAccessor->FindPlayer(creature->ToTempSummon()->GetSummonerGUID());
TeamId team = creator->GetTeamId();
@@ -548,8 +548,7 @@ void BattlefieldWG::OnCreatureCreate(Creature* creature)
}
else
{
- creature->setDeathState(DEAD);
- creature->RemoveFromWorld();
+ creature->DespawnOrUnsummon();
return;
}
}
@@ -564,8 +563,7 @@ void BattlefieldWG::OnCreatureCreate(Creature* creature)
}
else
{
- creature->setDeathState(DEAD);
- creature->RemoveFromWorld();
+ creature->DespawnOrUnsummon();
return;
}
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
index c57eeff9911..a348ec69b8a 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
@@ -177,7 +177,7 @@ void BattlegroundAV::HandleQuestComplete(uint32 questid, Player* player)
case AV_QUEST_H_COMMANDER3:
m_Team_QuestStatus[team][3]++;
RewardReputationToTeam(team, 1, player->GetTeam());
- if (m_Team_QuestStatus[team][1] == 120)
+ if (m_Team_QuestStatus[team][3] == 120)
sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BG_AV Quest %i completed (need to implement some events here", questid);
break;
case AV_QUEST_A_BOSS1:
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
index 28d524977fc..dab67fe3258 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
@@ -1514,12 +1514,12 @@ enum BG_AV_Objectives
struct BG_AV_NodeInfo
{
- uint16 TotalOwner;
- uint16 Owner;
- uint16 PrevOwner;
BG_AV_States State;
BG_AV_States PrevState;
uint32 Timer;
+ uint16 TotalOwner;
+ uint16 Owner;
+ uint16 PrevOwner;
bool Tower;
};
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp
index d4086b2e48e..402406f7fd0 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp
@@ -96,7 +96,7 @@ void BattlegroundBE::HandleKillPlayer(Player* player, Player* killer)
bool BattlegroundBE::HandlePlayerUnderMap(Player* player)
{
- player->TeleportTo(GetMapId(), 6238.930176f, 262.963470f, 0.889519f, player->GetOrientation(), false);
+ player->TeleportTo(GetMapId(), 6238.930176f, 262.963470f, 0.889519f, player->GetOrientation());
return true;
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp
index a39350d1f45..a64184261c7 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp
@@ -21,6 +21,7 @@
#include "Language.h"
#include "Player.h"
#include "WorldPacket.h"
+#include "GameObject.h"
BattlegroundDS::BattlegroundDS()
{
@@ -201,7 +202,7 @@ void BattlegroundDS::HandleAreaTrigger(Player* player, uint32 trigger)
bool BattlegroundDS::HandlePlayerUnderMap(Player* player)
{
- player->TeleportTo(GetMapId(), 1299.046f, 784.825f, 9.338f, 2.422f, false);
+ player->TeleportTo(GetMapId(), 1299.046f, 784.825f, 9.338f, 2.422f);
return true;
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
index 8725bf63a9b..fe3f214ebe5 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
@@ -384,7 +384,7 @@ bool BattlegroundIC::SetupBattleground()
}
}
- for (uint8 i = 0; i < MAX_NORMAL_NPCS_SPAWNS; ++i)
+ for (uint8 i = 2; i < MAX_NORMAL_NPCS_SPAWNS; ++i)
{
if (!AddCreature(BG_IC_NpcSpawnlocs[i].entry, BG_IC_NpcSpawnlocs[i].type, BG_IC_NpcSpawnlocs[i].team,
BG_IC_NpcSpawnlocs[i].x, BG_IC_NpcSpawnlocs[i].y,
@@ -860,6 +860,17 @@ void BattlegroundIC::DestroyGate(Player* player, GameObject* go)
break;
}
+ if (go->GetEntry() == GO_HORDE_GATE_1 || go->GetEntry() == GO_HORDE_GATE_2 || go->GetEntry() == GO_HORDE_GATE_3)
+ {
+ if (!GetBgMap()->GetCreature(BgCreatures[BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].type]) && !AddCreature(BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].entry, BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].type, BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].team, BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].x, BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].y, BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].z, BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].o, RESPAWN_ONE_DAY))
+ sLog->outError(LOG_FILTER_BATTLEGROUND, "Isle of Conquest: There was an error spawning creature %u", BG_IC_NpcSpawnlocs[BG_IC_NPC_OVERLORD_AGMAR].entry);
+ }
+ else if (go->GetEntry() == GO_ALLIANCE_GATE_1 || go->GetEntry() == GO_ALLIANCE_GATE_2 || go->GetEntry() == GO_ALLIANCE_GATE_3)
+ {
+ if (!GetBgMap()->GetCreature(BgCreatures[BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].type]) && !AddCreature(BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].entry, BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].type, BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].team, BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].x, BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].y, BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].z, BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].o, RESPAWN_ONE_DAY))
+ sLog->outError(LOG_FILTER_BATTLEGROUND, "Isle of Conquest: There was an error spawning creature %u", BG_IC_NpcSpawnlocs[BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE].entry);
+ }
+
SendMessage2ToAll(lang_entry, CHAT_MSG_BG_SYSTEM_NEUTRAL, NULL, (player->GetTeamId() == TEAM_ALLIANCE ? LANG_BG_IC_HORDE_KEEP : LANG_BG_IC_ALLIANCE_KEEP));
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp
index deb2e565b07..6677d665290 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp
@@ -93,7 +93,7 @@ void BattlegroundNA::HandleKillPlayer(Player* player, Player* killer)
bool BattlegroundNA::HandlePlayerUnderMap(Player* player)
{
- player->TeleportTo(GetMapId(), 4055.504395f, 2919.660645f, 13.611241f, player->GetOrientation(), false);
+ player->TeleportTo(GetMapId(), 4055.504395f, 2919.660645f, 13.611241f, player->GetOrientation());
return true;
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp
index 14c1052ed64..2c715193a3b 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp
@@ -93,7 +93,7 @@ void BattlegroundRL::HandleKillPlayer(Player* player, Player* killer)
bool BattlegroundRL::HandlePlayerUnderMap(Player* player)
{
- player->TeleportTo(GetMapId(), 1285.810547f, 1667.896851f, 39.957642f, player->GetOrientation(), false);
+ player->TeleportTo(GetMapId(), 1285.810547f, 1667.896851f, 39.957642f, player->GetOrientation());
return true;
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp
index 80018bce0a2..130ba4f3290 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp
@@ -137,7 +137,7 @@ void BattlegroundRV::HandleKillPlayer(Player* player, Player* killer)
bool BattlegroundRV::HandlePlayerUnderMap(Player* player)
{
- player->TeleportTo(GetMapId(), 763.5f, -284, 28.276f, 2.422f, false);
+ player->TeleportTo(GetMapId(), 763.5f, -284, 28.276f, 2.422f);
return true;
}
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 704f252c625..64e7d5b4b60 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1357,10 +1357,10 @@ struct LFGDungeonEntry
uint32 recmaxlevel; // 6
int32 map; // 7
uint32 difficulty; // 8
- //uint32 unk; // 9
+ uint32 flags; // 9
uint32 type; // 10
//uint32 unk2; // 11
- //char* unk3; // 12
+ //char* iconname; // 12
uint32 expansion; // 13
//uint32 unk4; // 14
uint32 grouptype; // 15
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index bffe9263549..f9339f7515a 100755
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -99,7 +99,7 @@ const char ItemLimitCategoryEntryfmt[]="nxii";
const char ItemRandomPropertiesfmt[]="nxiiixxs";
const char ItemRandomSuffixfmt[]="nsxiiiiiiiiii";
const char ItemSetEntryfmt[]="dsiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii";
-const char LFGDungeonEntryfmt[]="nxiiiiiiixixxixixxxxx";
+const char LFGDungeonEntryfmt[]="nxiiiiiiiiixxixixxxxx";
const char LiquidTypefmt[]="nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
const char PhaseEntryfmt[]="nsi";
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index 3a75066fa2d..2b425dffff0 100755
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -24,6 +24,7 @@
#include "SocialMgr.h"
#include "LFGMgr.h"
#include "GroupMgr.h"
+#include "GameEventMgr.h"
#include "LFGScripts.h"
#include "LFGGroupData.h"
#include "LFGPlayerData.h"
@@ -185,6 +186,38 @@ void LFGMgr::LoadRewards()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u lfg dungeon rewards in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
+void LFGMgr::LoadEntrancePositions()
+{
+ uint32 oldMSTime = getMSTime();
+ m_entrancePositions.clear();
+
+ QueryResult result = WorldDatabase.Query("SELECT dungeonId, position_x, position_y, position_z, orientation FROM lfg_entrances");
+
+ if (!result)
+ {
+ sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 dungeonId = fields[0].GetUInt32();
+ Position pos;
+ pos.m_positionX = fields[1].GetFloat();
+ pos.m_positionY = fields[2].GetFloat();
+ pos.m_positionZ = fields[3].GetFloat();
+ pos.m_orientation = fields[4].GetFloat();
+ m_entrancePositions[dungeonId] = pos;
+ ++count;
+ }
+ while (result->NextRow());
+
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u lfg entrance positions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
void LFGMgr::Update(uint32 diff)
{
if (!m_update)
@@ -438,6 +471,12 @@ void LFGMgr::InitializeLockedDungeons(Player* player)
locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL;
else if (dungeon->maxlevel < level)
locktype = LFG_LOCKSTATUS_TOO_HIGH_LEVEL;
+ else if (dungeon->flags & LFG_FLAG_SEASONAL)
+ {
+ if (HolidayIds holiday = sLFGMgr->GetDungeonSeason(dungeon->ID))
+ if (!IsHolidayActive(holiday))
+ locktype = LFG_LOCKSTATUS_NOT_IN_SEASON;
+ }
else if (locktype == LFG_LOCKSTATUS_OK && ar)
{
if (ar->achievement && !player->HasAchieved(ar->achievement))
@@ -460,7 +499,6 @@ void LFGMgr::InitializeLockedDungeons(Player* player)
locktype = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE;
locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL;
locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL;
- locktype = LFG_LOCKSTATUS_NOT_IN_SEASON; // Need list of instances and needed season to open
*/
if (locktype != LFG_LOCKSTATUS_OK)
@@ -1808,13 +1846,16 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
if (!mapid)
{
- AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon->map);
- if (!at)
+ LfgEntrancePositionMap::const_iterator itr = m_entrancePositions.find(dungeon->ID);
+ if (itr != m_entrancePositions.end())
{
- sLog->outError(LOG_FILTER_LFG, "LfgMgr::TeleportPlayer: Failed to teleport [" UI64FMTD "]: No areatrigger found for map: %u difficulty: %u", player->GetGUID(), dungeon->map, dungeon->difficulty);
- error = LFG_TELEPORTERROR_INVALID_LOCATION;
+ mapid = dungeon->map;
+ x = itr->second.GetPositionX();
+ y = itr->second.GetPositionY();
+ z = itr->second.GetPositionZ();
+ orientation = itr->second.GetOrientation();
}
- else
+ else if (AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon->map))
{
mapid = at->target_mapId;
x = at->target_X;
@@ -1822,6 +1863,11 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
z = at->target_Z;
orientation = at->target_Orientation;
}
+ else
+ {
+ sLog->outError(LOG_FILTER_LFG, "LfgMgr::TeleportPlayer: Failed to teleport [" UI64FMTD "]: No areatrigger found for map: %u difficulty: %u", player->GetGUID(), dungeon->map, dungeon->difficulty);
+ error = LFG_TELEPORTERROR_INVALID_LOCATION;
+ }
}
if (error == LFG_TELEPORTERROR_OK)
@@ -1889,11 +1935,11 @@ void LFGMgr::RewardDungeonDoneFor(const uint32 dungeonId, Player* player)
ClearState(guid);
SetState(guid, LFG_STATE_FINISHED_DUNGEON);
- // Give rewards only if its a random dungeon
+ // Give rewards only if its a random or seasonal dungeon
LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(rDungeonId);
- if (!dungeon || dungeon->type != LFG_TYPE_RANDOM)
+ if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && !(dungeon->flags & LFG_FLAG_SEASONAL)))
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RewardDungeonDoneFor: [" UI64FMTD "] dungeon %u is not random", guid, rDungeonId);
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RewardDungeonDoneFor: [" UI64FMTD "] dungeon %u is not random nor seasonal", guid, rDungeonId);
return;
}
@@ -2001,6 +2047,31 @@ std::string LFGMgr::ConcatenateGuids(LfgGuidList check)
return o.str();
}
+HolidayIds LFGMgr::GetDungeonSeason(uint32 dungeonId)
+{
+ HolidayIds holiday = HOLIDAY_NONE;
+
+ switch (dungeonId)
+ {
+ case 285:
+ holiday = HOLIDAY_HALLOWS_END;
+ break;
+ case 286:
+ holiday = HOLIDAY_FIRE_FESTIVAL;
+ break;
+ case 287:
+ holiday = HOLIDAY_BREWFEST;
+ break;
+ case 288:
+ holiday = HOLIDAY_LOVE_IS_IN_THE_AIR;
+ break;
+ default:
+ break;
+ }
+
+ return holiday;
+}
+
LfgState LFGMgr::GetState(uint64 guid)
{
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetState: [" UI64FMTD "]", guid);
diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h
index e341b21706f..9937759741b 100755
--- a/src/server/game/DungeonFinding/LFGMgr.h
+++ b/src/server/game/DungeonFinding/LFGMgr.h
@@ -41,6 +41,14 @@ enum LFGenum
LFG_SPELL_LUCK_OF_THE_DRAW = 72221
};
+enum LfgFlags
+{
+ LFG_FLAG_UNK1 = 0x1,
+ LFG_FLAG_UNK2 = 0x2,
+ LFG_FLAG_SEASONAL = 0x4,
+ LFG_FLAG_UNK3 = 0x8
+};
+
/// Determines the type of instance
enum LfgType
{
@@ -143,6 +151,7 @@ typedef std::map<uint64, LfgProposalPlayer*> LfgProposalPlayerMap;
typedef std::map<uint32, LfgPlayerBoot*> LfgPlayerBootMap;
typedef std::map<uint64, LfgGroupData> LfgGroupDataMap;
typedef std::map<uint64, LfgPlayerData> LfgPlayerDataMap;
+typedef std::map<uint32, Position> LfgEntrancePositionMap;
// Data needed by SMSG_LFG_JOIN_RESULT
struct LfgJoinResultData
@@ -279,6 +288,7 @@ class LFGMgr
void UpdateProposal(uint32 proposalId, uint64 guid, bool accept);
// Teleportation
+ void LoadEntrancePositions();
void TeleportPlayer(Player* player, bool out, bool fromOpcode = false);
// Vote kick
@@ -286,6 +296,8 @@ class LFGMgr
void UpdateBoot(Player* player, bool accept);
void OfferContinue(Group* grp);
+ HolidayIds GetDungeonSeason(uint32 dungeonId);
+
void InitializeLockedDungeons(Player* player);
void _LoadFromDB(Field* fields, uint64 guid);
@@ -349,6 +361,7 @@ class LFGMgr
uint32 m_NumWaitTimeHealer; ///< Num of players used to calc healers wait time
uint32 m_NumWaitTimeDps; ///< Num of players used to calc dps wait time
LfgDungeonMap m_CachedDungeonMap; ///< Stores all dungeons by groupType
+ LfgEntrancePositionMap m_entrancePositions; ///< Stores special entrance positions
// Reward System
LfgRewardMap m_RewardMap; ///< Stores rewards for random dungeons
// Queue
diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp
index e4b67e22221..36f04b3020b 100644
--- a/src/server/game/DungeonFinding/LFGScripts.cpp
+++ b/src/server/game/DungeonFinding/LFGScripts.cpp
@@ -123,8 +123,8 @@ void LFGGroupScript::OnRemoveMember(Group* group, uint64 guid, RemoveMethod meth
sLFGMgr->SetState(guid, LFG_STATE_NONE);
if (Player* player = ObjectAccessor::FindPlayer(guid))
{
- if (method == GROUP_REMOVEMETHOD_LEAVE && state != LFG_STATE_FINISHED_DUNGEON && player->HasAura(LFG_SPELL_DUNGEON_COOLDOWN))
- player->CastSpell(player, LFG_SPELL_DUNGEON_DESERTER, false);
+ if (method == GROUP_REMOVEMETHOD_LEAVE && sLFGMgr->GetState(gguid) != LFG_STATE_FINISHED_DUNGEON && sLFGMgr->GetDungeon(gguid, false))
+ player->CastSpell(player, LFG_SPELL_DUNGEON_DESERTER, true);
/*
else if (group->isLfgKickActive())
// Update internal kick cooldown of kicked
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index e619ac36b2f..d152dc5642f 100755
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -294,7 +294,7 @@ void GameObject::Update(uint32 diff)
else if (Unit* owner = GetOwner())
{
if (owner->isInCombat())
- m_cooldownTime = time(NULL) + goInfo->trap.cooldown;
+ m_cooldownTime = time(NULL) + goInfo->trap.startDelay;
}
m_lootState = GO_READY;
break;
@@ -418,7 +418,7 @@ void GameObject::Update(uint32 diff)
bool IsBattlegroundTrap = false;
//FIXME: this is activation radius (in different casting radius that must be selected from spell data)
//TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state
- float radius = (float)(goInfo->trap.radius)/2; // TODO rename radius to diameter (goInfo->trap.radius) should be (goInfo->trap.diameter)
+ float radius = (float)(goInfo->trap.radius)/3*2; // TODO rename radius to diameter (goInfo->trap.radius) should be (goInfo->trap.diameter)
if (!radius)
{
if (goInfo->trap.cooldown != 3) // cast in other case (at some triggering/linked go/etc explicit call)
@@ -1081,7 +1081,8 @@ void GameObject::Use(Unit* user)
if (sScriptMgr->OnGossipHello(playerUser, this))
return;
- AI()->GossipHello(playerUser);
+ if (AI()->GossipHello(playerUser))
+ return;
}
// If cooldown data present in template
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 34c5732af7b..9177672e8c7 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -7823,21 +7823,19 @@ void Player::DuelComplete(DuelCompleteType type)
break;
case DUEL_WON:
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL, 1);
- if (duel->opponent)
- {
- duel->opponent->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
+ duel->opponent->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
+
+ // Credit for quest Death's Challenge
+ if (getClass() == CLASS_DEATH_KNIGHT && duel->opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
+ duel->opponent->CastSpell(duel->opponent, 52994, true);
- //Credit for quest Death's Challenge
- if (getClass() == CLASS_DEATH_KNIGHT && duel->opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
- duel->opponent->CastSpell(duel->opponent, 52994, true);
- }
break;
default:
break;
}
// Victory emote spell
- if (type != DUEL_INTERRUPTED && duel->opponent)
+ if (type != DUEL_INTERRUPTED)
duel->opponent->CastSpell(duel->opponent, 52852, true);
//Remove Duel Flag object
@@ -9218,6 +9216,9 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
case 4100: // The Culling of Stratholme
NumberOfFields = 13;
break;
+ case 4987: // The Ruby Sanctum
+ NumberOfFields = 3;
+ break;
case 4273: // Ulduar
NumberOfFields = 10;
break;
@@ -9704,6 +9705,17 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
data << uint32(4345) << uint32(1); // 24 unknown
}
break;
+ // The Ruby Sanctum
+ case 4987:
+ if (instance && mapid == 724)
+ instance->FillInitialWorldStates(data);
+ else
+ {
+ data << uint32(5049) << uint32(50); // 9 WORLDSTATE_CORPOREALITY_MATERIAL
+ data << uint32(5050) << uint32(50); // 10 WORLDSTATE_CORPOREALITY_TWILIGHT
+ data << uint32(5051) << uint32(0); // 11 WORLDSTATE_CORPOREALITY_TOGGLE
+ }
+ break;
// Icecrown Citadel
case 4812:
if (instance && mapid == 631)
@@ -20975,6 +20987,9 @@ void Player::ContinueTaxiFlight()
sLog->outDebug(LOG_FILTER_UNITS, "WORLD: Restart character %u taxi flight", GetGUIDLow());
uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourceNode, GetTeam(), true);
+ if (!mountDisplayId)
+ return;
+
uint32 path = m_taxi.GetCurrentTaxiPath();
// search appropriate start path node
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 87a125a9ed8..af55c67eff3 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -9076,8 +9076,7 @@ Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo)
if (Unit* magnet = (*itr)->GetBase()->GetCaster())
if (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
&& spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK
- && _IsValidAttackTarget(magnet, spellInfo)
- && IsWithinLOSInMap(magnet))
+ && _IsValidAttackTarget(magnet, spellInfo))
{
// TODO: handle this charge drop by proc in cast phase on explicit target
(*itr)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 7b100be255d..7351d4b014b 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -802,21 +802,21 @@ enum MeleeHitOutcome
class DispelInfo
{
-private:
- Unit* const m_dispeller;
- uint32 const m_dispellerSpellId;
- uint8 m_chargesRemoved;
public:
- explicit DispelInfo(Unit* _dispeller, uint32 _dispellerSpellId, uint8 _chargesRemoved) :
- m_dispeller(_dispeller), m_dispellerSpellId(_dispellerSpellId), m_chargesRemoved(_chargesRemoved) {}
+ explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
+ _dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) {}
- Unit* GetDispeller() { return m_dispeller; }
- uint32 GetDispellerSpellId() const { return m_dispellerSpellId; }
- uint8 GetRemovedCharges() const { return m_chargesRemoved; }
+ Unit* GetDispeller() const { return _dispellerUnit; }
+ uint32 GetDispellerSpellId() const { return _dispellerSpell; }
+ uint8 GetRemovedCharges() const { return _chargesRemoved; }
void SetRemovedCharges(uint8 amount)
{
- m_chargesRemoved = amount;
+ _chargesRemoved = amount;
}
+private:
+ Unit* _dispellerUnit;
+ uint32 _dispellerSpell;
+ uint8 _chargesRemoved;
};
struct CleanDamage
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index b8937a58681..196e36ad82b 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -5481,7 +5481,7 @@ uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt
if (!mount_id)
{
sLog->outError(LOG_FILTER_SQL, "No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry);
- return false;
+ return 0;
}
}
}
diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp
index b4f74735568..c2d8dbb8ee0 100755
--- a/src/server/game/Handlers/LFGHandler.cpp
+++ b/src/server/game/Handlers/LFGHandler.cpp
@@ -23,6 +23,7 @@
#include "LFGMgr.h"
#include "ObjectMgr.h"
#include "GroupMgr.h"
+#include "GameEventMgr.h"
#include "InstanceScript.h"
void BuildPlayerLockDungeonBlock(WorldPacket& data, const LfgLockMap& lock)
@@ -158,16 +159,25 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*
sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST [" UI64FMTD "]", guid);
// Get Random dungeons that can be done at a certain level and expansion
- // FIXME - Should return seasonals (when not disabled)
LfgDungeonSet randomDungeons;
uint8 level = GetPlayer()->getLevel();
uint8 expansion = GetPlayer()->GetSession()->Expansion();
for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i)
{
LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i);
- if (dungeon && dungeon->type == LFG_TYPE_RANDOM && dungeon->expansion <= expansion &&
- dungeon->minlevel <= level && level <= dungeon->maxlevel)
+ if (dungeon && dungeon->expansion <= expansion && dungeon->minlevel <= level && level <= dungeon->maxlevel)
+ {
+ if (dungeon->flags & LFG_FLAG_SEASONAL)
+ {
+ if (HolidayIds holiday = sLFGMgr->GetDungeonSeason(dungeon->ID))
+ if (!IsHolidayActive(holiday))
+ continue;
+ }
+ else if (dungeon->type != LFG_TYPE_RANDOM)
+ continue;
+
randomDungeons.insert(dungeon->Entry());
+ }
}
// Get player locked Dungeons
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index 5c8f6c1f720..cd3b4fae75f 100755
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -325,7 +325,8 @@ void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket)
if (!go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
return;
- go->AI()->GossipHello(_player);
+ if (go->AI()->GossipHello(_player))
+ return;
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry());
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 5fabd49d7be..c0f4bfd1c24 100755
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2415,7 +2415,7 @@ bool InstanceMap::AddPlayerToMap(Player* player)
{
// solo saves should be reset when entering a group
InstanceGroupBind* groupBind = group->GetBoundInstance(this);
- if (playerBind)
+ if (playerBind && playerBind->save != mapSave)
{
sLog->outError(LOG_FILTER_MAPS, "InstanceMap::Add: player %s(%d) is being put into instance %d, %d, %d, %d, %d, %d but he is in group %d and is bound to instance %d, %d, %d, %d, %d, %d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(group->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
if (groupBind)
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
index 54a68f92c66..bd75e1c8912 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
@@ -32,6 +32,7 @@
template<class T>
void ConfusedMovementGenerator<T>::Initialize(T &unit)
{
+ unit.StopMoving();
float const wander_distance = 4;
float x = unit.GetPositionX();
float y = unit.GetPositionY();
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index 6e0c62107ff..c9497784988 100755
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -335,6 +335,7 @@ void FleeingMovementGenerator<Player>::Finalize(Player &owner)
{
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
+ owner.StopMoving();
}
template<>
diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h
index 73d611e0419..df20c513c90 100755
--- a/src/server/game/Movement/Waypoints/WaypointManager.h
+++ b/src/server/game/Movement/Waypoints/WaypointManager.h
@@ -27,9 +27,9 @@ struct WaypointData
{
uint32 id;
float x, y, z, orientation;
- bool run;
uint32 delay;
uint32 event_id;
+ bool run;
uint8 event_chance;
};
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index ac0d9466736..41ae9fb705f 100755
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -495,6 +495,7 @@ void AddSC_ruby_sanctum();
void AddSC_boss_baltharus_the_warborn();
void AddSC_boss_saviana_ragefire();
void AddSC_boss_general_zarithrian();
+void AddSC_boss_halion();
void AddSC_dalaran();
void AddSC_borean_tundra();
@@ -1208,6 +1209,7 @@ void AddNorthrendScripts()
AddSC_boss_baltharus_the_warborn();
AddSC_boss_saviana_ragefire();
AddSC_boss_general_zarithrian();
+ AddSC_boss_halion();
AddSC_dalaran();
AddSC_borean_tundra();
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index b645c57f154..0b62000fb3f 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -1856,7 +1856,8 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
if (sScriptMgr->OnGossipHello(player, gameObjTarget))
return;
- gameObjTarget->AI()->GossipHello(player);
+ if (gameObjTarget->AI()->GossipHello(player))
+ return;
switch (gameObjTarget->GetGoType())
{
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index e2c7ebf12d9..ab6c2b1df8b 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -645,7 +645,7 @@ SpellSpellGroupMapBounds SpellMgr::GetSpellSpellGroupMapBounds(uint32 spell_id)
return SpellSpellGroupMapBounds(mSpellSpellGroup.lower_bound(spell_id), mSpellSpellGroup.upper_bound(spell_id));
}
-uint32 SpellMgr::IsSpellMemberOfSpellGroup(uint32 spellid, SpellGroup groupid) const
+bool SpellMgr::IsSpellMemberOfSpellGroup(uint32 spellid, SpellGroup groupid) const
{
SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds(spellid);
for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
@@ -3430,7 +3430,7 @@ void SpellMgr::LoadDbcDataCorrections()
break;
case 69055: // Saber Lash (Lord Marrowgar)
case 70814: // Saber Lash (Lord Marrowgar)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_5_YARDS; // 5yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_5_YARDS; // 5yd
break;
case 69075: // Bone Storm (Lord Marrowgar)
case 70834: // Bone Storm (Lord Marrowgar)
@@ -3440,7 +3440,7 @@ void SpellMgr::LoadDbcDataCorrections()
case 71160: // Plague Stench (Stinky)
case 71161: // Plague Stench (Stinky)
case 71123: // Decimate (Stinky & Precious)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd
break;
case 72378: // Blood Nova (Deathbringer Saurfang)
case 73058: // Blood Nova (Deathbringer Saurfang)
@@ -3458,7 +3458,7 @@ void SpellMgr::LoadDbcDataCorrections()
spellInfo->Effect[2] = 0;
break;
case 70460: // Coldflame Jets (Traps after Saurfang)
- spellInfo->DurationIndex = 1; // 10 seconds
+ spellInfo->DurationIndex = 1; // 10 seconds
break;
case 71412: // Green Ooze Summon (Professor Putricide)
case 71415: // Orange Ooze Summon (Professor Putricide)
@@ -3481,7 +3481,7 @@ void SpellMgr::LoadDbcDataCorrections()
case 72464: // Mutated Plague (Professor Putricide)
case 72506: // Mutated Plague (Professor Putricide)
case 72507: // Mutated Plague (Professor Putricide)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 70911: // Unbound Plague (Professor Putricide) (needs target selection script)
case 72854: // Unbound Plague (Professor Putricide) (needs target selection script)
@@ -3492,7 +3492,7 @@ void SpellMgr::LoadDbcDataCorrections()
case 71518: // Unholy Infusion Quest Credit (Professor Putricide)
case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
case 72289: // Frost Infusion Quest Credit (Sindragosa)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // another missing radius
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // another missing radius
break;
case 71708: // Empowered Flare (Blood Prince Council)
case 72785: // Empowered Flare (Blood Prince Council)
@@ -3541,62 +3541,62 @@ void SpellMgr::LoadDbcDataCorrections()
case 73708: // Defile
case 73709: // Defile
case 73710: // Defile
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
break;
case 69030: // Val'kyr Target Search
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
break;
case 69198: // Raging Spirit Visual
- spellInfo->rangeIndex = 13; // 50000yd
+ spellInfo->rangeIndex = 13; // 50000yd
break;
case 73654: // Harvest Souls
case 74295: // Harvest Souls
case 74296: // Harvest Souls
case 74297: // Harvest Souls
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
- spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 73655: // Harvest Soul
spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
break;
case 73540: // Summon Shadow Trap
- spellInfo->DurationIndex = 23; // 90 seconds
+ spellInfo->DurationIndex = 23; // 90 seconds
break;
case 73530: // Shadow Trap (visual)
- spellInfo->DurationIndex = 28; // 5 seconds
+ spellInfo->DurationIndex = 28; // 5 seconds
break;
case 73529: // Shadow Trap
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_10_YARDS; // 10yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_10_YARDS; // 10yd
break;
case 74282: // Shadow Trap (searcher)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_3_YARDS; // 3yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_3_YARDS; // 3yd
break;
case 72595: // Restore Soul
case 73650: // Restore Soul
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
break;
case 74086: // Destroy Soul
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
break;
case 74302: // Summon Spirit Bomb
case 74342: // Summon Spirit Bomb
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
spellInfo->MaxAffectedTargets = 1;
break;
case 74341: // Summon Spirit Bomb
case 74343: // Summon Spirit Bomb
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
spellInfo->MaxAffectedTargets = 3;
break;
case 73579: // Summon Spirit Bomb
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
break;
case 72350: // Fury of Frostmourne
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 75127: // Kill Frostmourne Players
case 72351: // Fury of Frostmourne
@@ -3604,19 +3604,35 @@ void SpellMgr::LoadDbcDataCorrections()
case 72429: // Mass Resurrection
case 73159: // Play Movie
case 73582: // Trigger Vile Spirit (Inside, Heroic)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 72376: // Raise Dead
spellInfo->MaxAffectedTargets = 3;
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 71809: // Jump
- spellInfo->rangeIndex = 3; // 20yd
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
+ spellInfo->rangeIndex = 3; // 20yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
break;
case 72405: // Broken Frostmourne
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
+ break;
+ // ENDOF ICECROWN CITADEL SPELLS
+ //
+ // RUBY SANCTUM SPELLS
+ //
+ case 74769: // Twilight Cutter
+ case 77844: // Twilight Cutter
+ case 77845: // Twilight Cutter
+ case 77846: // Twilight Cutter
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd
break;
+ case 75509: // Twilight Mending
+ spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
+ spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
+ break;
+ // ENDOF RUBY SANCTUM SPELLS
+ //
case 40055: // Introspection
case 40165: // Introspection
case 40166: // Introspection
@@ -3627,6 +3643,13 @@ void SpellMgr::LoadDbcDataCorrections()
spellInfo->manaCost = 0;
spellInfo->manaPerSecond = 0;
break;
+ // OCULUS SPELLS
+ // The spells below are here, because their effect 1 is giving warning, because the triggered spell is not found in dbc and is missing from encounter sniff.
+ case 49462: // Call Ruby Drake
+ case 49461: // Call Amber Drake
+ case 49345: // Call Emerald Drake
+ spellInfo->Effect[1] = 0;
+ break;
default:
break;
}
@@ -3651,5 +3674,5 @@ void SpellMgr::LoadDbcDataCorrections()
properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(647)); // 52893
properties->Type = SUMMON_TYPE_TOTEM;
*/
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loading spell dbc data corrections in %u ms", GetMSTimeDiffToNow(oldMSTime));
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded spell dbc data corrections in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 9423ebf2893..9646bc9dabf 100755
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -643,7 +643,7 @@ class SpellMgr
// Spell Groups table
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const;
- uint32 IsSpellMemberOfSpellGroup(uint32 spellid, SpellGroup groupid) const;
+ bool IsSpellMemberOfSpellGroup(uint32 spellid, SpellGroup groupid) const;
SpellGroupSpellMapBounds GetSpellGroupSpellMapBounds(SpellGroup group_id) const;
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const;
diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h
index a5d77806739..c8126f8aaf3 100755
--- a/src/server/game/Spells/SpellScript.h
+++ b/src/server/game/Spells/SpellScript.h
@@ -582,8 +582,8 @@ class AuraScript : public _SpellScript
class ScriptStateStore
{
public:
- uint8 _currentScriptState;
AuraApplication const* _auraApplication;
+ uint8 _currentScriptState;
bool _defaultActionPrevented;
ScriptStateStore(uint8 currentScriptState, AuraApplication const* auraApplication, bool defaultActionPrevented)
: _currentScriptState(currentScriptState), _auraApplication(auraApplication), _defaultActionPrevented(defaultActionPrevented)
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index e1aa214c583..788e207eea8 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1470,6 +1470,9 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading LFG rewards...");
sLFGMgr->LoadRewards();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading LFG entrance positions...");
+ sLFGMgr->LoadEntrancePositions();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading SpellArea Data..."); // must be after quest load
sSpellMgr->LoadSpellAreas();
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index dd40a590647..7c7adafdfeb 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -476,12 +476,12 @@ public:
}
else if (map->IsDungeon())
{
- Map* map = target->GetMap();
+ Map* destMap = target->GetMap();
- if (map->Instanceable() && map->GetInstanceId() != map->GetInstanceId())
+ if (destMap->Instanceable() && destMap->GetInstanceId() != map->GetInstanceId())
target->UnbindInstance(map->GetInstanceId(), target->GetDungeonDifficulty(), true);
- // we are in instance, and can summon only player in our group with us as lead
+ // we are in an instance, and can only summon players in our group with us as leader
if (!handler->GetSession()->GetPlayer()->GetGroup() || !target->GetGroup() ||
(target->GetGroup()->GetLeaderGUID() != handler->GetSession()->GetPlayer()->GetGUID()) ||
(handler->GetSession()->GetPlayer()->GetGroup()->GetLeaderGUID() != handler->GetSession()->GetPlayer()->GetGUID()))
@@ -2567,7 +2567,7 @@ public:
{
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
// not let dismiss dead pet
- if (pet && pet->isAlive())
+ if (pet->isAlive())
player->RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
}
}
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
index 61df92c18e2..8cf964808d3 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
@@ -27,6 +27,7 @@ EndScriptData */
#include "ScriptedCreature.h"
#include "SpellMgr.h"
#include "scarlet_monastery.h"
+#include "LFGMgr.h"
//this texts are already used by 3975 and 3976
enum Says
@@ -562,6 +563,13 @@ public:
CAST_AI(mob_wisp_invis::mob_wisp_invisAI, wisp->AI())->SetType(4);
if (instance)
instance->SetData(DATA_HORSEMAN_EVENT, DONE);
+
+ Map::PlayerList const& players = me->GetMap()->GetPlayers();
+ if (!players.isEmpty())
+ for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
+ if (Player* player = i->getSource())
+ if (player->IsAtGroupRewardDistance(me))
+ sLFGMgr->RewardDungeonDoneFor(285, player);
}
void SpellHit(Unit* caster, const SpellInfo* spell)
diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp
index ebab2cb99a9..b34a990d39d 100644
--- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp
@@ -44,7 +44,7 @@ enum event
{
EVENT_SPAWN = 1,
EVENT_MINI,
- EVENT_ROOT,
+ EVENT_ROOT,
EVENT_BASH,
EVENT_BOLT,
EVENT_AURA
@@ -58,13 +58,13 @@ public:
struct boss_amanitarAI : public BossAI
{
boss_amanitarAI(Creature* creature) : BossAI(creature, DATA_AMANITAR) { }
-
+
void Reset()
{
_Reset();
-
+
me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
- me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
+ me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
summons.DespawnAll();
if (instance)
@@ -119,7 +119,7 @@ public:
{
trigger->DisappearAndDie();
}
- else
+ else
{
u = 1 - u;
trigger->DisappearAndDie();
@@ -143,7 +143,7 @@ public:
{
switch (eventId)
{
- case EVENT_SPAWN:
+ case EVENT_SPAWN:
SpawnAdds();
events.ScheduleEvent(EVENT_SPAWN, 20*IN_MILLISECONDS);
break;
@@ -151,7 +151,7 @@ public:
DoCast(SPELL_MINI);
events.ScheduleEvent(EVENT_MINI, urand(25,30)*IN_MILLISECONDS);
break;
- case EVENT_ROOT:
+ case EVENT_ROOT:
DoCast(SelectTarget(SELECT_TARGET_RANDOM,0, 100, true),SPELL_ENTANGLING_ROOTS,true);
events.ScheduleEvent(EVENT_ROOT, urand(10,15)*IN_MILLISECONDS);
break;
@@ -192,7 +192,7 @@ public:
{
events.Reset();
events.ScheduleEvent(EVENT_AURA, 1*IN_MILLISECONDS);
-
+
me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
DoCast(SPELL_PUTRID_MUSHROOM);
diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp
index 9274a016e2f..fe86f54ae15 100644
--- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp
@@ -17,6 +17,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
#include "ahnkahet.h"
enum Yells
@@ -30,22 +31,31 @@ enum Yells
enum Spells
{
- SPELL_BROOD_PLAGUE = 56130,
- H_SPELL_BROOD_PLAGUE = 59467,
- H_SPELL_BROOD_RAGE = 59465,
- SPELL_ENRAGE = 26662, // Enraged if too far away from home
- SPELL_SUMMON_SWARMERS = 56119, //2x 30178 -- 2x every 10secs
- SPELL_SUMMON_SWARM_GUARD = 56120, //1x 30176 -- every 25secs
+ SPELL_BROOD_PLAGUE = 56130,
+ H_SPELL_BROOD_RAGE = 59465,
+ SPELL_ENRAGE = 26662, // Enraged if too far away from home
+ SPELL_SUMMON_SWARMERS = 56119, // 2x 30178 -- 2x every 10secs
+ SPELL_SUMMON_SWARM_GUARD = 56120, // 1x 30176 -- every 25%
+ // Spells Adds
+ SPELL_SPRINT = 56354,
+ SPELL_GUARDIAN_AURA = 56151
};
enum Creatures
{
- MOB_AHNKAHAR_SWARMER = 30178,
- MOB_AHNKAHAR_GUARDIAN_ENTRY = 30176
+ NPC_AHNKAHAR_SWARMER = 30178,
+ NPC_AHNKAHAR_GUARDIAN = 30176
};
-#define ACTION_AHNKAHAR_GUARDIAN_DEAD 1
-#define DATA_RESPECT_YOUR_ELDERS 2
+enum Events
+{
+ EVENT_PLAGUE = 1,
+ EVENT_RAGE,
+ EVENT_SUMMON_SWARMER,
+ EVENT_CHECK_ENRAGE,
+ EVENT_SPRINT,
+ DATA_RESPECT_YOUR_ELDERS
+};
class boss_elder_nadox : public CreatureScript
{
@@ -54,32 +64,24 @@ class boss_elder_nadox : public CreatureScript
struct boss_elder_nadoxAI : public ScriptedAI
{
- boss_elder_nadoxAI(Creature* creature) : ScriptedAI(creature)
+ boss_elder_nadoxAI(Creature* creature) : ScriptedAI(creature), summons(me)
{
instance = creature->GetInstanceScript();
}
- uint32 uiPlagueTimer;
- uint32 uiRagueTimer;
-
- uint32 uiSwarmerSpawnTimer;
- uint32 uiGuardSpawnTimer;
- uint32 uiEnrageTimer;
-
- bool bGuardSpawned;
- bool respectYourElders;
-
+ bool GuardianDied;
+ uint8 AmountHealthModifier;
InstanceScript* instance;
+ SummonList summons;
+ EventMap events;
void Reset()
{
- uiPlagueTimer = 13000;
- uiRagueTimer = 20000;
- uiSwarmerSpawnTimer = 10000;
- uiGuardSpawnTimer = 25000;
- uiEnrageTimer = 5000;
- bGuardSpawned = false;
- respectYourElders = true;
+ events.Reset();
+ summons.DespawnAll();
+
+ AmountHealthModifier = 1;
+ GuardianDied = false;
if (instance)
instance->SetData(DATA_ELDER_NADOX_EVENT, NOT_STARTED);
@@ -91,98 +93,95 @@ class boss_elder_nadox : public CreatureScript
if (instance)
instance->SetData(DATA_ELDER_NADOX_EVENT, IN_PROGRESS);
- }
- void KilledUnit(Unit* /*who*/)
- {
- Talk(SAY_SLAY);
+ events.ScheduleEvent(EVENT_PLAGUE, 13*IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SUMMON_SWARMER, 10*IN_MILLISECONDS);
+
+ if (IsHeroic())
+ {
+ events.ScheduleEvent(EVENT_RAGE, 12*IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_CHECK_ENRAGE, 5*IN_MILLISECONDS);
+ }
}
- void JustDied(Unit* /*killer*/)
+ void JustSummoned(Creature* summon)
{
- Talk(SAY_DEATH);
-
- if (instance)
- instance->SetData(DATA_ELDER_NADOX_EVENT, DONE);
+ summons.Summon(summon);
+ summon->AI()->DoZoneInCombat();
}
- void DoAction(int32 const action)
+ void SummonedCreatureDies(Creature* summon, Unit* /*killer*/)
{
- if (action == ACTION_AHNKAHAR_GUARDIAN_DEAD)
- respectYourElders = false;
+ if (summon->GetEntry() == NPC_AHNKAHAR_GUARDIAN)
+ GuardianDied = true;
}
uint32 GetData(uint32 type)
{
if (type == DATA_RESPECT_YOUR_ELDERS)
- return respectYourElders ? 1 : 0;
+ return !GuardianDied ? 1 : 0;
return 0;
}
+ void KilledUnit(Unit* /*victim*/)
+ {
+ Talk(SAY_SLAY);
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ Talk(SAY_DEATH);
+
+ summons.DespawnAll();
+
+ if (instance)
+ instance->SetData(DATA_ELDER_NADOX_EVENT, DONE);
+ }
+
void UpdateAI(uint32 const diff)
{
if (!UpdateVictim())
return;
- if (uiPlagueTimer <= diff)
- {
- DoCastVictim(SPELL_BROOD_PLAGUE);
- uiPlagueTimer = 15000;
- }
- else
- uiPlagueTimer -= diff;
+ events.Update(diff);
- if (IsHeroic())
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (uiRagueTimer <= diff)
+ switch (eventId)
{
- if (Creature* Swarmer = me->FindNearestCreature(MOB_AHNKAHAR_SWARMER, 35.0f))
- {
- DoCast(Swarmer, H_SPELL_BROOD_RAGE, true);
- uiRagueTimer = 15000;
- }
+ case EVENT_PLAGUE:
+ DoCast(SelectTarget(SELECT_TARGET_RANDOM,0, 100, true),SPELL_BROOD_PLAGUE,true);
+ events.ScheduleEvent(EVENT_PLAGUE, 15*IN_MILLISECONDS);
+ break;
+ case EVENT_RAGE:
+ DoCast(H_SPELL_BROOD_RAGE);
+ events.ScheduleEvent(EVENT_RAGE, urand(10*IN_MILLISECONDS, 50*IN_MILLISECONDS));
+ break;
+ case EVENT_SUMMON_SWARMER:
+ DoCast(me, SPELL_SUMMON_SWARMERS);
+ if (urand(1, 3) == 3) // 33% chance of dialog
+ Talk(SAY_EGG_SAC);
+ events.ScheduleEvent(EVENT_SUMMON_SWARMER, 10*IN_MILLISECONDS);
+ break;
+ case EVENT_CHECK_ENRAGE:
+ if (me->HasAura(SPELL_ENRAGE))
+ return;
+ if (me->GetPositionZ() < 24.0f)
+ DoCast(me, SPELL_ENRAGE, true);
+ events.ScheduleEvent(EVENT_CHECK_ENRAGE, 5*IN_MILLISECONDS);
+ break;
+ default:
+ break;
}
- else
- uiRagueTimer -= diff;
}
- if (uiSwarmerSpawnTimer <= diff)
- {
- DoCast(me, SPELL_SUMMON_SWARMERS, true);
- DoCast(me, SPELL_SUMMON_SWARMERS);
- if (urand(1, 3) == 3) // 33% chance of dialog
- Talk(SAY_EGG_SAC);
-
- uiSwarmerSpawnTimer = 10000;
- }
- else
- uiSwarmerSpawnTimer -= diff;
-
- if (!bGuardSpawned && uiGuardSpawnTimer <= diff)
+ if (me->HealthBelowPct(100 - AmountHealthModifier * 25))
{
Talk(EMOTE_HATCHES, me->GetGUID());
DoCast(me, SPELL_SUMMON_SWARM_GUARD);
- bGuardSpawned = true;
+ ++AmountHealthModifier;
}
- else
- uiGuardSpawnTimer -= diff;
-
- if (uiEnrageTimer <= diff)
- {
- if (me->HasAura(SPELL_ENRAGE, 0))
- return;
-
- float x, y, z, o;
- me->GetHomePosition(x, y, z, o);
- if (z < 24)
- if (!me->IsNonMeleeSpellCasted(false))
- DoCast(me, SPELL_ENRAGE, true);
-
- uiEnrageTimer = 5000;
- }
- else
- uiEnrageTimer -= diff;
DoMeleeAttackIfReady();
}
@@ -194,12 +193,6 @@ class boss_elder_nadox : public CreatureScript
}
};
-enum AddSpells
-{
- SPELL_SPRINT = 56354,
- SPELL_GUARDIAN_AURA = 56151
-};
-
class mob_ahnkahar_nerubian : public CreatureScript
{
public:
@@ -207,50 +200,44 @@ class mob_ahnkahar_nerubian : public CreatureScript
struct mob_ahnkahar_nerubianAI : public ScriptedAI
{
- mob_ahnkahar_nerubianAI(Creature* creature) : ScriptedAI(creature)
- {
- instance = creature->GetInstanceScript();
- }
+ mob_ahnkahar_nerubianAI(Creature* creature) : ScriptedAI(creature) { }
- InstanceScript* instance;
- uint32 uiSprintTimer;
+ EventMap events;
void Reset()
{
- if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY)
+ if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN)
DoCast(me, SPELL_GUARDIAN_AURA, true);
- uiSprintTimer = 10000;
+
+ events.ScheduleEvent(EVENT_SPRINT, 13*IN_MILLISECONDS);
}
void JustDied(Unit* /*killer*/)
{
- if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY)
- if (Creature* Nadox = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ELDER_NADOX)))
- Nadox->AI()->DoAction(ACTION_AHNKAHAR_GUARDIAN_DEAD);
+ if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN)
+ me->RemoveAurasDueToSpell(SPELL_GUARDIAN_AURA);
}
- void EnterCombat(Unit* /*who*/) {}
-
- void UpdateAI(uint32 const diff)
+ void UpdateAI(const uint32 diff)
{
if (!UpdateVictim())
return;
- if (me->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY)
- me->RemoveAurasDueToSpell(SPELL_GUARDIAN_AURA);
+ events.Update(diff);
- if (instance)
- if (instance->GetData(DATA_ELDER_NADOX_EVENT) != IN_PROGRESS)
- me->DespawnOrUnsummon();
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (uiSprintTimer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- DoCast(me, SPELL_SPRINT);
- uiSprintTimer = 25000;
+ switch (eventId)
+ {
+ case EVENT_SPRINT:
+ DoCast(me, SPELL_SPRINT);
+ events.ScheduleEvent(EVENT_SPRINT, 20*IN_MILLISECONDS);
+ break;
+ }
}
- else
- uiSprintTimer -= diff;
-
DoMeleeAttackIfReady();
}
};
@@ -274,6 +261,7 @@ public:
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
creature->UpdateAllStats();
}
+
void Reset() {}
void EnterCombat(Unit* /*who*/) {}
void AttackStart(Unit* /*victim*/) {}
@@ -287,28 +275,68 @@ public:
}
};
-class achievement_respect_your_elders : public AchievementCriteriaScript
+class GuardianCheck
{
- public:
- achievement_respect_your_elders() : AchievementCriteriaScript("achievement_respect_your_elders") {}
+public:
+ bool operator()(const WorldObject* target) const
+ {
+ if (target->GetEntry() == NPC_AHNKAHAR_GUARDIAN)
+ return true;
+
+ return false;
+ }
+};
- bool OnCheck(Player* /*player*/, Unit* target)
+class spell_elder_nadox_guardian : public SpellScriptLoader
+{
+public:
+ spell_elder_nadox_guardian() : SpellScriptLoader("spell_elder_nadox_guardian") { }
+
+ class spell_elder_nadox_guardian_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_elder_nadox_guardian_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& targets)
{
- if (!target)
- return false;
+ targets.remove_if(GuardianCheck());
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_elder_nadox_guardian_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_elder_nadox_guardian_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ALLY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_elder_nadox_guardian_SpellScript();
+ }
+};
- if (Creature* Nadox = target->ToCreature())
- if (Nadox->AI()->GetData(DATA_RESPECT_YOUR_ELDERS))
- return true;
+class achievement_respect_your_elders : public AchievementCriteriaScript
+{
+public:
+ achievement_respect_your_elders() : AchievementCriteriaScript("achievement_respect_your_elders") {}
+ bool OnCheck(Player* /*player*/, Unit* target)
+ {
+ if (!target)
return false;
- }
+
+ if (Creature* Nadox = target->ToCreature())
+ if (Nadox->AI()->GetData(DATA_RESPECT_YOUR_ELDERS))
+ return true;
+
+ return false;
+ }
};
void AddSC_boss_elder_nadox()
{
- new boss_elder_nadox;
- new mob_ahnkahar_nerubian;
- new mob_nadox_eggs;
+ new boss_elder_nadox();
+ new mob_ahnkahar_nerubian();
+ new mob_nadox_eggs();
+ new spell_elder_nadox_guardian();
new achievement_respect_your_elders();
}
diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
index dcf1338bc74..3bc91855d36 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
@@ -25,10 +25,8 @@ enum Spells
SPELL_SUMMON_CARRION_BEETLES = 53521,
SPELL_LEECHING_SWARM = 53467,
SPELL_POUND = 53472,
- SPELL_POUND_H = 59433,
SPELL_SUBMERGE = 53421,
SPELL_IMPALE_DMG = 53454,
- SPELL_IMPALE_DMG_H = 59446,
SPELL_IMPALE_SHAKEGROUND = 53455,
SPELL_IMPALE_SPIKE = 53539, //this is not the correct visual effect
//SPELL_IMPALE_TARGET = 53458,
@@ -211,7 +209,7 @@ public:
break;
case IMPALE_PHASE_DMG:
if (Creature* impaleTarget = Unit::GetCreature(*me, ImpaleTarget))
- me->CastSpell(impaleTarget, DUNGEON_MODE(SPELL_IMPALE_DMG, SPELL_IMPALE_DMG_H), true);
+ me->CastSpell(impaleTarget, SPELL_IMPALE_DMG, true);
ImpalePhase = IMPALE_PHASE_TARGET;
ImpaleTimer = 9*IN_MILLISECONDS;
break;
@@ -328,7 +326,7 @@ public:
if (Unit* target = me->getVictim())
{
if (Creature* pImpaleTarget = DoSummonImpaleTarget(target))
- me->CastSpell(pImpaleTarget, DUNGEON_MODE(SPELL_POUND, SPELL_POUND_H), false);
+ me->CastSpell(pImpaleTarget, SPELL_POUND, false);
}
PoundTimer = 16500;
} else PoundTimer -= diff;
diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt
index dd8dd17c947..22d0f37a37f 100644
--- a/src/server/scripts/Northrend/CMakeLists.txt
+++ b/src/server/scripts/Northrend/CMakeLists.txt
@@ -51,6 +51,7 @@ set(scripts_STAT_SRCS
Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp
Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp
Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp
+ Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp
Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp
index 41eb31d815d..531e5d9268e 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp
@@ -158,9 +158,9 @@ class boss_general_zarithrian : public CreatureScript
{
case EVENT_SUMMON_ADDS:
{
- if (Creature* stalker1 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHIAN_SPAWN_STALKER_1)))
+ if (Creature* stalker1 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHRIAN_SPAWN_STALKER_1)))
stalker1->AI()->DoCast(stalker1, SPELL_SUMMON_FLAMECALLER);
- if (Creature* stalker2 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHIAN_SPAWN_STALKER_2)))
+ if (Creature* stalker2 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHRIAN_SPAWN_STALKER_2)))
stalker2->AI()->DoCast(stalker2, SPELL_SUMMON_FLAMECALLER);
Talk(SAY_ADDS);
events.ScheduleEvent(EVENT_SUMMON_ADDS, 42000);
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
new file mode 100644
index 00000000000..ce1e45f21e8
--- /dev/null
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
@@ -0,0 +1,1740 @@
+/*
+ * 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 "SpellScript.h"
+#include "SpellAuraEffects.h"
+#include "Spell.h"
+#include "Vehicle.h"
+#include "MapManager.h"
+#include "GameObjectAI.h"
+#include "ScriptedCreature.h"
+#include "ruby_sanctum.h"
+
+/* ScriptData
+SDName: ruby_sanctum
+SDAuthors: Kaelima, Warpten
+SD%Complete: 90%
+SDComment: Based on Kaelima's initial work (nearly half of it). Corporeality handling is a pure guess, we lack info.
+SDCategory: Chamber of Aspects
+EndScriptData */
+
+enum Texts
+{
+ // Shared
+ SAY_REGENERATE = 0, // Without pressure in both realms, %s begins to regenerate.
+
+ // Halion
+ SAY_INTRO = 1, // Meddlesome insects! You are too late. The Ruby Sanctum is lost!
+ SAY_AGGRO = 2, // Your world teeters on the brink of annihilation. You will ALL bear witness to the coming of a new age of DESTRUCTION!
+ SAY_METEOR_STRIKE = 3, // The heavens burn!
+ SAY_PHASE_TWO = 4, // You will find only suffering within the realm of twilight! Enter if you dare!
+ SAY_DEATH = 5, // Relish this victory, mortals, for it will be your last! This world will burn with the master's return!
+ SAY_KILL = 6, // Another "hero" falls.
+ SAY_BERSERK = 7, // Not good enough.
+ EMOTE_CORPOREALITY_POT = 8, // Your efforts force %s further out of the physical realm!
+ EMOTE_CORPOREALITY_PIP = 9, // Your companions' efforts force %s further into the physical realm!
+
+ // Twilight Halion
+ SAY_SPHERE_PULSE = 1, // Beware the shadow!
+ SAY_PHASE_THREE = 2, // I am the light and the darkness! Cower, mortals, before the herald of Deathwing!
+ EMOTE_CORPOREALITY_TIT = 3, // Your companions' efforts force %s further into the twilight realm!
+ EMOTE_CORPOREALITY_TOT = 4, // Your efforts force %s further out of the twilight realm!
+
+ EMOTE_WARN_LASER = 0, // The orbiting spheres pulse with dark energy!
+};
+
+enum Spells
+{
+ // Halion
+ SPELL_FLAME_BREATH = 74525,
+ SPELL_CLEAVE = 74524,
+ SPELL_METEOR_STRIKE = 74637,
+ SPELL_TAIL_LASH = 74531,
+
+ SPELL_FIERY_COMBUSTION = 74562,
+ SPELL_MARK_OF_COMBUSTION = 74567,
+ SPELL_FIERY_COMBUSTION_EXPLOSION = 74607,
+ SPELL_FIERY_COMBUSTION_SUMMON = 74610,
+
+ // Combustion & Consumption
+ SPELL_SCALE_AURA = 70507, // Aura created in spell_dbc.
+ SPELL_COMBUSTION_DAMAGE_AURA = 74629,
+ SPELL_CONSUMPTION_DAMAGE_AURA = 74803,
+
+ // Twilight Halion
+ SPELL_DARK_BREATH = 74806,
+
+ SPELL_MARK_OF_CONSUMPTION = 74795,
+ SPELL_SOUL_CONSUMPTION = 74792,
+ SPELL_SOUL_CONSUMPTION_EXPLOSION = 74799,
+ SPELL_SOUL_CONSUMPTION_SUMMON = 74800,
+
+ // Living Inferno
+ SPELL_BLAZING_AURA = 75885,
+
+ // Halion Controller
+ SPELL_COSMETIC_FIRE_PILLAR = 76006,
+ SPELL_FIERY_EXPLOSION = 76010,
+ SPELL_CLEAR_DEBUFFS = 75396,
+
+ // Meteor Strike
+ SPELL_METEOR_STRIKE_COUNTDOWN = 74641,
+ SPELL_METEOR_STRIKE_AOE_DAMAGE = 74648,
+ SPELL_METEOR_STRIKE_FIRE_AURA_1 = 74713,
+ SPELL_METEOR_STRIKE_FIRE_AURA_2 = 74718,
+ SPELL_BIRTH_NO_VISUAL = 40031,
+
+ // Shadow Orb
+ SPELL_TWILIGHT_CUTTER = 74768, // Unknown dummy effect (EFFECT_0)
+ SPELL_TWILIGHT_CUTTER_TRIGGERED = 74769,
+ SPELL_TWILIGHT_PULSE_PERIODIC = 78861,
+ SPELL_TRACK_ROTATION = 74758,
+
+ // Misc
+ SPELL_TWILIGHT_DIVISION = 75063, // Phase spell from phase 2 to phase 3
+ SPELL_LEAVE_TWILIGHT_REALM = 74812,
+ SPELL_TWILIGHT_PHASING = 74808, // Phase spell from phase 1 to phase 2
+ SPELL_SUMMON_TWILIGHT_PORTAL = 74809, // Summons go 202794
+ SPELL_SUMMON_EXIT_PORTALS = 74805, // Custom spell created in spell_dbc.
+ SPELL_TWILIGHT_MENDING = 75509,
+ SPELL_TWILIGHT_REALM = 74807,
+ SPELL_COPY_DAMAGE = 74810 // Aura not found in DBCs.
+};
+
+enum Events
+{
+ // Halion
+ EVENT_ACTIVATE_FIREWALL = 1,
+ EVENT_CLEAVE = 2,
+ EVENT_FLAME_BREATH = 3,
+ EVENT_METEOR_STRIKE = 4,
+ EVENT_FIERY_COMBUSTION = 5,
+ EVENT_TAIL_LASH = 6,
+
+ // Twilight Halion
+ EVENT_DARK_BREATH = 7,
+ EVENT_SOUL_CONSUMPTION = 8,
+
+ // Meteor Strike
+ EVENT_SPAWN_METEOR_FLAME = 9,
+
+ // Halion Controller
+ EVENT_START_INTRO = 10,
+ EVENT_INTRO_PROGRESS_1 = 11,
+ EVENT_INTRO_PROGRESS_2 = 12,
+ EVENT_INTRO_PROGRESS_3 = 13,
+ EVENT_CHECK_CORPOREALITY = 14,
+ EVENT_SHADOW_PULSARS_SHOOT = 15,
+ EVENT_TRIGGER_BERSERK = 16,
+ EVENT_TWILIGHT_MENDING = 17
+};
+
+enum Actions
+{
+ // Meteor Strike
+ ACTION_METEOR_STRIKE_BURN = 1,
+ ACTION_METEOR_STRIKE_AOE = 2,
+
+ // Halion Controller
+ ACTION_PHASE_TWO = 3,
+ ACTION_PHASE_THREE = 4,
+ ACTION_CLEANUP = 5,
+
+ // Orb Carrier
+ ACTION_SHOOT = 6
+};
+
+enum Phases
+{
+ PHASE_ALL = 0,
+ PHASE_INTRO = 1,
+ PHASE_ONE = 2,
+ PHASE_TWO = 3,
+ PHASE_THREE = 4,
+
+ PHASE_INTRO_MASK = 1 << PHASE_INTRO,
+ PHASE_ONE_MASK = 1 << PHASE_ONE,
+ PHASE_TWO_MASK = 1 << PHASE_TWO,
+ PHASE_THREE_MASK = 1 << PHASE_THREE
+};
+
+enum Misc
+{
+ DATA_TWILIGHT_DAMAGE_TAKEN = 1,
+ DATA_MATERIAL_DAMAGE_TAKEN = 2,
+ DATA_STACKS_DISPELLED = 3,
+ DATA_FIGHT_PHASE = 4,
+ DATA_EVADE_METHOD = 5
+};
+
+enum OrbCarrierSeats
+{
+ SEAT_NORTH = 0,
+ SEAT_SOUTH = 1,
+ SEAT_EAST = 2,
+ SEAT_WEST = 3
+};
+
+enum CorporealityEvent
+{
+ CORPOREALITY_NONE = 0,
+ CORPOREALITY_TWILIGHT_MENDING = 1,
+ CORPOREALITY_INCREASE = 2,
+ CORPOREALITY_DECREASE = 3
+};
+
+Position const HalionSpawnPos = {3156.67f, 533.8108f, 72.98822f, 3.159046f};
+
+uint8 const MAX_CORPOREALITY_STATE = 11;
+
+struct CorporealityEntry
+{
+ uint32 materialRealmSpell;
+ uint32 twilightRealmSpell;
+};
+
+CorporealityEntry const _corporealityReference[MAX_CORPOREALITY_STATE] = {
+ {74836, 74831},
+ {74835, 74830},
+ {74834, 74829},
+ {74833, 74828},
+ {74832, 74827},
+ {74826, 74826},
+ {74827, 74832},
+ {74828, 74833},
+ {74829, 74834},
+ {74830, 74835},
+ {74831, 74836}
+};
+
+struct generic_halionAI : public BossAI
+{
+ generic_halionAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId), _canEvade(false) { }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ _canEvade = false;
+ events.Reset();
+ events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000));
+ }
+
+ void EnterEvadeMode()
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ _EnterEvadeMode();
+ }
+
+ void ExecuteEvent(uint32 const eventId)
+ {
+ switch (eventId)
+ {
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000));
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ ExecuteEvent(eventId);
+
+ DoMeleeAttackIfReady();
+ }
+
+ void SetData(uint32 index, uint32 dataValue)
+ {
+ switch (index)
+ {
+ case DATA_EVADE_METHOD:
+ _canEvade = (dataValue == 1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void SpellHit(Unit* /*who*/, SpellInfo const* spellInfo)
+ {
+ if (spellInfo->Id == SPELL_TWILIGHT_MENDING)
+ Talk(SAY_REGENERATE);
+ }
+
+protected:
+ bool _canEvade;
+};
+
+class boss_halion : public CreatureScript
+{
+ public:
+ boss_halion() : CreatureScript("boss_halion") { }
+
+ struct boss_halionAI : public generic_halionAI
+ {
+ boss_halionAI(Creature* creature) : generic_halionAI(creature, DATA_HALION) { }
+
+ void Reset()
+ {
+ generic_halionAI::Reset();
+ me->SetReactState(REACT_DEFENSIVE);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+
+ me->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ }
+
+ void EnterEvadeMode()
+ {
+ // Phase 1: We always can evade. Phase 2 & 3: We can evade if and only if the controller tells us to.
+ // Controller has absolute priority over the phasemask.
+ if ((events.GetPhaseMask() & PHASE_ONE_MASK) || _canEvade)
+ generic_halionAI::EnterEvadeMode();
+ }
+
+ void EnterCombat(Unit* who)
+ {
+ generic_halionAI::EnterCombat(who);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
+ instance->SetBossState(DATA_HALION, IN_PROGRESS);
+
+ events.SetPhase(PHASE_ONE);
+ events.ScheduleEvent(EVENT_ACTIVATE_FIREWALL, 10000);
+ events.ScheduleEvent(EVENT_FLAME_BREATH, urand(10000, 12000));
+ events.ScheduleEvent(EVENT_METEOR_STRIKE, urand(20000, 25000));
+ events.ScheduleEvent(EVENT_FIERY_COMBUSTION, urand(15000, 18000));
+ events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_ONE);
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ _JustDied();
+
+ Talk(SAY_DEATH);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ me->Kill(controller);
+ }
+
+ Position const* GetMeteorStrikePosition() const { return &_meteorStrikePos; }
+
+ void DamageTaken(Unit* attacker, uint32& damage)
+ {
+ if (me->HealthBelowPctDamaged(75, damage) && (events.GetPhaseMask() & PHASE_ONE_MASK))
+ {
+ events.SetPhase(PHASE_TWO);
+ Talk(SAY_PHASE_TWO);
+
+ me->CastStop();
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ DoCast(me, SPELL_TWILIGHT_PHASING);
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_TWO);
+ return;
+ }
+
+ if (events.GetPhaseMask() & PHASE_THREE_MASK)
+ {
+ // Don't consider copied damage.
+ if (!me->InSamePhase(attacker))
+ return;
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_MATERIAL_DAMAGE_TAKEN, damage);
+ }
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (events.GetPhaseMask() & PHASE_TWO_MASK)
+ return;
+
+ generic_halionAI::UpdateAI(diff);
+ }
+
+ void ExecuteEvent(uint32 const eventId)
+ {
+ switch (eventId)
+ {
+ case EVENT_ACTIVATE_FIREWALL:
+ {
+ // Flame ring is activated 10 seconds after starting encounter, DOOR_TYPE_ROOM is only instant.
+ for (uint8 i = DATA_FLAME_RING; i <= DATA_TWILIGHT_FLAME_RING; ++i)
+ if (GameObject* flameRing = ObjectAccessor::GetGameObject(*me, instance->GetData64(i)))
+ instance->HandleGameObject(instance->GetData64(DATA_FLAME_RING), false, flameRing);
+ break;
+ }
+ case EVENT_FLAME_BREATH:
+ DoCast(me, SPELL_FLAME_BREATH);
+ events.ScheduleEvent(EVENT_FLAME_BREATH, 25000);
+ break;
+ case EVENT_TAIL_LASH:
+ DoCastAOE(SPELL_TAIL_LASH);
+ events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
+ break;
+ case EVENT_METEOR_STRIKE:
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_TWILIGHT_REALM))
+ {
+ target->GetPosition(&_meteorStrikePos);
+ me->CastSpell(_meteorStrikePos.GetPositionX(), _meteorStrikePos.GetPositionY(), _meteorStrikePos.GetPositionZ(), SPELL_METEOR_STRIKE, true, NULL, NULL, me->GetGUID());
+ Talk(SAY_METEOR_STRIKE);
+ }
+ events.ScheduleEvent(EVENT_METEOR_STRIKE, 40000);
+ break;
+ }
+ case EVENT_FIERY_COMBUSTION:
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_TWILIGHT_REALM))
+ DoCast(target, SPELL_FIERY_COMBUSTION);
+ events.ScheduleEvent(EVENT_FIERY_COMBUSTION, 25000);
+ break;
+ }
+ default:
+ generic_halionAI::ExecuteEvent(eventId);
+ break;
+ }
+ }
+
+ void SetData(uint32 index, uint32 value)
+ {
+ switch (index)
+ {
+ case DATA_FIGHT_PHASE:
+ events.SetPhase(value);
+ break;
+ default:
+ generic_halionAI::SetData(index, value);
+ }
+ }
+
+ private:
+ Position _meteorStrikePos;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<boss_halionAI>(creature);
+ }
+};
+
+typedef boss_halion::boss_halionAI HalionAI;
+
+class boss_twilight_halion : public CreatureScript
+{
+ public:
+ boss_twilight_halion() : CreatureScript("boss_twilight_halion") { }
+
+ struct boss_twilight_halionAI : public generic_halionAI
+ {
+ boss_twilight_halionAI(Creature* creature) : generic_halionAI(creature, DATA_TWILIGHT_HALION)
+ {
+ Creature* halion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION));
+ if (!halion)
+ return;
+
+ // We use explicit targeting here to avoid conditions + SPELL_ATTR6_CANT_TARGET_SELF.
+ // Using AddAura because no spell cast packet in sniffs.
+ halion->AddAura(SPELL_COPY_DAMAGE, me);
+ me->AddAura(SPELL_COPY_DAMAGE, halion);
+
+ me->SetHealth(halion->GetHealth());
+ me->SetPhaseMask(0x20, true);
+ me->SetReactState(REACT_AGGRESSIVE);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2);
+
+ events.Reset();
+ events.SetPhase(PHASE_TWO);
+ events.ScheduleEvent(EVENT_DARK_BREATH, urand(10000, 15000));
+ events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20000);
+ events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
+ }
+
+ void EnterEvadeMode()
+ {
+ // We don't care about evading, we will be despawned.
+ }
+
+ void KilledUnit(Unit* victim)
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_KILL);
+
+ // Victims should not be in the Twilight Realm
+ me->CastSpell(victim, SPELL_LEAVE_TWILIGHT_REALM, true);
+ }
+
+ void JustDied(Unit* killer)
+ {
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION)))
+ {
+ // Ensure looting
+ if (me->IsDamageEnoughForLootingAndReward())
+ halion->LowerPlayerDamageReq(halion->GetMaxHealth());
+
+ if (halion->isAlive())
+ killer->Kill(halion);
+ }
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->Kill(controller);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ }
+
+ void DamageTaken(Unit* attacker, uint32& damage)
+ {
+ if (me->HealthBelowPctDamaged(50, damage) && (events.GetPhaseMask() & PHASE_TWO_MASK))
+ {
+ events.SetPhase(PHASE_THREE);
+ me->CastStop();
+ DoCast(me, SPELL_TWILIGHT_DIVISION);
+ Talk(SAY_PHASE_THREE);
+ return;
+ }
+
+ if (events.GetPhaseMask() & PHASE_THREE_MASK)
+ {
+ // Don't consider copied damage.
+ if (!me->InSamePhase(attacker))
+ return;
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_TWILIGHT_DAMAGE_TAKEN, damage);
+ }
+ }
+
+ void SpellHit(Unit* who, SpellInfo const* spell)
+ {
+ switch (spell->Id)
+ {
+ case SPELL_TWILIGHT_DIVISION:
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_THREE);
+ break;
+ default:
+ generic_halionAI::SpellHit(who, spell);
+ break;
+ }
+ }
+
+ void ExecuteEvent(uint32 const eventId)
+ {
+ switch (eventId)
+ {
+ case EVENT_DARK_BREATH:
+ DoCast(me, SPELL_DARK_BREATH);
+ events.ScheduleEvent(EVENT_DARK_BREATH, urand(10000, 15000));
+ break;
+ case EVENT_SOUL_CONSUMPTION:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, SPELL_TWILIGHT_REALM))
+ DoCast(target, SPELL_SOUL_CONSUMPTION);
+ events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20000);
+ break;
+ case EVENT_TAIL_LASH:
+ DoCastAOE(SPELL_TAIL_LASH);
+ events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
+ break;
+ default:
+ generic_halionAI::ExecuteEvent(eventId);
+ break;
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<boss_twilight_halionAI>(creature);
+ }
+};
+
+class npc_halion_controller : public CreatureScript
+{
+ public:
+ npc_halion_controller() : CreatureScript("npc_halion_controller") { }
+
+ struct npc_halion_controllerAI : public ScriptedAI
+ {
+ npc_halion_controllerAI(Creature* creature) : ScriptedAI(creature),
+ _instance(creature->GetInstanceScript()), _summons(me)
+ {
+ me->SetPhaseMask(me->GetPhaseMask() | 0x20, true);
+ _events.SetPhase(PHASE_INTRO);
+ }
+
+ void Reset()
+ {
+ _summons.DespawnAll();
+ _events.Reset();
+ _materialCorporealityValue = 5;
+
+ DoCast(me, SPELL_CLEAR_DEBUFFS);
+ }
+
+ void JustSummoned(Creature* who)
+ {
+ _summons.Summon(who);
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ _events.Reset();
+ _summons.DespawnAll();
+
+ DoCast(me, SPELL_CLEAR_DEBUFFS);
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ _twilightDamageTaken = 0;
+ _materialDamageTaken = 0;
+
+ _events.ScheduleEvent(EVENT_TRIGGER_BERSERK, 8 * MINUTE * IN_MILLISECONDS);
+ }
+
+ void JustReachedHome()
+ {
+ if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_TWILIGHT_HALION)))
+ twilightHalion->DespawnOrUnsummon();
+
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION)))
+ {
+ halion->AI()->SetData(DATA_EVADE_METHOD, 1);
+ halion->AI()->EnterEvadeMode();
+ }
+
+ _instance->SetBossState(DATA_HALION, FAIL);
+ }
+
+ void DoAction(int32 const action)
+ {
+ switch (action)
+ {
+ case ACTION_INTRO_HALION:
+ _events.Reset();
+ _events.SetPhase(PHASE_INTRO);
+ _events.ScheduleEvent(EVENT_START_INTRO, 2000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ // The isInCombat() check is needed because that check should be false when Halion is
+ // not engaged, while it would return true without as UpdateVictim() checks for
+ // combat state.
+ if (!(_events.GetPhaseMask() & PHASE_INTRO_MASK) && me->isInCombat() && !UpdateVictim())
+ {
+ EnterEvadeMode();
+ return;
+ }
+
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_START_INTRO:
+ DoCast(me, SPELL_COSMETIC_FIRE_PILLAR, true);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_1, 4000);
+ break;
+ case EVENT_INTRO_PROGRESS_1:
+ for (uint8 i = DATA_BURNING_TREE_3; i <= DATA_BURNING_TREE_4; ++i)
+ if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetData64(i)))
+ _instance->HandleGameObject(_instance->GetData64(i), true, tree);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_2, 4000);
+ break;
+ case EVENT_INTRO_PROGRESS_2:
+ for (uint8 i = DATA_BURNING_TREE_1; i <= DATA_BURNING_TREE_2; ++i)
+ if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetData64(i)))
+ _instance->HandleGameObject(_instance->GetData64(i), true, tree);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_3, 4000);
+ break;
+ case EVENT_INTRO_PROGRESS_3:
+ DoCast(me, SPELL_FIERY_EXPLOSION);
+ if (Creature* halion = me->GetMap()->SummonCreature(NPC_HALION, HalionSpawnPos))
+ halion->AI()->Talk(SAY_INTRO);
+ break;
+ case EVENT_TWILIGHT_MENDING:
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION)))
+ if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_TWILIGHT_HALION)))
+ twilightHalion->CastSpell((Unit*)NULL, SPELL_TWILIGHT_MENDING, true);
+ break;
+ case EVENT_TRIGGER_BERSERK:
+ for (uint8 i = DATA_HALION; i <= DATA_TWILIGHT_HALION; i++)
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(i)))
+ halion->CastSpell(halion, SPELL_BERSERK, true);
+ break;
+ case EVENT_SHADOW_PULSARS_SHOOT:
+ if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_TWILIGHT_HALION)))
+ twilightHalion->AI()->Talk(SAY_SPHERE_PULSE);
+
+ if (Creature* orbCarrier = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ORB_CARRIER)))
+ orbCarrier->AI()->DoAction(ACTION_SHOOT);
+
+ _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 29000);
+ break;
+ case EVENT_CHECK_CORPOREALITY:
+ UpdateCorporeality();
+ _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 5000);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void SetData(uint32 id, uint32 value)
+ {
+ switch (id)
+ {
+ case DATA_MATERIAL_DAMAGE_TAKEN:
+ _materialDamageTaken += value;
+ break;
+ case DATA_TWILIGHT_DAMAGE_TAKEN:
+ _twilightDamageTaken += value;
+ break;
+ case DATA_FIGHT_PHASE:
+ _events.SetPhase(value);
+ switch (value)
+ {
+ case PHASE_ONE:
+ DoZoneInCombat();
+ break;
+ case PHASE_TWO:
+ // Timer taken from a 4.3.4 solo video and confirmed by TankSpot's 3.3.5 guide. http://www.tankspot.com/showthread.php?67195-Halion-Encounter-Guide-Live
+ _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 29000);
+ break;
+ case PHASE_THREE:
+ _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 5000);
+ // Load up corporeality data.
+ for (uint8 itr = DATA_HALION; itr <= DATA_TWILIGHT_HALION; itr++)
+ {
+ Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(itr));
+ if (!halion)
+ continue;
+
+ halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), false);
+ halion->AI()->SetData(DATA_FIGHT_PHASE, PHASE_THREE);
+
+ if (itr == DATA_TWILIGHT_HALION)
+ continue;
+
+ halion->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING);
+ halion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ }
+
+ // Summon Twilight portals
+ DoCast(me, SPELL_SUMMON_EXIT_PORTALS);
+
+ _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TOGGLE, 1);
+ // Hardcoding doesn't really matter here.
+ _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, 50);
+ _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 50);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ private:
+ /// TODO: Find out a better scaling, if any.
+ // [0 , 0.98[: Corporeality goes down
+ // [0.98, 0.99]: Do nothing
+ // ]0.99, 1.01[: Twilight Mending
+ // [1.01, 1.02]: Do nothing
+ // ]1.02, +oo [: Corporeality goes up
+ void UpdateCorporeality()
+ {
+ uint8 oldValue = _materialCorporealityValue;
+ if (_twilightDamageTaken == 0 || _materialDamageTaken == 0)
+ {
+ _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, 100);
+ _twilightDamageTaken = 0;
+ _materialDamageTaken = 0;
+ return;
+ }
+
+ float damageRatio = float(_materialDamageTaken) / float(_twilightDamageTaken);
+
+ CorporealityEvent action = CORPOREALITY_NONE;
+ if (damageRatio < 0.98f) // [0 , 0.98[: Corporeality goes down
+ action = CORPOREALITY_DECREASE;
+ else if (0.99f < damageRatio && damageRatio < 1.0f) // ]0.99, 1.01[: Twilight Mending
+ action = CORPOREALITY_TWILIGHT_MENDING;
+ else if (1.02f < damageRatio) // ]1.02, +oo [: Corporeality goes up
+ action = CORPOREALITY_INCREASE;
+
+ switch (action)
+ {
+ case CORPOREALITY_NONE:
+ return;
+ case CORPOREALITY_INCREASE:
+ {
+ if (_materialCorporealityValue >= (MAX_CORPOREALITY_STATE - 1))
+ return;
+ ++_materialCorporealityValue;
+ break;
+ }
+ case CORPOREALITY_DECREASE:
+ {
+ if (_materialCorporealityValue <= 0)
+ return;
+ --_materialCorporealityValue;
+ break;
+ }
+ case CORPOREALITY_TWILIGHT_MENDING:
+ {
+ _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, 100);
+ _materialDamageTaken = 0;
+ _twilightDamageTaken = 0;
+ return;
+ }
+ default:
+ break;
+ }
+
+ _materialDamageTaken = 0;
+ _twilightDamageTaken = 0;
+
+ _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, _materialCorporealityValue * 10);
+ _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 100 - _materialCorporealityValue * 10);
+
+ for (uint8 itr = DATA_HALION; itr <= DATA_TWILIGHT_HALION; itr++)
+ {
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(itr)))
+ {
+ RemoveCorporeality(halion, itr == DATA_TWILIGHT_HALION);
+ halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), true);
+
+ if (itr == DATA_TWILIGHT_HALION)
+ halion->AI()->Talk(oldValue < _materialCorporealityValue ? EMOTE_CORPOREALITY_TOT : EMOTE_CORPOREALITY_TIT, halion->GetGUID());
+ else // if (itr == DATA_HALION)
+ halion->AI()->Talk(oldValue > _materialCorporealityValue ? EMOTE_CORPOREALITY_POT : EMOTE_CORPOREALITY_PIP, halion->GetGUID());
+ }
+ }
+ }
+
+ void RemoveCorporeality(Creature* who, bool isTwilight = false)
+ {
+ for (uint8 i = 0; i < MAX_CORPOREALITY_STATE; i++)
+ {
+ uint32 spellID = (isTwilight ? _corporealityReference[i].twilightRealmSpell : _corporealityReference[i].materialRealmSpell);
+ if (who->HasAura(spellID))
+ {
+ who->RemoveAurasDueToSpell(spellID);
+ break;
+ }
+ }
+ }
+
+ uint32 GetSpell(uint8 pctValue, bool isTwilight = false) const
+ {
+ CorporealityEntry entry = _corporealityReference[pctValue];
+ return isTwilight ? entry.twilightRealmSpell : entry.materialRealmSpell;
+ }
+
+ EventMap _events;
+ InstanceScript* _instance;
+ SummonList _summons;
+
+ bool _corporealityCheck;
+
+ uint32 _twilightDamageTaken;
+ uint32 _materialDamageTaken;
+ uint8 _materialCorporealityValue;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_halion_controllerAI>(creature);
+ }
+};
+
+typedef npc_halion_controller::npc_halion_controllerAI controllerAI;
+
+class npc_orb_carrier : public CreatureScript
+{
+ public:
+ npc_orb_carrier() : CreatureScript("npc_orb_carrier") { }
+
+ struct npc_orb_carrierAI : public ScriptedAI
+ {
+ npc_orb_carrierAI(Creature* creature) : ScriptedAI(creature),
+ instance(creature->GetInstanceScript())
+ {
+ ASSERT(creature->GetVehicleKit());
+ }
+
+ void UpdateAI(uint32 const /*diff*/)
+ {
+ /// According to sniffs this spell is cast every 1 or 2 seconds.
+ /// However, refreshing it looks bad, so just cast the spell if
+ /// we are not channeling it.
+ if (!me->HasUnitState(UNIT_STATE_CASTING))
+ me->CastSpell((Unit*)NULL, SPELL_TRACK_ROTATION, false);
+
+ /// Workaround: This is here because even though the above spell has SPELL_ATTR1_CHANNEL_TRACK_TARGET,
+ /// we are having two creatures involded here. This attribute is handled clientside, meaning the client
+ /// sends orientation update itself. Here, no packet is sent, and the creature does not rotate. By
+ /// forcing the carrier to always be facing the rotation focus, we ensure everything works as it should.
+ if (Creature* rotationFocus = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ORB_ROTATION_FOCUS)))
+ me->SetFacingToObject(rotationFocus); // setInFront
+ }
+
+ void DoAction(int32 const action)
+ {
+ if (action == ACTION_SHOOT)
+ {
+ Vehicle* vehicle = me->GetVehicleKit();
+ Unit* southOrb = vehicle->GetPassenger(SEAT_SOUTH);
+ Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH);
+ if (southOrb && northOrb)
+ {
+ if (northOrb->GetTypeId() == TYPEID_UNIT)
+ northOrb->ToCreature()->AI()->Talk(EMOTE_WARN_LASER);
+ TriggerCutter(northOrb, southOrb);
+ }
+
+ if (!IsHeroic())
+ return;
+
+ Unit* eastOrb = vehicle->GetPassenger(SEAT_EAST);
+ Unit* westOrb = vehicle->GetPassenger(SEAT_WEST);
+ if (eastOrb && westOrb)
+ TriggerCutter(eastOrb, westOrb);
+ }
+ }
+ private:
+ InstanceScript* instance;
+
+ void TriggerCutter(Unit* caster, Unit* target)
+ {
+ caster->CastSpell(caster, SPELL_TWILIGHT_PULSE_PERIODIC, true);
+ target->CastSpell(target, SPELL_TWILIGHT_PULSE_PERIODIC, true);
+ caster->CastSpell(target, SPELL_TWILIGHT_CUTTER, false);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_orb_carrierAI>(creature);
+ }
+};
+
+class npc_meteor_strike_initial : public CreatureScript
+{
+ public:
+ npc_meteor_strike_initial() : CreatureScript("npc_meteor_strike_initial") { }
+
+ struct npc_meteor_strike_initialAI : public Scripted_NoMovementAI
+ {
+ npc_meteor_strike_initialAI(Creature* creature) : Scripted_NoMovementAI(creature),
+ _instance(creature->GetInstanceScript())
+ { }
+
+ void DoAction(int32 const action)
+ {
+ switch (action)
+ {
+ case ACTION_METEOR_STRIKE_AOE:
+ DoCast(me, SPELL_METEOR_STRIKE_AOE_DAMAGE, true);
+ DoCast(me, SPELL_METEOR_STRIKE_FIRE_AURA_1, true);
+ for (std::list<Creature*>::iterator itr = _meteorList.begin(); itr != _meteorList.end(); ++itr)
+ (*itr)->AI()->DoAction(ACTION_METEOR_STRIKE_BURN);
+ break;
+ }
+ }
+
+ void IsSummonedBy(Unit* summoner)
+ {
+ Creature* owner = summoner->ToCreature();
+ if (!owner)
+ return;
+
+ // Let Halion Controller count as summoner
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(me);
+
+ DoCast(me, SPELL_METEOR_STRIKE_COUNTDOWN);
+ DoCast(me, SPELL_BIRTH_NO_VISUAL); // Unknown purpose
+
+ if (HalionAI* halionAI = CAST_AI(HalionAI, owner->AI()))
+ {
+ Position const* ownerPos = halionAI->GetMeteorStrikePosition();
+ Position newPos;
+ float angle[4];
+ angle[0] = me->GetAngle(ownerPos);
+ angle[1] = me->GetAngle(ownerPos) - static_cast<float>(M_PI/2);
+ angle[2] = me->GetAngle(ownerPos) - static_cast<float>(-M_PI/2);
+ angle[3] = me->GetAngle(ownerPos) - static_cast<float>(M_PI);
+
+ _meteorList.clear();
+ for (uint8 i = 0; i < 4; i++)
+ {
+ angle[i] = Position::NormalizeOrientation(angle[i]);
+ me->SetOrientation(angle[i]);
+ me->GetNearPosition(newPos, 10.0f, 0.0f); // Exact distance
+ if (Creature* meteor = me->SummonCreature(NPC_METEOR_STRIKE_NORTH + i, newPos, TEMPSUMMON_TIMED_DESPAWN, 30000))
+ _meteorList.push_back(meteor);
+ }
+ }
+ }
+
+ void UpdateAI(uint32 const /*diff*/) { }
+ void EnterEvadeMode() { }
+ private:
+ InstanceScript* _instance;
+ std::list<Creature*> _meteorList;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_meteor_strike_initialAI>(creature);
+ }
+};
+
+class npc_meteor_strike : public CreatureScript
+{
+ public:
+ npc_meteor_strike() : CreatureScript("npc_meteor_strike") { }
+
+ struct npc_meteor_strikeAI : public Scripted_NoMovementAI
+ {
+ npc_meteor_strikeAI(Creature* creature) : Scripted_NoMovementAI(creature),
+ _instance(creature->GetInstanceScript())
+ {
+ _range = 5.0f;
+ _spawnCount = 0;
+ }
+
+ void DoAction(int32 const action)
+ {
+ if (action == ACTION_METEOR_STRIKE_BURN)
+ {
+ DoCast(me, SPELL_METEOR_STRIKE_FIRE_AURA_2, true);
+ me->setActive(true);
+ _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 500);
+ }
+ }
+
+ void IsSummonedBy(Unit* /*summoner*/)
+ {
+ // Let Halion Controller count as summoner.
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(me);
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (_spawnCount > 5)
+ return;
+
+ _events.Update(diff);
+
+ if (_events.ExecuteEvent() == EVENT_SPAWN_METEOR_FLAME)
+ {
+ Position pos;
+ me->GetNearPosition(pos, _range, 0.0f);
+
+ if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25000))
+ {
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(flame);
+
+ flame->CastSpell(flame, SPELL_METEOR_STRIKE_FIRE_AURA_2, true);
+ ++_spawnCount;
+ }
+ _range += 5.0f;
+ _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 800);
+ }
+ }
+
+ private:
+ InstanceScript* _instance;
+ EventMap _events;
+ float _range;
+ uint8 _spawnCount;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_meteor_strikeAI>(creature);
+ }
+};
+
+class npc_combustion_consumption : public CreatureScript
+{
+ public:
+ npc_combustion_consumption() : CreatureScript("npc_combustion_consumption") { }
+
+ struct npc_combustion_consumptionAI : public Scripted_NoMovementAI
+ {
+ npc_combustion_consumptionAI(Creature* creature) : Scripted_NoMovementAI(creature),
+ _summonerGuid(0), _instance(creature->GetInstanceScript())
+ {
+ switch (me->GetEntry())
+ {
+ case NPC_COMBUSTION:
+ _explosionSpell = SPELL_FIERY_COMBUSTION_EXPLOSION;
+ _damageSpell = SPELL_COMBUSTION_DAMAGE_AURA;
+ me->SetPhaseMask(0x01, true);
+ break;
+ case NPC_CONSUMPTION:
+ _explosionSpell = SPELL_SOUL_CONSUMPTION_EXPLOSION;
+ _damageSpell = SPELL_CONSUMPTION_DAMAGE_AURA;
+ me->SetPhaseMask(0x20, true);
+ break;
+ default: // Should never happen
+ _explosionSpell = 0;
+ _damageSpell = 0;
+ break;
+ }
+
+ if (IsHeroic())
+ me->SetPhaseMask(0x01 | 0x20, true);
+ }
+
+ void IsSummonedBy(Unit* summoner)
+ {
+ // Let Halion Controller count as summoner
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(me);
+
+ _summonerGuid = summoner->GetGUID();
+ }
+
+ void SetData(uint32 type, uint32 stackAmount)
+ {
+ Unit* summoner = ObjectAccessor::GetUnit(*me, _summonerGuid);
+
+ if (type != DATA_STACKS_DISPELLED || !_damageSpell || !_explosionSpell || !summoner)
+ return;
+
+ me->CastCustomSpell(SPELL_SCALE_AURA, SPELLVALUE_AURA_STACK, stackAmount, me);
+ DoCast(me, _damageSpell);
+
+ int32 damage = 1200 + (stackAmount * 1290); // Needs more researches.
+ summoner->CastCustomSpell(_explosionSpell, SPELLVALUE_BASE_POINT0, damage, summoner);
+ }
+
+ void UpdateAI(uint32 const /*diff*/) { }
+
+ private:
+ InstanceScript* _instance;
+ uint32 _explosionSpell;
+ uint32 _damageSpell;
+ uint64 _summonerGuid;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_combustion_consumptionAI>(creature);
+ }
+};
+
+class npc_living_inferno : public CreatureScript
+{
+ public:
+ npc_living_inferno() : CreatureScript("npc_living_inferno") { }
+
+ struct npc_living_infernoAI : public ScriptedAI
+ {
+ npc_living_infernoAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void JustSummoned(Creature* /*summoner*/)
+ {
+ me->SetInCombatWithZone();
+ DoCast(me, SPELL_BLAZING_AURA);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_living_infernoAI>(creature);
+ }
+};
+
+//! Need sniff data
+class npc_living_ember : public CreatureScript
+{
+ public:
+ npc_living_ember() : CreatureScript("npc_living_ember") { }
+
+ struct npc_living_emberAI : public ScriptedAI
+ {
+ npc_living_emberAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void Reset()
+ {
+ _hasEnraged = false;
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ _enrageTimer = 20000;
+ _hasEnraged = false;
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (!_hasEnraged && _enrageTimer <= diff)
+ {
+ _hasEnraged = true;
+ DoCast(me, SPELL_BERSERK);
+ }
+ else _enrageTimer -= diff;
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ uint32 _enrageTimer;
+ bool _hasEnraged;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_living_emberAI>(creature);
+ }
+};
+
+class go_twilight_portal : public GameObjectScript
+{
+ public:
+ go_twilight_portal() : GameObjectScript("go_twilight_portal") { }
+
+ struct go_twilight_portalAI : public GameObjectAI
+ {
+ go_twilight_portalAI(GameObject* gameobject) : GameObjectAI(gameobject),
+ _instance(gameobject->GetInstanceScript()), _deleted(false)
+ {
+ switch (gameobject->GetEntry())
+ {
+ case GO_HALION_PORTAL_EXIT:
+ gameobject->SetPhaseMask(0x20, true);
+ _spellId = gameobject->GetGOInfo()->goober.spellId;
+ break;
+ case GO_HALION_PORTAL_1:
+ case GO_HALION_PORTAL_2: // Not used, not seen in sniffs. Just in case.
+ gameobject->SetPhaseMask(0x1, true);
+ /// Because WDB template has non-existent spell ID, not seen in sniffs either, meh
+ _spellId = SPELL_TWILIGHT_REALM;
+ break;
+ default:
+ _spellId = 0;
+ break;
+ }
+ }
+
+ bool GossipHello(Player* player)
+ {
+ if (_spellId != 0)
+ player->CastSpell(player, _spellId, true);
+ return true;
+ }
+
+ void UpdateAI(uint32 /*diff*/)
+ {
+ if (_instance->GetBossState(DATA_HALION) == IN_PROGRESS)
+ return;
+
+ if (!_deleted)
+ {
+ _deleted = true;
+ go->Delete();
+ }
+ }
+
+ private:
+ InstanceScript* _instance;
+ uint32 _spellId;
+ bool _deleted;
+ };
+
+ GameObjectAI* GetAI(GameObject* gameobject) const
+ {
+ return GetRubySanctumAI<go_twilight_portalAI>(gameobject);
+ }
+};
+
+class spell_halion_meteor_strike_marker : public SpellScriptLoader
+{
+ public:
+ spell_halion_meteor_strike_marker() : SpellScriptLoader("spell_halion_meteor_strike_marker") { }
+
+ class spell_halion_meteor_strike_marker_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_halion_meteor_strike_marker_AuraScript);
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (!GetCaster())
+ return;
+
+ if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
+ if (Creature* creCaster = GetCaster()->ToCreature())
+ creCaster->AI()->DoAction(ACTION_METEOR_STRIKE_AOE);
+ }
+
+ void Register()
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_halion_meteor_strike_marker_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_halion_meteor_strike_marker_AuraScript();
+ }
+};
+
+class spell_halion_combustion_consumption : public SpellScriptLoader
+{
+ public:
+ spell_halion_combustion_consumption(char const* scriptName, uint32 spell) : SpellScriptLoader(scriptName), _spellID(spell) { }
+
+ class spell_halion_combustion_consumption_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_halion_combustion_consumption_AuraScript);
+
+ public:
+ spell_halion_combustion_consumption_AuraScript(uint32 spellID) : AuraScript(), _markSpell(spellID) { }
+
+ bool Validate(SpellEntry const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(_markSpell))
+ return false;
+ return true;
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH)
+ return;
+
+ if (GetTarget()->HasAura(_markSpell))
+ GetTarget()->RemoveAurasDueToSpell(_markSpell, 0, 0, AURA_REMOVE_BY_EXPIRE);
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->CastSpell(GetTarget(), _markSpell, true);
+ }
+
+ void AddMarkStack(AuraEffect const* /*aurEff*/)
+ {
+ GetTarget()->CastSpell(GetTarget(), _markSpell, true);
+ }
+
+ void Register()
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_halion_combustion_consumption_AuraScript::AddMarkStack, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
+ AfterEffectApply += AuraEffectApplyFn(spell_halion_combustion_consumption_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_halion_combustion_consumption_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
+ }
+
+ uint32 _markSpell;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_halion_combustion_consumption_AuraScript(_spellID);
+ }
+
+ private:
+ uint32 _spellID;
+};
+
+class spell_halion_marks : public SpellScriptLoader
+{
+ public:
+ spell_halion_marks(char const* scriptName, uint32 summonSpell, uint32 removeSpell) : SpellScriptLoader(scriptName),
+ _summonSpell(summonSpell), _removeSpell(removeSpell) { }
+
+ class spell_halion_marks_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_halion_marks_AuraScript);
+
+ public:
+ spell_halion_marks_AuraScript(uint32 summonSpell, uint32 removeSpell) : AuraScript(),
+ _summonSpellId(summonSpell), _removeSpellId(removeSpell) { }
+
+ bool Validate(SpellEntry const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(_summonSpellId))
+ return false;
+ return true;
+ }
+
+ /// We were purged. Force removed stacks to zero and trigger the appropriated remove handler.
+ void BeforeDispel(DispelInfo* dispelData)
+ {
+ // Prevent any stack from being removed at this point.
+ dispelData->SetRemovedCharges(0);
+
+ if (Unit* dispelledUnit = GetUnitOwner())
+ if (dispelledUnit->HasAura(_removeSpellId))
+ dispelledUnit->RemoveAurasDueToSpell(_removeSpellId, 0, 0, AURA_REMOVE_BY_EXPIRE);
+ }
+
+ void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
+ return;
+
+ // Stacks marker
+ GetTarget()->CastCustomSpell(_summonSpellId, SPELLVALUE_BASE_POINT1, aurEff->GetBase()->GetStackAmount(), GetTarget(), TRIGGERED_FULL_MASK, NULL, NULL, GetCasterGUID());
+ }
+
+ void Register()
+ {
+ OnDispel += AuraDispelFn(spell_halion_marks_AuraScript::BeforeDispel);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_halion_marks_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+
+ uint32 _summonSpellId;
+ uint32 _removeSpellId;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_halion_marks_AuraScript(_summonSpell, _removeSpell);
+ }
+
+ private:
+ uint32 _summonSpell;
+ uint32 _removeSpell;
+};
+
+class spell_halion_damage_aoe_summon : public SpellScriptLoader
+{
+ public:
+ spell_halion_damage_aoe_summon() : SpellScriptLoader("spell_halion_damage_aoe_summon") { }
+
+ class spell_halion_damage_aoe_summon_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_halion_damage_aoe_summon_SpellScript);
+
+ void HandleSummon(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ Unit* caster = GetCaster();
+ uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue);
+ SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(uint32(GetSpellInfo()->Effects[effIndex].MiscValueB));
+ uint32 duration = uint32(GetSpellInfo()->GetDuration());
+
+ Position pos;
+ caster->GetPosition(&pos);
+ if (Creature* summon = caster->GetMap()->SummonCreature(entry, pos, properties, duration, caster, GetSpellInfo()->Id))
+ if (summon->IsAIEnabled)
+ summon->AI()->SetData(DATA_STACKS_DISPELLED, GetSpellValue()->EffectBasePoints[EFFECT_1]);
+ }
+
+ void Register()
+ {
+ OnEffectHit += SpellEffectFn(spell_halion_damage_aoe_summon_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_damage_aoe_summon_SpellScript();
+ }
+};
+
+class spell_halion_twilight_realm_handlers : public SpellScriptLoader
+{
+ public:
+ spell_halion_twilight_realm_handlers(const char* scriptName, uint32 beforeHitSpell, bool isApplyHandler) : SpellScriptLoader(scriptName),
+ _beforeHitSpell(beforeHitSpell), _isApplyHandler(isApplyHandler)
+ { }
+
+ class spell_halion_twilight_realm_handlers_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_halion_twilight_realm_handlers_AuraScript);
+
+ public:
+ spell_halion_twilight_realm_handlers_AuraScript(uint32 beforeHitSpell, bool isApplyHandler) : AuraScript(),
+ _isApply(isApplyHandler), _beforeHitSpellId(beforeHitSpell)
+ { }
+
+ bool Validate(SpellInfo const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(_beforeHitSpellId))
+ return false;
+ return true;
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*handle*/)
+ {
+ GetTarget()->RemoveAurasDueToSpell(SPELL_TWILIGHT_REALM);
+ if (InstanceScript* instance = GetTarget()->GetInstanceScript())
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_UNK7);
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*handle*/)
+ {
+ Unit* target = GetTarget();
+ if (!target)
+ return;
+
+ target->RemoveAurasDueToSpell(_beforeHitSpellId, 0, 0, AURA_REMOVE_BY_ENEMY_SPELL);
+ if (InstanceScript* instance = target->GetInstanceScript())
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_UNK7);
+ }
+
+ void Register()
+ {
+ if (!_isApply)
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_halion_twilight_realm_handlers_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_halion_twilight_realm_handlers_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ else
+ AfterEffectApply += AuraEffectApplyFn(spell_halion_twilight_realm_handlers_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PHASE, AURA_EFFECT_HANDLE_REAL);
+ }
+
+ bool _isApply;
+ uint32 _beforeHitSpellId;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_halion_twilight_realm_handlers_AuraScript(_beforeHitSpell, _isApplyHandler);
+ }
+
+ private:
+ uint32 _beforeHitSpell;
+ bool _isApplyHandler;
+};
+
+class spell_halion_clear_debuffs : public SpellScriptLoader
+{
+ public:
+ spell_halion_clear_debuffs() : SpellScriptLoader("spell_halion_clear_debuffs") { }
+
+ class spell_halion_clear_debuffs_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_halion_clear_debuffs_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_CLEAR_DEBUFFS))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_TWILIGHT_REALM))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ if (GetHitUnit()->HasAura(GetSpellInfo()->Effects[effIndex].CalcValue()))
+ GetHitUnit()->RemoveAurasDueToSpell(GetSpellInfo()->Effects[effIndex].CalcValue());
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_halion_clear_debuffs_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_clear_debuffs_SpellScript();
+ }
+};
+
+class TwilightCutterSelector
+{
+ public:
+ TwilightCutterSelector(Unit* caster, Unit* cutterCaster) : _caster(caster), _cutterCaster(cutterCaster) {}
+
+ bool operator()(WorldObject* unit)
+ {
+ return !unit->IsInBetween(_caster, _cutterCaster, 4.0f);
+ }
+
+ private:
+ Unit* _caster;
+ Unit* _cutterCaster;
+};
+
+class spell_halion_twilight_cutter : public SpellScriptLoader
+{
+ public:
+ spell_halion_twilight_cutter() : SpellScriptLoader("spell_halion_twilight_cutter") { }
+
+ class spell_halion_twilight_cutter_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_halion_twilight_cutter_SpellScript);
+
+ void RemoveNotBetween(std::list<WorldObject*>& unitList)
+ {
+ if (unitList.empty())
+ return;
+
+ Unit* caster = GetCaster();
+ if (Aura* cutter = caster->GetAura(SPELL_TWILIGHT_CUTTER))
+ {
+ if (Unit* cutterCaster = cutter->GetCaster())
+ {
+ unitList.remove_if(TwilightCutterSelector(caster, cutterCaster));
+ return;
+ }
+ }
+
+ // In case cutter caster werent found for some reason
+ unitList.clear();
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_halion_twilight_cutter_SpellScript::RemoveNotBetween, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_twilight_cutter_SpellScript();
+ }
+};
+
+class spell_halion_twilight_phasing : public SpellScriptLoader
+{
+ public:
+ spell_halion_twilight_phasing() : SpellScriptLoader("spell_halion_twilight_phasing") { }
+
+ class spell_halion_twilight_phasing_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_halion_twilight_phasing_SpellScript);
+
+ void Phase()
+ {
+ Unit* caster = GetCaster();
+ caster->CastSpell(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ(), SPELL_SUMMON_TWILIGHT_PORTAL, true);
+ caster->GetMap()->SummonCreature(NPC_TWILIGHT_HALION, HalionSpawnPos);
+ }
+
+ void Register()
+ {
+ OnHit += SpellHitFn(spell_halion_twilight_phasing_SpellScript::Phase);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_twilight_phasing_SpellScript();
+ }
+};
+
+class spell_halion_summon_exit_portals : public SpellScriptLoader
+{
+ public:
+ spell_halion_summon_exit_portals() : SpellScriptLoader("spell_halion_summon_exit_portals") { }
+
+ class spell_halion_summon_exit_portals_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_halion_summon_exit_portals_SpellScript);
+
+ void OnSummon(SpellEffIndex effIndex)
+ {
+ WorldLocation summonPos = *GetExplTargetDest();
+ Position offset = {0.0f, 20.0f, 0.0f, 0.0f};
+ if (effIndex == EFFECT_1)
+ offset.m_positionY = -20.0f;
+
+ summonPos.RelocateOffset(offset);
+
+ SetExplTargetDest(summonPos);
+ GetHitDest()->RelocateOffset(offset);
+ }
+
+ void Register()
+ {
+ OnEffectLaunch += SpellEffectFn(spell_halion_summon_exit_portals_SpellScript::OnSummon, EFFECT_0, SPELL_EFFECT_SUMMON_OBJECT_WILD);
+ OnEffectLaunch += SpellEffectFn(spell_halion_summon_exit_portals_SpellScript::OnSummon, EFFECT_1, SPELL_EFFECT_SUMMON_OBJECT_WILD);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_summon_exit_portals_SpellScript();
+ }
+};
+
+void AddSC_boss_halion()
+{
+ new boss_halion();
+ new boss_twilight_halion();
+
+ new npc_halion_controller();
+ new npc_meteor_strike_initial();
+ new npc_meteor_strike();
+ new npc_combustion_consumption();
+ new npc_orb_carrier();
+ new npc_living_inferno();
+ new npc_living_ember();
+
+ new go_twilight_portal();
+
+ new spell_halion_meteor_strike_marker();
+ new spell_halion_combustion_consumption("spell_halion_soul_consumption", SPELL_MARK_OF_CONSUMPTION);
+ new spell_halion_combustion_consumption("spell_halion_fiery_combustion", SPELL_MARK_OF_COMBUSTION);
+ new spell_halion_marks("spell_halion_mark_of_combustion", SPELL_FIERY_COMBUSTION_SUMMON, SPELL_FIERY_COMBUSTION);
+ new spell_halion_marks("spell_halion_mark_of_consumption", SPELL_SOUL_CONSUMPTION_SUMMON, SPELL_SOUL_CONSUMPTION);
+ new spell_halion_damage_aoe_summon();
+ new spell_halion_twilight_realm_handlers("spell_halion_leave_twilight_realm", SPELL_SOUL_CONSUMPTION, false);
+ new spell_halion_twilight_realm_handlers("spell_halion_enter_twilight_realm", SPELL_FIERY_COMBUSTION, true);
+ new spell_halion_summon_exit_portals();
+ new spell_halion_twilight_phasing();
+ new spell_halion_twilight_cutter();
+ new spell_halion_clear_debuffs();
+}
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
index 5678bbbeb83..a6b50467538 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
@@ -37,18 +37,23 @@ class instance_ruby_sanctum : public InstanceMapScript
{
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
- BaltharusTheWarbornGUID = 0;
- GeneralZarithrianGUID = 0;
- SavianaRagefireGUID = 0;
- HalionGUID = 0;
- HalionControllerGUID = 0;
+ BaltharusTheWarbornGUID = 0;
+ GeneralZarithrianGUID = 0;
+ SavianaRagefireGUID = 0;
+ HalionGUID = 0;
+ TwilightHalionGUID = 0;
+ OrbCarrierGUID = 0;
+ OrbRotationFocusGUID = 0;
+ HalionControllerGUID = 0;
+ CombatStalkerGUID = 0;
CrystalChannelTargetGUID = 0;
- XerestraszaGUID = 0;
- BaltharusSharedHealth = 0;
- FlameWallsGUID = 0;
- FlameRingGUID = 0;
- memset(ZarithianSpawnStalkerGUID, 0, 2*sizeof(uint64));
- memset(BurningTreeGUID, 0, 4*sizeof(uint64));
+ XerestraszaGUID = 0;
+ BaltharusSharedHealth = 0;
+ FlameWallsGUID = 0;
+ FlameRingGUID = 0;
+
+ memset(ZarithrianSpawnStalkerGUID, 0, 2 * sizeof(uint64));
+ memset(BurningTreeGUID, 0, 4 * sizeof(uint64));
}
void OnCreatureCreate(Creature* creature)
@@ -67,19 +72,32 @@ class instance_ruby_sanctum : public InstanceMapScript
case NPC_HALION:
HalionGUID = creature->GetGUID();
break;
+ case NPC_TWILIGHT_HALION:
+ TwilightHalionGUID = creature->GetGUID();
+ break;
case NPC_HALION_CONTROLLER:
HalionControllerGUID = creature->GetGUID();
+ break;
+ case NPC_ORB_CARRIER:
+ OrbCarrierGUID = creature->GetGUID();
+ break;
+ case NPC_ORB_ROTATION_FOCUS:
+ OrbRotationFocusGUID = creature->GetGUID();
+ break;
+ case NPC_COMBAT_STALKER:
+ CombatStalkerGUID = creature->GetGUID();
+ break;
case NPC_BALTHARUS_TARGET:
CrystalChannelTargetGUID = creature->GetGUID();
break;
case NPC_XERESTRASZA:
XerestraszaGUID = creature->GetGUID();
break;
- case NPC_ZARITHIAN_SPAWN_STALKER:
- if (!ZarithianSpawnStalkerGUID[0])
- ZarithianSpawnStalkerGUID[0] = creature->GetGUID();
+ case NPC_ZARITHRIAN_SPAWN_STALKER:
+ if (!ZarithrianSpawnStalkerGUID[0])
+ ZarithrianSpawnStalkerGUID[0] = creature->GetGUID();
else
- ZarithianSpawnStalkerGUID[1] = creature->GetGUID();
+ ZarithrianSpawnStalkerGUID[1] = creature->GetGUID();
break;
default:
break;
@@ -101,6 +119,9 @@ class instance_ruby_sanctum : public InstanceMapScript
case GO_FLAME_RING:
FlameRingGUID = go->GetGUID();
break;
+ case GO_TWILIGHT_FLAME_RING:
+ TwilightFlameRingGUID = go->GetGUID();
+ break;
case GO_BURNING_TREE_1:
BurningTreeGUID[0] = go->GetGUID();
if (GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE)
@@ -152,24 +173,30 @@ class instance_ruby_sanctum : public InstanceMapScript
return SavianaRagefireGUID;
case DATA_GENERAL_ZARITHRIAN:
return GeneralZarithrianGUID;
- case DATA_ZARITHIAN_SPAWN_STALKER_1:
- return ZarithianSpawnStalkerGUID[0];
- case DATA_ZARITHIAN_SPAWN_STALKER_2:
- return ZarithianSpawnStalkerGUID[1];
+ case DATA_ZARITHRIAN_SPAWN_STALKER_1:
+ case DATA_ZARITHRIAN_SPAWN_STALKER_2:
+ return ZarithrianSpawnStalkerGUID[type - DATA_ZARITHRIAN_SPAWN_STALKER_1];
case DATA_HALION:
return HalionGUID;
+ case DATA_TWILIGHT_HALION:
+ return TwilightHalionGUID;
+ case DATA_ORB_CARRIER:
+ return OrbCarrierGUID;
+ case DATA_ORB_ROTATION_FOCUS:
+ return OrbRotationFocusGUID;
case DATA_HALION_CONTROLLER:
return HalionControllerGUID;
case DATA_BURNING_TREE_1:
- return BurningTreeGUID[0];
case DATA_BURNING_TREE_2:
- return BurningTreeGUID[1];
case DATA_BURNING_TREE_3:
- return BurningTreeGUID[2];
case DATA_BURNING_TREE_4:
- return BurningTreeGUID[3];
+ return BurningTreeGUID[type - DATA_BURNING_TREE_1];
case DATA_FLAME_RING:
return FlameRingGUID;
+ case DATA_TWILIGHT_FLAME_RING:
+ return TwilightFlameRingGUID;
+ case DATA_COMBAT_STALKER:
+ return CombatStalkerGUID;
default:
break;
}
@@ -180,7 +207,14 @@ class instance_ruby_sanctum : public InstanceMapScript
bool SetBossState(uint32 type, EncounterState state)
{
if (!InstanceScript::SetBossState(type, state))
+ {
+ // Summon Halion on instance loading if conditions are met. Without those lines,
+ // InstanceScript::SetBossState returns false, thus preventing the switch from being called.
+ if (type == DATA_HALION && state != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE && !GetData64(DATA_HALION_CONTROLLER))
+ if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos))
+ halionController->AI()->DoAction(ACTION_INTRO_HALION);
return false;
+ }
switch (type)
{
@@ -205,20 +239,30 @@ class instance_ruby_sanctum : public InstanceMapScript
break;
}
case DATA_GENERAL_ZARITHRIAN:
+ {
if (GetBossState(DATA_SAVIANA_RAGEFIRE) == DONE && GetBossState(DATA_BALTHARUS_THE_WARBORN) == DONE)
HandleGameObject(FlameWallsGUID, state != IN_PROGRESS);
- /*
- if (state == DONE)
+
+ // Not called at instance loading, no big deal.
+ if (state == DONE && GetBossState(DATA_HALION) != DONE)
if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos))
halionController->AI()->DoAction(ACTION_INTRO_HALION);
- */
break;
+ }
case DATA_HALION:
- /*
- if (state != IN_PROGRESS)
+ {
+ DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TOGGLE, 0);
+ DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 0);
+ DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, 0);
+
+ // Reopen rings on wipe or success
+ if (state == DONE || state == FAIL)
+ {
HandleGameObject(FlameRingGUID, true);
- */
+ HandleGameObject(TwilightFlameRingGUID, true);
+ }
break;
+ }
default:
break;
}
@@ -228,25 +272,18 @@ class instance_ruby_sanctum : public InstanceMapScript
void SetData(uint32 type, uint32 data)
{
- switch (type)
- {
- case DATA_BALTHARUS_SHARED_HEALTH:
- BaltharusSharedHealth = data;
- break;
- }
+ if (type != DATA_BALTHARUS_SHARED_HEALTH)
+ return;
+
+ BaltharusSharedHealth = data;
}
uint32 GetData(uint32 type)
{
- switch (type)
- {
- case DATA_BALTHARUS_SHARED_HEALTH:
- return BaltharusSharedHealth;
- default:
- break;
- }
+ if (type != DATA_BALTHARUS_SHARED_HEALTH)
+ return 0;
- return 0;
+ return BaltharusSharedHealth;
}
std::string GetSaveData()
@@ -260,6 +297,13 @@ class instance_ruby_sanctum : public InstanceMapScript
return saveStream.str();
}
+ void FillInitialWorldStates(WorldPacket& data)
+ {
+ data << uint32(WORLDSTATE_CORPOREALITY_MATERIAL) << uint32(50);
+ data << uint32(WORLDSTATE_CORPOREALITY_TWILIGHT) << uint32(50);
+ data << uint32(WORLDSTATE_CORPOREALITY_TOGGLE) << uint32(0);
+ }
+
void Load(char const* str)
{
if (!str)
@@ -298,13 +342,19 @@ class instance_ruby_sanctum : public InstanceMapScript
uint64 GeneralZarithrianGUID;
uint64 SavianaRagefireGUID;
uint64 HalionGUID;
+ uint64 TwilightHalionGUID;
uint64 HalionControllerGUID;
+ uint64 OrbCarrierGUID;
+ uint64 OrbRotationFocusGUID;
uint64 CrystalChannelTargetGUID;
uint64 XerestraszaGUID;
uint64 FlameWallsGUID;
- uint64 ZarithianSpawnStalkerGUID[2];
+ uint64 ZarithrianSpawnStalkerGUID[2];
uint64 BurningTreeGUID[4];
uint64 FlameRingGUID;
+ uint64 TwilightFlameRingGUID;
+ uint64 CombatStalkerGUID;
+
uint32 BaltharusSharedHealth;
};
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
index 02ade2ff3e7..7eb1b73721c 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
@@ -21,6 +21,7 @@
#include "SpellScript.h"
#include "Map.h"
#include "Creature.h"
+#include "GameObjectAI.h"
#define RSScriptName "instance_ruby_sanctum"
uint32 const EncounterCount = 4;
@@ -36,17 +37,22 @@ enum DataTypes
DATA_HALION = 3,
// Etc
- DATA_XERESTRASZA = 4,
- DATA_CRYSTAL_CHANNEL_TARGET = 5,
- DATA_BALTHARUS_SHARED_HEALTH = 6,
- DATA_ZARITHIAN_SPAWN_STALKER_1 = 7,
- DATA_ZARITHIAN_SPAWN_STALKER_2 = 8,
- DATA_HALION_CONTROLLER = 9,
- DATA_BURNING_TREE_1 = 10,
- DATA_BURNING_TREE_2 = 11,
- DATA_BURNING_TREE_3 = 12,
- DATA_BURNING_TREE_4 = 13,
- DATA_FLAME_RING = 14,
+ DATA_TWILIGHT_HALION = 4,
+ DATA_XERESTRASZA = 5,
+ DATA_CRYSTAL_CHANNEL_TARGET = 6,
+ DATA_BALTHARUS_SHARED_HEALTH = 7,
+ DATA_ZARITHRIAN_SPAWN_STALKER_1 = 8,
+ DATA_ZARITHRIAN_SPAWN_STALKER_2 = 9,
+ DATA_HALION_CONTROLLER = 10,
+ DATA_ORB_CARRIER = 11,
+ DATA_ORB_ROTATION_FOCUS = 12,
+ DATA_BURNING_TREE_1 = 13,
+ DATA_BURNING_TREE_2 = 14,
+ DATA_BURNING_TREE_3 = 15,
+ DATA_BURNING_TREE_4 = 16,
+ DATA_FLAME_RING = 17,
+ DATA_TWILIGHT_FLAME_RING = 18,
+ DATA_COMBAT_STALKER = 19,
};
enum SharedActions
@@ -66,14 +72,14 @@ enum CreaturesIds
// General Zarithrian
NPC_GENERAL_ZARITHRIAN = 39746,
NPC_ONYX_FLAMECALLER = 39814,
- NPC_ZARITHIAN_SPAWN_STALKER = 39794,
+ NPC_ZARITHRIAN_SPAWN_STALKER = 39794,
// Saviana Ragefire
NPC_SAVIANA_RAGEFIRE = 39747,
// Halion
NPC_HALION = 39863,
- NPC_HALION_TWILIGHT = 40142,
+ NPC_TWILIGHT_HALION = 40142,
NPC_HALION_CONTROLLER = 40146,
NPC_LIVING_INFERNO = 40681,
NPC_LIVING_EMBER = 40683,
@@ -81,6 +87,8 @@ enum CreaturesIds
NPC_ORB_ROTATION_FOCUS = 40091,
NPC_SHADOW_ORB_N = 40083,
NPC_SHADOW_ORB_S = 40100,
+ NPC_SHADOW_ORB_E = 40468,
+ NPC_SHADOW_ORB_W = 40469,
NPC_METEOR_STRIKE_MARK = 40029,
NPC_METEOR_STRIKE_NORTH = 40041,
NPC_METEOR_STRIKE_EAST = 40042,
@@ -88,6 +96,8 @@ enum CreaturesIds
NPC_METEOR_STRIKE_SOUTH = 40044,
NPC_METEOR_STRIKE_FLAME = 40055,
NPC_COMBUSTION = 40001,
+ NPC_CONSUMPTION = 40135,
+ NPC_COMBAT_STALKER = 40151,
// Xerestrasza
NPC_XERESTRASZA = 40429,
@@ -101,6 +111,7 @@ enum GameObjectsIds
GO_FIRE_FIELD = 203005,
GO_FLAME_WALLS = 203006,
GO_FLAME_RING = 203007,
+ GO_TWILIGHT_FLAME_RING = 203624,
GO_BURNING_TREE_1 = 203034,
GO_BURNING_TREE_2 = 203035,
GO_BURNING_TREE_3 = 203036,
@@ -114,6 +125,11 @@ enum WorldStatesRS
WORLDSTATE_CORPOREALITY_TOGGLE = 5051,
};
+enum InstanceSpell
+{
+ SPELL_BERSERK = 26662,
+};
+
template<class AI>
CreatureAI* GetRubySanctumAI(Creature* creature)
{
@@ -124,4 +140,15 @@ CreatureAI* GetRubySanctumAI(Creature* creature)
return NULL;
}
+template<class AI>
+GameObjectAI* GetRubySanctumAI(GameObject* go)
+{
+ if (InstanceMap* instance = go->GetMap()->ToInstanceMap())
+ if (instance->GetInstanceScript())
+ if (instance->GetScriptId() == sObjectMgr->GetScriptId(RSScriptName))
+ return new AI(go);
+
+ return NULL;
+}
+
#endif // RUBY_SANCTUM_H_
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp
index 270e31f4350..c691db4230c 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp
@@ -68,51 +68,6 @@ enum Actions
ACTION_SET_NORMAL_EVENTS = 1
};
-/*Ruby Drake,
-(npc 27756) (item 37860)
-(summoned by spell Ruby Essence = 37860 ---> Call Amber Drake == 49462 ---> Summon 27756)
-*/
-enum RubyDrake
-{
- NPC_RUBY_DRAKE_VEHICLE = 27756,
- SPELL_RIDE_RUBY_DRAKE_QUE = 49463, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49464
- SPELL_RUBY_DRAKE_SADDLE = 49464, //Allows you to ride on the back of an Amber Drake. ---> Dummy
- SPELL_RUBY_SEARING_WRATH = 50232, //(60 yds) - Instant - Breathes a stream of fire at an enemy dragon, dealing 6800 to 9200 Fire damage and then jumping to additional dragons within 30 yards. Each jump increases the damage by 50%. Affects up to 5 total targets
- SPELL_RUBY_EVASIVE_AURA = 50248, //Instant - Allows the Ruby Drake to generate Evasive Charges when hit by hostile attacks and spells.
- SPELL_RUBY_EVASIVE_MANEUVERS = 50240, //Instant - 5 sec. cooldown - Allows your drake to dodge all incoming attacks and spells. Requires Evasive Charges to use. Each attack or spell dodged while this ability is active burns one Evasive Charge. Lasts 30 sec. or until all charges are exhausted.
- //you do not have acces to until you kill Mage-Lord Urom
- SPELL_RUBY_MARTYR = 50253 //Instant - 10 sec. cooldown - Redirect all harmful spells cast at friendly drakes to yourself for 10 sec.
-};
-/*Amber Drake,
-(npc 27755) (item 37859)
-(summoned by spell Amber Essence = 37859 ---> Call Amber Drake == 49461 ---> Summon 27755)
-*/
-enum AmberDrake
-{
- NPC_AMBER_DRAKE_VEHICLE = 27755,
- SPELL_RIDE_AMBER_DRAKE_QUE = 49459, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49460
- SPELL_AMBER_DRAKE_SADDLE = 49460, //Allows you to ride on the back of an Amber Drake. ---> Dummy
- SPELL_AMBER_SHOCK_LANCE = 49840, //(60 yds) - Instant - Deals 4822 to 5602 Arcane damage and detonates all Shock Charges on an enemy dragon. Damage is increased by 6525 for each detonated.
-// SPELL_AMBER_STOP_TIME //Instant - 1 min cooldown - Halts the passage of time, freezing all enemy dragons in place for 10 sec. This attack applies 5 Shock Charges to each affected target.
- //you do not have access to until you kill the Mage-Lord Urom.
- SPELL_AMBER_TEMPORAL_RIFT = 49592 //(60 yds) - Channeled - Channels a temporal rift on an enemy dragon for 10 sec. While trapped in the rift, all damage done to the target is increased by 100%. In addition, for every 15, 000 damage done to a target affected by Temporal Rift, 1 Shock Charge is generated.
-};
-
-/*Emerald Drake,
-(npc 27692) (item 37815),
- (summoned by spell Emerald Essence = 37815 ---> Call Emerald Drake == 49345 ---> Summon 27692)
-*/
-enum EmeraldDrake
-{
- NPC_EMERALD_DRAKE_VEHICLE = 27692,
- SPELL_RIDE_EMERALD_DRAKE_QUE = 49427, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49346
- SPELL_EMERALD_DRAKE_SADDLE = 49346, //Allows you to ride on the back of an Amber Drake. ---> Dummy
- SPELL_EMERALD_LEECHING_POISON = 50328, //(60 yds) - Instant - Poisons the enemy dragon, leeching 1300 to the caster every 2 sec. for 12 sec. Stacks up to 3 times.
- SPELL_EMERALD_TOUCH_THE_NIGHTMARE = 50341, //(60 yds) - Instant - Consumes 30% of the caster's max health to inflict 25, 000 nature damage to an enemy dragon and reduce the damage it deals by 25% for 30 sec.
- // you do not have access to until you kill the Mage-Lord Urom
- SPELL_EMERALD_DREAM_FUNNEL = 50344 //(60 yds) - Channeled - Transfers 5% of the caster's max health to a friendly drake every second for 10 seconds as long as the caster channels.
-};
-
enum EregosData
{
DATA_RUBY_VOID = 0, // http://www.wowhead.com/achievement=2044
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp
index 791bc0180e5..179dedb290b 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp
@@ -38,7 +38,8 @@ enum Spells
SPELL_SUMMON_MENAGERIE_3 = 50496,
SPELL_TELEPORT = 51112, //Teleports to the center of Oculus
SPELL_TIME_BOMB = 51121, //Deals arcane damage to a random player, and after 6 seconds, deals zone damage to nearby equal to the health missing of the target afflicted by the debuff.
- SPELL_TIME_BOMB_2 = 59376
+ SPELL_TIME_BOMB_2 = 59376,
+ SPELL_EVOCATE = 51602 // He always cast it on reset or after teleportation
};
enum Yells
@@ -103,8 +104,7 @@ public:
void Reset()
{
- if (instance->GetBossState(DATA_VAROS_EVENT) != DONE)
- DoCast(SPELL_ARCANE_SHIELD);
+ me->CastSpell(me, SPELL_EVOCATE);
_Reset();
@@ -307,14 +307,17 @@ public:
case SPELL_SUMMON_MENAGERIE:
me->SetHomePosition(968.66f, 1042.53f, 527.32f, 0.077f);
LeaveCombat();
+ me->CastSpell(me, SPELL_EVOCATE);
break;
case SPELL_SUMMON_MENAGERIE_2:
me->SetHomePosition(1164.02f, 1170.85f, 527.321f, 3.66f);
LeaveCombat();
+ me->CastSpell(me, SPELL_EVOCATE);
break;
case SPELL_SUMMON_MENAGERIE_3:
me->SetHomePosition(1118.31f, 1080.377f, 508.361f, 4.25f);
LeaveCombat();
+ me->CastSpell(me, SPELL_EVOCATE);
break;
case SPELL_TELEPORT:
//! Unconfirmed, previous below
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
index ca4ae883747..a0b5aded315 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
@@ -56,9 +56,13 @@ public:
eregosCacheGUID = 0;
- azureDragonsList.clear();
+ gwhelpList.clear();
gameObjectList.clear();
- }
+
+ belgaristraszGUID = 0;
+ eternosGUID = 0;
+ verdisaGUID = 0;
+}
void OnUnitDeath(Unit* unit)
{
@@ -112,17 +116,49 @@ public:
break;
case NPC_VAROS:
varosGUID = creature->GetGUID();
+ if (GetBossState(DATA_DRAKOS_EVENT) == DONE)
+ creature->SetPhaseMask(1, true);
break;
case NPC_UROM:
uromGUID = creature->GetGUID();
+ if (GetBossState(DATA_VAROS_EVENT) == DONE)
+ creature->SetPhaseMask(1, true);
break;
case NPC_EREGOS:
eregosGUID = creature->GetGUID();
+ if (GetBossState(DATA_UROM_EVENT) == DONE)
+ creature->SetPhaseMask(1, true);
break;
case NPC_CENTRIFUGE_CONSTRUCT:
if (creature->isAlive())
DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_AMOUNT, ++centrifugueConstructCounter);
break;
+ case NPC_BELGARISTRASZ:
+ belgaristraszGUID = creature->GetGUID();
+ if (GetBossState(DATA_DRAKOS_EVENT) == DONE)
+ creature->SetWalk(true),
+ creature->GetMotionMaster()->MovePoint(0, 941.453f, 1044.1f, 359.967f),
+ creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ break;
+ case NPC_ETERNOS:
+ eternosGUID = creature->GetGUID();
+ if (GetBossState(DATA_DRAKOS_EVENT) == DONE)
+ creature->SetWalk(true),
+ creature->GetMotionMaster()->MovePoint(0, 943.202f, 1059.35f, 359.967f),
+ creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ break;
+ case NPC_VERDISA:
+ verdisaGUID = creature->GetGUID();
+ if (GetBossState(DATA_DRAKOS_EVENT) == DONE)
+ creature->SetWalk(true),
+ creature->GetMotionMaster()->MovePoint(0, 949.188f, 1032.91f, 359.967f),
+ creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ break;
+ case NPC_GREATER_WHELP:
+ if (GetBossState(DATA_UROM_EVENT) == DONE)
+ creature->SetPhaseMask(1, true);
+ gwhelpList.push_back(creature->GetGUID());
+ break;
}
}
@@ -159,11 +195,22 @@ public:
DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_SHOW, 1);
DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_AMOUNT, centrifugueConstructCounter);
OpenCageDoors();
+ FreeDragons();
+ if (Creature* varos = instance->GetCreature(varosGUID))
+ varos->SetPhaseMask(1, true);
}
break;
case DATA_VAROS_EVENT:
if (state == DONE)
DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_SHOW, 0);
+ if (Creature* urom = instance->GetCreature(uromGUID))
+ urom->SetPhaseMask(1, true);
+ break;
+ case DATA_UROM_EVENT:
+ if (state == DONE)
+ if (Creature* eregos = instance->GetCreature(eregosGUID))
+ eregos->SetPhaseMask(1, true);
+ GreaterWhelps();
break;
case DATA_EREGOS_EVENT:
if (state == DONE)
@@ -221,6 +268,31 @@ public:
}
}
+ void FreeDragons()
+ {
+ if (Creature* belgaristrasz = instance->GetCreature(belgaristraszGUID))
+ belgaristrasz->SetWalk(true),
+ belgaristrasz->GetMotionMaster()->MovePoint(0, 941.453f, 1044.1f, 359.967f);
+ if (Creature* eternos = instance->GetCreature(eternosGUID))
+ eternos->SetWalk(true),
+ eternos->GetMotionMaster()->MovePoint(0, 943.202f, 1059.35f, 359.967f);
+ if (Creature* verdisa = instance->GetCreature(verdisaGUID))
+ verdisa->SetWalk(true),
+ verdisa->GetMotionMaster()->MovePoint(0, 949.188f, 1032.91f, 359.967f);
+ }
+
+ void GreaterWhelps()
+ {
+ if (gwhelpList.empty())
+ return;
+
+ for (std::list<uint64>::const_iterator itr = gwhelpList.begin(); itr != gwhelpList.end(); ++itr)
+ {
+ if (Creature* gwhelp = instance->GetCreature(*itr))
+ gwhelp->SetPhaseMask(1, true);
+ }
+ }
+
std::string GetSaveData()
{
OUT_SAVE_INST_DATA;
@@ -269,6 +341,10 @@ public:
uint64 uromGUID;
uint64 eregosGUID;
+ uint64 belgaristraszGUID;
+ uint64 eternosGUID;
+ uint64 verdisaGUID;
+
uint8 platformUrom;
uint8 centrifugueConstructCounter;
@@ -277,9 +353,8 @@ public:
std::string str_data;
std::list<uint64> gameObjectList;
- std::list<uint64> azureDragonsList;
+ std::list<uint64> gwhelpList;
};
-
};
void AddSC_instance_oculus()
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
index 1d8b5b986f6..39fff139b52 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
@@ -20,6 +20,8 @@
#include "ScriptedGossip.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
+#include "Vehicle.h"
+#include "CombatAI.h"
#include "oculus.h"
#define GOSSIP_ITEM_DRAKES "So where do we go from here?"
@@ -32,7 +34,7 @@
#define HAS_ESSENCE(a) ((a)->HasItemCount(ITEM_EMERALD_ESSENCE, 1) || (a)->HasItemCount(ITEM_AMBER_ESSENCE, 1) || (a)->HasItemCount(ITEM_RUBY_ESSENCE, 1))
-enum Drakes
+enum GossipNPCs
{
GOSSIP_TEXTID_DRAKES = 13267,
GOSSIP_TEXTID_BELGARISTRASZ1 = 12916,
@@ -49,23 +51,65 @@ enum Drakes
ITEM_AMBER_ESSENCE = 37859,
ITEM_RUBY_ESSENCE = 37860,
- NPC_VERDISA = 27657,
- NPC_BELGARISTRASZ = 27658,
- NPC_ETERNOS = 27659,
+ SPELL_SHOCK_CHARGE = 49836
+};
+
+enum Drakes
+{
+/*Ruby Drake,
+(npc 27756) (item 37860)
+(summoned by spell Ruby Essence = 37860 ---> Call Amber Drake == 49462 ---> Summon 27756)
+*/
+ SPELL_RIDE_RUBY_DRAKE_QUE = 49463, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49464
+ SPELL_RUBY_DRAKE_SADDLE = 49464, //Allows you to ride on the back of an Amber Drake. ---> Dummy
+ SPELL_RUBY_SEARING_WRATH = 50232, //(60 yds) - Instant - Breathes a stream of fire at an enemy dragon, dealing 6800 to 9200 Fire damage and then jumping to additional dragons within 30 yards. Each jump increases the damage by 50%. Affects up to 5 total targets
+ SPELL_RUBY_EVASIVE_AURA = 50248, //Instant - Allows the Ruby Drake to generate Evasive Charges when hit by hostile attacks and spells.
+ SPELL_RUBY_EVASIVE_MANEUVERS = 50240, //Instant - 5 sec. cooldown - Allows your drake to dodge all incoming attacks and spells. Requires Evasive Charges to use. Each attack or spell dodged while this ability is active burns one Evasive Charge. Lasts 30 sec. or until all charges are exhausted.
+ //you do not have acces to until you kill Mage-Lord Urom
+ SPELL_RUBY_MARTYR = 50253, //Instant - 10 sec. cooldown - Redirect all harmful spells cast at friendly drakes to yourself for 10 sec.
+
+/*Amber Drake,
+(npc 27755) (item 37859)
+(summoned by spell Amber Essence = 37859 ---> Call Amber Drake == 49461 ---> Summon 27755)
+*/
- SPELL_SHOCK_CHARGE = 49836,
+ SPELL_RIDE_AMBER_DRAKE_QUE = 49459, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49460
+ SPELL_AMBER_DRAKE_SADDLE = 49460, //Allows you to ride on the back of an Amber Drake. ---> Dummy
+ SPELL_AMBER_SHOCK_LANCE = 49840, //(60 yds) - Instant - Deals 4822 to 5602 Arcane damage and detonates all Shock Charges on an enemy dragon. Damage is increased by 6525 for each detonated.
+ // SPELL_AMBER_STOP_TIME //Instant - 1 min cooldown - Halts the passage of time, freezing all enemy dragons in place for 10 sec. This attack applies 5 Shock Charges to each affected target.
+ //you do not have access to until you kill the Mage-Lord Urom.
+ SPELL_AMBER_TEMPORAL_RIFT = 49592, //(60 yds) - Channeled - Channels a temporal rift on an enemy dragon for 10 sec. While trapped in the rift, all damage done to the target is increased by 100%. In addition, for every 15, 000 damage done to a target affected by Temporal Rift, 1 Shock Charge is generated.
+
+/*Emerald Drake,
+(npc 27692) (item 37815),
+ (summoned by spell Emerald Essence = 37815 ---> Call Emerald Drake == 49345 ---> Summon 27692)
+*/
+ SPELL_RIDE_EMERALD_DRAKE_QUE = 49427, //Apply Aura: Periodic Trigger, Interval: 3 seconds ---> 49346
+ SPELL_EMERALD_DRAKE_SADDLE = 49346, //Allows you to ride on the back of an Amber Drake. ---> Dummy
+ SPELL_EMERALD_LEECHING_POISON = 50328, //(60 yds) - Instant - Poisons the enemy dragon, leeching 1300 to the caster every 2 sec. for 12 sec. Stacks up to 3 times.
+ SPELL_EMERALD_TOUCH_THE_NIGHTMARE = 50341, //(60 yds) - Instant - Consumes 30% of the caster's max health to inflict 25, 000 nature damage to an enemy dragon and reduce the damage it deals by 25% for 30 sec.
+ // you do not have access to until you kill the Mage-Lord Urom
+ SPELL_EMERALD_DREAM_FUNNEL = 50344, //(60 yds) - Channeled - Transfers 5% of the caster's max health to a friendly drake every second for 10 seconds as long as the caster channels.
};
enum Says
{
- SAY_VAROS = 0,
- SAY_UROM = 1
+ SAY_VAROS = 0,
+ SAY_UROM = 1,
+ SAY_BELGARISTRASZ = 0,
+ SAY_DRAKES_TAKEOFF = 0,
+ WHISPER_DRAKES_WELCOME = 1,
+ WHISPER_DRAKES_ABILITIES = 2,
+ WHISPER_DRAKES_SPECIAL = 3,
+ WHISPER_DRAKES_LOWHEALTH = 4
};
-class npc_oculus_drake : public CreatureScript
+class npc_verdisa_beglaristrasz_eternos : public CreatureScript
{
public:
- npc_oculus_drake() : CreatureScript("npc_oculus_drake") { }
+ npc_verdisa_beglaristrasz_eternos() : CreatureScript("npc_verdisa_beglaristrasz_eternos") { }
+
+ InstanceScript* instance;
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action)
{
@@ -184,6 +228,28 @@ public:
return true;
}
+ struct npc_verdisa_beglaristrasz_eternosAI : public ScriptedAI
+ {
+ npc_verdisa_beglaristrasz_eternosAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void MovementInform(uint32 type, uint32 id)
+ {
+ // When Belgaristraz finish his moving say grateful text
+ if (me->GetEntry() == NPC_BELGARISTRASZ)
+ if (id == 0)
+ {
+ Talk(SAY_BELGARISTRASZ);
+ }
+ // The gossip flag should activate when Drakos die and not from DB
+ if (id == 0)
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_verdisa_beglaristrasz_eternosAI(creature);
+ }
};
class npc_image_belgaristrasz : public CreatureScript
@@ -193,7 +259,7 @@ public:
struct npc_image_belgaristraszAI : public ScriptedAI
{
- npc_image_belgaristraszAI(Creature* creature) : ScriptedAI(creature) {}
+ npc_image_belgaristraszAI(Creature* creature) : ScriptedAI(creature) { }
void IsSummonedBy(Unit* summoner)
{
@@ -216,6 +282,176 @@ public:
}
};
+class npc_ruby_emerald_amber_drake : public CreatureScript
+{
+public:
+ npc_ruby_emerald_amber_drake() : CreatureScript("npc_ruby_emerald_amber_drake") { }
+
+ struct npc_ruby_emerald_amber_drakeAI : public VehicleAI
+ {
+ npc_ruby_emerald_amber_drakeAI(Creature* creature) : VehicleAI(creature)
+ {
+ instance = creature->GetInstanceScript();
+ }
+
+ InstanceScript* instance;
+
+ uint64 summonerGUID;
+ uint32 WelcomeTimer;
+ uint32 WelcomeSequelTimer;
+ uint32 SpecialTimer;
+ uint32 WarningTimer;
+ uint32 TakeOffTimer;
+
+ bool WelcomeOff;
+ bool WelcomeSequelOff;
+ bool SpecialOff;
+ bool HealthWarningOff;
+ bool DisableTakeOff;
+
+ void Reset()
+ {
+ summonerGUID = 0;
+ WelcomeTimer = 4500;
+ WelcomeSequelTimer = 4500;
+ SpecialTimer = 10000;
+ WarningTimer = 25000;
+ TakeOffTimer = 3500;
+
+ WelcomeOff = false;
+ WelcomeSequelOff = false;
+ SpecialOff = false;
+ HealthWarningOff = false;
+ DisableTakeOff = false;
+ }
+
+ void IsSummonedBy(Unit* summoner)
+ {
+ if (instance->GetBossState(DATA_EREGOS_EVENT) == IN_PROGRESS)
+ if (Creature* eregos = me->FindNearestCreature(NPC_EREGOS, 450.0f, true))
+ {
+ eregos->DespawnOrUnsummon(); // On retail this kills abusive call of drake during engaged Eregos
+ }
+ summonerGUID = summoner->GetGUID();
+ me->SetFacingToObject(summoner);
+ // TO DO: Drake Ques should be casted from vehicle to player, however the way core handle triggered spells from auras break it no matter the conditions. So this change the caster and give the same result until someone fix triggered spells from auras that involve implicit targets or make exception for this case.
+ if (me->GetEntry() == NPC_RUBY_DRAKE_VEHICLE)
+ summoner->CastSpell(summoner, SPELL_RIDE_RUBY_DRAKE_QUE);
+ if (me->GetEntry() == NPC_EMERALD_DRAKE_VEHICLE)
+ summoner->CastSpell(summoner, SPELL_RIDE_EMERALD_DRAKE_QUE);
+ if (me->GetEntry() == NPC_AMBER_DRAKE_VEHICLE)
+ summoner->CastSpell(summoner, SPELL_RIDE_AMBER_DRAKE_QUE);
+ Position pos;
+ summoner->GetPosition(&pos);
+ me->GetMotionMaster()->MovePoint(0, pos);
+ }
+
+ void MovementInform(uint32 type, uint32 id)
+ {
+ if (type == POINT_MOTION_TYPE && id == 0)
+ {
+ me->SetDisableGravity(false); // Needed this for proper animation after spawn, the summon in air fall to ground bug leave no other option for now, if this isn't used the drake will only walk on move.
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!(instance->GetBossState(DATA_VAROS_EVENT) == DONE))
+ {
+ if (me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE))
+ {
+ if (!(WelcomeOff))
+ {
+ if (WelcomeTimer <= diff)
+ {
+ Talk(WHISPER_DRAKES_WELCOME, me->GetCreatorGUID());
+ WelcomeOff = true;
+ WelcomeSequelOff = true;
+ }
+ else WelcomeTimer -= diff;
+ }
+ }
+ }
+ if (me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE))
+ {
+ if (WelcomeSequelOff)
+ {
+ if (WelcomeSequelTimer <= diff)
+ {
+ Talk(WHISPER_DRAKES_ABILITIES, me->GetCreatorGUID());
+ WelcomeSequelOff = false;
+ }
+ else WelcomeSequelTimer -= diff;
+ }
+ }
+ if (me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE))
+ {
+ if (instance->GetBossState(DATA_UROM_EVENT) == DONE)
+ {
+ if (!(SpecialOff))
+ {
+ if (SpecialTimer <= diff)
+ {
+ Talk(WHISPER_DRAKES_SPECIAL, me->GetCreatorGUID());
+ SpecialOff = true;
+ }
+ else SpecialTimer -= diff;
+ }
+ }
+ }
+ if (me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE))
+ {
+ if (!(HealthWarningOff))
+ {
+ if (me->GetHealthPct() <= 40.0f)
+ {
+ Talk(WHISPER_DRAKES_LOWHEALTH, me->GetCreatorGUID());
+ HealthWarningOff = true;
+ }
+ }
+ }
+ if (me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE))
+ {
+ if (HealthWarningOff)
+ {
+ if (WarningTimer <= diff)
+ {
+ HealthWarningOff = false;
+ WarningTimer = 25000;
+ }
+ else WarningTimer -= diff;
+ }
+ }
+ if (!(me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE)))
+ {
+ if (!(DisableTakeOff))
+ {
+ if (TakeOffTimer <= diff)
+ {
+ me->DespawnOrUnsummon(2050);
+ me->SetOrientation(2.5f);
+ me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
+ Talk(SAY_DRAKES_TAKEOFF);
+ Position pos;
+ me->GetPosition(&pos);
+ pos.m_positionX += 10.0f;
+ pos.m_positionY += 10.0f;
+ pos.m_positionZ += 12.0f;
+ me->GetMotionMaster()->MovePoint(1, pos);
+ DisableTakeOff = true;
+ }
+ else TakeOffTimer -= diff;
+ }
+ }
+ };
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_ruby_emerald_amber_drakeAI(creature);
+ }
+};
+
class spell_gen_stop_time : public SpellScriptLoader
{
public:
@@ -247,9 +483,50 @@ public:
}
};
+class spell_call_ruby_emerald_amber_drake : public SpellScriptLoader
+{
+public:
+ spell_call_ruby_emerald_amber_drake() : SpellScriptLoader("spell_call_ruby_emerald_amber_drake") { }
+
+ class spell_call_ruby_emerald_amber_drake_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_call_ruby_emerald_amber_drake_SpellScript);
+
+ void ChangeSummonPos(SpellEffIndex /*effIndex*/)
+ {
+ // Adjust effect summon position
+ WorldLocation summonPos = *GetExplTargetDest();
+ Position offset = {0.0f, 0.0f, 12.0f, 0.0f};
+ summonPos.RelocateOffset(offset);
+ SetExplTargetDest(summonPos);
+ GetHitDest()->RelocateOffset(offset);
+ }
+
+ void ModDestHeight(SpellEffIndex /*effIndex*/)
+ {
+ // Used to cast visual effect at proper position
+ Position offset = {0.0f, 0.0f, 12.0f, 0.0f};
+ const_cast<WorldLocation*>(GetExplTargetDest())->RelocateOffset(offset);
+ }
+
+ void Register()
+ {
+ OnEffectHit += SpellEffectFn(spell_call_ruby_emerald_amber_drake_SpellScript::ChangeSummonPos, EFFECT_0, SPELL_EFFECT_SUMMON);
+ OnEffectLaunch += SpellEffectFn(spell_call_ruby_emerald_amber_drake_SpellScript::ModDestHeight, EFFECT_0, SPELL_EFFECT_SUMMON);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_call_ruby_emerald_amber_drake_SpellScript();
+ }
+};
+
void AddSC_oculus()
{
- new npc_oculus_drake();
+ new npc_verdisa_beglaristrasz_eternos();
new npc_image_belgaristrasz();
+ new npc_ruby_emerald_amber_drake();
new spell_gen_stop_time();
+ new spell_call_ruby_emerald_amber_drake();
}
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.h b/src/server/scripts/Northrend/Nexus/Oculus/oculus.h
index 81d1e9f9ea8..c536b43f905 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.h
+++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.h
@@ -35,15 +35,22 @@ enum Data64
DATA_EREGOS
};
-enum Bosses
+enum Bosses_NPCs
{
NPC_DRAKOS = 27654,
NPC_VAROS = 27447,
NPC_UROM = 27655,
NPC_EREGOS = 27656,
- NPC_AZURE_RING_GUARDIAN = 28236,
- NPC_CENTRIFUGE_CONSTRUCT = 27641,
+ NPC_AZURE_RING_GUARDIAN = 28236,
+ NPC_CENTRIFUGE_CONSTRUCT = 27641,
+ NPC_RUBY_DRAKE_VEHICLE = 27756,
+ NPC_EMERALD_DRAKE_VEHICLE = 27692,
+ NPC_AMBER_DRAKE_VEHICLE = 27755,
+ NPC_VERDISA = 27657,
+ NPC_BELGARISTRASZ = 27658,
+ NPC_ETERNOS = 27659,
+ NPC_GREATER_WHELP = 28276
};
enum GameObjects
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp
index 0967c38c2e7..92e56d4dd9a 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp
@@ -255,7 +255,12 @@ class boss_steelbreaker : public CreatureScript
{
DoScriptText(RAND(SAY_STEELBREAKER_DEATH_1, SAY_STEELBREAKER_DEATH_2), me);
if (IsEncounterComplete(instance, me))
- instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE);
+ {
+ instance->SetBossState(BOSS_ASSEMBLY_OF_IRON, DONE);
+ instance->SetBossState(BOSS_STEELBREAKER, DONE);
+ instance->SetBossState(BOSS_MOLGEIM, DONE);
+ instance->SetBossState(BOSS_BRUNDIR, DONE);
+ }
else
me->SetLootRecipient(NULL);
@@ -379,7 +384,12 @@ class boss_runemaster_molgeim : public CreatureScript
{
DoScriptText(RAND(SAY_MOLGEIM_DEATH_1, SAY_MOLGEIM_DEATH_2), me);
if (IsEncounterComplete(instance, me))
- instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE);
+ {
+ instance->SetBossState(BOSS_ASSEMBLY_OF_IRON, DONE);
+ instance->SetBossState(BOSS_STEELBREAKER, DONE);
+ instance->SetBossState(BOSS_MOLGEIM, DONE);
+ instance->SetBossState(BOSS_BRUNDIR, DONE);
+ }
else
me->SetLootRecipient(NULL);
@@ -620,7 +630,12 @@ class boss_stormcaller_brundir : public CreatureScript
{
DoScriptText(RAND(SAY_BRUNDIR_DEATH_1, SAY_BRUNDIR_DEATH_2), me);
if (IsEncounterComplete(instance, me))
- instance->SetData(BOSS_ASSEMBLY_OF_IRON, DONE);
+ {
+ instance->SetBossState(BOSS_ASSEMBLY_OF_IRON, DONE);
+ instance->SetBossState(BOSS_STEELBREAKER, DONE);
+ instance->SetBossState(BOSS_MOLGEIM, DONE);
+ instance->SetBossState(BOSS_BRUNDIR, DONE);
+ }
else
me->SetLootRecipient(NULL);
diff --git a/src/server/scripts/Northrend/wintergrasp.cpp b/src/server/scripts/Northrend/wintergrasp.cpp
index 59e9a31c4cf..2aed813550d 100644
--- a/src/server/scripts/Northrend/wintergrasp.cpp
+++ b/src/server/scripts/Northrend/wintergrasp.cpp
@@ -541,6 +541,11 @@ public:
}
};
+enum WgTeleport
+{
+ SPELL_WINTERGRASP_TELEPORT_TRIGGER = 54643,
+};
+
class spell_wintergrasp_defender_teleport : public SpellScriptLoader
{
public:
@@ -554,7 +559,7 @@ public:
{
if (Battlefield* wg = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG))
if (Player* target = GetExplTargetUnit()->ToPlayer())
- if (target->GetTeamId() != wg->GetDefenderTeam())
+ if (target->GetTeamId() != wg->GetDefenderTeam() || target->HasAura(SPELL_WINTERGRASP_TELEPORT_TRIGGER))
return SPELL_FAILED_BAD_TARGETS;
return SPELL_CAST_OK;
}
@@ -571,6 +576,37 @@ public:
}
};
+class spell_wintergrasp_defender_teleport_trigger : public SpellScriptLoader
+{
+public:
+ spell_wintergrasp_defender_teleport_trigger() : SpellScriptLoader("spell_wintergrasp_defender_teleport_trigger") { }
+
+ class spell_wintergrasp_defender_teleport_trigger_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_wintergrasp_defender_teleport_trigger_SpellScript);
+
+ void HandleDummy(SpellEffIndex /*effindex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ {
+ WorldLocation loc;
+ target->GetPosition(&loc);
+ SetExplTargetDest(loc);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_wintergrasp_defender_teleport_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_wintergrasp_defender_teleport_trigger_SpellScript();
+ }
+};
+
void AddSC_wintergrasp()
{
new npc_wg_queue();
@@ -582,4 +618,5 @@ void AddSC_wintergrasp()
new spell_wintergrasp_grab_passenger();
new achievement_wg_didnt_stand_a_chance();
new spell_wintergrasp_defender_teleport();
+ new spell_wintergrasp_defender_teleport_trigger();
}
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index 31aafe8dd38..9c922f2c6fb 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -277,27 +277,31 @@ class spell_hun_masters_call : public SpellScriptLoader
return true;
}
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* ally = GetHitUnit())
+ if (Player* caster = GetCaster()->ToPlayer())
+ if (Pet* target = caster->GetPet())
+ {
+ TriggerCastFlags castMask = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_CASTER_AURASTATE);
+ target->CastSpell(ally, GetEffectValue(), castMask);
+ target->CastSpell(ally, GetSpellInfo()->Effects[EFFECT_0].CalcValue(), castMask);
+ }
+ }
+
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
{
// Cannot be processed while pet is dead
TriggerCastFlags castMask = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_CASTER_AURASTATE);
- target->CastSpell(target, GetEffectValue(), castMask);
target->CastSpell(target, HUNTER_SPELL_MASTERS_CALL_TRIGGERED, castMask);
- // there is a possibility that this effect should access effect 0 (dummy) target, but i dubt that
- // it's more likely that on on retail it's possible to call target selector based on dbc values
- // anyways, we're using GetExplTargetUnit() here and it's ok
- if (Unit* ally = GetExplTargetUnit())
- {
- target->CastSpell(ally, GetEffectValue(), castMask);
- target->CastSpell(ally, GetSpellInfo()->Effects[EFFECT_0].CalcValue(), castMask);
- }
}
}
void Register()
{
+ OnEffectHitTarget += SpellEffectFn(spell_hun_masters_call_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
OnEffectHitTarget += SpellEffectFn(spell_hun_masters_call_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp
index 3ce136b9737..2a5d58122ed 100644
--- a/src/server/scripts/World/go_scripts.cpp
+++ b/src/server/scripts/World/go_scripts.cpp
@@ -53,12 +53,14 @@ EndContentData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
+#include "GameObjectAI.h"
+#include "Spell.h"
/*######
## go_cat_figurine
######*/
-enum eCatFigurine
+enum CatFigurine
{
SPELL_SUMMON_GHOST_SABER = 5968,
};
@@ -178,7 +180,7 @@ public:
## go_gilded_brazier (Paladin First Trail quest (9678))
######*/
-enum eGildedBrazier
+enum GildedBrazier
{
NPC_STILLBLADE = 17716,
};
@@ -282,7 +284,7 @@ public:
## go_ethereum_prison
######*/
-enum eEthereumPrison
+enum EthereumPrison
{
SPELL_REP_LC = 39456,
SPELL_REP_SHAT = 39457,
@@ -367,7 +369,7 @@ public:
## go_resonite_cask
######*/
-enum eResoniteCask
+enum ResoniteCask
{
NPC_GOGGEROC = 11920
};
@@ -410,7 +412,7 @@ public:
## go_shrine_of_the_birds
######*/
-enum eShrineOfTheBirds
+enum ShrineOfTheBirds
{
NPC_HAWK_GUARD = 22992,
NPC_EAGLE_GUARD = 22993,
@@ -456,7 +458,7 @@ public:
## go_southfury_moonstone
######*/
-enum eSouthfury
+enum Southfury
{
NPC_RIZZLE = 23002,
SPELL_BLACKJACK = 39865, //stuns player
@@ -484,7 +486,7 @@ public:
## go_tele_to_dalaran_crystal
######*/
-enum eDalaranCrystal
+enum DalaranCrystal
{
QUEST_LEARN_LEAVE_RETURN = 12790,
QUEST_TELE_CRYSTAL_FLAG = 12845
@@ -536,7 +538,7 @@ public:
#define GOSSIP_FEL_CRYSTALFORGE_ITEM_5 "Purchase 5 Unstable Flask of the Beast for the cost of 50 Apexis Shards"
#define GOSSIP_FEL_CRYSTALFORGE_ITEM_RETURN "Use the fel crystalforge to make another purchase."
-enum eFelCrystalforge
+enum FelCrystalforge
{
SPELL_CREATE_1_FLASK_OF_BEAST = 40964,
SPELL_CREATE_5_FLASK_OF_BEAST = 40965,
@@ -595,7 +597,7 @@ public:
#define GOSSIP_BASHIR_CRYSTALFORGE_ITEM_5 "Purchase 5 Unstable Flask of the Sorcerer for the cost of 50 Apexis Shards"
#define GOSSIP_BASHIR_CRYSTALFORGE_ITEM_RETURN "Use the bashir crystalforge to make another purchase."
-enum eBashirCrystalforge
+enum BashirCrystalforge
{
SPELL_CREATE_1_FLASK_OF_SORCERER = 40968,
SPELL_CREATE_5_FLASK_OF_SORCERER = 40970,
@@ -648,7 +650,7 @@ public:
## matrix_punchograph
######*/
-enum eMatrixPunchograph
+enum MatrixPunchograph
{
ITEM_WHITE_PUNCH_CARD = 9279,
ITEM_YELLOW_PUNCH_CARD = 9280,
@@ -713,7 +715,7 @@ public:
## go_scourge_cage
######*/
-enum eScourgeCage
+enum ScourgeCage
{
NPC_SCOURGE_PRISONER = 25610
};
@@ -740,7 +742,7 @@ public:
## go_arcane_prison
######*/
-enum eArcanePrison
+enum ArcanePrison
{
QUEST_PRISON_BREAK = 11587,
SPELL_ARCANE_PRISONER_KILL_CREDIT = 45456
@@ -787,7 +789,7 @@ public:
## go_jotunheim_cage
######*/
-enum eJotunheimCage
+enum JotunheimCage
{
NPC_EBON_BLADE_PRISONER_HUMAN = 30186,
NPC_EBON_BLADE_PRISONER_NE = 30194,
@@ -842,7 +844,7 @@ public:
}
};
-enum eTableTheka
+enum TableTheka
{
GOSSIP_TABLE_THEKA = 1653,
@@ -869,7 +871,7 @@ public:
## go_inconspicuous_landmark
######*/
-enum eInconspicuousLandmark
+enum InconspicuousLandmark
{
SPELL_SUMMON_PIRATES_TREASURE_AND_TRIGGER_MOB = 11462,
ITEM_CUERGOS_KEY = 9275,
@@ -895,7 +897,7 @@ public:
## go_ethereal_teleport_pad
######*/
-enum eEtherealTeleportPad
+enum EtherealTeleportPad
{
NPC_IMAGE_WIND_TRADER = 20518,
ITEM_TELEPORTER_POWER_PACK = 28969,
@@ -921,45 +923,105 @@ public:
## go_soulwell
######*/
-class go_soulwell : public GameObjectScript
+enum SoulWellData
{
-public:
- go_soulwell() : GameObjectScript("go_soulwell") { }
+ GO_SOUL_WELL_R1 = 181621,
+ GO_SOUL_WELL_R2 = 193169,
- bool OnGossipHello(Player* player, GameObject* go)
- {
- Unit* caster = go->GetOwner();
- if (!caster || caster->GetTypeId() != TYPEID_PLAYER)
- return true;
+ SPELL_IMPROVED_HEALTH_STONE_R1 = 18692,
+ SPELL_IMPROVED_HEALTH_STONE_R2 = 18693,
- if (!player->IsInSameRaidWith(static_cast<Player*>(caster)))
- return true;
+ SPELL_CREATE_MASTER_HEALTH_STONE_R0 = 34130,
+ SPELL_CREATE_MASTER_HEALTH_STONE_R1 = 34149,
+ SPELL_CREATE_MASTER_HEALTH_STONE_R2 = 34150,
+
+ SPELL_CREATE_FEL_HEALTH_STONE_R0 = 58890,
+ SPELL_CREATE_FEL_HEALTH_STONE_R1 = 58896,
+ SPELL_CREATE_FEL_HEALTH_STONE_R2 = 58898,
+};
- // Repeating this at every use is ugly and inefficient. But as long as we don't have proper
- // GO scripting with at least On Create and On Update events, the other options are no less
- // ugly and hacky.
- uint32 newSpell = 0;
- if (go->GetEntry() == 193169) // Soulwell for rank 2
+class go_soulwell : public GameObjectScript
+{
+ public:
+ go_soulwell() : GameObjectScript("go_soulwell") {}
+
+ struct go_soulwellAI : public GameObjectAI
{
- if (caster->HasAura(18693)) // Improved Healthstone rank 2
- newSpell = 58898;
- else if (caster->HasAura(18692)) // Improved Healthstone rank 1
- newSpell = 58896;
- else newSpell = 58890;
- }
- else if (go->GetEntry() == 181621) // Soulwell for rank 1
+ go_soulwellAI(GameObject* go) : GameObjectAI(go)
+ {
+ _stoneSpell = 0;
+ _stoneId = 0;
+ switch (go->GetEntry())
+ {
+ case GO_SOUL_WELL_R1:
+ _stoneSpell = SPELL_CREATE_MASTER_HEALTH_STONE_R0;
+ if (Unit* owner = go->GetOwner())
+ {
+ if (owner->HasAura(SPELL_IMPROVED_HEALTH_STONE_R1))
+ _stoneSpell = SPELL_CREATE_MASTER_HEALTH_STONE_R1;
+ else if (owner->HasAura(SPELL_CREATE_MASTER_HEALTH_STONE_R2))
+ _stoneSpell = SPELL_CREATE_MASTER_HEALTH_STONE_R2;
+ }
+ break;
+ case GO_SOUL_WELL_R2:
+ _stoneSpell = SPELL_CREATE_FEL_HEALTH_STONE_R0;
+ if (Unit* owner = go->GetOwner())
+ {
+ if (owner->HasAura(SPELL_IMPROVED_HEALTH_STONE_R1))
+ _stoneSpell = SPELL_CREATE_FEL_HEALTH_STONE_R1;
+ else if (owner->HasAura(SPELL_CREATE_MASTER_HEALTH_STONE_R2))
+ _stoneSpell = SPELL_CREATE_FEL_HEALTH_STONE_R2;
+ }
+ break;
+ }
+ if (_stoneSpell == 0) // Should never happen
+ return;
+
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(_stoneSpell);
+ if (!spellInfo)
+ return;
+
+ _stoneId = spellInfo->Effects[EFFECT_0].ItemType;
+ }
+
+ /// Due to the fact that this GameObject triggers CMSG_GAMEOBJECT_USE
+ /// _and_ CMSG_GAMEOBJECT_REPORT_USE, this GossipHello hook is called
+ /// twice. The script's handling is fine as it won't remove two charges
+ /// on the well. We have to find how to segregate REPORT_USE and USE.
+ bool GossipHello(Player* player)
+ {
+ Unit* owner = go->GetOwner();
+ if (_stoneSpell == 0 || _stoneId == 0)
+ return true;
+
+ if (!owner || owner->GetTypeId() != TYPEID_PLAYER || !player->IsInSameRaidWith(owner->ToPlayer()))
+ return true;
+
+ // Don't try to add a stone if we already have one.
+ if (player->HasItemCount(_stoneId, 1))
+ {
+ if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(_stoneSpell))
+ Spell::SendCastResult(player, spell, 0, SPELL_FAILED_TOO_MANY_OF_ITEM);
+ return true;
+ }
+
+ owner->CastSpell(player, _stoneSpell, true);
+ // Item has to actually be created to remove a charge on the well.
+ if (player->HasItemCount(_stoneId, 1))
+ go->AddUse();
+
+ return false;
+ }
+
+ private:
+ uint32 _stoneSpell;
+ uint32 _stoneId;
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const
{
- if (caster->HasAura(18693)) // Improved Healthstone rank 2
- newSpell = 34150;
- else if (caster->HasAura(18692)) // Improved Healthstone rank 1
- newSpell = 34149;
- else newSpell = 34130;
+ return new go_soulwellAI(go);
}
-
- go->AddUse();
- player->CastSpell(player, newSpell, true);
- return true;
- }
};
/*######
@@ -967,7 +1029,7 @@ public:
## go_dragonflayer_cage
######*/
-enum ePrisonersOfWyrmskull
+enum PrisonersOfWyrmskull
{
QUEST_PRISONERS_OF_WYRMSKULL = 11255,
NPC_PRISONER_PRIEST = 24086,
@@ -1017,7 +1079,7 @@ public:
## go_tadpole_cage
######*/
-enum eTadpoles
+enum Tadpoles
{
QUEST_OH_NOES_THE_TADPOLES = 11560,
NPC_WINTERFIN_TADPOLE = 25201
@@ -1052,7 +1114,7 @@ public:
#define GOSSIP_USE_OUTHOUSE "Use the outhouse."
#define GO_ANDERHOLS_SLIDER_CIDER_NOT_FOUND "Quest item Anderhol's Slider Cider not found."
-enum eAmberpineOuthouse
+enum AmberpineOuthouse
{
ITEM_ANDERHOLS_SLIDER_CIDER = 37247,
NPC_OUTHOUSE_BUNNY = 27326,
@@ -1114,7 +1176,7 @@ public:
## go_hive_pod
######*/
-enum eHives
+enum Hives
{
QUEST_HIVE_IN_THE_TOWER = 9544,
NPC_HIVE_AMBUSHER = 13301
@@ -1281,7 +1343,7 @@ public:
## go_midsummer_bonfire
######*/
-enum eMidsummerBonfire
+enum MidsummerBonfire
{
STAMP_OUT_BONFIRE_QUEST_COMPLETE = 45458,
};
diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp
index 67e46dd26da..0897c8814ab 100755
--- a/src/server/shared/Utilities/Util.cpp
+++ b/src/server/shared/Utilities/Util.cpp
@@ -28,16 +28,19 @@ static SFMTRandTSS sfmtRand;
int32 irand(int32 min, int32 max)
{
+ assert(max >= min);
return int32(sfmtRand->IRandom(min, max));
}
uint32 urand(uint32 min, uint32 max)
{
+ assert(max >= min);
return sfmtRand->URandom(min, max);
}
float frand(float min, float max)
{
+ assert(max >= min);
return float(sfmtRand->Random() * (max - min) + min);
}
@@ -488,7 +491,7 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse
for (int32 i = init; i != end; i += op)
{
char buffer[4];
- sprintf(buffer, "%02X ", bytes[i]);
+ sprintf(buffer, "%02X", bytes[i]);
ss << buffer;
}
diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h
index 21aaa36498d..f84e5155bb1 100755
--- a/src/server/shared/Utilities/Util.h
+++ b/src/server/shared/Utilities/Util.h
@@ -31,7 +31,7 @@ template<typename T, class S> struct Finder
{
T val_;
T S::* idMember_;
-
+
Finder(T val, T S::* idMember) : val_(val), idMember_(idMember) {}
bool operator()(const std::pair<int, S> &obj) { return obj.second.*idMember_ == val_; }
};