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.cpp2
-rwxr-xr-xsrc/server/game/Battlegrounds/Zones/BattlegroundIC.cpp23
-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
-rwxr-xr-xsrc/server/game/DataStores/DBCStructure.h2
-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
-rwxr-xr-xsrc/server/game/Entities/Player/Player.cpp31
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp3
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h20
-rwxr-xr-xsrc/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/Waypoints/WaypointManager.h2
-rwxr-xr-xsrc/server/game/Scripting/ScriptLoader.cpp2
-rwxr-xr-xsrc/server/game/Spells/SpellEffects.cpp3
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.cpp78
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.h2
-rwxr-xr-xsrc/server/game/Spells/SpellScript.h2
-rwxr-xr-xsrc/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/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_urom.cpp4
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp2
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp36
-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.cpp3
-rwxr-xr-xsrc/server/shared/Utilities/Util.h2
49 files changed, 2504 insertions, 402 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 ae58f3504b4..1c99934bafc 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -999,7 +999,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;
@@ -1069,7 +1069,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 d8f1883cbda..a64184261c7 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp
@@ -202,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 1c5041da017..90c0dae9f5e 100755
--- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
@@ -843,12 +843,6 @@ void BattlegroundIC::DestroyGate(Player* player, GameObject* go)
switch (go->GetEntry())
{
case GO_HORDE_GATE_1:
- if (!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);
- }
lang_entry = LANG_BG_IC_NORTH_GATE_DESTROYED;
break;
case GO_HORDE_GATE_2:
@@ -860,18 +854,23 @@ void BattlegroundIC::DestroyGate(Player* player, GameObject* go)
lang_entry = LANG_BG_IC_EAST_GATE_DESTROYED;
break;
case GO_ALLIANCE_GATE_3:
- if (!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);
- }
lang_entry = LANG_BG_IC_SOUTH_GATE_DESTROYED;
break;
default:
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 ef949f43f49..e4ba3ebb12e 100755
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1203,7 +1203,7 @@ struct LFGDungeonEntry
uint32 recmaxlevel; // 22
int32 map; // 23
uint32 difficulty; // 24
- //uint32 flags; // 25 (flags & 4) = IsHoliday
+ uint32 flags; // 25
uint32 type; // 26
//uint32 unk; // 27
//char* iconname; // 28
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index 39d031e96f9..39f9009419e 100755
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -77,7 +77,7 @@ const char ItemLimitCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
const char ItemRandomPropertiesfmt[]="nxiiixxssssssssssssssssx";
const char ItemRandomSuffixfmt[]="nssssssssssssssssxxiiixxiiixx";
const char ItemSetEntryfmt[]="dssssssssssssssssxiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii";
-const char LFGDungeonEntryfmt[]="nxxxxxxxxxxxxxxxxxiiiiiiixixxixixxxxxxxxxxxxxxxxx";
+const char LFGDungeonEntryfmt[]="nxxxxxxxxxxxxxxxxxiiiiiiiiixxixixxxxxxxxxxxxxxxxx";
const char LiquidTypefmt[]="nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxssssssssssssssssx";
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 c4d42f7a537..da6e4ef8407 100755
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -293,7 +293,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;
@@ -417,7 +417,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)
@@ -1080,7 +1080,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 c41436e1947..50f5fd4c978 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -7620,21 +7620,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
@@ -9113,6 +9111,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;
@@ -9639,6 +9640,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)
@@ -20831,6 +20843,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 3742503c786..d171fa635d2 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -10102,8 +10102,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 9b29d644c36..ce329098bc6 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -795,21 +795,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 fd2a2fe143a..95a27fd14e1 100755
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -5531,7 +5531,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 aa6d208ad3a..f5d5a0b67e2 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)
@@ -156,16 +157,25 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recv_data
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 afaa38527bb..0e5d68d51e4 100755
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -303,7 +303,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 25ffc1d19f2..954dac232ab 100755
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2430,7 +2430,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/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 6442a35f0c3..5f3400804c3 100755
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -503,6 +503,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();
@@ -1224,6 +1225,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 5db0e589e1b..a88ffffd5ea 100755
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -2002,7 +2002,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 c89442855e1..ec7359a7ba4 100755
--- 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)
@@ -3402,7 +3402,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)
@@ -3412,7 +3412,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)
@@ -3430,7 +3430,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)
@@ -3453,7 +3453,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)
@@ -3464,7 +3464,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)
@@ -3513,62 +3513,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
@@ -3576,19 +3576,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
@@ -3630,5 +3646,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 39effcf217e..2f022fac4e6 100755
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1475,6 +1475,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 2c9623b23a6..f7280cf906e 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()))
@@ -2568,7 +2568,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 028cf640d21..ca91fb920b1 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/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..64210e97122
--- /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] = MapManager::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_urom.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp
index 8e7863259ad..179dedb290b 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp
@@ -105,8 +105,8 @@ public:
void Reset()
{
me->CastSpell(me, SPELL_EVOCATE);
-
- _Reset();
+
+ _Reset();
if (instance->GetData(DATA_UROM_PLATAFORM) == 0)
{
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
index 1f4a3d1b229..a0b5aded315 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
@@ -278,7 +278,7 @@ public:
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);
+ verdisa->GetMotionMaster()->MovePoint(0, 949.188f, 1032.91f, 359.967f);
}
void GreaterWhelps()
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
index f2fa3158603..39fff139b52 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
@@ -108,10 +108,10 @@ class npc_verdisa_beglaristrasz_eternos : public CreatureScript
{
public:
npc_verdisa_beglaristrasz_eternos() : CreatureScript("npc_verdisa_beglaristrasz_eternos") { }
-
- InstanceScript* instance;
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action)
+
+ InstanceScript* instance;
+
+ bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action)
{
player->PlayerTalkClass->ClearMenus();
switch (creature->GetEntry())
@@ -245,7 +245,7 @@ public:
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
}
};
-
+
CreatureAI* GetAI(Creature* creature) const
{
return new npc_verdisa_beglaristrasz_eternosAI(creature);
@@ -293,7 +293,7 @@ public:
{
instance = creature->GetInstanceScript();
}
-
+
InstanceScript* instance;
uint64 summonerGUID;
@@ -324,9 +324,9 @@ public:
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))
{
@@ -357,7 +357,7 @@ public:
void UpdateAI(const uint32 diff)
{
if (!(instance->GetBossState(DATA_VAROS_EVENT) == DONE))
- {
+ {
if (me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE))
{
if (!(WelcomeOff))
@@ -380,7 +380,7 @@ public:
{
Talk(WHISPER_DRAKES_ABILITIES, me->GetCreatorGUID());
WelcomeSequelOff = false;
- }
+ }
else WelcomeSequelTimer -= diff;
}
}
@@ -391,10 +391,10 @@ public:
if (!(SpecialOff))
{
if (SpecialTimer <= diff)
- {
+ {
Talk(WHISPER_DRAKES_SPECIAL, me->GetCreatorGUID());
SpecialOff = true;
- }
+ }
else SpecialTimer -= diff;
}
}
@@ -402,25 +402,25 @@ public:
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)))
{
@@ -433,7 +433,7 @@ public:
me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
Talk(SAY_DRAKES_TAKEOFF);
Position pos;
- me->GetPosition(&pos);
+ me->GetPosition(&pos);
pos.m_positionX += 10.0f;
pos.m_positionY += 10.0f;
pos.m_positionZ += 12.0f;
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 9778e86d444..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);
}
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_; }
};