diff options
| author | Jeremy <Golrag@users.noreply.github.com> | 2024-03-28 19:29:22 +0100 |
|---|---|---|
| committer | funjoker <funjoker109@gmail.com> | 2024-03-28 20:38:55 +0100 |
| commit | d0d5d309bb5877dc2fcb27f6cb123707a31ec1e8 (patch) | |
| tree | f487ecb6ff8fd052357ea582ffa630027dc8bd07 /src/server/scripts/Battlegrounds/IsleOfConquest | |
| parent | aefa15ece72bccdeb47cbdbdc75df87837c9da00 (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')
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 |
