diff options
| author | Jeremy <Golrag@users.noreply.github.com> | 2024-03-28 19:29:22 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-28 19:29:22 +0100 |
| commit | be11f42a16d1fa0482e9572bf54e99e4dedd3c78 (patch) | |
| tree | 3d33413d7ed5cada34d7ced7f430380731160d5b /src/server/scripts/Battlegrounds/AlteracValley | |
| parent | 78635f640ee3b632a487a50dcf492ae62c2a0933 (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
Diffstat (limited to 'src/server/scripts/Battlegrounds/AlteracValley')
7 files changed, 2193 insertions, 0 deletions
diff --git a/src/server/scripts/Battlegrounds/AlteracValley/alterac_valley.cpp b/src/server/scripts/Battlegrounds/AlteracValley/alterac_valley.cpp new file mode 100644 index 00000000000..94af6a25a53 --- /dev/null +++ b/src/server/scripts/Battlegrounds/AlteracValley/alterac_valley.cpp @@ -0,0 +1,228 @@ +/* + * 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 "alterac_valley.h" +#include "ScriptMgr.h" +#include "Battleground.h" +#include "GameObject.h" +#include "GameObjectAI.h" +#include "Player.h" +#include "ScriptedCreature.h" + +#include <chrono> + +enum Spells +{ + SPELL_CHARGE = 22911, + SPELL_CLEAVE = 40504, + SPELL_DEMORALIZING_SHOUT = 23511, + SPELL_ENRAGE = 8599, + SPELL_WHIRLWIND = 13736 +}; + +enum Creatures +{ + NPC_NORTH_MARSHAL = 14762, + NPC_SOUTH_MARSHAL = 14763, + NPC_ICEWING_MARSHAL = 14764, + NPC_STONEHEARTH_MARSHAL = 14765, + NPC_EAST_FROSTWOLF_WARMASTER = 14772, + NPC_ICEBLOOD_WARMASTER = 14773, + NPC_TOWER_POINT_WARMASTER = 14776, + NPC_WEST_FROSTWOLF_WARMASTER = 14777 +}; + +enum Events +{ + EVENT_CHARGE_TARGET = 1, + EVENT_CLEAVE = 2, + EVENT_DEMORALIZING_SHOUT = 3, + EVENT_WHIRLWIND = 4, + EVENT_ENRAGE = 5, + EVENT_CHECK_RESET = 6 +}; + +struct npc_av_marshal_or_warmaster : public ScriptedAI +{ + npc_av_marshal_or_warmaster(Creature* creature) : ScriptedAI(creature) { } + + void Reset() override + { + events.Reset(); + events.ScheduleEvent(EVENT_CHARGE_TARGET, 2s, 12s); + events.ScheduleEvent(EVENT_CLEAVE, 1s, 11s); + events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 2s); + events.ScheduleEvent(EVENT_WHIRLWIND, 5s, 20s); + events.ScheduleEvent(EVENT_ENRAGE, 5s, 20s); + events.ScheduleEvent(EVENT_CHECK_RESET, 5s); + } + + void JustAppeared() override + { + Reset(); + } + + 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_CHARGE_TARGET: + DoCastVictim(SPELL_CHARGE); + events.ScheduleEvent(EVENT_CHARGE, 10s, 25s); + break; + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 10s, 16s); + break; + case EVENT_DEMORALIZING_SHOUT: + DoCast(me, SPELL_DEMORALIZING_SHOUT); + events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 10s, 15s); + break; + case EVENT_WHIRLWIND: + DoCast(me, SPELL_WHIRLWIND); + events.ScheduleEvent(EVENT_WHIRLWIND, 10s, 25s); + break; + case EVENT_ENRAGE: + DoCast(me, SPELL_ENRAGE); + events.ScheduleEvent(EVENT_ENRAGE, 10s, 30s); + break; + case EVENT_CHECK_RESET: + { + Position const& _homePosition = me->GetHomePosition(); + if (me->GetDistance2d(_homePosition.GetPositionX(), _homePosition.GetPositionY()) > 50.0f) + { + EnterEvadeMode(); + return; + } + events.ScheduleEvent(EVENT_CHECK_RESET, 5s); + break; + } + } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + } + +private: + EventMap events; +}; + +struct go_av_capturable_object : public GameObjectAI +{ + go_av_capturable_object(GameObject* go) : GameObjectAI(go) { } + + void Reset() override + { + me->setActive(true); + } + + bool OnGossipHello(Player* player) override + { + if (me->GetGoState() != GO_STATE_READY) + return true; + + if (ZoneScript* zonescript = me->GetZoneScript()) + { + zonescript->DoAction(ACTION_AV_INTERACT_CAPTURABLE_OBJECT, player, me); + return false; + } + + return true; + } +}; + +struct go_av_contested_object : public go_av_capturable_object +{ + go_av_contested_object(GameObject* go) : go_av_capturable_object(go) { } + + void Reset() override + { + go_av_capturable_object::Reset(); + _scheduler.Schedule(4min, [&](TaskContext) + { + if (ZoneScript* zonescript = me->GetZoneScript()) + zonescript->DoAction(ACTION_AV_CAPTURE_CAPTURABLE_OBJECT, me, me); + }); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; +}; + +class at_av_exploit : public AreaTriggerScript +{ +public: + at_av_exploit() : AreaTriggerScript("at_av_exploit") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override + { + if (Battleground* battleground = player->GetBattleground()) + if (battleground->GetStatus() == STATUS_WAIT_JOIN) + battleground->TeleportPlayerToExploitLocation(player); + + return true; + } +}; + +template<AlteracValleySharedActions ActionId> +class quest_alterac_valley : public QuestScript +{ +public: + quest_alterac_valley(char const* scriptName) : QuestScript(scriptName) { } + + void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override + { + if (newStatus != QUEST_STATUS_REWARDED) + return; + + if (ZoneScript* zoneScript = player->FindZoneScript()) + zoneScript->DoAction(ActionId, player, player); + } +}; + +void AddSC_alterac_valley() +{ + RegisterCreatureAI(npc_av_marshal_or_warmaster); + RegisterGameObjectAI(go_av_capturable_object); + RegisterGameObjectAI(go_av_contested_object); + new at_av_exploit(); + new quest_alterac_valley<ACTION_TURN_IN_SCRAPS>("quest_alterac_valley_armor_scraps"); + new quest_alterac_valley<ACTION_TURN_IN_COMMANDER_1>("quest_alterac_valley_call_of_air_slidore_guse"); + new quest_alterac_valley<ACTION_TURN_IN_COMMANDER_2>("quest_alterac_valley_call_of_air_vipore_jeztor"); + new quest_alterac_valley<ACTION_TURN_IN_COMMANDER_3>("quest_alterac_valley_call_of_air_ichman_mulverick"); + new quest_alterac_valley<ACTION_TURN_IN_BOSS_1>("quest_alterac_valley_boss_5"); + new quest_alterac_valley<ACTION_TURN_IN_BOSS_2>("quest_alterac_valley_boss_1"); + new quest_alterac_valley<ACTION_TURN_IN_NEAR_MINE>("quest_alterac_valley_near_mine"); + new quest_alterac_valley<ACTION_TURN_IN_OTHER_MINE>("quest_alterac_valley_other_mine"); + new quest_alterac_valley<ACTION_TURN_IN_RIDER_HIDE>("quest_alterac_valley_ram_harnesses"); + new quest_alterac_valley<ACTION_TURN_IN_RIDER_TAME>("quest_alterac_valley_empty_stables"); +} diff --git a/src/server/scripts/Battlegrounds/AlteracValley/alterac_valley.h b/src/server/scripts/Battlegrounds/AlteracValley/alterac_valley.h new file mode 100644 index 00000000000..4bd5dea255a --- /dev/null +++ b/src/server/scripts/Battlegrounds/AlteracValley/alterac_valley.h @@ -0,0 +1,39 @@ +/* + * 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 __ALTERAC_VALLEY_H +#define __ALTERAC_VALLEY_H + +enum AlteracValleySharedActions +{ + ACTION_BUFF_YELL = -30001, + ACTION_AV_INTERACT_CAPTURABLE_OBJECT = 1, + ACTION_AV_CAPTURE_CAPTURABLE_OBJECT = 2, + + ACTION_TURN_IN_SCRAPS = 3, + ACTION_TURN_IN_COMMANDER_1 = 4, + ACTION_TURN_IN_COMMANDER_2 = 5, + ACTION_TURN_IN_COMMANDER_3 = 6, + ACTION_TURN_IN_BOSS_1, + ACTION_TURN_IN_BOSS_2, + ACTION_TURN_IN_NEAR_MINE, + ACTION_TURN_IN_OTHER_MINE, + ACTION_TURN_IN_RIDER_HIDE, + ACTION_TURN_IN_RIDER_TAME +}; + +#endif diff --git a/src/server/scripts/Battlegrounds/AlteracValley/battleground_alterac_valley.cpp b/src/server/scripts/Battlegrounds/AlteracValley/battleground_alterac_valley.cpp new file mode 100644 index 00000000000..1616b77ec1e --- /dev/null +++ b/src/server/scripts/Battlegrounds/AlteracValley/battleground_alterac_valley.cpp @@ -0,0 +1,1369 @@ +/* + * 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 "alterac_valley.h" +#include "Battleground.h" +#include "BattlegroundMgr.h" +#include "BattlegroundPackets.h" +#include "Creature.h" +#include "CreatureAI.h" +#include "GameObject.h" +#include "GameTime.h" +#include "Log.h" +#include "Map.h" +#include "Player.h" +#include "ScriptMgr.h" + +constexpr uint32 BG_AV_SCORE_INITIAL_POINTS = 700; +constexpr uint32 BG_AV_EVENT_START_BATTLE = 9166; // Achievement: The Alterac Blitz + +enum BG_AV_BroadcastTexts +{ + BG_AV_TEXT_START_ONE_MINUTE = 10638, + BG_AV_TEXT_START_HALF_MINUTE = 10639, + BG_AV_TEXT_BATTLE_HAS_BEGUN = 10640, + + BG_AV_TEXT_ALLIANCE_NEAR_LOSE = 23210, + BG_AV_TEXT_HORDE_NEAR_LOSE = 23211 +}; + +enum BG_AV_Sounds +{ + AV_SOUND_NEAR_VICTORY = 8456, /// @todo: Not confirmed yet + + AV_SOUND_ALLIANCE_ASSAULTS = 8212, //tower, grave + enemy boss if someone tries to attack him + AV_SOUND_HORDE_ASSAULTS = 8174, + AV_SOUND_ALLIANCE_GOOD = 8173, //if something good happens for the team: wins(maybe only through killing the boss), captures mine or grave, destroys tower and defends grave + AV_SOUND_HORDE_GOOD = 8213, + AV_SOUND_BOTH_TOWER_DEFEND = 8192, + + AV_SOUND_ALLIANCE_CAPTAIN = 8232, //gets called when someone attacks them and at the beginning after 5min+rand(x)*10sec (maybe buff) + AV_SOUND_HORDE_CAPTAIN = 8333 +}; + +constexpr Seconds BG_AV_MINE_RESOURCE_TIMER = 45s; + +enum class AlteracValleyMine : uint8 +{ + North = 0, + South +}; + +enum BG_AV_CreatureIds +{ + BG_AV_CREATURE_VANNDAR = 11948, + BG_AV_CREATURE_DREKTHAR = 11946, + BG_AV_CREATURE_BALINDA = 11949, + BG_AV_CREATURE_GALVANGAR = 11947, + BG_AV_CREATURE_MORLOCH = 11657, + BG_AV_CREATURE_UMI_THORSON = 13078, + BG_AV_CREATURE_KEETAR = 13079, + BG_AV_CREATURE_TASKMASTER_SNIVVLE = 11677, + BG_AV_CREATURE_AGI_RUMBLESTOMP = 13086, + BG_AV_CREATURE_MASHA_SWIFTCUT = 13088, + BG_AV_CREATURE_HERALD = 14848, + + BG_AV_CREATURE_STORMPIKE_DEFENDER = 12050, + BG_AV_CREATURE_FROSTWOLF_GUARDIAN = 12053, + BG_AV_CREATURE_SEASONED_DEFENDER = 13326, + BG_AV_CREATURE_SEASONED_GUARDIAN = 13328, + BG_AV_CREATURE_VETERAN_DEFENDER = 13331, + BG_AV_CREATURE_VETERAN_GUARDIAN = 13332, + BG_AV_CREATURE_CHAMPION_DEFENDER = 13422, + BG_AV_CREATURE_CHAMPION_GUARDIAN = 13421 +}; + +enum BG_AV_ObjectIds +{ + //cause the mangos-system is a bit different, we don't use the right go-ids for every node.. if we want to be 100% like another big server, we must take one object for every node + //snowfall 4flags as eyecandy 179424 (alliance neutral) + //Banners - stolen from battleground_AB.h ;-) + BG_AV_OBJECTID_BANNER_A = 178925, // can only be used by horde + BG_AV_OBJECTID_BANNER_H = 178943, // can only be used by alliance + BG_AV_OBJECTID_BANNER_CONT_A = 178940, // can only be used by horde + BG_AV_OBJECTID_BANNER_CONT_H = 179435, // can only be used by alliance + + BG_AV_OBJECTID_BANNER_A_B = 178365, + BG_AV_OBJECTID_BANNER_H_B = 178364, + BG_AV_OBJECTID_BANNER_CONT_A_B = 179286, + BG_AV_OBJECTID_BANNER_CONT_H_B = 179287, + BG_AV_OBJECTID_BANNER_SNOWFALL_N = 180418, + + //snowfall eyecandy banner: + BG_AV_OBJECTID_SNOWFALL_CANDY_A = 179044, + BG_AV_OBJECTID_SNOWFALL_CANDY_PA = 179424, + BG_AV_OBJECTID_SNOWFALL_CANDY_H = 179064, + BG_AV_OBJECTID_SNOWFALL_CANDY_PH = 179425, + + //banners on top of towers: + BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG + + //Auras + BG_AV_OBJECTID_AURA_A = 180421, + BG_AV_OBJECTID_AURA_H = 180422, + BG_AV_OBJECTID_AURA_N = 180423, + BG_AV_OBJECTID_AURA_A_S = 180100, + BG_AV_OBJECTID_AURA_H_S = 180101, + BG_AV_OBJECTID_AURA_N_S = 180102, + + BG_AV_OBJECTID_GATE = 180424, + BG_AV_GHOST_GATE = 180322, + + //mine supplies + BG_AV_OBJECTID_MINE_N = 178785, + BG_AV_OBJECTID_MINE_S = 178784, + + BG_AV_OBJECTID_FIRE = 179065, + BG_AV_OBJECTID_SMOKE = 179066, + + // Towers + BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_TOWER_BANNER = 178927, + BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_BANNER = 178925, + BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_BANNER = 179435, + BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_TOWER_BANNER = 179436, + + BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_TOWER_BANNER = 178932, + BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_BANNER = 178929, + BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_BANNER = 179439, + BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_TOWER_BANNER = 179440, + + BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_TOWER_BANNER = 178956, + BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_BANNER = 178944, + BG_AV_OBJECTID_EAST_TOWER_CONTESTED_BANNER = 179449, + BG_AV_OBJECTID_EAST_TOWER_CONTESTED_TOWER_BANNER = 179450, + + BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_TOWER_BANNER = 178955, + BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_BANNER = 178943, + BG_AV_OBJECTID_WEST_TOWER_CONTESTED_BANNER = 179445, + BG_AV_OBJECTID_WEST_TOWER_CONTESTED_TOWER_BANNER = 179446, + + BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_TOWER_BANNER = 178957, + BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_BANNER = 178945, + BG_AV_OBJECTID_TOWER_POINT_CONTESTED_BANNER = 179453, + BG_AV_OBJECTID_TOWER_POINT_CONTESTED_TOWER_BANNER = 179454, + + BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_TOWER_BANNER = 178958, + BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_BANNER = 178946, + BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_BANNER = 178940, + BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_TOWER_BANNER = 179458, + + BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_TOWER_BANNER = 178948, + BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_BANNER = 178936, + BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_BANNER = 179443, + BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_TOWER_BANNER = 179444, + + BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_TOWER_BANNER = 178947, + BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_BANNER = 178935, + BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_BANNER = 179441, + BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_TOWER_BANNER = 179442, + + // Graveyards + BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTROLLED = 179465, + BG_AV_OBJECTID_AID_STATION_HORDE_CONTESTED = 179468, + BG_AV_OBJECTID_AID_STATION_HORDE_CONTROLLED = 179467, + BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTESTED = 179466, + + BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTROLLED = 178389, + BG_AV_OBJECTID_STORMPIKE_HORDE_CONTESTED = 179287, + BG_AV_OBJECTID_STORMPIKE_HORDE_CONTROLLED = 178388, + BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTESTED = 179286, + + BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTESTED = 179310, + BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTROLLED = 179285, + BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTESTED = 179308, + BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTROLLED = 179284, + + BG_AV_OBJECTID_SNOWFALL_NEUTRAL = 180418, + BG_AV_OBJECTID_SNOWFALL_HORDE_CONTESTED = 180420, + BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTESTED = 180419, + BG_AV_OBJECTID_SNOWFALL_HORDE_CONTROLLED = 178364, + BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTROLLED = 178365, + + BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTROLLED = 179483, + BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTESTED = 179482, + BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTROLLED = 179481, + BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTESTED = 179484, + + BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTROLLED = 178393, + BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTESTED = 179304, + BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTROLLED = 178394, + BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTESTED = 179305, + + BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTROLLED = 179472, + BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTESTED = 179471, + BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTROLLED = 179470, + BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTESTED = 179473 +}; + +enum BG_AV_Nodes +{ + BG_AV_NODES_FIRSTAID_STATION = 0, + BG_AV_NODES_STORMPIKE_GRAVE = 1, + BG_AV_NODES_STONEHEART_GRAVE = 2, + BG_AV_NODES_SNOWFALL_GRAVE = 3, + BG_AV_NODES_ICEBLOOD_GRAVE = 4, + BG_AV_NODES_FROSTWOLF_GRAVE = 5, + BG_AV_NODES_FROSTWOLF_HUT = 6, + BG_AV_NODES_DUNBALDAR_SOUTH = 7, + BG_AV_NODES_DUNBALDAR_NORTH = 8, + BG_AV_NODES_ICEWING_BUNKER = 9, + BG_AV_NODES_STONEHEART_BUNKER = 10, + BG_AV_NODES_ICEBLOOD_TOWER = 11, + BG_AV_NODES_TOWER_POINT = 12, + BG_AV_NODES_FROSTWOLF_ETOWER = 13, + BG_AV_NODES_FROSTWOLF_WTOWER = 14, + + BG_AV_NODES_MAX = 15 +}; + +enum BG_AV_BUFF +{ /// @todo: Add all other buffs here + AV_BUFF_ARMOR = 21163, + AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does + AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does +}; +enum BG_AV_States +{ + POINT_NEUTRAL = 0, + POINT_ASSAULTED = 1, + POINT_DESTROYED = 2, + POINT_CONTROLED = 3 +}; + +enum BG_AV_WorldStates +{ + AV_WS_ALLIANCE_REINFORCEMENTS = 3127, + AV_WS_HORDE_REINFORCEMENTS = 3128, + AV_WS_SHOW_HORDE_REINFORCEMENTS = 3133, + AV_WS_SHOW_ALLIANCE_REINFORCEMENTS = 3134, + AV_WS_MAX_REINFORCEMENTS = 3136, + +// Graves + // Alliance + //Stormpike first aid station + AV_WS_STORMPIKE_AID_STATION_ALLIANCE_CONTROLLED = 1325, + AV_WS_STORMPIKE_AID_STATION_IN_CONFLICT_ALLIANCE_ATTACKING = 1326, + AV_WS_STORMPIKE_AID_STATION_HORDE_CONTROLLED = 1327, + AV_WS_STORMPIKE_AID_STATION_IN_CONFLICT_HORDE_ATTACKING = 1328, + //Stormpike Graveyard + AV_WS_STORMPIKE_GRAVEYARD_ALLIANCE_CONTROLLED = 1333, + AV_WS_STORMPIKE_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1335, + AV_WS_STORMPIKE_GRAVEYARD_HORDE_CONTROLLED = 1334, + AV_WS_STORMPIKE_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1336, + //Stoneheart Grave + AV_WS_STONEHEARTH_GRAVEYARD_ALLIANCE_CONTROLLED = 1302, + AV_WS_STONEHEARTH_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1304, + AV_WS_STONEHEARTH_GRAVEYARD_HORDE_CONTROLLED = 1301, + AV_WS_STONEHEARTH_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1303, + //Neutral + //Snowfall Grave + AV_WS_SNOWFALL_GRAVEYARD_UNCONTROLLED = 1966, + AV_WS_SNOWFALL_GRAVEYARD_ALLIANCE_CONTROLLED = 1341, + AV_WS_SNOWFALL_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1343, + AV_WS_SNOWFALL_GRAVEYARD_HORDE_CONTROLLED = 1342, + AV_WS_SNOWFALL_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1344, + //Horde + //Iceblood grave + AV_WS_ICEBLOOD_GRAVEYARD_ALLIANCE_CONTROLLED = 1346, + AV_WS_ICEBLOOD_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1348, + AV_WS_ICEBLOOD_GRAVEYARD_HORDE_CONTROLLED = 1347, + AV_WS_ICEBLOOD_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1349, + //Frostwolf Grave + AV_WS_FROSTWOLF_GRAVEYARD_ALLIANCE_CONTROLLED = 1337, + AV_WS_FROSTWOLF_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1339, + AV_WS_FROSTWOLF_GRAVEYARD_HORDE_CONTROLLED = 1338, + AV_WS_FROSTWOLF_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1340, + //Frostwolf Hut + AV_WS_FROSTWOLF_RELIEF_HUT_ALLIANCE_CONTROLLED = 1329, + AV_WS_FROSTWOLF_RELIEF_HUT_IN_CONFLICT_ALLIANCE_ATTACKING = 1331, + AV_WS_FROSTWOLF_RELIEF_HUT_HORDE_CONTROLLED = 1330, + AV_WS_FROSTWOLF_RELIEF_HUT_IN_CONFLICT_HORDE_ATTACKING = 1332, + +//Towers + //Alliance + //Dunbaldar South Bunker + AV_WS_DUN_BALDAR_SOUTH_BUNKER_OWNER = 1181, + AV_WS_DUN_BALDAR_SOUTH_BUNKER_ALLIANCE_CONTROLLED = 1361, + AV_WS_DUN_BALDAR_SOUTH_BUNKER_DESTROYED = 1370, + AV_WS_DUN_BALDAR_SOUTH_BUNKER_IN_CONFLICT_HORDE_ATTACKING = 1378, + AV_WS_DUN_BALDAR_SOUTH_BUNKER_IN_CONFLICT_ALLIANCE_ATTACKING = 1374, // unused + //Dunbaldar North Bunker + AV_WS_DUN_BALDAR_NORTH_BUNKER_OWNER = 1182, + AV_WS_DUN_BALDAR_NORTH_BUNKER_ALLIANCE_CONTROLLED = 1362, + AV_WS_DUN_BALDAR_NORTH_BUNKER_DESTROYED = 1371, + AV_WS_DUN_BALDAR_NORTH_BUNKER_IN_CONFLICT_HORDE_ATTACKING = 1379, + AV_WS_DUN_BALDAR_NORTH_BUNKER_IN_CONFLICT_ALLIANCE_ATTACKING = 1375, // unused + //Icewing Bunker + AV_WS_ICEWING_BUNKER_OWNER = 1183, + AV_WS_ICEWING_BUNKER_ALLIANCE_CONTROLLED = 1363, + AV_WS_ICEWING_BUNKER_DESTROYED = 1372, + AV_WS_ICEWING_BUNKER_IN_CONFLICT_HORDE_ATTACKING = 1380, + AV_WS_ICEWING_BUNKER_IN_CONFLICT_ALLIANCE_ATTACKING = 1376, // unused + //Stoneheart Bunker + AV_WS_STONEHEARTH_BUNKER_OWNER = 1184, + AV_WS_STONEHEARTH_BUNKER_ALLIANCE_CONTROLLED = 1364, + AV_WS_STONEHEARTH_BUNKER_DESTROYED = 1373, + AV_WS_STONEHEARTH_BUNKER_IN_CONFLICT_HORDE_ATTACKING = 1381, + AV_WS_STONEHEARTH_BUNKER_IN_CONFLICT_ALLIANCE_ATTACKING = 1377, // unused + //Horde + //Iceblood Tower + AV_WS_ICEBLOOD_TOWER_OWNER = 1187, + AV_WS_ICEBLOOD_TOWER_DESTROYED = 1368, + AV_WS_ICEBLOOD_TOWER_HORDE_CONTROLLED = 1385, + AV_WS_ICEBLOOD_TOWER_IN_CONFLICT_ALLIANCE_ATTACKING = 1390, + AV_WS_ICEBLOOD_TOWER_IN_CONFLICT_HORDE_ATTACKING = 1395, // unused + //Tower Point + AV_WS_TOWER_POINT_OWNER = 1188, + AV_WS_TOWER_POINT_DESTROYED = 1367, + AV_WS_TOWER_POINT_HORDE_CONTROLLED = 1384, + AV_WS_TOWER_POINT_IN_CONFLICT_ALLIANCE_ATTACKING = 1389, + AV_WS_TOWER_POINT_IN_CONFLICT_HORDE_ATTACKING = 1394, // unused + //Frostwolf West + AV_WS_WEST_FROSTWOLF_TOWER_OWNER = 1185, + AV_WS_WEST_FROSTWOLF_TOWER_DESTROYED = 1365, + AV_WS_WEST_FROSTWOLF_TOWER_HORDE_CONTROLLED = 1382, + AV_WS_WEST_FROSTWOLF_TOWER_IN_CONFLICT_ALLIANCE_ATTACKING = 1387, + AV_WS_WEST_FROSTWOLF_TOWER_IN_CONFLICT_HORDE_ATTACKING = 1392, // unused + //Frostwolf East + AV_WS_EAST_FROSTWOLF_TOWER_OWNER = 1186, + AV_WS_EAST_FROSTWOLF_TOWER_DESTROYED = 1366, + AV_WS_EAST_FROSTWOLF_TOWER_HORDE_CONTROLLED = 1383, + AV_WS_EAST_FROSTWOLF_TOWER_IN_CONFLICT_ALLIANCE_ATTACKING = 1388, + AV_WS_EAST_FROSTWOLF_TOWER_IN_CONFLICT_HORDE_ATTACKING = 1393, // unused + +//Mines + AV_WS_IRONDEEP_MINE_OWNER = 801, + AV_WS_IRONDEEP_MINE_TROGG_CONTROLLED = 1360, + AV_WS_IRONDEEP_MINE_ALLIANCE_CONTROLLED = 1358, + AV_WS_IRONDEEP_MINE_HORDE_CONTROLLED = 1359, + + AV_WS_COLDTOOTH_MINE_OWNER = 804, + AV_WS_COLDTOOTH_MINE_KOBOLD_CONTROLLED = 1357, + AV_WS_COLDTOOTH_MINE_ALLIANCE_CONTROLLED = 1355, + AV_WS_COLDTOOTH_MINE_HORDE_CONTROLLED = 1356, + +//Turnins + AV_WS_IVUS_STORM_CRYSTAL_COUNT = 1043, + AV_WS_IVUS_STORM_CRYSTAL_MAX = 1044, + AV_WS_LOKHOLAR_STORMPIKE_SOLDIERS_BLOOD_COUNT = 923, + AV_WS_LOKHOLAR_STORMPIKE_SOLDIERS_BLOOD_MAX = 922, + +//Bosses + AV_WS_DREKTHAR_ALIVE = 601, + AV_WS_VANDAAR_ALIVE = 602, + +//Captains + AV_WS_GALVAGAR_ALIVE = 1352, + AV_WS_BALINDA_ALIVE = 1351, +}; + +struct StaticMineInfo +{ + int32 WorldStateOwner; + int32 WorldStateAllianceControlled; + int32 WorldStateHordeControlled; + int32 WorldStateNeutralControlled; + uint8 TextIdAlliance; + uint8 TextIdHorde; +}; + +struct AlteracValleyMineInfo +{ + Team Owner; + + StaticMineInfo StaticInfo; +}; + +struct StaticNodeInfo +{ + BG_AV_Nodes NodeId; + + struct + { + uint8 AllianceCapture; + uint8 AllianceAttack; + uint8 HordeCapture; + uint8 HordeAttack; + } TextIds; + + struct + { + int32 AllianceControl; + int32 AllianceAssault; + int32 HordeControl; + int32 HordeAssault; + int32 Owner; + } WorldStateIds; + + struct + { + std::string AllianceOrDefend; + std::string HordeOrDestroy; + } StringIds; +}; + +static StaticNodeInfo const BGAVNodeInfo[] = +{ + { BG_AV_NODES_FIRSTAID_STATION, { 47, 48, 45, 46 }, { 1325, 1326, 1327, 1328, 0 }, { "bg_av_herald_stormpike_aid_station_alliance", "bg_av_herald_stormpike_aid_station_horde" } }, // Stormpike First Aid Station + { BG_AV_NODES_STORMPIKE_GRAVE, { 1, 2, 3, 4 }, { 1333, 1335, 1334, 1336, 0 }, { "bg_av_herald_stormpike_alliance", "bg_av_herald_stormpike_horde" } }, // Stormpike Graveyard + { BG_AV_NODES_STONEHEART_GRAVE, { 55, 56, 53, 54 }, { 1302, 1304, 1301, 1303, 0 }, { "bg_av_herald_stonehearth_alliance", "bg_av_herald_stonehearth_horde" } }, // Stoneheart Graveyard + { BG_AV_NODES_SNOWFALL_GRAVE, { 5, 6, 7, 8 }, { 1341, 1343, 1342, 1344, 0 }, { "bg_av_herald_snowfall_alliance", "bg_av_herald_snowfall_horde" } }, // Snowfall Graveyard + { BG_AV_NODES_ICEBLOOD_GRAVE, { 59, 60, 57, 58 }, { 1346, 1348, 1347, 1349, 0 }, { "bg_av_herald_iceblood_alliance", "bg_av_herald_iceblood_horde" } }, // Iceblood Graveyard + { BG_AV_NODES_FROSTWOLF_GRAVE, { 9, 10, 11, 12 }, { 1337, 1339, 1338, 1340, 0 }, { "bg_av_herald_frostwolf_alliance", "bg_av_herald_frostwolf_horde" } }, // Frostwolf Graveyard + { BG_AV_NODES_FROSTWOLF_HUT, { 51, 52, 49, 50 }, { 1329, 1331, 1330, 1332, 0 }, { "bg_av_herald_frostwolf_hut_alliance", "bg_av_herald_frostwolf_hut_horde" } }, // Frostwolf Hut + { BG_AV_NODES_DUNBALDAR_SOUTH, { 16, 15, 14, 13 }, { 1361, 1375, 1370, 1378, 1181 }, { "bg_av_herald_south_bunker_defend", "bg_av_herald_south_bunker_attack" } }, // Dunbaldar South Bunker + { BG_AV_NODES_DUNBALDAR_NORTH, { 20, 19, 18, 17 }, { 1362, 1374, 1371, 1379, 1182 }, { "bg_av_herald_north_bunker_defend", "bg_av_herald_south_bunker_attack" } }, // Dunbaldar North Bunker + { BG_AV_NODES_ICEWING_BUNKER, { 24, 23, 22, 21 }, { 1363, 1376, 1372, 1380, 1183 }, { "bg_av_herald_icewing_bunker_defend", "bg_av_herald_icewing_bunker_attack" } }, // Icewing Bunker + { BG_AV_NODES_STONEHEART_BUNKER, { 28, 27, 26, 25 }, { 1364, 1377, 1373, 1381, 1184 }, { "bg_av_herald_stonehearth_bunker_defend", "bg_av_herald_stonehearth_bunker_attack" } }, // Stoneheart Bunker + { BG_AV_NODES_ICEBLOOD_TOWER, { 44, 43, 42, 41 }, { 1368, 1390, 1385, 1395, 1188 }, { "bg_av_herald_iceblood_tower_defend", "bg_av_herald_iceblood_tower_attack" } }, // Iceblood Tower + { BG_AV_NODES_TOWER_POINT, { 40, 39, 38, 37 }, { 1367, 1389, 1384, 1394, 1187 }, { "bg_av_herald_tower_point_defend", "bg_av_herald_tower_point_attack" } }, // Tower Point + { BG_AV_NODES_FROSTWOLF_ETOWER, { 36, 35, 34, 33 }, { 1366, 1388, 1383, 1393, 1186 }, { "bg_av_herald_east_tower_defend", "bg_av_herald_east_tower_attack" } }, // Frostwolf East Tower + { BG_AV_NODES_FROSTWOLF_WTOWER, { 32, 31, 30, 29 }, { 1365, 1387, 1382, 1392, 1185 }, { "bg_av_herald_west_tower_defend", "bg_av_herald_west_tower_attack" } }, // Frostwolf West Tower +}; + +enum Texts +{ + // Herold + // Towers/Graveyards = 1 - 60 + TEXT_COLDTOOTH_MINE_ALLIANCE_TAKEN = 61, + TEXT_IRONDEEP_MINE_ALLIANCE_TAKEN = 62, + TEXT_COLDTOOTH_MINE_HORDE_TAKEN = 63, + TEXT_IRONDEEP_MINE_HORDE_TAKEN = 64, + TEXT_FROSTWOLF_GENERAL_DEAD = 65, /// @todo: sound is missing + TEXT_STORMPIKE_GENERAL_DEAD = 66, /// @todo: sound is missing + TEXT_ALLIANCE_WINS = 67, // NYI /// @todo: sound is missing + TEXT_HORDE_WINS = 68, // NYI /// @todo: sound is missing + + // Taskmaster Snivvle + TEXT_SNIVVLE_RANDOM = 0 +}; + +enum BG_AV_ExploitTeleportLocations +{ + AV_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3664, + AV_EXPLOIT_TELEPORT_LOCATION_HORDE = 3665 +}; + +struct BG_AV_NodeInfo +{ + BG_AV_States State; + BG_AV_States PrevState; + uint16 TotalOwner; + Team Owner; + uint16 PrevOwner; + bool Tower; +}; + +inline BG_AV_Nodes& operator++(BG_AV_Nodes& i) { return i = BG_AV_Nodes(i + 1); } + +struct battleground_alterac_valley : BattlegroundScript +{ + enum QuestIds + { + AV_QUEST_A_SCRAPS1 = 7223, + AV_QUEST_A_SCRAPS2 = 6781, + AV_QUEST_H_SCRAPS1 = 7224, + AV_QUEST_H_SCRAPS2 = 6741, + AV_QUEST_A_COMMANDER1 = 6942, //soldier + AV_QUEST_H_COMMANDER1 = 6825, + AV_QUEST_A_COMMANDER2 = 6941, //leutnant + AV_QUEST_H_COMMANDER2 = 6826, + AV_QUEST_A_COMMANDER3 = 6943, //commander + AV_QUEST_H_COMMANDER3 = 6827, + AV_QUEST_A_BOSS1 = 7386, // 5 cristal/blood + AV_QUEST_H_BOSS1 = 7385, + AV_QUEST_A_BOSS2 = 6881, // 1 + AV_QUEST_H_BOSS2 = 6801, + AV_QUEST_A_NEAR_MINE = 5892, //the mine near start location of team + AV_QUEST_H_NEAR_MINE = 5893, + AV_QUEST_A_OTHER_MINE = 6982, //the other mine ;) + AV_QUEST_H_OTHER_MINE = 6985, + AV_QUEST_A_RIDER_HIDE = 7026, + AV_QUEST_H_RIDER_HIDE = 7002, + AV_QUEST_A_RIDER_TAME = 7027, + AV_QUEST_H_RIDER_TAME = 7001 + }; + + enum Data : uint32 + { + DATA_DEFENDER_TIER_HORDE = 1, + DATA_DEFENDER_TIER_ALLIANCE = 2, + }; + + enum DefenderTier : uint32 + { + BG_AV_DEFENDER_TIER_DEFENDER, + BG_AV_DEFENDER_TIER_SEASONED, + BG_AV_DEFENDER_TIER_VETERAN, + BG_AV_DEFENDER_TIER_CHAMPION + }; + + enum PvpStats + { + PVP_STAT_TOWERS_ASSAULTED = 61, + PVP_STAT_GRAVEYARDS_ASSAULTED = 63, + PVP_STAT_TOWERS_DEFENDED = 64, + PVP_STAT_GRAVEYARDS_DEFENDED = 65, + PVP_STAT_SECONDARY_OBJECTIVES = 82 + }; + + enum Misc + { + NEAR_LOSE_POINTS = 140 + }; + + enum HonorKillBonus + { + HONOR_KILL_BONUS_BOSS = 4, + HONOR_KILL_BONUS_CAPTAIN = 3, + HONOR_KILL_BONUS_SURVIVING_TOWER = 2, + HONOR_KILL_BONUS_SURVIVING_CAPTAIN = 2, + HONOR_KILL_BONUS_DESTROY_TOWER = 3 + }; + + enum ReputationGains + { + REP_GAIN_BOSS = 350, + REP_GAIN_CAPTAIN = 125, + REP_GAIN_DESTROY_TOWER = 12, + REP_GAIN_SURVIVING_TOWER = 12, + REP_GAIN_SURVIVING_CAPTAIN = 125 + }; + + enum ResourceLoss + { + RESOURCE_LOSS_TOWER = -75, + RESOURCE_LOSS_CAPTAIN = -100 + }; + + enum Spells + { + SPELL_COMPLETE_ALTERAC_VALLEY_QUEST = 23658, + }; + + enum Factions + { + FACTION_FROSTWOLF_CLAN = 729, + FACTION_STORMPIKE_GUARD = 730, + }; + + explicit battleground_alterac_valley(BattlegroundMap* map) : BattlegroundScript(map) + { + _teamResources = { BG_AV_SCORE_INITIAL_POINTS, BG_AV_SCORE_INITIAL_POINTS }; + _isInformedNearVictory = { false, false }; + + for (uint8 i = 0; i < 2; i++) //forloop for both teams (it just make 0 == alliance and 1 == horde also for both mines 0=north 1=south + { + for (uint8 j = 0; j < 9; j++) + _teamQuestStatus[i][j] = 0; + + _captainBuffTimer[i].Reset(120000 + urand(0, 4) * 60); //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes @todo get the right times + } + + _mineInfo[uint8(AlteracValleyMine::North)] = { TEAM_OTHER, { AV_WS_IRONDEEP_MINE_OWNER, AV_WS_IRONDEEP_MINE_ALLIANCE_CONTROLLED, AV_WS_IRONDEEP_MINE_HORDE_CONTROLLED, AV_WS_IRONDEEP_MINE_TROGG_CONTROLLED, TEXT_IRONDEEP_MINE_ALLIANCE_TAKEN, TEXT_IRONDEEP_MINE_HORDE_TAKEN } }; + _mineInfo[uint8(AlteracValleyMine::South)] = { TEAM_OTHER, { AV_WS_COLDTOOTH_MINE_OWNER, AV_WS_COLDTOOTH_MINE_ALLIANCE_CONTROLLED, AV_WS_COLDTOOTH_MINE_HORDE_CONTROLLED, AV_WS_COLDTOOTH_MINE_KOBOLD_CONTROLLED, TEXT_COLDTOOTH_MINE_ALLIANCE_TAKEN, TEXT_COLDTOOTH_MINE_HORDE_TAKEN } }; + + for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_STONEHEART_GRAVE; ++i) //alliance graves + InitNode(i, ALLIANCE, false); + for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) //alliance towers + InitNode(i, ALLIANCE, true); + for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_GRAVE; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) //horde graves + InitNode(i, HORDE, false); + for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) //horde towers + InitNode(i, HORDE, true); + InitNode(BG_AV_NODES_SNOWFALL_GRAVE, TEAM_OTHER, false); //give snowfall neutral owner + + _mineResourceTimer.Reset(BG_AV_MINE_RESOURCE_TIMER); + } + + void OnUpdate(uint32 diff) override + { + if (battleground->GetStatus() != STATUS_IN_PROGRESS) + return; + + _mineResourceTimer.Update(diff); + if (_mineResourceTimer.Passed()) + { + for (AlteracValleyMineInfo const& info : _mineInfo) + { + if (info.Owner == TEAM_OTHER) + continue; + + UpdateScore(info.Owner, 1); + } + + _mineResourceTimer.Reset(BG_AV_MINE_RESOURCE_TIMER); + } + + for (uint8 i = TEAM_ALLIANCE; i <= TEAM_HORDE; i++) + { + if (!IsCaptainAlive(TeamId(i))) + continue; + + _captainBuffTimer[i].Update(diff); + if (_captainBuffTimer[i].Passed()) + { + if (i == 0) + { + battleground->CastSpellOnTeam(AV_BUFF_A_CAPTAIN, ALLIANCE); + if (Creature const* creature = battlegroundMap->GetCreature(_balindaGUID)) + creature->AI()->DoAction(ACTION_BUFF_YELL); + } + else + { + battleground->CastSpellOnTeam(AV_BUFF_H_CAPTAIN, HORDE); + if (Creature const* creature = battlegroundMap->GetCreature(_galvangarGUID)) + creature->AI()->DoAction(ACTION_BUFF_YELL); + } + + _captainBuffTimer[i].Reset(120000 + urand(0, 4) * 60000); //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes @todo get the right times + } + } + } + + void OnPlayerKilled(Player* victim, Player* /*killer*/) override + { + UpdateScore(battleground->GetPlayerTeam(victim->GetGUID()), -1); + } + + void OnUnitKilled(Creature* victim, Unit* killer) override + { + switch (victim->GetEntry()) + { + case BG_AV_CREATURE_VANNDAR: + { + UpdateWorldState(AV_WS_VANDAAR_ALIVE, 0); + battleground->CastSpellOnTeam(SPELL_COMPLETE_ALTERAC_VALLEY_QUEST, HORDE); //this is a spell which finishes a quest where a player has to kill the boss + battleground->RewardReputationToTeam(FACTION_FROSTWOLF_CLAN, REP_GAIN_BOSS, HORDE); + battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(HONOR_KILL_BONUS_BOSS), HORDE); + battleground->EndBattleground(HORDE); + break; + } + case BG_AV_CREATURE_DREKTHAR: + { + UpdateWorldState(AV_WS_DREKTHAR_ALIVE, 0); + battleground->CastSpellOnTeam(SPELL_COMPLETE_ALTERAC_VALLEY_QUEST, ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss + battleground->RewardReputationToTeam(FACTION_STORMPIKE_GUARD, REP_GAIN_BOSS, ALLIANCE); + battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(HONOR_KILL_BONUS_BOSS), ALLIANCE); + battleground->EndBattleground(ALLIANCE); + break; + } + case BG_AV_CREATURE_BALINDA: + { + UpdateWorldState(AV_WS_BALINDA_ALIVE, 0); + battleground->RewardReputationToTeam(FACTION_FROSTWOLF_CLAN, REP_GAIN_CAPTAIN, HORDE); + battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(HONOR_KILL_BONUS_CAPTAIN), HORDE); + UpdateScore(ALLIANCE, RESOURCE_LOSS_CAPTAIN); + if (Creature const* herald = FindHerald("bg_av_herald_horde_win")) + herald->AI()->Talk(TEXT_STORMPIKE_GENERAL_DEAD); + break; + } + case BG_AV_CREATURE_GALVANGAR: + { + UpdateWorldState(AV_WS_GALVAGAR_ALIVE, 0); + battleground->RewardReputationToTeam(FACTION_STORMPIKE_GUARD, REP_GAIN_CAPTAIN, ALLIANCE); + battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(HONOR_KILL_BONUS_CAPTAIN), ALLIANCE); + UpdateScore(HORDE, RESOURCE_LOSS_CAPTAIN); + if (Creature const* herald = FindHerald("bg_av_herald_alliance_win")) + herald->AI()->Talk(TEXT_FROSTWOLF_GENERAL_DEAD); + break; + } + case BG_AV_CREATURE_MORLOCH: + { + // if mine is not owned by morloch, then nothing happens + if (_mineInfo[uint8(AlteracValleyMine::North)].Owner != TEAM_OTHER) + break; + + Team const killerTeam = battleground->GetPlayerTeam(Coalesce<Unit>(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), killer)->GetGUID()); + ChangeMineOwner(AlteracValleyMine::North, killerTeam); + break; + } + case BG_AV_CREATURE_TASKMASTER_SNIVVLE: + { + if (_mineInfo[uint8(AlteracValleyMine::South)].Owner != TEAM_OTHER) + break; + + Team const killerTeam = battleground->GetPlayerTeam(Coalesce<Unit>(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), killer)->GetGUID()); + ChangeMineOwner(AlteracValleyMine::South, killerTeam); + break; + } + case BG_AV_CREATURE_UMI_THORSON: + case BG_AV_CREATURE_KEETAR: + { + Team const killerTeam = battleground->GetPlayerTeam(Coalesce<Unit>(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), killer)->GetGUID()); + ChangeMineOwner(AlteracValleyMine::North, killerTeam); + break; + } + case BG_AV_CREATURE_AGI_RUMBLESTOMP: + case BG_AV_CREATURE_MASHA_SWIFTCUT: + { + Team const killerTeam = battleground->GetPlayerTeam(Coalesce<Unit>(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), killer)->GetGUID()); + ChangeMineOwner(AlteracValleyMine::South, killerTeam); + break; + } + } + } + + bool IsCaptainAlive(TeamId teamId) const + { + if (teamId == TEAM_HORDE) + return battlegroundMap->GetWorldStateValue(AV_WS_GALVAGAR_ALIVE) == 1; + + if (teamId == TEAM_ALLIANCE) + return battlegroundMap->GetWorldStateValue(AV_WS_BALINDA_ALIVE) == 1; + + return false; + } + + void OnStart() override + { + UpdateWorldState(AV_WS_SHOW_HORDE_REINFORCEMENTS, 1); + UpdateWorldState(AV_WS_SHOW_ALLIANCE_REINFORCEMENTS, 1); + + // Achievement: The Alterac Blitz + TriggerGameEvent(BG_AV_EVENT_START_BATTLE); + + for (ObjectGuid const& guid : _doorGUIDs) + { + if (GameObject* gameObject = battlegroundMap->GetGameObject(guid)) + { + gameObject->UseDoorOrButton(); + Seconds delay = gameObject->GetEntry() == BG_AV_GHOST_GATE ? 0s : 3s; + gameObject->DespawnOrUnsummon(delay); + } + } + } + + void OnEnd(Team winner) override + { + BattlegroundScript::OnEnd(winner); + //calculate bonuskills for both teams: + //first towers: + std::array<uint8, PVP_TEAMS_COUNT> kills = { 0, 0 }; + std::array<uint8, PVP_TEAMS_COUNT> rep = { 0, 0 }; + + for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) + { + if (_nodes[i].State == POINT_CONTROLED) + { + if (_nodes[i].Owner == ALLIANCE) + { + rep[TEAM_ALLIANCE] += REP_GAIN_SURVIVING_TOWER; + kills[TEAM_ALLIANCE] += HONOR_KILL_BONUS_SURVIVING_TOWER; + } + else + { + rep[TEAM_HORDE] += REP_GAIN_SURVIVING_TOWER; + kills[TEAM_HORDE] += HONOR_KILL_BONUS_SURVIVING_TOWER; + } + } + } + + for (uint8 i = TEAM_ALLIANCE; i <= TEAM_HORDE; ++i) + { + if (IsCaptainAlive(TeamId(i))) + { + kills[i] += HONOR_KILL_BONUS_SURVIVING_CAPTAIN; + rep[i] += REP_GAIN_SURVIVING_CAPTAIN; + } + if (rep[i] != 0) + battleground->RewardReputationToTeam(i == 0 ? FACTION_STORMPIKE_GUARD : FACTION_FROSTWOLF_CLAN, rep[i], i == 0 ? ALLIANCE : HORDE); + if (kills[i] != 0) + battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(kills[i]), i == 0 ? ALLIANCE : HORDE); + } + } + + void OnPlayerLeft(Player* player) override + { + BattlegroundScript::OnPlayerLeft(player); + if (!player) + return; + + player->RemoveAurasDueToSpell(AV_BUFF_ARMOR); + } + + void EventPlayerDestroyedPoint(GameObject* gameobject) + { + if (!gameobject) + return; + + BG_AV_Nodes const node = GetNodeThroughObject(gameobject->GetEntry()); + DestroyNode(node); + UpdateNodeWorldState(node); + + Team const owner = _nodes[node].Owner; + if (IsTower(node)) + { + UpdateScore((owner == ALLIANCE) ? HORDE : ALLIANCE, RESOURCE_LOSS_TOWER); + battleground->RewardReputationToTeam(owner == ALLIANCE ? FACTION_STORMPIKE_GUARD : FACTION_FROSTWOLF_CLAN, REP_GAIN_DESTROY_TOWER, owner); + battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(HONOR_KILL_BONUS_DESTROY_TOWER), owner); + } + + if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node)) + if (Creature const* herald = FindHerald(nodeInfo->StringIds.HordeOrDestroy)) + herald->AI()->Talk(owner == ALLIANCE ? nodeInfo->TextIds.AllianceCapture : nodeInfo->TextIds.HordeCapture); + + battlegroundMap->UpdateSpawnGroupConditions(); + } + + void DoAction(uint32 actionId, WorldObject* source, WorldObject* target) override + { + Team const team = battleground->GetPlayerTeam(source->GetGUID()); + TeamId const teamIndex = Battleground::GetTeamIndexByTeamId(team); + + switch (actionId) + { + case ACTION_AV_CAPTURE_CAPTURABLE_OBJECT: + EventPlayerDestroyedPoint(source->ToGameObject()); + break; + case ACTION_AV_INTERACT_CAPTURABLE_OBJECT: + if (target && source && source->IsPlayer()) + HandleInteractCapturableObject(source->ToPlayer(), target->ToGameObject()); + break; + case ACTION_TURN_IN_SCRAPS: + _teamQuestStatus[teamIndex][0] += 20; + break; + case ACTION_TURN_IN_COMMANDER_1: + _teamQuestStatus[teamIndex][1]++; + battleground->RewardReputationToTeam(teamIndex, 1, team); + if (_teamQuestStatus[teamIndex][1] == 30) + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here", actionId); + break; + case ACTION_TURN_IN_COMMANDER_2: + _teamQuestStatus[teamIndex][2]++; + battleground->RewardReputationToTeam(teamIndex, 1, team); + if (_teamQuestStatus[teamIndex][2] == 60) + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here", actionId); + break; + case ACTION_TURN_IN_COMMANDER_3: + _teamQuestStatus[teamIndex][3]++; + battleground->RewardReputationToTeam(teamIndex, 1, team); + if (_teamQuestStatus[teamIndex][3] == 120) + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here", actionId); + break; + case ACTION_TURN_IN_BOSS_1: + _teamQuestStatus[teamIndex][4] += 4; //you can turn in 5 or 1 item.. + [[fallthrough]]; + case ACTION_TURN_IN_BOSS_2: + _teamQuestStatus[teamIndex][4]++; + if (_teamQuestStatus[teamIndex][4] >= 200) + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here", actionId); + UpdateWorldState(teamIndex == TEAM_ALLIANCE ? AV_WS_IVUS_STORM_CRYSTAL_COUNT : AV_WS_LOKHOLAR_STORMPIKE_SOLDIERS_BLOOD_COUNT, _teamQuestStatus[teamIndex][4]); + break; + case ACTION_TURN_IN_NEAR_MINE: + _teamQuestStatus[teamIndex][5]++; + if (_teamQuestStatus[teamIndex][5] == 28) + { + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here", actionId); + if (_teamQuestStatus[teamIndex][6] == 7) + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here - ground assault ready", actionId); + } + break; + case ACTION_TURN_IN_OTHER_MINE: + _teamQuestStatus[teamIndex][6]++; + if (_teamQuestStatus[teamIndex][6] == 7) + { + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here", actionId); + if (_teamQuestStatus[teamIndex][5] == 20) + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here - ground assault ready", actionId); + } + break; + case ACTION_TURN_IN_RIDER_HIDE: + _teamQuestStatus[teamIndex][7]++; + if (_teamQuestStatus[teamIndex][7] == 25) + { + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here", actionId); + if (_teamQuestStatus[teamIndex][8] == 25) + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here - rider assault ready", actionId); + } + break; + case ACTION_TURN_IN_RIDER_TAME: + _teamQuestStatus[teamIndex][8]++; + if (_teamQuestStatus[teamIndex][8] == 25) + { + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here", actionId); + if (_teamQuestStatus[teamIndex][7] == 25) + TC_LOG_DEBUG("bg.battleground", "BG_AV action {} completed (need to implement some events here - rider assault ready", actionId); + } + break; + default: + TC_LOG_ERROR("bg.battleground", "BattlegroundAV::DoAction: {}. Unhandled action.", actionId); + break; + } + } + + void ChangeMineOwner(AlteracValleyMine mine, Team team, bool initial = false) + { + if (team != ALLIANCE && team != HORDE) + team = TEAM_OTHER; + + AlteracValleyMineInfo& mineInfo = _mineInfo[uint8(mine)]; + + if (mineInfo.Owner == team && !initial) + return; + + mineInfo.Owner = team; + + SendMineWorldStates(mine); + + uint8 const textId = team == ALLIANCE ? mineInfo.StaticInfo.TextIdAlliance : mineInfo.StaticInfo.TextIdHorde; + + std::string const stringId = team == ALLIANCE ? "bg_av_herald_mine_alliance" : "bg_av_herald_mine_horde"; + + if (Creature const* herald = FindHerald(stringId)) + herald->AI()->Talk(textId); + } + + static BG_AV_Nodes GetNodeThroughObject(uint32 object) + { + switch (object) + { + case BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_AID_STATION_HORDE_CONTESTED: + case BG_AV_OBJECTID_AID_STATION_HORDE_CONTROLLED: + case BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTESTED: + return BG_AV_NODES_FIRSTAID_STATION; + case BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_STORMPIKE_HORDE_CONTESTED: + case BG_AV_OBJECTID_STORMPIKE_HORDE_CONTROLLED: + case BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTESTED: + return BG_AV_NODES_STORMPIKE_GRAVE; + case BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTESTED: + case BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTROLLED: + case BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTROLLED: + return BG_AV_NODES_STONEHEART_GRAVE; + case BG_AV_OBJECTID_SNOWFALL_NEUTRAL: + case BG_AV_OBJECTID_SNOWFALL_HORDE_CONTESTED: + case BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_SNOWFALL_HORDE_CONTROLLED: + case BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTROLLED: + return BG_AV_NODES_SNOWFALL_GRAVE; + case BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTROLLED: + case BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTESTED: + return BG_AV_NODES_ICEBLOOD_GRAVE; + case BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTROLLED: + case BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTESTED: + return BG_AV_NODES_FROSTWOLF_GRAVE; + case BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTROLLED: + case BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTESTED: + return BG_AV_NODES_FROSTWOLF_HUT; + case BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_TOWER_BANNER: + case BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_BANNER: + case BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_TOWER_BANNER: + return BG_AV_NODES_DUNBALDAR_SOUTH; + case BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_TOWER_BANNER: + case BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_BANNER: + case BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_TOWER_BANNER: + return BG_AV_NODES_DUNBALDAR_NORTH; + case BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_TOWER_BANNER: + case BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_EAST_TOWER_CONTESTED_BANNER: + case BG_AV_OBJECTID_EAST_TOWER_CONTESTED_TOWER_BANNER: + return BG_AV_NODES_FROSTWOLF_ETOWER; + case BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_TOWER_BANNER: + case BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_WEST_TOWER_CONTESTED_BANNER: + case BG_AV_OBJECTID_WEST_TOWER_CONTESTED_TOWER_BANNER: + return BG_AV_NODES_FROSTWOLF_WTOWER; + case BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_TOWER_BANNER: + case BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_BANNER: + case BG_AV_OBJECTID_TOWER_POINT_CONTESTED_BANNER: + case BG_AV_OBJECTID_TOWER_POINT_CONTESTED_TOWER_BANNER: + return BG_AV_NODES_TOWER_POINT; + case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_TOWER_BANNER: + case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_BANNER: + case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_TOWER_BANNER: + return BG_AV_NODES_ICEBLOOD_TOWER; + case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_TOWER_BANNER: + case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_BANNER: + case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_TOWER_BANNER: + return BG_AV_NODES_STONEHEART_BUNKER; + case BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_TOWER_BANNER: + case BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_BANNER: + case BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_TOWER_BANNER: + return BG_AV_NODES_ICEWING_BUNKER; + default: + TC_LOG_ERROR("bg.battleground", "BattlegroundAV: ERROR! GetPlace got a wrong object :("); + ABORT(); + return BG_AV_Nodes(0); + } + } + + void HandleInteractCapturableObject(Player* player, GameObject* target) + { + if (!player || !target) + return; + + switch (target->GetEntry()) + { + // graveyards + case BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_AID_STATION_HORDE_CONTROLLED: + case BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTROLLED: + case BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTROLLED: + case BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTROLLED: + case BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTROLLED: + case BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_STORMPIKE_HORDE_CONTROLLED: + // Snowfall + case BG_AV_OBJECTID_SNOWFALL_NEUTRAL: + case BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTROLLED: + case BG_AV_OBJECTID_SNOWFALL_HORDE_CONTROLLED: + // towers + case BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_BANNER: + case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_BANNER: + case BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_BANNER: + EventPlayerAssaultsPoint(player, target->GetEntry()); + break; + // graveyards + case BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_AID_STATION_HORDE_CONTESTED: + case BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTESTED: + case BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTESTED: + case BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTESTED: + case BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTESTED: + case BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_STORMPIKE_HORDE_CONTESTED: + // towers + case BG_AV_OBJECTID_EAST_TOWER_CONTESTED_BANNER: + case BG_AV_OBJECTID_WEST_TOWER_CONTESTED_BANNER: + case BG_AV_OBJECTID_TOWER_POINT_CONTESTED_BANNER: + case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_BANNER: + case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_BANNER: + case BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_BANNER: + case BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_BANNER: + case BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_BANNER: + EventPlayerDefendsPoint(player, target->GetEntry()); + break; + // Snowfall special cases (either defend/assault) + case BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTESTED: + case BG_AV_OBJECTID_SNOWFALL_HORDE_CONTESTED: + { + BG_AV_Nodes const node = GetNodeThroughObject(target->GetEntry()); + if (_nodes[node].TotalOwner == TEAM_OTHER) + EventPlayerAssaultsPoint(player, target->GetEntry()); + else + EventPlayerDefendsPoint(player, target->GetEntry()); + break; + } + default: + break; + } + } + + void EventPlayerDefendsPoint(Player* player, uint32 object) + { + BG_AV_Nodes node = GetNodeThroughObject(object); + + Team const owner = _nodes[node].Owner; + Team const team = battleground->GetPlayerTeam(player->GetGUID()); + + if (owner == team || _nodes[node].State != POINT_ASSAULTED) + return; + + TC_LOG_DEBUG("bg.battleground", "player defends point object: {} node: {}", object, node); + if (_nodes[node].PrevOwner != team) + { + TC_LOG_ERROR("bg.battleground", "BG_AV: player defends point which doesn't belong to his team {}", node); + return; + } + + DefendNode(node, team); + UpdateNodeWorldState(node); + + if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node)) + { + std::string stringId; + + if (IsTower(node)) + stringId = nodeInfo->StringIds.AllianceOrDefend; + else + stringId = team == ALLIANCE ? nodeInfo->StringIds.AllianceOrDefend : nodeInfo->StringIds.HordeOrDestroy; + + if (Creature const* herald = FindHerald(stringId)) + herald->AI()->Talk(team == ALLIANCE ? nodeInfo->TextIds.AllianceCapture : nodeInfo->TextIds.HordeCapture); + } + + // update the statistic for the defending player + battleground->UpdatePvpStat(player, IsTower(node) ? PVP_STAT_TOWERS_DEFENDED : PVP_STAT_GRAVEYARDS_DEFENDED, 1); + battlegroundMap->UpdateSpawnGroupConditions(); + } + + void EventPlayerAssaultsPoint(Player* player, uint32 object) + { + BG_AV_Nodes node = GetNodeThroughObject(object); + Team const owner = _nodes[node].Owner; //maybe name it prevowner + Team const team = battleground->GetPlayerTeam(player->GetGUID()); + + TC_LOG_DEBUG("bg.battleground", "bg_av: player assaults point object {} node {}", object, node); + if (owner == team || team == _nodes[node].TotalOwner) + return; //surely a gm used this object + + AssaultNode(node, team); + UpdateNodeWorldState(node); + + if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node)) + { + std::string stringId; + if (IsTower(node)) + stringId = nodeInfo->StringIds.HordeOrDestroy; + else + stringId = team == ALLIANCE ? nodeInfo->StringIds.AllianceOrDefend : nodeInfo->StringIds.HordeOrDestroy; + + if (Creature const* herald = FindHerald(stringId)) + herald->AI()->Talk(team == ALLIANCE ? nodeInfo->TextIds.AllianceAttack : nodeInfo->TextIds.HordeAttack); + } + + // update the statistic for the assaulting player + battleground->UpdatePvpStat(player, (IsTower(node)) ? PVP_STAT_TOWERS_ASSAULTED : PVP_STAT_GRAVEYARDS_ASSAULTED, 1); + battlegroundMap->UpdateSpawnGroupConditions(); + } + + void UpdateNodeWorldState(BG_AV_Nodes node) const + { + if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node)) + { + uint16 const owner = _nodes[node].Owner; + BG_AV_States const state = _nodes[node].State; + + UpdateWorldState(nodeInfo->WorldStateIds.AllianceAssault, owner == ALLIANCE && state == POINT_ASSAULTED); + UpdateWorldState(nodeInfo->WorldStateIds.AllianceControl, owner == ALLIANCE && state >= POINT_DESTROYED); + UpdateWorldState(nodeInfo->WorldStateIds.HordeAssault, owner == HORDE && state == POINT_ASSAULTED); + UpdateWorldState(nodeInfo->WorldStateIds.HordeControl, owner == HORDE && state >= POINT_DESTROYED); + if (nodeInfo->WorldStateIds.Owner) + UpdateWorldState(nodeInfo->WorldStateIds.Owner, owner == HORDE ? 2 : owner == ALLIANCE ? 1 : 0); + } + + if (node == BG_AV_NODES_SNOWFALL_GRAVE) + UpdateWorldState(AV_WS_SNOWFALL_GRAVEYARD_UNCONTROLLED, _nodes[node].Owner == TEAM_OTHER); + } + + void SendMineWorldStates(AlteracValleyMine mine) const + { + AlteracValleyMineInfo const& mineInfo = _mineInfo[uint8(mine)]; + UpdateWorldState(mineInfo.StaticInfo.WorldStateHordeControlled, mineInfo.Owner == HORDE); + UpdateWorldState(mineInfo.StaticInfo.WorldStateAllianceControlled, mineInfo.Owner == ALLIANCE); + UpdateWorldState(mineInfo.StaticInfo.WorldStateNeutralControlled, mineInfo.Owner == TEAM_OTHER); + UpdateWorldState(mineInfo.StaticInfo.WorldStateOwner, mineInfo.Owner == HORDE ? 2 : mineInfo.Owner == ALLIANCE ? 1 : 0); + } + + void AssaultNode(BG_AV_Nodes node, Team team) + { + _nodes[node].PrevOwner = _nodes[node].Owner; + _nodes[node].Owner = team; + _nodes[node].PrevState = _nodes[node].State; + _nodes[node].State = POINT_ASSAULTED; + } + + void DestroyNode(BG_AV_Nodes node) + { + _nodes[node].TotalOwner = _nodes[node].Owner; + _nodes[node].PrevOwner = _nodes[node].Owner; + _nodes[node].PrevState = _nodes[node].State; + _nodes[node].State = (_nodes[node].Tower) ? POINT_DESTROYED : POINT_CONTROLED; + } + + void InitNode(BG_AV_Nodes node, Team team, bool tower) + { + _nodes[node].TotalOwner = team; + _nodes[node].Owner = team; + _nodes[node].PrevOwner = 0; + _nodes[node].State = POINT_CONTROLED; + _nodes[node].PrevState = _nodes[node].State; + _nodes[node].State = POINT_CONTROLED; + _nodes[node].Tower = tower; + } + + void DefendNode(BG_AV_Nodes node, Team team) + { + _nodes[node].PrevOwner = _nodes[node].Owner; + _nodes[node].Owner = team; + _nodes[node].PrevState = _nodes[node].State; + _nodes[node].State = POINT_CONTROLED; + } + + Team GetPrematureWinner() override + { + uint32 const allianceScore = _teamResources[Battleground::GetTeamIndexByTeamId(ALLIANCE)]; + uint32 const hordeScore = _teamResources[Battleground::GetTeamIndexByTeamId(HORDE)]; + + if (allianceScore > hordeScore) + return ALLIANCE; + if (hordeScore > allianceScore) + return HORDE; + + return BattlegroundScript::GetPrematureWinner(); + } + + void OnGameObjectCreate(GameObject* gameObject) override + { + switch (gameObject->GetEntry()) + { + case BG_AV_GHOST_GATE: + case BG_AV_OBJECTID_GATE: + _doorGUIDs.insert(gameObject->GetGUID()); + break; + default: + break; + } + } + + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case BG_AV_CREATURE_GALVANGAR: + _galvangarGUID = creature->GetGUID(); + break; + case BG_AV_CREATURE_BALINDA: + _balindaGUID = creature->GetGUID(); + break; + case BG_AV_CREATURE_HERALD: + _heraldGUIDs.insert(creature->GetGUID()); + break; + default: + break; + } + } + + uint32 GetData(uint32 dataId) const override + { + auto getDefenderTierForTeam = [&](TeamId teamId) -> DefenderTier + { + if (_teamQuestStatus[teamId][0] < 500) + return BG_AV_DEFENDER_TIER_DEFENDER; + + if (_teamQuestStatus[teamId][0] < 1000) + return BG_AV_DEFENDER_TIER_SEASONED; + + if (_teamQuestStatus[teamId][0] < 1500) + return BG_AV_DEFENDER_TIER_VETERAN; + + return BG_AV_DEFENDER_TIER_CHAMPION; + }; + + switch (dataId) + { + case DATA_DEFENDER_TIER_ALLIANCE: + return getDefenderTierForTeam(TEAM_ALLIANCE); + case DATA_DEFENDER_TIER_HORDE: + return getDefenderTierForTeam(TEAM_HORDE); + default: + return BattlegroundScript::GetData(dataId); + } + } + + Creature* FindHerald(std::string_view stringId) const + { + for (ObjectGuid const& guid : _heraldGUIDs) + if (Creature* creature = battlegroundMap->GetCreature(guid)) + if (creature->HasStringId(stringId)) + return creature; + + return nullptr; + } + + static StaticNodeInfo const* GetStaticNodeInfo(BG_AV_Nodes node) + { + for (const auto& nodeInfo : BGAVNodeInfo) + if (nodeInfo.NodeId == node) + return &nodeInfo; + + return nullptr; + } + + bool IsTower(BG_AV_Nodes node) const { return _nodes[node].Tower; } + + void UpdateScore(Team team, int16 points) + { + ASSERT(team == ALLIANCE || team == HORDE); + TeamId const teamindex = Battleground::GetTeamIndexByTeamId(team); + _teamResources[teamindex] += points; + + UpdateWorldState(teamindex == TEAM_HORDE ? AV_WS_HORDE_REINFORCEMENTS : AV_WS_ALLIANCE_REINFORCEMENTS, _teamResources[teamindex]); + if (points < 0) + { + if (_teamResources[teamindex] < 1) + { + _teamResources[teamindex] = 0; + battleground->EndBattleground(teamindex == TEAM_HORDE ? ALLIANCE : HORDE); + } + else if (!_isInformedNearVictory[teamindex] && _teamResources[teamindex] < NEAR_LOSE_POINTS) + { + if (teamindex == TEAM_ALLIANCE) + battleground->SendBroadcastText(BG_AV_TEXT_ALLIANCE_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_ALLIANCE); + else + battleground->SendBroadcastText(BG_AV_TEXT_HORDE_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_HORDE); + battleground->PlaySoundToAll(AV_SOUND_NEAR_VICTORY); + _isInformedNearVictory[teamindex] = true; + } + } + } + +private: + /*variables */ + std::array<int32, PVP_TEAMS_COUNT> _teamResources; + uint32 _teamQuestStatus[PVP_TEAMS_COUNT][9]; //[x][y] x=team y=questcounter + + std::array<BG_AV_NodeInfo, BG_AV_NODES_MAX> _nodes; + + TimeTracker _mineResourceTimer; //ticks for both teams + + std::array<AlteracValleyMineInfo, 2> _mineInfo; + + std::array<TimeTracker, PVP_TEAMS_COUNT> _captainBuffTimer; + + std::array<bool, PVP_TEAMS_COUNT> _isInformedNearVictory; + GuidUnorderedSet _doorGUIDs; + ObjectGuid _balindaGUID; + ObjectGuid _galvangarGUID; + GuidUnorderedSet _heraldGUIDs; +}; + +void AddSC_battleground_alterac_valley() +{ + RegisterBattlegroundMapScript(battleground_alterac_valley, 30); +} diff --git a/src/server/scripts/Battlegrounds/AlteracValley/boss_balinda.cpp b/src/server/scripts/Battlegrounds/AlteracValley/boss_balinda.cpp new file mode 100644 index 00000000000..38987c82428 --- /dev/null +++ b/src/server/scripts/Battlegrounds/AlteracValley/boss_balinda.cpp @@ -0,0 +1,184 @@ +/* + * 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 "ObjectAccessor.h" +#include "ScriptedCreature.h" + +enum Spells +{ + SPELL_ARCANE_EXPLOSION = 46608, + SPELL_CONE_OF_COLD = 38384, + SPELL_FIREBALL = 46988, + SPELL_FROSTBOLT = 46987, + SPELL_SUMMON_WATER_ELEMENTAL = 45067, + SPELL_ICEBLOCK = 46604 +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_EVADE = 1, + SAY_SALVATION = 2, +}; + +enum Action +{ + ACTION_BUFF_YELL = -30001 // shared from Battleground +}; + +enum Events +{ + // Balinda + EVENT_ARCANE_EXPLOSION = 1, + EVENT_CONE_OF_COLD, + EVENT_FIREBOLT, + EVENT_FROSTBOLT, + EVENT_SUMMON_WATER_ELEMENTAL, + EVENT_CHECK_RESET, // Checks if Balinda or the Water Elemental are outside of building. +}; + +struct boss_balinda : public ScriptedAI +{ + boss_balinda(Creature* creature) : ScriptedAI(creature), summons(me) + { + Initialize(); + } + + void Initialize() + { + WaterElementalGUID.Clear(); + HasCastIceblock = false; + } + + void Reset() override + { + Initialize(); + events.Reset(); + summons.DespawnAll(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 5s, 15s); + events.ScheduleEvent(EVENT_CONE_OF_COLD, 8s); + events.ScheduleEvent(EVENT_FIREBOLT, 1s); + events.ScheduleEvent(EVENT_FROSTBOLT, 4s); + events.ScheduleEvent(EVENT_SUMMON_WATER_ELEMENTAL, 3s); + events.ScheduleEvent(EVENT_CHECK_RESET, 5s); + } + + void JustSummoned(Creature* summoned) override + { + summoned->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 50, true)); + summoned->SetFaction(me->GetFaction()); + WaterElementalGUID = summoned->GetGUID(); + summons.Summon(summoned); + } + + void SummonedCreatureDespawn(Creature* summoned) override + { + summons.Despawn(summoned); + } + + void JustDied(Unit* /*killer*/) override + { + summons.DespawnAll(); + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_BUFF_YELL) + Talk(SAY_AGGRO); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + { + if (me->HealthBelowPctDamaged(40, damage) && !HasCastIceblock) + { + DoCast(SPELL_ICEBLOCK); + HasCastIceblock = true; + } + } + + 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_ARCANE_EXPLOSION: + DoCastVictim(SPELL_ARCANE_EXPLOSION); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 5s, 15s); + break; + case EVENT_CONE_OF_COLD: + DoCastVictim(SPELL_CONE_OF_COLD); + events.ScheduleEvent(EVENT_CONE_OF_COLD, 10s, 20s); + break; + case EVENT_FIREBOLT: + DoCastVictim(SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBOLT, 5s, 9s); + break; + case EVENT_FROSTBOLT: + DoCastVictim(SPELL_FROSTBOLT); + events.ScheduleEvent(EVENT_FROSTBOLT, 4s, 12s); + break; + case EVENT_SUMMON_WATER_ELEMENTAL: + if (summons.empty()) + DoCast(SPELL_SUMMON_WATER_ELEMENTAL); + events.ScheduleEvent(EVENT_SUMMON_WATER_ELEMENTAL, 50s); + break; + case EVENT_CHECK_RESET: + if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) + { + EnterEvadeMode(); + Talk(SAY_EVADE); + } + if (Creature* elemental = ObjectAccessor::GetCreature(*me, WaterElementalGUID)) + if (elemental->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) + elemental->AI()->EnterEvadeMode(); + events.ScheduleEvent(EVENT_CHECK_RESET, 5s); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + } + +private: + EventMap events; + SummonList summons; + ObjectGuid WaterElementalGUID; + bool HasCastIceblock; +}; + +void AddSC_boss_balinda() +{ + RegisterCreatureAI(boss_balinda); +} diff --git a/src/server/scripts/Battlegrounds/AlteracValley/boss_drekthar.cpp b/src/server/scripts/Battlegrounds/AlteracValley/boss_drekthar.cpp new file mode 100644 index 00000000000..f7ec0bb3da9 --- /dev/null +++ b/src/server/scripts/Battlegrounds/AlteracValley/boss_drekthar.cpp @@ -0,0 +1,137 @@ +/* + * 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 "ScriptedCreature.h" + +enum Spells +{ + SPELL_WHIRLWIND = 15589, + SPELL_WHIRLWIND2 = 13736, + SPELL_KNOCKDOWN = 19128, + SPELL_FRENZY = 8269, + SPELL_SWEEPING_STRIKES = 18765, // not sure + SPELL_CLEAVE = 20677, // not sure + SPELL_WINDFURY = 35886, // not sure + SPELL_STORMPIKE = 51876 // not sure +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_EVADE = 1, + SAY_RESPAWN = 2, + SAY_RANDOM = 3 +}; + +enum Events +{ + EVENT_WHIRLWIND = 1, + EVENT_WHIRLWIND2, + EVENT_KNOCKDOWN, + EVENT_FRENZY, + EVENT_RANDOM_YELL +}; + +struct boss_drekthar : public ScriptedAI +{ + boss_drekthar(Creature* creature) : ScriptedAI(creature) { } + + void Reset() override + { + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_WHIRLWIND, 1s, 20s); + events.ScheduleEvent(EVENT_WHIRLWIND2, 1s, 20s); + events.ScheduleEvent(EVENT_KNOCKDOWN, 12s); + events.ScheduleEvent(EVENT_FRENZY, 6s); + events.ScheduleEvent(EVENT_RANDOM_YELL, 20s, 30s); + } + + void JustAppeared() override + { + Reset(); + Talk(SAY_RESPAWN); + } + + bool CheckInRoom() override + { + if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) + { + EnterEvadeMode(); + Talk(SAY_EVADE); + return false; + } + + return true; + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_WHIRLWIND: + DoCastVictim(SPELL_WHIRLWIND); + events.ScheduleEvent(EVENT_WHIRLWIND, 8s, 18s); + break; + case EVENT_WHIRLWIND2: + DoCastVictim(SPELL_WHIRLWIND2); + events.ScheduleEvent(EVENT_WHIRLWIND2, 7s, 25s); + break; + case EVENT_KNOCKDOWN: + DoCastVictim(SPELL_KNOCKDOWN); + events.ScheduleEvent(EVENT_KNOCKDOWN, 10s, 15s); + break; + case EVENT_FRENZY: + DoCastVictim(SPELL_FRENZY); + events.ScheduleEvent(EVENT_FRENZY, 20s, 30s); + break; + case EVENT_RANDOM_YELL: + Talk(SAY_RANDOM); + events.ScheduleEvent(EVENT_RANDOM_YELL, 20s, 30s); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + } + + private: + EventMap events; +}; + +void AddSC_boss_drekthar() +{ + RegisterCreatureAI(boss_drekthar); +} diff --git a/src/server/scripts/Battlegrounds/AlteracValley/boss_galvangar.cpp b/src/server/scripts/Battlegrounds/AlteracValley/boss_galvangar.cpp new file mode 100644 index 00000000000..741387ec033 --- /dev/null +++ b/src/server/scripts/Battlegrounds/AlteracValley/boss_galvangar.cpp @@ -0,0 +1,138 @@ +/* + * 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 "ScriptedCreature.h" + +enum Spells +{ + SPELL_CLEAVE = 15284, + SPELL_FRIGHTENING_SHOUT = 19134, + SPELL_WHIRLWIND1 = 15589, + SPELL_WHIRLWIND2 = 13736, + SPELL_MORTAL_STRIKE = 16856 +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_EVADE = 1, + SAY_BUFF = 2 +}; + +enum Events +{ + EVENT_CLEAVE = 1, + EVENT_FRIGHTENING_SHOUT, + EVENT_WHIRLWIND1, + EVENT_WHIRLWIND2, + EVENT_MORTAL_STRIKE +}; + +enum Action +{ + ACTION_BUFF_YELL = -30001 // shared from Battleground +}; + +struct boss_galvangar : public ScriptedAI +{ + boss_galvangar(Creature* creature) : ScriptedAI(creature) { } + + void Reset() override + { + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_CLEAVE, 1s, 9s); + events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 2s, 19s); + events.ScheduleEvent(EVENT_WHIRLWIND1, 1s, 13s); + events.ScheduleEvent(EVENT_WHIRLWIND2, 5s, 20s); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, 5s, 20s); + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_BUFF_YELL) + Talk(SAY_BUFF); + } + + bool CheckInRoom() override + { + if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) + { + EnterEvadeMode(); + Talk(SAY_EVADE); + return false; + } + + return true; + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 10s, 16s); + break; + case EVENT_FRIGHTENING_SHOUT: + DoCastVictim(SPELL_FRIGHTENING_SHOUT); + events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 10s, 15s); + break; + case EVENT_WHIRLWIND1: + DoCastVictim(SPELL_WHIRLWIND1); + events.ScheduleEvent(EVENT_WHIRLWIND1, 6s, 10s); + break; + case EVENT_WHIRLWIND2: + DoCastVictim(SPELL_WHIRLWIND2); + events.ScheduleEvent(EVENT_WHIRLWIND2, 10s, 25s); + break; + case EVENT_MORTAL_STRIKE: + DoCastVictim(SPELL_MORTAL_STRIKE); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, 10s, 30s); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + } + +private: + EventMap events; +}; + +void AddSC_boss_galvangar() +{ + RegisterCreatureAI(boss_galvangar); +} diff --git a/src/server/scripts/Battlegrounds/AlteracValley/boss_vanndar.cpp b/src/server/scripts/Battlegrounds/AlteracValley/boss_vanndar.cpp new file mode 100644 index 00000000000..83c1fcc813e --- /dev/null +++ b/src/server/scripts/Battlegrounds/AlteracValley/boss_vanndar.cpp @@ -0,0 +1,98 @@ +/* + * 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 "ScriptedCreature.h" + +enum Yells +{ + YELL_AGGRO = 0, + YELL_EVADE = 1, + //YELL_RESPAWN1 = -1810010, // Missing in database + //YELL_RESPAWN2 = -1810011, // Missing in database + YELL_RANDOM = 2, + YELL_SPELL = 3, +}; + +enum Spells +{ + SPELL_AVATAR = 19135, + SPELL_THUNDERCLAP = 15588, + SPELL_STORMBOLT = 20685 // not sure +}; + +struct boss_vanndar : public ScriptedAI +{ + boss_vanndar(Creature* creature) : ScriptedAI(creature) { } + + void Reset() override + { + _scheduler.CancelAll(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _scheduler + .Schedule(3s, [this](TaskContext task) + { + DoCastVictim(SPELL_AVATAR); + task.Repeat(15s, 20s); + }) + .Schedule(4s, [this](TaskContext task) + { + DoCastVictim(SPELL_THUNDERCLAP); + task.Repeat(5s, 15s); + }) + .Schedule(6s, [this](TaskContext task) + { + DoCastVictim(SPELL_STORMBOLT); + task.Repeat(10s, 25s); + }) + .Schedule(20s, 30s, [this](TaskContext task) + { + Talk(YELL_RANDOM); + task.Repeat(20s, 30s); + }) + .Schedule(5s, [this](TaskContext task) + { + if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) + { + EnterEvadeMode(); + Talk(YELL_EVADE); + } + task.Repeat(); + }); + + Talk(YELL_AGGRO); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; +}; + +void AddSC_boss_vanndar() +{ + RegisterCreatureAI(boss_vanndar); +} |
