aboutsummaryrefslogtreecommitdiff
path: root/src/server/scripts/Battlegrounds/IsleOfConquest
diff options
context:
space:
mode:
authorJeremy <Golrag@users.noreply.github.com>2024-03-28 19:29:22 +0100
committerfunjoker <funjoker109@gmail.com>2024-03-28 20:38:55 +0100
commitd0d5d309bb5877dc2fcb27f6cb123707a31ec1e8 (patch)
treef487ecb6ff8fd052357ea582ffa630027dc8bd07 /src/server/scripts/Battlegrounds/IsleOfConquest
parentaefa15ece72bccdeb47cbdbdc75df87837c9da00 (diff)
Core/Battlegrounds: Move to scripts (#29799)
* Introduce new BattlegroundScript class for map/bg specific scripts * Remove all sub, zone specific, battleground classes except Arena * Move all bg zone scripts to new BattlegroundScripts class in script folder * Remove ZoneScript from Battleground class * Remove some unused hooks from Battleground (cherry picked from commit be11f42a16d1fa0482e9572bf54e99e4dedd3c78)
Diffstat (limited to 'src/server/scripts/Battlegrounds/IsleOfConquest')
-rw-r--r--src/server/scripts/Battlegrounds/IsleOfConquest/battleground_isle_of_conquest.cpp902
-rw-r--r--src/server/scripts/Battlegrounds/IsleOfConquest/boss_ioc_horde_alliance.cpp123
-rw-r--r--src/server/scripts/Battlegrounds/IsleOfConquest/isle_of_conquest.cpp393
-rw-r--r--src/server/scripts/Battlegrounds/IsleOfConquest/isle_of_conquest.h132
4 files changed, 1550 insertions, 0 deletions
diff --git a/src/server/scripts/Battlegrounds/IsleOfConquest/battleground_isle_of_conquest.cpp b/src/server/scripts/Battlegrounds/IsleOfConquest/battleground_isle_of_conquest.cpp
new file mode 100644
index 00000000000..5d55df8d6b7
--- /dev/null
+++ b/src/server/scripts/Battlegrounds/IsleOfConquest/battleground_isle_of_conquest.cpp
@@ -0,0 +1,902 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 "BattlegroundScript.h"
+#include "Battleground.h"
+#include "BattlegroundMgr.h"
+#include "GameTime.h"
+#include "isle_of_conquest.h"
+#include "Map.h"
+#include "Player.h"
+#include "ScriptMgr.h"
+#include "TaskScheduler.h"
+#include "TemporarySummon.h"
+#include "Timer.h"
+#include "Transport.h"
+#include "TransportMgr.h"
+#include "Vehicle.h"
+
+inline constexpr uint16 MAX_REINFORCEMENTS = 400;
+
+enum BannersTypes
+{
+ BANNER_A_CONTROLLED,
+ BANNER_A_CONTESTED,
+ BANNER_H_CONTROLLED,
+ BANNER_H_CONTESTED
+};
+
+enum BG_IC_ExploitTeleportLocations
+{
+ IC_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3986,
+ IC_EXPLOIT_TELEPORT_LOCATION_HORDE = 3983
+};
+
+enum BG_IC_GateState
+{
+ BG_IC_GATE_OK = 1,
+ BG_IC_GATE_DAMAGED = 2,
+ BG_IC_GATE_DESTROYED = 3
+};
+
+enum ICDoorList
+{
+ BG_IC_H_FRONT,
+ BG_IC_H_WEST,
+ BG_IC_H_EAST,
+ BG_IC_A_FRONT,
+ BG_IC_A_WEST,
+ BG_IC_A_EAST,
+ BG_IC_MAXDOOR
+};
+
+enum ICNodePointType
+{
+ NODE_TYPE_REFINERY,
+ NODE_TYPE_QUARRY,
+ NODE_TYPE_DOCKS,
+ NODE_TYPE_HANGAR,
+ NODE_TYPE_WORKSHOP,
+
+ // Graveyards
+ NODE_TYPE_GRAVEYARD_A,
+ NODE_TYPE_GRAVEYARD_H,
+
+ MAX_NODE_TYPES
+};
+
+enum class IsleOfConquestNodeState
+{
+ Neutral,
+ ConflictA,
+ ConflictH,
+ ControlledA,
+ ControlledH
+};
+
+enum ICBroadcastTexts
+{
+ BG_IC_TEXT_FRONT_GATE_HORDE_DESTROYED = 35409,
+ BG_IC_TEXT_FRONT_GATE_ALLIANCE_DESTROYED = 35410,
+ BG_IC_TEXT_WEST_GATE_HORDE_DESTROYED = 35411,
+ BG_IC_TEXT_WEST_GATE_ALLIANCE_DESTROYED = 35412,
+ BG_IC_TEXT_EAST_GATE_HORDE_DESTROYED = 35413,
+ BG_IC_TEXT_EAST_GATE_ALLIANCE_DESTROYED = 35414
+};
+
+// I.E: Hangar, Quarry, Graveyards .. etc
+struct IoCStaticNodeInfo
+{
+ ICNodePointType NodeType;
+
+ struct
+ {
+ uint32 Assaulted;
+ uint32 Defended;
+ uint32 AllianceTaken;
+ uint32 HordeTaken;
+ } TextIds;
+
+ struct
+ {
+ int32 Uncontrolled;
+ int32 ConflictA;
+ int32 ConflictH;
+ int32 ControlledA;
+ int32 ControlledH;
+ } WorldStateIds;
+};
+
+class ICNodePoint
+{
+public:
+ explicit ICNodePoint(IsleOfConquestNodeState state, IoCStaticNodeInfo const& nodeInfo) : _state(state), _nodeInfo(nodeInfo)
+ {
+ switch (state)
+ {
+ case IsleOfConquestNodeState::ControlledH:
+ _lastControlled = TEAM_HORDE;
+ break;
+ case IsleOfConquestNodeState::ControlledA:
+ _lastControlled = TEAM_ALLIANCE;
+ break;
+ case IsleOfConquestNodeState::ConflictA:
+ case IsleOfConquestNodeState::ConflictH:
+ case IsleOfConquestNodeState::Neutral:
+ _lastControlled = TEAM_NEUTRAL;
+ break;
+ }
+ }
+
+ IsleOfConquestNodeState GetState() const { return _state; }
+
+ bool IsContested() const
+ {
+ return _state == IsleOfConquestNodeState::ConflictA || _state == IsleOfConquestNodeState::ConflictH;
+ }
+
+ TeamId GetLastControlledTeam() const { return _lastControlled; }
+
+ IoCStaticNodeInfo const& GetNodeInfo() const { return _nodeInfo; }
+
+ void UpdateState(IsleOfConquestNodeState state)
+ {
+ switch (state)
+ {
+ case IsleOfConquestNodeState::ControlledA:
+ _lastControlled = TEAM_ALLIANCE;
+ break;
+ case IsleOfConquestNodeState::ControlledH:
+ _lastControlled = TEAM_HORDE;
+ break;
+ case IsleOfConquestNodeState::Neutral:
+ _lastControlled = TEAM_NEUTRAL;
+ break;
+ case IsleOfConquestNodeState::ConflictA:
+ case IsleOfConquestNodeState::ConflictH:
+ break;
+ }
+
+ _state = state;
+ }
+private:
+ IsleOfConquestNodeState _state;
+ TeamId _lastControlled;
+ IoCStaticNodeInfo _nodeInfo;
+};
+
+const IoCStaticNodeInfo nodePointInitial[MAX_NODE_TYPES] =
+{
+ { NODE_TYPE_REFINERY, { 35377, 35378, 35379, 35380 }, { BG_IC_REFINERY_UNCONTROLLED, BG_IC_REFINERY_CONFLICT_A, BG_IC_REFINERY_CONFLICT_H, BG_IC_REFINERY_CONTROLLED_A, BG_IC_REFINERY_CONTROLLED_H } },
+ { NODE_TYPE_QUARRY, { 35373, 35374, 35375, 35376 }, { BG_IC_QUARRY_UNCONTROLLED, BG_IC_QUARRY_CONFLICT_A, BG_IC_QUARRY_CONFLICT_H, BG_IC_QUARRY_CONTROLLED_A, BG_IC_QUARRY_CONTROLLED_H } },
+ { NODE_TYPE_DOCKS, { 35365, 35366, 35367, 35368 }, { BG_IC_DOCKS_UNCONTROLLED, BG_IC_DOCKS_CONFLICT_A, BG_IC_DOCKS_CONFLICT_H, BG_IC_DOCKS_CONTROLLED_A, BG_IC_DOCKS_CONTROLLED_H } },
+ { NODE_TYPE_HANGAR, { 35369, 35370, 35371, 35372 }, { BG_IC_HANGAR_UNCONTROLLED, BG_IC_HANGAR_CONFLICT_A, BG_IC_HANGAR_CONFLICT_H, BG_IC_HANGAR_CONTROLLED_A, BG_IC_HANGAR_CONTROLLED_H } },
+ { NODE_TYPE_WORKSHOP, { 35278, 35286, 35279, 35280 }, { BG_IC_WORKSHOP_UNCONTROLLED, BG_IC_WORKSHOP_CONFLICT_A, BG_IC_WORKSHOP_CONFLICT_H, BG_IC_WORKSHOP_CONTROLLED_A, BG_IC_WORKSHOP_CONTROLLED_H } },
+ { NODE_TYPE_GRAVEYARD_A, { 35461, 35459, 35463, 35466 }, { BG_IC_ALLIANCE_KEEP_UNCONTROLLED, BG_IC_ALLIANCE_KEEP_CONFLICT_A, BG_IC_ALLIANCE_KEEP_CONFLICT_H, BG_IC_ALLIANCE_KEEP_CONTROLLED_A, BG_IC_ALLIANCE_KEEP_CONTROLLED_H } },
+ { NODE_TYPE_GRAVEYARD_H, { 35462, 35460, 35464, 35465 }, { BG_IC_HORDE_KEEP_UNCONTROLLED, BG_IC_HORDE_KEEP_CONFLICT_A, BG_IC_HORDE_KEEP_CONFLICT_H, BG_IC_HORDE_KEEP_CONTROLLED_A, BG_IC_HORDE_KEEP_CONTROLLED_H } }
+};
+
+enum HonorRewards
+{
+ RESOURCE_HONOR_AMOUNT = 12,
+ WINNER_HONOR_AMOUNT = 500
+};
+
+enum IsleOfConquestPvpStats
+{
+ PVP_STAT_BASES_ASSAULTED = 245,
+ PVP_STAT_BASES_DEFENDED = 246
+};
+
+enum IsleOfConquestGameObjects
+{
+ GO_TELEPORTER_1 = 195314, // 195314 H-OUT 66549
+ GO_TELEPORTER_2 = 195313, // 195313 H-IN 66548
+
+ GO_TELEPORTER_3 = 195315, // 195315 A-OUT 66549
+ GO_TELEPORTER_4 = 195316, // 195316 A-IN 66548
+
+ GO_TELEPORTER_EFFECTS_A = 195701,
+ GO_TELEPORTER_EFFECTS_H = 195702,
+
+ GO_DOODAD_HU_PORTCULLIS01 = 195436,
+ GO_DOODAD_ND_HUMAN_GATE_CLOSEDFX_DOOR01 = 195703,
+ GO_DOODAD_PORTCULLISACTIVE02 = 195452,
+ GO_DOODAD_VR_PORTCULLIS01 = 195437,
+
+ GO_HORDE_GATE_1 = 195494,
+ GO_HORDE_GATE_2 = 195495,
+ GO_HORDE_GATE_3 = 195496,
+
+ GO_ALLIANCE_GATE_1 = 195699,
+ GO_ALLIANCE_GATE_2 = 195700,
+ GO_ALLIANCE_GATE_3 = 195698,
+
+ GO_DOODAD_ND_WINTERORC_WALL_GATEFX_DOOR01 = 195491,
+
+ // banners
+ GO_BANNER_WORKSHOP_CONTROLLED_H = 195130,
+ GO_BANNER_WORKSHOP_CONTROLLED_A = 195132,
+ GO_BANNER_WORKSHOP_CONTROLLED_N = 195133,
+ GO_BANNER_WORKSHOP_CONTESTED_A = 195144,
+ GO_BANNER_WORKSHOP_CONTESTED_H = 195145,
+
+ GO_BANNER_DOCKS_CONTROLLED_A = 195149,
+ GO_BANNER_DOCKS_CONTESTED_A = 195150,
+ GO_BANNER_DOCKS_CONTROLLED_H = 195151,
+ GO_BANNER_DOCKS_CONTESTED_H = 195152,
+ GO_BANNER_DOCKS_CONTROLLED_N = 195157,
+
+ GO_BANNER_HANGAR_CONTROLLED_A = 195153,
+ GO_BANNER_HANGAR_CONTESTED_A = 195154,
+ GO_BANNER_HANGAR_CONTROLLED_H = 195155,
+ GO_BANNER_HANGAR_CONTESTED_H = 195156,
+ GO_BANNER_HANGAR_CONTROLLED_N = 195158,
+
+ GO_BANNER_QUARRY_CONTROLLED_A = 195334,
+ GO_BANNER_QUARRY_CONTROLLED_H = 195336,
+ GO_BANNER_QUARRY_CONTESTED_A = 195335,
+ GO_BANNER_QUARRY_CONTESTED_H = 195337,
+ GO_BANNER_QUARRY_CONTROLLED_N = 195338,
+
+ GO_BANNER_REFINERY_CONTROLLED_A = 195339,
+ GO_BANNER_REFINERY_CONTROLLED_H = 195341,
+ GO_BANNER_REFINERY_CONTESTED_A = 195340,
+ GO_BANNER_REFINERY_CONTESTED_H = 195342,
+ GO_BANNER_REFINERY_CONTROLLED_N = 195343,
+
+ GO_BANNER_HORDE_KEEP_CONTROLLED_A = 195391,
+ GO_BANNER_HORDE_KEEP_CONTROLLED_H = 195393,
+ GO_BANNER_HORDE_KEEP_CONTESTED_A = 195392,
+ GO_BANNER_HORDE_KEEP_CONTESTED_H = 195394,
+
+ GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A = 195396,
+ GO_BANNER_ALLIANCE_KEEP_CONTROLLED_H = 195398,
+ GO_BANNER_ALLIANCE_KEEP_CONTESTED_A = 195397,
+ GO_BANNER_ALLIANCE_KEEP_CONTESTED_H = 195399,
+
+ GO_KEEP_GATE_H = 195223,
+ GO_KEEP_GATE_A = 195451,
+ GO_KEEP_GATE_2_A = 195452,
+
+ GO_HORDE_GUNSHIP = 195276,
+ GO_ALLIANCE_GUNSHIP = 195121
+};
+
+static constexpr Seconds IOC_RESOURCE_TIMER = 45s;
+
+static constexpr Position GunshipTeleportTriggerPosition[2] =
+{
+ { 11.69964981079101562f, 0.034145999699831008f, 20.62075996398925781f, 3.211405754089355468f },
+ { 7.30560922622680664f, -0.09524600207805633f, 34.51021575927734375f, 3.159045934677124023f }
+};
+
+struct battleground_isle_of_conquest : BattlegroundScript
+{
+ explicit battleground_isle_of_conquest(BattlegroundMap* map) : BattlegroundScript(map)
+ {
+ _factionReinforcements = { MAX_REINFORCEMENTS, MAX_REINFORCEMENTS };
+
+ _gateStatus = { BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK };
+
+ _gunshipGUIDs = { };
+ _cannonGUIDs = { };
+ _nodePoints = { };
+ _keepGateGUIDs = { };
+ _keepBannerGUIDs = { };
+
+ _nodePoints[NODE_TYPE_REFINERY] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_REFINERY]);
+ _nodePoints[NODE_TYPE_QUARRY] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_QUARRY]);
+ _nodePoints[NODE_TYPE_DOCKS] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_DOCKS]);
+ _nodePoints[NODE_TYPE_HANGAR] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_HANGAR]);
+ _nodePoints[NODE_TYPE_WORKSHOP] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_WORKSHOP]);
+ _nodePoints[NODE_TYPE_GRAVEYARD_A] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::ControlledA, nodePointInitial[NODE_TYPE_GRAVEYARD_A]);
+ _nodePoints[NODE_TYPE_GRAVEYARD_H] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::ControlledH, nodePointInitial[NODE_TYPE_GRAVEYARD_H]);
+
+ _resourceTimer.Reset(IOC_RESOURCE_TIMER);
+ }
+
+ void OnUpdate(uint32 diff) override
+ {
+ BattlegroundScript::OnUpdate(diff);
+
+ if (battleground->GetStatus() != STATUS_IN_PROGRESS)
+ return;
+
+ _scheduler.Update(diff);
+ _resourceTimer.Update(diff);
+ if (_resourceTimer.Passed())
+ {
+ for (uint8 i = 0; i < NODE_TYPE_DOCKS; ++i)
+ {
+ if (_nodePoints[i]->GetLastControlledTeam() != TEAM_NEUTRAL && !_nodePoints[i]->IsContested())
+ {
+ _factionReinforcements[_nodePoints[i]->GetLastControlledTeam()] += 1;
+ battleground->RewardHonorToTeam(RESOURCE_HONOR_AMOUNT, _nodePoints[i]->GetLastControlledTeam() == TEAM_ALLIANCE ? ALLIANCE : HORDE);
+ UpdateWorldState((_nodePoints[i]->GetLastControlledTeam() == TEAM_ALLIANCE ? BG_IC_ALLIANCE_REINFORCEMENTS : BG_IC_HORDE_REINFORCEMENTS), _factionReinforcements[_nodePoints[i]->GetLastControlledTeam()]);
+ }
+ }
+
+ _resourceTimer.Reset(IOC_RESOURCE_TIMER);
+ }
+ }
+
+ void OnStart() override
+ {
+ BattlegroundScript::OnStart();
+
+ auto gameobjectAction = [&](GuidVector const& guids, std::function<void(GameObject*)> const& action) -> void
+ {
+ for (ObjectGuid const& guid : guids)
+ if (GameObject* gameObject = battlegroundMap->GetGameObject(guid))
+ action(gameObject);
+ };
+
+ gameobjectAction(_mainGateDoorGUIDs, [&](GameObject* gameobject) -> void
+ {
+ gameobject->UseDoorOrButton();
+ gameobject->DespawnOrUnsummon(20s);
+ });
+
+ gameobjectAction(_portcullisGUIDs, [&](GameObject* gameobject) -> void
+ {
+ gameobject->UseDoorOrButton();
+ });
+
+ gameobjectAction(_teleporterGUIDs, [&](GameObject* gameobject) -> void
+ {
+ gameobject->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
+ });
+
+ gameobjectAction(_teleporterEffectGUIDs, [&](GameObject* gameobject) -> void
+ {
+ gameobject->SetGoState(GO_STATE_ACTIVE);
+ });
+
+ _scheduler.Schedule(20s, [&](TaskContext)
+ {
+ for (ObjectGuid const& guid : _wallGUIDs)
+ if (GameObject* gameobject = battlegroundMap->GetGameObject(guid))
+ gameobject->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED);
+ });
+ }
+
+ void OnUnitKilled(Creature* unit, Unit* killer) override
+ {
+ BattlegroundScript::OnUnitKilled(unit, killer);
+
+ if (battleground->GetStatus() != STATUS_IN_PROGRESS)
+ return;
+
+ uint32 entry = unit->GetEntry();
+ if (entry == NPC_HIGH_COMMANDER_HALFORD_WYRMBANE)
+ {
+ battleground->RewardHonorToTeam(WINNER_HONOR_AMOUNT, HORDE);
+ battleground->EndBattleground(HORDE);
+ }
+ else if (entry == NPC_OVERLORD_AGMAR)
+ {
+ battleground->RewardHonorToTeam(WINNER_HONOR_AMOUNT, ALLIANCE);
+ battleground->EndBattleground(ALLIANCE);
+ }
+
+ //Achievement Mowed Down
+ // TO-DO: This should be done on the script of each vehicle of the BG.
+ if (unit->IsVehicle())
+ {
+ if (Player* killerPlayer = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
+ killerPlayer->CastSpell(killerPlayer, SPELL_DESTROYED_VEHICLE_ACHIEVEMENT, true);
+ }
+ }
+
+ void OnPlayerKilled(Player* player, Player* killer) override
+ {
+ BattlegroundScript::OnPlayerKilled(player, killer);
+
+ if (battleground->GetStatus() != STATUS_IN_PROGRESS)
+ return;
+
+ TeamId const victimTeamId = Battleground::GetTeamIndexByTeamId(battleground->GetPlayerTeam(player->GetGUID()));
+ _factionReinforcements[victimTeamId] -= 1;
+
+ UpdateWorldState((battleground->GetPlayerTeam(player->GetGUID()) == ALLIANCE ? BG_IC_ALLIANCE_REINFORCEMENTS : BG_IC_HORDE_REINFORCEMENTS), _factionReinforcements[victimTeamId]);
+
+ // we must end the battleground
+ if (_factionReinforcements[victimTeamId] < 1)
+ battleground->EndBattleground(battleground->GetPlayerTeam(killer->GetGUID()));
+ }
+
+ static uint32 GetGateIDFromEntry(uint32 id)
+ {
+ switch (id)
+ {
+ case GO_HORDE_GATE_1:
+ return BG_IC_H_FRONT;
+ case GO_HORDE_GATE_2:
+ return BG_IC_H_WEST;
+ case GO_HORDE_GATE_3:
+ return BG_IC_H_EAST;
+ case GO_ALLIANCE_GATE_3:
+ return BG_IC_A_FRONT;
+ case GO_ALLIANCE_GATE_1:
+ return BG_IC_A_WEST;
+ case GO_ALLIANCE_GATE_2:
+ return BG_IC_A_EAST;
+ default:
+ return 0;
+ }
+ }
+
+ static int32 GetWorldStateFromGateEntry(uint32 id, bool open)
+ {
+ int32 uws = 0;
+
+ switch (id)
+ {
+ case GO_HORDE_GATE_1:
+ uws = (open ? BG_IC_GATE_FRONT_H_WS_OPEN : BG_IC_GATE_FRONT_H_WS_CLOSED);
+ break;
+ case GO_HORDE_GATE_2:
+ uws = (open ? BG_IC_GATE_WEST_H_WS_OPEN : BG_IC_GATE_WEST_H_WS_CLOSED);
+ break;
+ case GO_HORDE_GATE_3:
+ uws = (open ? BG_IC_GATE_EAST_H_WS_OPEN : BG_IC_GATE_EAST_H_WS_CLOSED);
+ break;
+ case GO_ALLIANCE_GATE_3:
+ uws = (open ? BG_IC_GATE_FRONT_A_WS_OPEN : BG_IC_GATE_FRONT_A_WS_CLOSED);
+ break;
+ case GO_ALLIANCE_GATE_1:
+ uws = (open ? BG_IC_GATE_WEST_A_WS_OPEN : BG_IC_GATE_WEST_A_WS_CLOSED);
+ break;
+ case GO_ALLIANCE_GATE_2:
+ uws = (open ? BG_IC_GATE_EAST_A_WS_OPEN : BG_IC_GATE_EAST_A_WS_CLOSED);
+ break;
+ default:
+ break;
+ }
+ return uws;
+ }
+
+ void UpdateNodeWorldState(ICNodePoint const& node) const
+ {
+ UpdateWorldState(node.GetNodeInfo().WorldStateIds.ConflictA, node.GetState() == IsleOfConquestNodeState::ConflictA);
+ UpdateWorldState(node.GetNodeInfo().WorldStateIds.ConflictH, node.GetState() == IsleOfConquestNodeState::ConflictH);
+ UpdateWorldState(node.GetNodeInfo().WorldStateIds.ControlledA, node.GetState() == IsleOfConquestNodeState::ControlledA);
+ UpdateWorldState(node.GetNodeInfo().WorldStateIds.ControlledH, node.GetState() == IsleOfConquestNodeState::ControlledH);
+ UpdateWorldState(node.GetNodeInfo().WorldStateIds.Uncontrolled, node.GetState() == IsleOfConquestNodeState::Neutral);
+ }
+
+ static ICNodePointType BannerToNodeType(uint32 bannerId)
+ {
+ switch (bannerId)
+ {
+ case GO_BANNER_ALLIANCE_KEEP_CONTESTED_A:
+ case GO_BANNER_ALLIANCE_KEEP_CONTESTED_H:
+ case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A:
+ case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_H:
+ return NODE_TYPE_GRAVEYARD_A;
+ case GO_BANNER_HORDE_KEEP_CONTESTED_A:
+ case GO_BANNER_HORDE_KEEP_CONTESTED_H:
+ case GO_BANNER_HORDE_KEEP_CONTROLLED_A:
+ case GO_BANNER_HORDE_KEEP_CONTROLLED_H:
+ return NODE_TYPE_GRAVEYARD_H;
+ case GO_BANNER_DOCKS_CONTESTED_A:
+ case GO_BANNER_DOCKS_CONTESTED_H:
+ case GO_BANNER_DOCKS_CONTROLLED_A:
+ case GO_BANNER_DOCKS_CONTROLLED_H:
+ case GO_BANNER_DOCKS_CONTROLLED_N:
+ return NODE_TYPE_DOCKS;
+ case GO_BANNER_HANGAR_CONTESTED_A:
+ case GO_BANNER_HANGAR_CONTESTED_H:
+ case GO_BANNER_HANGAR_CONTROLLED_A:
+ case GO_BANNER_HANGAR_CONTROLLED_H:
+ case GO_BANNER_HANGAR_CONTROLLED_N:
+ return NODE_TYPE_HANGAR;
+ case GO_BANNER_WORKSHOP_CONTESTED_A:
+ case GO_BANNER_WORKSHOP_CONTESTED_H:
+ case GO_BANNER_WORKSHOP_CONTROLLED_A:
+ case GO_BANNER_WORKSHOP_CONTROLLED_H:
+ case GO_BANNER_WORKSHOP_CONTROLLED_N:
+ return NODE_TYPE_WORKSHOP;
+ case GO_BANNER_QUARRY_CONTESTED_A:
+ case GO_BANNER_QUARRY_CONTESTED_H:
+ case GO_BANNER_QUARRY_CONTROLLED_A:
+ case GO_BANNER_QUARRY_CONTROLLED_H:
+ case GO_BANNER_QUARRY_CONTROLLED_N:
+ return NODE_TYPE_QUARRY;
+ case GO_BANNER_REFINERY_CONTESTED_A:
+ case GO_BANNER_REFINERY_CONTESTED_H:
+ case GO_BANNER_REFINERY_CONTROLLED_A:
+ case GO_BANNER_REFINERY_CONTROLLED_H:
+ case GO_BANNER_REFINERY_CONTROLLED_N:
+ return NODE_TYPE_REFINERY;
+ default:
+ break;
+ }
+
+ return MAX_NODE_TYPES;
+ }
+
+ void HandleCapturedNodes(ICNodePoint& node)
+ {
+ if (node.GetLastControlledTeam() == TEAM_NEUTRAL)
+ return;
+
+ switch (node.GetNodeInfo().NodeType)
+ {
+ case NODE_TYPE_QUARRY:
+ case NODE_TYPE_REFINERY:
+ battlegroundMap->UpdateAreaDependentAuras();
+ break;
+ case NODE_TYPE_HANGAR:
+ if (Transport* transport = battlegroundMap->GetTransport(_gunshipGUIDs[node.GetLastControlledTeam()]))
+ {
+ // Can't have this in spawngroup, creature is on a transport
+ if (TempSummon* trigger = transport->SummonPassenger(NPC_WORLD_TRIGGER_NOT_FLOATING, GunshipTeleportTriggerPosition[node.GetLastControlledTeam()], TEMPSUMMON_MANUAL_DESPAWN))
+ _gunshipTeleportTarget = trigger->GetGUID();
+
+ transport->EnableMovement(true);
+ }
+
+ for (ObjectGuid const& guid : _cannonGUIDs[node.GetLastControlledTeam()])
+ if (Creature* cannon = battlegroundMap->GetCreature(guid))
+ cannon->SetUninteractible(false);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnCreatureCreate(Creature* creature) override
+ {
+ BattlegroundScript::OnCreatureCreate(creature);
+
+ if (creature->HasStringId("bg_ioc_faction_1735"))
+ creature->SetFaction(FACTION_HORDE_GENERIC_WG);
+ else if (creature->HasStringId("bg_ioc_faction_1732"))
+ creature->SetFaction(FACTION_ALLIANCE_GENERIC_WG);
+
+ switch (creature->GetEntry())
+ {
+ case NPC_ALLIANCE_GUNSHIP_CANNON:
+ _cannonGUIDs[TEAM_ALLIANCE].emplace_back(creature->GetGUID());
+ creature->SetUninteractible(true);
+ creature->SetControlled(true, UNIT_STATE_ROOT);
+ break;
+ case NPC_HORDE_GUNSHIP_CANNON:
+ _cannonGUIDs[TEAM_HORDE].emplace_back(creature->GetGUID());
+ creature->SetUninteractible(true);
+ creature->SetControlled(true, UNIT_STATE_ROOT);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnGameObjectCreate(GameObject* gameobject) override
+ {
+ BattlegroundScript::OnGameObjectCreate(gameobject);
+
+ if (gameobject->IsDestructibleBuilding())
+ _wallGUIDs.emplace_back(gameobject->GetGUID());
+
+ if (gameobject->HasStringId("bg_ioc_faction_1735"))
+ gameobject->SetFaction(FACTION_HORDE_GENERIC_WG);
+ else if (gameobject->HasStringId("bg_ioc_faction_1732"))
+ gameobject->SetFaction(FACTION_ALLIANCE_GENERIC_WG);
+
+ switch (gameobject->GetEntry())
+ {
+ case GO_TELEPORTER_1:
+ case GO_TELEPORTER_2:
+ case GO_TELEPORTER_3:
+ case GO_TELEPORTER_4:
+ _teleporterGUIDs.emplace_back(gameobject->GetGUID());
+ break;
+ case GO_TELEPORTER_EFFECTS_A:
+ case GO_TELEPORTER_EFFECTS_H:
+ _teleporterEffectGUIDs.emplace_back(gameobject->GetGUID());
+ break;
+ case GO_DOODAD_ND_HUMAN_GATE_CLOSEDFX_DOOR01:
+ case GO_DOODAD_ND_WINTERORC_WALL_GATEFX_DOOR01:
+ _mainGateDoorGUIDs.emplace_back(gameobject->GetGUID());
+ break;
+ case GO_DOODAD_HU_PORTCULLIS01:
+ case GO_DOODAD_VR_PORTCULLIS01:
+ _portcullisGUIDs.emplace_back(gameobject->GetGUID());
+ break;
+ case GO_KEEP_GATE_H:
+ _keepGateGUIDs[TEAM_HORDE].emplace_back(gameobject->GetGUID());
+ break;
+ case GO_KEEP_GATE_A:
+ case GO_KEEP_GATE_2_A:
+ _keepGateGUIDs[TEAM_ALLIANCE].emplace_back(gameobject->GetGUID());
+ break;
+ case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A:
+ _keepBannerGUIDs[TEAM_ALLIANCE] = gameobject->GetGUID();
+ break;
+ case GO_BANNER_HORDE_KEEP_CONTROLLED_H:
+ _keepBannerGUIDs[TEAM_HORDE] = gameobject->GetGUID();
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnInit() override
+ {
+ BattlegroundScript::OnInit();
+
+ if (Transport* transport = sTransportMgr->CreateTransport(GO_HORDE_GUNSHIP, battlegroundMap))
+ {
+ _gunshipGUIDs[TEAM_HORDE] = transport->GetGUID();
+ transport->EnableMovement(false);
+ }
+
+ if (Transport* transport = sTransportMgr->CreateTransport(GO_ALLIANCE_GUNSHIP, battlegroundMap))
+ {
+ _gunshipGUIDs[TEAM_ALLIANCE] = transport->GetGUID();
+ transport->EnableMovement(false);
+ }
+ }
+
+ void DoAction(uint32 actionId, WorldObject* source, WorldObject* target) override
+ {
+ BattlegroundScript::DoAction(actionId, source, target);
+
+ switch (actionId)
+ {
+ case ACTION_IOC_INTERACT_CAPTURABLE_OBJECT:
+ OnPlayerInteractWithBanner(WorldObject::ToPlayer(source), WorldObject::ToGameObject(target));
+ break;
+ case ACTION_IOC_CAPTURE_CAPTURABLE_OBJECT:
+ HandleCaptureNodeAction(WorldObject::ToGameObject(target));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnPlayerInteractWithBanner(Player* player, GameObject* banner)
+ {
+ if (!player || !banner)
+ return;
+
+ Team const playerTeam = battleground->GetPlayerTeam(player->GetGUID());
+ TeamId const playerTeamId = Battleground::GetTeamIndexByTeamId(playerTeam);
+ ICNodePointType const nodeType = BannerToNodeType(banner->GetEntry());
+ if (nodeType == MAX_NODE_TYPES)
+ return;
+
+ ICNodePoint& node = *_nodePoints[nodeType];
+
+ bool assault = false;
+ bool defend = false;
+
+ switch (node.GetState())
+ {
+ case IsleOfConquestNodeState::Neutral:
+ assault = true;
+ break;
+ case IsleOfConquestNodeState::ControlledH:
+ assault = playerTeamId != TEAM_HORDE;
+ break;
+ case IsleOfConquestNodeState::ControlledA:
+ assault = playerTeamId != TEAM_ALLIANCE;
+ break;
+ case IsleOfConquestNodeState::ConflictA:
+ defend = playerTeamId == node.GetLastControlledTeam();
+ assault = !defend && playerTeamId == TEAM_HORDE;
+ break;
+ case IsleOfConquestNodeState::ConflictH:
+ defend = playerTeamId == node.GetLastControlledTeam();
+ assault = !defend && playerTeamId == TEAM_ALLIANCE;
+ break;
+ }
+
+ if (assault)
+ OnPlayerAssaultNode(player, node);
+ else if (defend)
+ OnPlayerDefendNode(player, node);
+
+ battlegroundMap->UpdateSpawnGroupConditions();
+ }
+
+ void OnPlayerAssaultNode(Player* player, ICNodePoint& node)
+ {
+ if (!player)
+ return;
+
+ Team const playerTeam = battleground->GetPlayerTeam(player->GetGUID());
+ TeamId const playerTeamId = Battleground::GetTeamIndexByTeamId(playerTeam);
+
+ IsleOfConquestNodeState const newState = playerTeamId == TEAM_HORDE ? IsleOfConquestNodeState::ConflictH : IsleOfConquestNodeState::ConflictA;
+ node.UpdateState(newState);
+
+ battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
+
+ ChatMsg const messageType = playerTeamId == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
+ battleground->SendBroadcastText(node.GetNodeInfo().TextIds.Assaulted, messageType, player);
+ UpdateNodeWorldState(node);
+
+ // apply side effects of each node, only if it wasn't neutral before
+ if (node.GetLastControlledTeam() == TEAM_NEUTRAL)
+ return;
+
+ switch (node.GetNodeInfo().NodeType)
+ {
+ case NODE_TYPE_HANGAR:
+ if (Transport* transport = battlegroundMap->GetTransport(_gunshipGUIDs[node.GetLastControlledTeam()]))
+ transport->EnableMovement(false);
+
+ for (ObjectGuid const& guid : _cannonGUIDs[node.GetLastControlledTeam()])
+ {
+ if (Creature* cannon = battlegroundMap->GetCreature(guid))
+ {
+ cannon->GetVehicleKit()->RemoveAllPassengers();
+ cannon->SetUninteractible(true);
+ }
+ }
+
+ // Despawn teleport trigger target
+ if (Creature* creature = battlegroundMap->GetCreature(_gunshipTeleportTarget))
+ creature->DespawnOrUnsummon();
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnPlayerDefendNode(Player* player, ICNodePoint& node)
+ {
+ if (!player)
+ return;
+
+ Team const playerTeam = battleground->GetPlayerTeam(player->GetGUID());
+ TeamId const playerTeamId = Battleground::GetTeamIndexByTeamId(playerTeam);
+
+ node.UpdateState(playerTeamId == TEAM_HORDE ? IsleOfConquestNodeState::ControlledH : IsleOfConquestNodeState::ControlledA);
+ HandleCapturedNodes(node);
+ battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
+
+ ChatMsg const messageType = playerTeamId == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
+ battleground->SendBroadcastText(node.GetNodeInfo().TextIds.Defended, messageType, player);
+ UpdateNodeWorldState(node);
+ }
+
+ void ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker) override
+ {
+ BattlegroundScript::ProcessEvent(target, eventId, invoker);
+
+ if (GameObject* obj = Object::ToGameObject(target))
+ if (obj->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
+ if (obj->GetGOInfo()->destructibleBuilding.DestroyedEvent == eventId)
+ OnGateDestroyed(obj, invoker);
+ }
+
+ void HandleCaptureNodeAction(GameObject* banner)
+ {
+ if (!banner)
+ return;
+
+ ICNodePointType const nodeType = BannerToNodeType(banner->GetEntry());
+ if (nodeType == MAX_NODE_TYPES)
+ return;
+
+ ICNodePoint& node = *_nodePoints[nodeType];
+ if (node.GetState() == IsleOfConquestNodeState::ConflictH)
+ node.UpdateState(IsleOfConquestNodeState::ControlledH);
+ else if (node.GetState() == IsleOfConquestNodeState::ConflictA)
+ node.UpdateState(IsleOfConquestNodeState::ControlledA);
+
+ HandleCapturedNodes(node);
+
+ ChatMsg const messageType = node.GetLastControlledTeam() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
+ uint32 const textId = node.GetLastControlledTeam() == TEAM_ALLIANCE ? node.GetNodeInfo().TextIds.AllianceTaken : node.GetNodeInfo().TextIds.HordeTaken;
+ battleground->SendBroadcastText(textId, messageType);
+ UpdateNodeWorldState(node);
+ }
+
+ void OnGateDestroyed(GameObject* gate, WorldObject* destroyer)
+ {
+ _gateStatus[GetGateIDFromEntry(gate->GetEntry())] = BG_IC_GATE_DESTROYED;
+ int32 const wsGateOpen = GetWorldStateFromGateEntry(gate->GetEntry(), true);
+ int32 const wsGateClosed = GetWorldStateFromGateEntry(gate->GetEntry(), false);
+ if (wsGateOpen)
+ {
+ UpdateWorldState(wsGateClosed, 0);
+ UpdateWorldState(wsGateOpen, 1);
+ }
+
+ TeamId teamId = TEAM_NEUTRAL;
+ uint32 textId;
+ ChatMsg msgType;
+ switch (gate->GetEntry())
+ {
+ case GO_HORDE_GATE_1:
+ textId = BG_IC_TEXT_FRONT_GATE_HORDE_DESTROYED;
+ msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
+ teamId = TEAM_HORDE;
+ break;
+ case GO_HORDE_GATE_2:
+ textId = BG_IC_TEXT_WEST_GATE_HORDE_DESTROYED;
+ msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
+ teamId = TEAM_HORDE;
+ break;
+ case GO_HORDE_GATE_3:
+ textId = BG_IC_TEXT_EAST_GATE_HORDE_DESTROYED;
+ msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
+ teamId = TEAM_HORDE;
+ break;
+ case GO_ALLIANCE_GATE_1:
+ textId = BG_IC_TEXT_WEST_GATE_ALLIANCE_DESTROYED;
+ msgType = CHAT_MSG_BG_SYSTEM_HORDE;
+ teamId = TEAM_ALLIANCE;
+ break;
+ case GO_ALLIANCE_GATE_2:
+ textId = BG_IC_TEXT_EAST_GATE_ALLIANCE_DESTROYED;
+ msgType = CHAT_MSG_BG_SYSTEM_HORDE;
+ teamId = TEAM_ALLIANCE;
+ break;
+ case GO_ALLIANCE_GATE_3:
+ textId = BG_IC_TEXT_FRONT_GATE_ALLIANCE_DESTROYED;
+ msgType = CHAT_MSG_BG_SYSTEM_HORDE;
+ teamId = TEAM_ALLIANCE;
+ break;
+ default:
+ return;
+ }
+
+ if (teamId != TEAM_NEUTRAL)
+ {
+ GuidVector const keepGates = _keepGateGUIDs[teamId];
+ ObjectGuid const bannerGuid = _keepBannerGUIDs[teamId];
+
+ for (ObjectGuid const& guid : keepGates)
+ if (GameObject* keepGate = battlegroundMap->GetGameObject(guid))
+ keepGate->UseDoorOrButton();
+
+ if (GameObject* banner = battlegroundMap->GetGameObject(bannerGuid))
+ banner->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
+ }
+
+ battleground->SendBroadcastText(textId, msgType, destroyer);
+ }
+
+private:
+ std::array<uint16, PVP_TEAMS_COUNT> _factionReinforcements;
+ std::array<BG_IC_GateState, 6> _gateStatus;
+ std::array<std::unique_ptr<ICNodePoint>, 7> _nodePoints;
+ std::array<ObjectGuid, PVP_TEAMS_COUNT> _gunshipGUIDs;
+ GuidVector _teleporterGUIDs;
+ GuidVector _teleporterEffectGUIDs;
+ GuidVector _mainGateDoorGUIDs;
+ GuidVector _portcullisGUIDs;
+ GuidVector _wallGUIDs;
+ std::array<GuidVector, PVP_TEAMS_COUNT> _cannonGUIDs;
+ std::array<GuidVector, PVP_TEAMS_COUNT> _keepGateGUIDs;
+ std::array<ObjectGuid, PVP_TEAMS_COUNT> _keepBannerGUIDs;
+ ObjectGuid _gunshipTeleportTarget;
+
+ TaskScheduler _scheduler;
+ TimeTracker _resourceTimer;
+};
+
+void AddSC_battleground_isle_of_conquest()
+{
+ RegisterBattlegroundMapScript(battleground_isle_of_conquest, 628);
+}
diff --git a/src/server/scripts/Battlegrounds/IsleOfConquest/boss_ioc_horde_alliance.cpp b/src/server/scripts/Battlegrounds/IsleOfConquest/boss_ioc_horde_alliance.cpp
new file mode 100644
index 00000000000..05a13de842b
--- /dev/null
+++ b/src/server/scripts/Battlegrounds/IsleOfConquest/boss_ioc_horde_alliance.cpp
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 "isle_of_conquest.h"
+#include "ScriptedCreature.h"
+
+enum BossSpells
+{
+ SPELL_BRUTAL_STRIKE = 58460,
+ SPELL_DAGGER_THROW = 67280,
+ SPELL_CRUSHING_LEAP = 68506,
+ SPELL_RAGE = 66776
+};
+
+enum BossEvents
+{
+ EVENT_BRUTAL_STRIKE = 1,
+ EVENT_DAGGER_THROW = 2,
+ EVENT_CRUSHING_LEAP = 3,
+ EVENT_CHECK_RANGE = 4
+};
+
+struct boss_ioc_horde_alliance : public ScriptedAI
+{
+ boss_ioc_horde_alliance(Creature* creature) : ScriptedAI(creature) { }
+
+ void Reset() override
+ {
+ _events.Reset();
+
+ uint32 _npcGuard;
+ if (me->GetEntry() == NPC_HIGH_COMMANDER_HALFORD_WYRMBANE)
+ _npcGuard = NPC_SEVEN_TH_LEGION_INFANTRY;
+ else
+ _npcGuard = NPC_KOR_KRON_GUARD;
+
+ std::list<Creature*> guardsList;
+ me->GetCreatureListWithEntryInGrid(guardsList, _npcGuard, 100.0f);
+ for (std::list<Creature*>::const_iterator itr = guardsList.begin(); itr != guardsList.end(); ++itr)
+ (*itr)->Respawn();
+ };
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ _events.ScheduleEvent(EVENT_BRUTAL_STRIKE, 5s);
+ _events.ScheduleEvent(EVENT_DAGGER_THROW, 7s);
+ _events.ScheduleEvent(EVENT_CHECK_RANGE, 1s);
+ _events.ScheduleEvent(EVENT_CRUSHING_LEAP, 15s);
+ }
+
+ void SpellHit(WorldObject* caster, SpellInfo const* /*spellInfo*/) override
+ {
+ Unit* unitCaster = caster->ToUnit();
+ if (!unitCaster)
+ return;
+
+ if (unitCaster->IsVehicle())
+ Unit::Kill(me, unitCaster);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_BRUTAL_STRIKE:
+ DoCastVictim(SPELL_BRUTAL_STRIKE);
+ _events.ScheduleEvent(EVENT_BRUTAL_STRIKE, 5s);
+ break;
+ case EVENT_DAGGER_THROW:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
+ DoCast(target, SPELL_DAGGER_THROW);
+ _events.ScheduleEvent(EVENT_DAGGER_THROW, 7s);
+ break;
+ case EVENT_CRUSHING_LEAP:
+ DoCastVictim(SPELL_CRUSHING_LEAP);
+ _events.ScheduleEvent(EVENT_CRUSHING_LEAP, 25s);
+ break;
+ case EVENT_CHECK_RANGE:
+ if (me->GetDistance(me->GetHomePosition()) > 25.0f)
+ DoCast(me, SPELL_RAGE);
+ else
+ me->RemoveAurasDueToSpell(SPELL_RAGE);
+ _events.ScheduleEvent(EVENT_CHECK_RANGE, 1s);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+private:
+ EventMap _events;
+};
+
+void AddSC_boss_ioc_horde_alliance()
+{
+ RegisterCreatureAI(boss_ioc_horde_alliance);
+}
diff --git a/src/server/scripts/Battlegrounds/IsleOfConquest/isle_of_conquest.cpp b/src/server/scripts/Battlegrounds/IsleOfConquest/isle_of_conquest.cpp
new file mode 100644
index 00000000000..2c9fdce6596
--- /dev/null
+++ b/src/server/scripts/Battlegrounds/IsleOfConquest/isle_of_conquest.cpp
@@ -0,0 +1,393 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 "isle_of_conquest.h"
+#include "ScriptMgr.h"
+#include "Battleground.h"
+#include "GameObject.h"
+#include "GameObjectAI.h"
+#include "Map.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellInfo.h"
+#include "SpellScript.h"
+#include "Vehicle.h"
+#include "WorldStateMgr.h"
+
+// TO-DO: This should be done with SmartAI, but yet it does not correctly support vehicles's AIs.
+// Even adding ReactState Passive we still have issues using SmartAI.
+
+struct npc_four_car_garage : public NullCreatureAI
+{
+ npc_four_car_garage(Creature* creature) : NullCreatureAI(creature) { }
+
+ void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
+ {
+ if (apply)
+ {
+ uint32 spellId = 0;
+
+ switch (me->GetEntry())
+ {
+ case NPC_DEMOLISHER:
+ spellId = SPELL_DRIVING_CREDIT_DEMOLISHER;
+ break;
+ case NPC_GLAIVE_THROWER_A:
+ case NPC_GLAIVE_THROWER_H:
+ spellId = SPELL_DRIVING_CREDIT_GLAIVE;
+ break;
+ case NPC_SIEGE_ENGINE_H:
+ case NPC_SIEGE_ENGINE_A:
+ spellId = SPELL_DRIVING_CREDIT_SIEGE;
+ break;
+ case NPC_CATAPULT:
+ spellId = SPELL_DRIVING_CREDIT_CATAPULT;
+ break;
+ default:
+ return;
+ }
+
+ me->CastSpell(who, spellId, true);
+ }
+ }
+};
+
+enum Events
+{
+ EVENT_TALK = 1,
+ EVENT_DESPAWN
+};
+
+enum Texts
+{
+ SAY_ONBOARD = 0
+};
+
+struct npc_ioc_gunship_captain : public ScriptedAI
+{
+ npc_ioc_gunship_captain(Creature* creature) : ScriptedAI(creature) { }
+
+ void JustAppeared() override
+ {
+ DoCast(me, SPELL_SIMPLE_TELEPORT);
+ _events.ScheduleEvent(EVENT_TALK, 3s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_TALK:
+ _events.ScheduleEvent(EVENT_DESPAWN, 1s);
+ Talk(SAY_ONBOARD);
+ DoCast(me, SPELL_TELEPORT_VISUAL_ONLY);
+ break;
+ case EVENT_DESPAWN:
+ me->DespawnOrUnsummon();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+private:
+ EventMap _events;
+};
+
+struct npc_ioc_siege_engine : public ScriptedAI
+{
+ npc_ioc_siege_engine(Creature* creature) : ScriptedAI(creature) { }
+
+ static constexpr uint32 SPELL_DAMAGED = 67323;
+ static constexpr uint32 VEHICLE_REC_ID = 514;
+ static constexpr int32 ACTION_REPAIRED = 1;
+
+ void JustAppeared() override
+ {
+ me->RemoveVehicleKit(false);
+ DoCastSelf(SPELL_DAMAGED);
+ }
+
+ void DoAction(int32 actionId) override
+ {
+ // there should be some moving involved first
+ if (actionId == ACTION_REPAIRED)
+ {
+ me->CreateVehicleKit(VEHICLE_REC_ID, me->GetEntry(), false);
+ me->GetVehicleKit()->InstallAllAccessories(false);
+ }
+ }
+};
+
+struct go_ioc_capturable_object : public GameObjectAI
+{
+ go_ioc_capturable_object(GameObject* go) : GameObjectAI(go) { }
+
+ bool OnGossipHello(Player* player) override
+ {
+ if (me->GetGoState() != GO_STATE_READY || me->HasFlag(GO_FLAG_NOT_SELECTABLE))
+ return true;
+
+ if (ZoneScript* zonescript = me->GetZoneScript())
+ {
+ zonescript->DoAction(ACTION_IOC_INTERACT_CAPTURABLE_OBJECT, player, me);
+ return false;
+ }
+
+ return true;
+ }
+};
+
+struct go_ioc_contested_object : public go_ioc_capturable_object
+{
+ go_ioc_contested_object(GameObject* go) : go_ioc_capturable_object(go) { }
+
+ void Reset() override
+ {
+ go_ioc_capturable_object::Reset();
+ _scheduler.Schedule(1min, [&](TaskContext)
+ {
+ if (ZoneScript* zonescript = me->GetZoneScript())
+ zonescript->DoAction(ACTION_IOC_CAPTURE_CAPTURABLE_OBJECT, me, me);
+ });
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _scheduler.Update(diff);
+ }
+
+private:
+ TaskScheduler _scheduler;
+};
+
+// 67323 - Damaged
+class spell_ioc_damaged : public AuraScript
+{
+ void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) const
+ {
+ if (Creature const* creatureTarget = GetTarget()->ToCreature())
+ if (UnitAI* ai = creatureTarget->GetAI())
+ ai->DoAction(npc_ioc_siege_engine::ACTION_REPAIRED);
+ }
+
+ void Register() override
+ {
+ OnEffectRemove += AuraEffectRemoveFn(spell_ioc_damaged::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 66630 - Alliance Gunship Portal
+// 66637 - Horde Gunship Portal
+class spell_ioc_gunship_portal : public SpellScript
+{
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Player* caster = GetCaster()->ToPlayer();
+ /*
+ * HACK: GetWorldLocation() returns real position and not transportposition.
+ * ServertoClient: SMSG_MOVE_TELEPORT (0x0B39)
+ * counter: 45
+ * Tranpsort Guid: Full: xxxx Type: MOTransport Low: xxx
+ * Transport Position X: 0 Y: 0 Z: 0 O: 0
+ * Position: X: 7.305609 Y: -0.095246 Z: 34.51022 O: 0
+ */
+ caster->TeleportTo(GetHitCreature()->GetWorldLocation(), TELE_TO_NOT_LEAVE_TRANSPORT);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_ioc_gunship_portal::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 66656 - Parachute
+class spell_ioc_parachute_ic : public AuraScript
+{
+ void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ if (Player* target = GetTarget()->ToPlayer())
+ if (target->m_movementInfo.GetFallTime() > 2000 && !target->GetTransport())
+ target->CastSpell(target, SPELL_PARACHUTE_IC, true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_ioc_parachute_ic::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+};
+
+class StartLaunchEvent : public BasicEvent
+{
+ public:
+ StartLaunchEvent(Position const& pos, ObjectGuid const& guid) : _pos(pos), _guid(guid)
+ {
+ }
+
+ bool Execute(uint64 /*time*/, uint32 /*diff*/) override
+ {
+ Player* player = ObjectAccessor::FindPlayer(_guid);
+ if (!player || !player->GetVehicle())
+ return true;
+
+ player->AddAura(SPELL_LAUNCH_NO_FALLING_DAMAGE, player); // prevents falling damage
+ float speedZ = 10.0f;
+ float dist = player->GetExactDist2d(&_pos);
+
+ player->ExitVehicle();
+ player->GetMotionMaster()->MoveJump(_pos, dist, speedZ, EVENT_JUMP, true);
+ return true;
+ }
+
+ private:
+ Position _pos;
+ ObjectGuid _guid;
+};
+
+// 66218 - Launch
+class spell_ioc_launch : public SpellScript
+{
+ void Launch()
+ {
+ if (!GetCaster()->ToCreature() || !GetExplTargetDest())
+ return;
+
+ GetCaster()->ToCreature()->m_Events.AddEvent(new StartLaunchEvent(*GetExplTargetDest(), ASSERT_NOTNULL(GetHitPlayer())->GetGUID()), GetCaster()->ToCreature()->m_Events.CalculateTime(2500ms));
+ }
+
+ void Register() override
+ {
+ AfterHit += SpellHitFn(spell_ioc_launch::Launch);
+ }
+};
+
+enum SeaforiumBombSpells
+{
+ SPELL_SEAFORIUM_BLAST = 66676,
+ SPELL_HUGE_SEAFORIUM_BLAST = 66672,
+ SPELL_A_BOMB_INABLE_CREDIT = 68366,
+ SPELL_A_BOMB_INATION_CREDIT = 68367
+};
+
+// 66672 - Huge Seaforium Blast
+// 66676 - Seaforium Blast
+class spell_ioc_seaforium_blast_credit : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_A_BOMB_INABLE_CREDIT, SPELL_A_BOMB_INATION_CREDIT });
+ }
+
+ void HandleAchievementCredit(SpellEffIndex /*effIndex*/)
+ {
+ uint32 _creditSpell = 0;
+ Unit* caster = GetOriginalCaster();
+ if (!caster)
+ return;
+
+ if (GetSpellInfo()->Id == SPELL_SEAFORIUM_BLAST)
+ _creditSpell = SPELL_A_BOMB_INABLE_CREDIT;
+ else if (GetSpellInfo()->Id == SPELL_HUGE_SEAFORIUM_BLAST)
+ _creditSpell = SPELL_A_BOMB_INATION_CREDIT;
+
+ if (GetHitGObj() && GetHitGObj()->IsDestructibleBuilding())
+ caster->CastSpell(caster, _creditSpell, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_ioc_seaforium_blast_credit::HandleAchievementCredit, EFFECT_1, SPELL_EFFECT_GAMEOBJECT_DAMAGE);
+ }
+};
+
+class at_ioc_exploit : public AreaTriggerScript
+{
+public:
+ at_ioc_exploit() : AreaTriggerScript("at_ioc_exploit") { }
+
+ bool OnExit(Player* player, AreaTriggerEntry const* /*trigger*/) override
+ {
+ if (Battleground* battleground = player->GetBattleground())
+ if (battleground->GetStatus() == STATUS_WAIT_JOIN)
+ battleground->TeleportPlayerToExploitLocation(player);
+
+ return true;
+ }
+};
+
+class at_ioc_backdoor_job : public AreaTriggerScript
+{
+public:
+ static constexpr uint32 AT_HORDE_KEEP = 5535;
+ static constexpr uint32 AT_ALLIANCE_KEEP = 5536;
+
+ at_ioc_backdoor_job() : AreaTriggerScript("at_ioc_backdoor_job") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override
+ {
+ /// @hack: this spell should be cast by npc 22515 (World Trigger) and not by the player
+ if (player->GetBGTeam() == HORDE && trigger->ID == AT_ALLIANCE_KEEP)
+ {
+ bool keepClosed = sWorldStateMgr->GetValue(BG_IC_GATE_EAST_A_WS_CLOSED, player->GetMap()) == 1
+ && sWorldStateMgr->GetValue(BG_IC_GATE_WEST_A_WS_CLOSED, player->GetMap()) == 1
+ && sWorldStateMgr->GetValue(BG_IC_GATE_FRONT_A_WS_CLOSED, player->GetMap()) == 1;
+
+ if (keepClosed)
+ player->CastSpell(player, SPELL_BACK_DOOR_JOB_ACHIEVEMENT, true);
+ }
+ else if (player->GetBGTeam() == ALLIANCE && trigger->ID == AT_HORDE_KEEP)
+ {
+ bool keepClosed = sWorldStateMgr->GetValue(BG_IC_GATE_EAST_H_WS_CLOSED, player->GetMap()) == 1
+ && sWorldStateMgr->GetValue(BG_IC_GATE_WEST_H_WS_CLOSED, player->GetMap()) == 1
+ && sWorldStateMgr->GetValue(BG_IC_GATE_FRONT_H_WS_CLOSED, player->GetMap()) == 1;
+
+ if (keepClosed)
+ player->CastSpell(player, SPELL_BACK_DOOR_JOB_ACHIEVEMENT, true);
+ }
+
+ return true;
+ }
+};
+
+void AddSC_isle_of_conquest()
+{
+ RegisterCreatureAI(npc_four_car_garage);
+ RegisterCreatureAI(npc_ioc_gunship_captain);
+ RegisterCreatureAI(npc_ioc_siege_engine);
+ RegisterGameObjectAI(go_ioc_capturable_object);
+ RegisterGameObjectAI(go_ioc_contested_object);
+ RegisterSpellScript(spell_ioc_damaged);
+ RegisterSpellScript(spell_ioc_gunship_portal);
+ RegisterSpellScript(spell_ioc_parachute_ic);
+ RegisterSpellScript(spell_ioc_launch);
+ RegisterSpellScript(spell_ioc_seaforium_blast_credit);
+ new at_ioc_exploit();
+ new at_ioc_backdoor_job();
+}
diff --git a/src/server/scripts/Battlegrounds/IsleOfConquest/isle_of_conquest.h b/src/server/scripts/Battlegrounds/IsleOfConquest/isle_of_conquest.h
new file mode 100644
index 00000000000..ab4c92abae6
--- /dev/null
+++ b/src/server/scripts/Battlegrounds/IsleOfConquest/isle_of_conquest.h
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITYCORE_ISLE_OF_CONQUEST_H
+#define TRINITYCORE_ISLE_OF_CONQUEST_H
+
+enum CreaturesIC
+{
+ NPC_HIGH_COMMANDER_HALFORD_WYRMBANE = 34924, // Alliance Boss
+ NPC_OVERLORD_AGMAR = 34922, // Horde Boss
+ NPC_KOR_KRON_GUARD = 34918, // horde guard
+ NPC_SEVEN_TH_LEGION_INFANTRY = 34919, // alliance guard
+ NPC_KEEP_CANNON = 34944,
+ NPC_DEMOLISHER = 34775,
+ NPC_SIEGE_ENGINE_H = 35069,
+ NPC_SIEGE_ENGINE_A = 34776,
+ NPC_GLAIVE_THROWER_A = 34802,
+ NPC_GLAIVE_THROWER_H = 35273,
+ NPC_CATAPULT = 34793,
+ NPC_HORDE_GUNSHIP_CANNON = 34935,
+ NPC_ALLIANCE_GUNSHIP_CANNON = 34929,
+ NPC_HORDE_GUNSHIP_CAPTAIN = 35003,
+ NPC_ALLIANCE_GUNSHIP_CAPTAIN = 34960,
+ NPC_WORLD_TRIGGER_NOT_FLOATING = 34984,
+ NPC_WORLD_TRIGGER_ALLIANCE_FRIENDLY = 20213,
+ NPC_WORLD_TRIGGER_HORDE_FRIENDLY = 20212
+};
+
+enum Actions
+{
+ ACTION_GUNSHIP_READY = 1,
+ ACTION_IOC_INTERACT_CAPTURABLE_OBJECT = 2,
+ ACTION_IOC_CAPTURE_CAPTURABLE_OBJECT = 3
+};
+
+enum Spells
+{
+ SPELL_OIL_REFINERY = 68719,
+ SPELL_QUARRY = 68720,
+ SPELL_PARACHUTE = 66656,
+ SPELL_SLOW_FALL = 12438,
+ SPELL_DESTROYED_VEHICLE_ACHIEVEMENT = 68357,
+ SPELL_BACK_DOOR_JOB_ACHIEVEMENT = 68502,
+ SPELL_DRIVING_CREDIT_DEMOLISHER = 68365,
+ SPELL_DRIVING_CREDIT_GLAIVE = 68363,
+ SPELL_DRIVING_CREDIT_SIEGE = 68364,
+ SPELL_DRIVING_CREDIT_CATAPULT = 68362,
+ SPELL_SIMPLE_TELEPORT = 12980,
+ SPELL_TELEPORT_VISUAL_ONLY = 51347,
+ SPELL_PARACHUTE_IC = 66657,
+ SPELL_LAUNCH_NO_FALLING_DAMAGE = 66251
+};
+
+enum ICWorldStates
+{
+ BG_IC_ALLIANCE_REINFORCEMENTS_SET = 4221,
+ BG_IC_HORDE_REINFORCEMENTS_SET = 4222,
+ BG_IC_ALLIANCE_REINFORCEMENTS = 4226,
+ BG_IC_HORDE_REINFORCEMENTS = 4227,
+ BG_IC_MAX_REINFORCEMENTS = 17377,
+
+ BG_IC_GATE_FRONT_H_WS_CLOSED = 4317,
+ BG_IC_GATE_WEST_H_WS_CLOSED = 4318,
+ BG_IC_GATE_EAST_H_WS_CLOSED = 4319,
+ BG_IC_GATE_FRONT_A_WS_CLOSED = 4328,
+ BG_IC_GATE_WEST_A_WS_CLOSED = 4327,
+ BG_IC_GATE_EAST_A_WS_CLOSED = 4326,
+ BG_IC_GATE_FRONT_H_WS_OPEN = 4322,
+ BG_IC_GATE_WEST_H_WS_OPEN = 4321,
+ BG_IC_GATE_EAST_H_WS_OPEN = 4320,
+ BG_IC_GATE_FRONT_A_WS_OPEN = 4323,
+ BG_IC_GATE_WEST_A_WS_OPEN = 4324,
+ BG_IC_GATE_EAST_A_WS_OPEN = 4325,
+
+ BG_IC_DOCKS_UNCONTROLLED = 4301,
+ BG_IC_DOCKS_CONFLICT_A = 4305,
+ BG_IC_DOCKS_CONFLICT_H = 4302,
+ BG_IC_DOCKS_CONTROLLED_A = 4304,
+ BG_IC_DOCKS_CONTROLLED_H = 4303,
+
+ BG_IC_HANGAR_UNCONTROLLED = 4296,
+ BG_IC_HANGAR_CONFLICT_A = 4300,
+ BG_IC_HANGAR_CONFLICT_H = 4297,
+ BG_IC_HANGAR_CONTROLLED_A = 4299,
+ BG_IC_HANGAR_CONTROLLED_H = 4298,
+
+ BG_IC_QUARRY_UNCONTROLLED = 4306,
+ BG_IC_QUARRY_CONFLICT_A = 4310,
+ BG_IC_QUARRY_CONFLICT_H = 4307,
+ BG_IC_QUARRY_CONTROLLED_A = 4309,
+ BG_IC_QUARRY_CONTROLLED_H = 4308,
+
+ BG_IC_REFINERY_UNCONTROLLED = 4311,
+ BG_IC_REFINERY_CONFLICT_A = 4315,
+ BG_IC_REFINERY_CONFLICT_H = 4312,
+ BG_IC_REFINERY_CONTROLLED_A = 4314,
+ BG_IC_REFINERY_CONTROLLED_H = 4313,
+
+ BG_IC_WORKSHOP_UNCONTROLLED = 4294,
+ BG_IC_WORKSHOP_CONFLICT_A = 4228,
+ BG_IC_WORKSHOP_CONFLICT_H = 4293,
+ BG_IC_WORKSHOP_CONTROLLED_A = 4229,
+ BG_IC_WORKSHOP_CONTROLLED_H = 4230,
+
+ BG_IC_ALLIANCE_KEEP_UNCONTROLLED = 4341,
+ BG_IC_ALLIANCE_KEEP_CONFLICT_A = 4342,
+ BG_IC_ALLIANCE_KEEP_CONFLICT_H = 4343,
+ BG_IC_ALLIANCE_KEEP_CONTROLLED_A = 4339,
+ BG_IC_ALLIANCE_KEEP_CONTROLLED_H = 4340,
+
+ BG_IC_HORDE_KEEP_UNCONTROLLED = 4346,
+ BG_IC_HORDE_KEEP_CONFLICT_A = 4347,
+ BG_IC_HORDE_KEEP_CONFLICT_H = 4348,
+ BG_IC_HORDE_KEEP_CONTROLLED_A = 4344,
+ BG_IC_HORDE_KEEP_CONTROLLED_H = 4345
+};
+
+#endif