diff --git a/sql/scriptdev2/scriptdev2.sql b/sql/scriptdev2/scriptdev2.sql index 155acb71dae..0f65a91fc54 100644 --- a/sql/scriptdev2/scriptdev2.sql +++ b/sql/scriptdev2/scriptdev2.sql @@ -1034,6 +1034,7 @@ UPDATE creature_template SET ScriptName='npc_grand_admiral_westwind' WHERE entry /* ISLE OF QUEL'DANAS */ UPDATE creature_template SET ScriptName='npc_converted_sentry' WHERE entry=24981; +UPDATE creature_template SET ScriptName='npc_suns_reach_reclamation' WHERE entry IN(24965,24967,25061,25057,24932,25108,25069,25046,24975,25112,25163); /* KARAZHAN */ UPDATE instance_template SET ScriptName='instance_karazhan' WHERE map=532; diff --git a/sql/scriptdev2/spell.sql b/sql/scriptdev2/spell.sql index fac791ea920..a3800b04262 100644 --- a/sql/scriptdev2/spell.sql +++ b/sql/scriptdev2/spell.sql @@ -204,6 +204,11 @@ INSERT INTO spell_scripts(Id, ScriptName) VALUES (34630,'spell_scrap_reaver_spell'), (44935,'spell_razorthorn_root'), (44881,'spell_charm_ravager'), +(44948,'spell_living_flare_detonator'), +(44877,'spell_living_flare_master'), +(44943,'spell_living_flare_unstable'), +(45188,'spell_dawnblade_attack'), +(38858,'spell_queldanas_shoot'), (34800,'spell_getting_sleepy_aura'), (43364,'spell_getting_sleepy_aura'); diff --git a/src/game/AI/ScriptDevAI/scripts/world/suns_reach_reclamation.cpp b/src/game/AI/ScriptDevAI/scripts/world/suns_reach_reclamation.cpp new file mode 100644 index 00000000000..8c856eb4bc1 --- /dev/null +++ b/src/game/AI/ScriptDevAI/scripts/world/suns_reach_reclamation.cpp @@ -0,0 +1,66 @@ +/* This file is part of the ScriptDev2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AI/ScriptDevAI/include/sc_common.h" +#include "World/WorldState.h" +#include "Spells/Scripts/SpellScript.h" + +bool QuestRewarded_suns_reach_reclamation(Player* player, Creature* creature, Quest const* quest) +{ + sWorldState.AddSunsReachProgress(quest->GetQuestId()); + return true; +} + +enum +{ + SPELL_SHOOT = 38858, + SPELL_DAWNBLADE_ATTACK_RESPONSE = 45189, +}; + +struct DawnbladeAttack : public SpellScript +{ + void OnInit(Spell* spell) const override + { + spell->SetMaxAffectedTargets(1); + } + + void OnEffectExecute(Spell* spell, SpellEffectIndex /*effIdx*/) const override + { + if (urand(0, 1) == 0) + if (Unit* target = spell->GetUnitTarget()) + target->AI()->DoCastSpellIfCan(spell->GetCaster(), SPELL_SHOOT); + } +}; + +struct QuelDanasShoot : public SpellScript +{ + void OnHit(Spell* spell, SpellMissInfo /*missInfo*/) const override + { + if (Unit* target = spell->GetUnitTarget()) + target->AI()->DoCastSpellIfCan(spell->GetCaster(), SPELL_DAWNBLADE_ATTACK_RESPONSE); + } +}; + +void AddSC_suns_reach_reclamation() +{ + Script* pNewScript = new Script; + pNewScript->Name = "npc_suns_reach_reclamation"; + pNewScript->pQuestRewardedNPC = &QuestRewarded_suns_reach_reclamation; + pNewScript->RegisterSelf(); + + RegisterSpellScript("spell_dawnblade_attack"); + RegisterSpellScript("spell_queldanas_shoot"); +} \ No newline at end of file diff --git a/src/game/AI/ScriptDevAI/system/ScriptLoader.cpp b/src/game/AI/ScriptDevAI/system/ScriptLoader.cpp index d7aadf7a730..6770e1d6212 100644 --- a/src/game/AI/ScriptDevAI/system/ScriptLoader.cpp +++ b/src/game/AI/ScriptDevAI/system/ScriptLoader.cpp @@ -29,6 +29,7 @@ extern void AddSC_spell_scripts(); extern void AddSC_world_map_scripts(); extern void AddSC_boss_highlord_kruul(); extern void AddSC_war_effort(); +extern void AddSC_suns_reach_reclamation(); extern void AddSC_world_map_ebon_hold(); extern void AddSC_shade_of_the_horseman(); @@ -525,6 +526,7 @@ void AddScripts() AddSC_world_map_scripts(); AddSC_boss_highlord_kruul(); AddSC_war_effort(); + AddSC_suns_reach_reclamation(); AddSC_world_map_ebon_hold(); AddSC_shade_of_the_horseman(); diff --git a/src/game/Chat/Chat.cpp b/src/game/Chat/Chat.cpp index 5d1754820a0..8652a62ee2c 100644 --- a/src/game/Chat/Chat.cpp +++ b/src/game/Chat/Chat.cpp @@ -836,9 +836,18 @@ ChatCommand* ChatHandler::getCommandTable() { nullptr, 0, false, nullptr, "", nullptr } }; + static ChatCommand sunsReachReclamationTable[] = + { + { "phase", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSunsReachReclamationPhaseCommand, "", nullptr }, + { "subphase", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSunsReachReclamationSubPhaseCommand, "", nullptr }, + { "counter", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSunsReachReclamationCounterCommand, "", nullptr }, + { nullptr, 0, false, nullptr, "", nullptr } + }; + static ChatCommand worldStateTable[] = { { "wareffort", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWarEffortCommand, "", nullptr }, + { "sunsreach", SEC_ADMINISTRATOR, false, nullptr, "", sunsReachReclamationTable }, { "expansion", SEC_ADMINISTRATOR, false, &ChatHandler::HandleExpansionRelease, "", nullptr }, { nullptr, 0, false, nullptr, "", nullptr } }; diff --git a/src/game/Chat/Chat.h b/src/game/Chat/Chat.h index 5a6b4af0314..23782c8edc9 100644 --- a/src/game/Chat/Chat.h +++ b/src/game/Chat/Chat.h @@ -780,6 +780,9 @@ class ChatHandler // worldstate bool HandleWarEffortCommand(char* args); + bool HandleSunsReachReclamationPhaseCommand(char* args); + bool HandleSunsReachReclamationSubPhaseCommand(char* args); + bool HandleSunsReachReclamationCounterCommand(char* args); bool HandleExpansionRelease(char* args); // Battleground diff --git a/src/game/Chat/Level3.cpp b/src/game/Chat/Level3.cpp index 6c80da259d9..7e699ab5fd1 100644 --- a/src/game/Chat/Level3.cpp +++ b/src/game/Chat/Level3.cpp @@ -7277,6 +7277,50 @@ bool ChatHandler::HandleWarEffortCommand(char* args) return true; } +bool ChatHandler::HandleSunsReachReclamationPhaseCommand(char* args) +{ + uint32 param; + if (!ExtractUInt32(&args, param)) + { + PSendSysMessage("%s", sWorldState.GetSunsReachPrintout().data()); + return true; + } + sWorldState.HandleSunsReachPhaseTransition(param); + return true; +} + +bool ChatHandler::HandleSunsReachReclamationSubPhaseCommand(char* args) +{ + uint32 param; + if (!ExtractUInt32(&args, param)) + { + PSendSysMessage("%s", sWorldState.GetSunsReachPrintout().data()); + return true; + } + sWorldState.HandleSunsReachSubPhaseTransition(param); + return true; +} + +bool ChatHandler::HandleSunsReachReclamationCounterCommand(char* args) +{ + uint32 index; + if (!ExtractUInt32(&args, index) || index >= COUNTERS_MAX) + { + PSendSysMessage("Enter valid index for counter."); + return true; + } + + uint32 value; + if (!ExtractUInt32(&args, value)) + { + PSendSysMessage("Enter valid value for counter."); + return true; + } + + sWorldState.SetSunsReachCounter(SunsReachCounters(index), value); + return true; +} + bool ChatHandler::HandleExpansionRelease(char* args) { uint32 curExpansion = sWorldState.GetExpansion(); diff --git a/src/game/Spells/SpellMgr.h b/src/game/Spells/SpellMgr.h index bbdd675118b..6a4eb3c1c18 100644 --- a/src/game/Spells/SpellMgr.h +++ b/src/game/Spells/SpellMgr.h @@ -591,6 +591,7 @@ inline bool IsSpellRemovedOnEvade(SpellEntry const* spellInfo) case 44604: // Enchantment of Spell Haste case 44855: // Out of Phase case 45033: // Abyssal Transformation + case 45187: // Dawnblade Attack case 45822: // Iceblood Warmaster case 45823: // Tower Point Warmaster case 45824: // West Frostwolf Warmaster diff --git a/src/game/World/WorldState.cpp b/src/game/World/WorldState.cpp index 28375bd5906..11f6c103d5a 100644 --- a/src/game/World/WorldState.cpp +++ b/src/game/World/WorldState.cpp @@ -116,7 +116,23 @@ void WorldState::Load() break; } case SAVE_ID_QUEL_DANAS: // TODO: + { + if (data.size()) + { + try + { + loadStream >> m_sunsReachData.m_phase >> m_sunsReachData.m_subphaseMask; + for (uint32 i = 0; i < COUNTERS_MAX; ++i) + loadStream >> m_sunsReachData.m_sunsReachReclamationCounters[i]; + } + catch (std::exception& e) + { + sLog.outError("%s", e.what()); + memset(m_loveIsInTheAirData.counters, 0, sizeof(LoveIsInTheAir)); + } + } break; + } case SAVE_ID_HIGHLORD_KRUUL: { auto curTime = World::GetCurrentClockTime(); @@ -172,6 +188,8 @@ void WorldState::Load() } StartWarEffortEvent(); RespawnEmeraldDragons(); + StartSunsReachPhase(true); + HandleSunsReachSubPhaseTransition(m_sunsReachData.m_subphaseMask, true); StartExpansionEvent(); } @@ -202,15 +220,18 @@ void WorldState::Save(SaveIds saveId) SaveHelper(expansionData, SAVE_ID_EXPANSION_RELEASE); break; } + case SAVE_ID_QUEL_DANAS: + { + std::string expansionData = m_sunsReachData.GetData(); + SaveHelper(expansionData, SAVE_ID_QUEL_DANAS); + break; + } case SAVE_ID_EXPANSION_RELEASE: { std::string expansionData = std::to_string(m_expansion); SaveHelper(expansionData, SAVE_ID_EXPANSION_RELEASE); break; } - // TODO: Add saving for AQ and QD - case SAVE_ID_QUEL_DANAS: - break; case SAVE_ID_LOVE_IS_IN_THE_AIR: { std::string loveData; @@ -365,9 +386,9 @@ void WorldState::HandlePlayerEnterZone(Player* player, uint32 zoneId) { std::lock_guard guard(m_mutex); if (m_isMagtheridonHeadSpawnedAlliance && player->GetTeam() == ALLIANCE) - player->CastSpell(player, SPELL_TROLLBANES_COMMAND, TRIGGERED_OLD_TRIGGERED); + player->CastSpell(nullptr, SPELL_TROLLBANES_COMMAND, TRIGGERED_OLD_TRIGGERED); if (m_isMagtheridonHeadSpawnedHorde && player->GetTeam() == HORDE) - player->CastSpell(player, SPELL_NAZGRELS_FAVOR, TRIGGERED_OLD_TRIGGERED); + player->CastSpell(nullptr, SPELL_NAZGRELS_FAVOR, TRIGGERED_OLD_TRIGGERED); m_magtheridonHeadPlayers.push_back(player->GetObjectGuid()); break; } @@ -378,10 +399,20 @@ void WorldState::HandlePlayerEnterZone(Player* player, uint32 zoneId) { std::lock_guard guard(m_mutex); if (m_adalSongOfBattleTimer) - player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, TRIGGERED_OLD_TRIGGERED); + player->CastSpell(nullptr, SPELL_ADAL_SONG_OF_BATTLE, TRIGGERED_OLD_TRIGGERED); m_adalSongOfBattlePlayers.push_back(player->GetObjectGuid()); break; } + case ZONEID_ISLE_OF_QUEL_DANAS: + case ZONEID_MAGISTERS_TERRACE: + case ZONEID_SUNWELL_PLATEAU: + { + std::lock_guard guard(m_sunsReachData.m_sunsReachReclamationMutex); + m_sunsReachData.m_sunsReachReclamationPlayers.push_back(player->GetObjectGuid()); + if (zoneId != ZONEID_SUNWELL_PLATEAU && m_sunsReachData.m_subphaseMask == SUBPHASE_ALL) + player->CastSpell(nullptr, SPELL_KIRU_SONG_OF_VICTORY, TRIGGERED_OLD_TRIGGERED); + break; + } default: break; } @@ -441,6 +472,17 @@ void WorldState::HandlePlayerLeaveZone(Player* player, uint32 zoneId) m_adalSongOfBattlePlayers.erase(position); break; } + case ZONEID_ISLE_OF_QUEL_DANAS: + case ZONEID_MAGISTERS_TERRACE: + case ZONEID_SUNWELL_PLATEAU: + { + std::lock_guard guard(m_sunsReachData.m_sunsReachReclamationMutex); + player->RemoveAurasDueToSpell(SPELL_KIRU_SONG_OF_VICTORY); + auto position = std::find(m_sunsReachData.m_sunsReachReclamationPlayers.begin(), m_sunsReachData.m_sunsReachReclamationPlayers.end(), player->GetObjectGuid()); + if (position != m_sunsReachData.m_sunsReachReclamationPlayers.end()) + m_sunsReachData.m_sunsReachReclamationPlayers.erase(position); + break; + } default: break; } @@ -633,14 +675,6 @@ void WorldState::SendWorldstateUpdate(std::mutex& mutex, uint32 value, uint32 wo player->SendUpdateWorldState(worldStateId, value); } -void WorldState::SendLoveIsInTheAirWorldstateUpdate(uint32 value, uint32 worldStateId) -{ - std::lock_guard guard(m_loveIsInTheAirMutex); - for (ObjectGuid& guid : m_loveIsInTheAirCapitalsPlayers) - if (Player* player = sObjectMgr.GetPlayer(guid)) - player->SendUpdateWorldState(worldStateId, value); -} - void WorldState::BuffAdalsSongOfBattle() { for (ObjectGuid& guid : m_adalSongOfBattlePlayers) @@ -954,6 +988,364 @@ bool WorldState::SetExpansion(uint8 expansion) return true; } +enum +{ + QUEST_ERRATIC_BEHAVIOR = 11524, + QUEST_SANCTUM_WARDS = 11496, + QUEST_BATTLE_FOR_THE_SUNS_REACH_ARMORY = 11538, + QUEST_DISTRACTION_AT_THE_DEAD_SCAR = 11532, + QUEST_INTERCEPTING_THE_MANA_CELLS = 11513, + QUEST_INTERCEPT_THE_REINFORCEMENTS = 11542, + QUEST_TAKING_THE_HARBOR = 11539, + QUEST_MAKING_READY = 11535, + QUEST_DISCOVERING_YOUR_ROOTS = 11520, + QUEST_A_CHARITABLE_DONATION = 11545, + QUEST_A_MAGNANIMOUS_BENEFACTOR = 11549, + + COUNTER_MAX_VAL_REQ = 10000, +}; + +void WorldState::AddSunsReachProgress(uint32 questId) +{ + uint32 counter = 0; + int32 otherCounter = -1; + int32 worldState = 0; + uint32 subPhaseMask = 0; + uint32 addedValue = 1; + switch (questId) + { + case QUEST_ERRATIC_BEHAVIOR: counter = COUNTER_ERRATIC_BEHAVIOR; otherCounter = COUNTER_SANCTUM_WARDS; worldState = WORLD_STATE_QUEL_DANAS_SANCTUM; break; + case QUEST_SANCTUM_WARDS: counter = COUNTER_SANCTUM_WARDS; otherCounter = COUNTER_SANCTUM_WARDS; worldState = WORLD_STATE_QUEL_DANAS_SANCTUM; break; + case QUEST_BATTLE_FOR_THE_SUNS_REACH_ARMORY: counter = COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY; otherCounter = COUNTER_DISTRACTION_AT_THE_DEAD_SCAR; worldState = WORLD_STATE_QUEL_DANAS_ARMORY; break; + case QUEST_DISTRACTION_AT_THE_DEAD_SCAR: counter = COUNTER_DISTRACTION_AT_THE_DEAD_SCAR; otherCounter = COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY; worldState = WORLD_STATE_QUEL_DANAS_ARMORY; break; + case QUEST_INTERCEPTING_THE_MANA_CELLS: counter = COUNTER_INTERCEPTING_THE_MANA_CELLS; subPhaseMask = SUBPHASE_PORTAL; worldState = WORLD_STATE_QUEL_DANAS_PORTAL; break; + case QUEST_INTERCEPT_THE_REINFORCEMENTS: counter = COUNTER_INTERCEPT_THE_REINFORCEMENTS; otherCounter = COUNTER_TAKING_THE_HARBOR; worldState = WORLD_STATE_QUEL_DANAS_HARBOR; break; + case QUEST_TAKING_THE_HARBOR: counter = COUNTER_TAKING_THE_HARBOR; otherCounter = COUNTER_INTERCEPT_THE_REINFORCEMENTS; worldState = WORLD_STATE_QUEL_DANAS_HARBOR; break; + case QUEST_MAKING_READY: counter = COUNTER_MAKING_READY; subPhaseMask = SUBPHASE_ANVIL; worldState = WORLD_STATE_QUEL_DANAS_ANVIL; break; + case QUEST_DISCOVERING_YOUR_ROOTS: counter = COUNTER_DISCOVERING_YOUR_ROOTS; subPhaseMask = SUBPHASE_ALCHEMY_LAB; worldState = WORLD_STATE_QUEL_DANAS_ALCHEMY_LAB; break; + case QUEST_A_CHARITABLE_DONATION: counter = COUNTER_A_CHARITABLE_DONATION; subPhaseMask = SUBPHASE_MONUMENT; worldState = WORLD_STATE_QUEL_DANAS_MONUMENT; break; + case QUEST_A_MAGNANIMOUS_BENEFACTOR: counter = COUNTER_A_CHARITABLE_DONATION; subPhaseMask = SUBPHASE_MONUMENT; worldState = WORLD_STATE_QUEL_DANAS_MONUMENT; addedValue = 150; break; + default: return; + } + + uint32 previousValue = 0; + uint32 newValue = 0; + + if (!subPhaseMask) + previousValue = m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase); + else + previousValue = m_sunsReachData.GetSubPhasePercentage(subPhaseMask); + m_sunsReachData.m_sunsReachReclamationCounters[counter] += addedValue; + if (!subPhaseMask) + newValue = m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase); + else + newValue = m_sunsReachData.GetSubPhasePercentage(subPhaseMask); + if (previousValue != newValue) + SendWorldstateUpdate(m_sunsReachData.m_sunsReachReclamationMutex, newValue, worldState); + + bool save = true; + if (m_sunsReachData.m_sunsReachReclamationCounters[counter] >= COUNTER_MAX_VAL_REQ) + { + if (otherCounter == -1 || m_sunsReachData.m_sunsReachReclamationCounters[otherCounter] >= COUNTER_MAX_VAL_REQ) + { + save = false; + switch (questId) + { + case QUEST_ERRATIC_BEHAVIOR: + case QUEST_SANCTUM_WARDS: + { + if (m_sunsReachData.m_phase == SUNS_REACH_PHASE_1_STAGING_AREA) + HandleSunsReachPhaseTransition(SUNS_REACH_PHASE_2_SANCTUM); + break; + } + case QUEST_BATTLE_FOR_THE_SUNS_REACH_ARMORY: + case QUEST_DISTRACTION_AT_THE_DEAD_SCAR: + { + if (m_sunsReachData.m_phase == SUNS_REACH_PHASE_2_SANCTUM) + HandleSunsReachPhaseTransition(SUNS_REACH_PHASE_3_ARMORY); + break; + } + case QUEST_INTERCEPTING_THE_MANA_CELLS: + { + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_PORTAL) == 0) + HandleSunsReachSubPhaseTransition(SUBPHASE_PORTAL); + break; + } + case QUEST_INTERCEPT_THE_REINFORCEMENTS: + case QUEST_TAKING_THE_HARBOR: + { + if (m_sunsReachData.m_phase == SUNS_REACH_PHASE_3_ARMORY) + HandleSunsReachPhaseTransition(SUNS_REACH_PHASE_4_HARBOR); + break; + } + case QUEST_MAKING_READY: + { + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ANVIL) == 0) + HandleSunsReachSubPhaseTransition(SUBPHASE_ANVIL); + break; + } + case QUEST_DISCOVERING_YOUR_ROOTS: + { + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALCHEMY_LAB) == 0) + HandleSunsReachSubPhaseTransition(SUBPHASE_ALCHEMY_LAB); + break; + } + case QUEST_A_CHARITABLE_DONATION: + case QUEST_A_MAGNANIMOUS_BENEFACTOR: + { + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_MONUMENT) == 0) + HandleSunsReachSubPhaseTransition(SUBPHASE_MONUMENT); + break; + } + } + } + } + if (save) + Save(SAVE_ID_QUEL_DANAS); +} + +void WorldState::HandleSunsReachPhaseTransition(uint32 newPhase) +{ + if (newPhase < m_sunsReachData.m_phase) + { + while (newPhase != m_sunsReachData.m_phase) + { + StopSunsReachPhase(newPhase > m_sunsReachData.m_phase); + --m_sunsReachData.m_phase; + } + StartSunsReachPhase(); + } + else + { + StopSunsReachPhase(newPhase > m_sunsReachData.m_phase); + bool moreThanOne = newPhase > m_sunsReachData.m_phase + 1; // custom command case + m_sunsReachData.m_phase = newPhase; + StartSunsReachPhase(moreThanOne); + } + switch (m_sunsReachData.m_phase) + { + case SUNS_REACH_PHASE_2_SANCTUM: if ((m_sunsReachData.m_subphaseMask & SUBPHASE_PORTAL) == 0) sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_NO_PORTAL); break; + case SUNS_REACH_PHASE_3_ARMORY: if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ANVIL) == 0) sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_NO_ANVIL); break; + case SUNS_REACH_PHASE_4_HARBOR: + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALCHEMY_LAB) == 0) sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_NO_MONUMENT); + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_MONUMENT) == 0) sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_NO_ALCHEMY_LAB); + break; + default: break; + } + SendWorldstateUpdate(m_sunsReachData.m_sunsReachReclamationMutex, m_sunsReachData.m_phase, WORLD_STATE_QUEL_DANAS_MUSIC); +} + +void WorldState::HandleSunsReachSubPhaseTransition(int32 subPhaseMask, bool initial) +{ + bool start = true; + if (subPhaseMask < 0) + { + start = false; + subPhaseMask = -subPhaseMask; + } + bool all = false; + if (start) + { + m_sunsReachData.m_subphaseMask |= subPhaseMask; + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALL) == SUBPHASE_ALL) + all = true; + } + else + { + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALL) == SUBPHASE_ALL) + all = true; + m_sunsReachData.m_subphaseMask &= ~subPhaseMask; + } + if (initial && subPhaseMask == 0) + { + switch (m_sunsReachData.m_phase) + { + case SUNS_REACH_PHASE_2_SANCTUM: sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_NO_PORTAL); break; + case SUNS_REACH_PHASE_3_ARMORY: sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_NO_ANVIL); break; + case SUNS_REACH_PHASE_4_HARBOR: sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_NO_MONUMENT); sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_NO_ALCHEMY_LAB); break; + default: break; + } + } + if ((subPhaseMask & SUBPHASE_PORTAL)) + { + uint32 first = GAME_EVENT_QUEL_DANAS_PHASE_2_NO_PORTAL; + uint32 second = GAME_EVENT_QUEL_DANAS_PHASE_2_PORTAL; + if (start) + { + sGameEventMgr.StopEvent(first); + sGameEventMgr.StartEvent(second); + } + else + { + sGameEventMgr.StopEvent(second); + sGameEventMgr.StartEvent(first); + } + } + if ((subPhaseMask & SUBPHASE_ANVIL)) + { + uint32 first = GAME_EVENT_QUEL_DANAS_PHASE_3_NO_ANVIL; + uint32 second = GAME_EVENT_QUEL_DANAS_PHASE_3_ANVIL; + if (start) + { + sGameEventMgr.StopEvent(first); + sGameEventMgr.StartEvent(second); + } + else + { + sGameEventMgr.StopEvent(second); + sGameEventMgr.StartEvent(first); + } + } + if ((subPhaseMask & SUBPHASE_ALCHEMY_LAB)) + { + uint32 first = GAME_EVENT_QUEL_DANAS_PHASE_4_NO_ALCHEMY_LAB; + uint32 second = GAME_EVENT_QUEL_DANAS_PHASE_4_ALCHEMY_LAB; + if (start) + { + sGameEventMgr.StopEvent(first); + sGameEventMgr.StartEvent(second); + } + else + { + sGameEventMgr.StopEvent(second); + sGameEventMgr.StartEvent(first); + } + } + if ((subPhaseMask & SUBPHASE_MONUMENT)) + { + uint32 first = GAME_EVENT_QUEL_DANAS_PHASE_4_NO_MONUMENT; + uint32 second = GAME_EVENT_QUEL_DANAS_PHASE_4_MONUMENT; + if (start) + { + sGameEventMgr.StopEvent(first); + sGameEventMgr.StartEvent(second); + } + else + { + sGameEventMgr.StopEvent(second); + sGameEventMgr.StartEvent(first); + } + } + if (all) + { + if (start) + sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_KIRU); + else + sGameEventMgr.StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_KIRU); + + if (!initial) + { + std::lock_guard guard(m_sunsReachData.m_sunsReachReclamationMutex); + for (ObjectGuid& guid : m_sunsReachData.m_sunsReachReclamationPlayers) + { + if (Player* player = sObjectMgr.GetPlayer(guid)) + { + if (player->GetZoneId() == ZONEID_SUNWELL_PLATEAU) + continue; + + if (start) + { + player->GetMap()->GetMessager().AddMessage([guid](Map* map) -> void + { + if (Player* player = map->GetPlayer(guid)) + player->CastSpell(nullptr, SPELL_KIRU_SONG_OF_VICTORY, TRIGGERED_OLD_TRIGGERED); + }); + } + else + { + player->GetMap()->GetMessager().AddMessage([guid](Map* map) -> void + { + if (Player* player = map->GetPlayer(guid)) + player->RemoveAurasDueToSpell(SPELL_KIRU_SONG_OF_VICTORY); + }); + } + } + } + } + } + if (!initial) + Save(SAVE_ID_QUEL_DANAS); +} + +void WorldState::SetSunsReachCounter(SunsReachCounters index, uint32 value) +{ + m_sunsReachData.m_sunsReachReclamationCounters[index] = value; +} + +void WorldState::StopSunsReachPhase(bool forward) +{ + switch (m_sunsReachData.m_phase) + { + case SUNS_REACH_PHASE_1_STAGING_AREA: sGameEventMgr.StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_1); break; + case SUNS_REACH_PHASE_2_SANCTUM: sGameEventMgr.StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_ONLY); if (!forward) sGameEventMgr.StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT); break; + case SUNS_REACH_PHASE_3_ARMORY: sGameEventMgr.StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_ONLY); if (!forward) sGameEventMgr.StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_PERMANENT); break; + case SUNS_REACH_PHASE_4_HARBOR: sGameEventMgr.StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_4); break; + default: break; + } +} + +void WorldState::StartSunsReachPhase(bool initial) +{ + switch (m_sunsReachData.m_phase) + { + case SUNS_REACH_PHASE_1_STAGING_AREA: sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_1); break; + case SUNS_REACH_PHASE_2_SANCTUM: sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_ONLY); sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT); break; + case SUNS_REACH_PHASE_3_ARMORY: + if (initial) + sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT); + sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_ONLY); sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_PERMANENT); + break; + case SUNS_REACH_PHASE_4_HARBOR: + if (initial) + { + sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT); + sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_PERMANENT); + } + sGameEventMgr.StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4); + break; + default: break; + } +} + +std::string WorldState::GetSunsReachPrintout() +{ + std::string output = "Phase: " + std::to_string(m_sunsReachData.m_phase) + " Subphase mask: " + std::to_string(m_sunsReachData.m_subphaseMask) + "\nValues:"; + for (uint32 value : m_sunsReachData.m_sunsReachReclamationCounters) + output += " " + std::to_string(value); + return output; +} + +std::string SunsReachReclamationData::GetData() +{ + std::string output = std::to_string(m_phase) + " " + std::to_string(m_subphaseMask); + for (uint32 value : m_sunsReachReclamationCounters) + output += " " + std::to_string(value); + return output; +} + +uint32 SunsReachReclamationData::GetPhasePercentage(uint32 phase) +{ + switch (phase) + { + case SUNS_REACH_PHASE_1_STAGING_AREA: return uint32((m_sunsReachReclamationCounters[COUNTER_ERRATIC_BEHAVIOR] + m_sunsReachReclamationCounters[COUNTER_SANCTUM_WARDS]) * 100 / (2 * COUNTER_MAX_VAL_REQ)); + case SUNS_REACH_PHASE_2_SANCTUM: return uint32((m_sunsReachReclamationCounters[COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY] + m_sunsReachReclamationCounters[COUNTER_DISTRACTION_AT_THE_DEAD_SCAR]) * 100 / (2 * COUNTER_MAX_VAL_REQ)); + case SUNS_REACH_PHASE_3_ARMORY: return uint32((m_sunsReachReclamationCounters[COUNTER_INTERCEPT_THE_REINFORCEMENTS] + m_sunsReachReclamationCounters[COUNTER_TAKING_THE_HARBOR]) * 100 / (2 * COUNTER_MAX_VAL_REQ)); + default: return 0; + } +} + +uint32 SunsReachReclamationData::GetSubPhasePercentage(uint32 subPhase) +{ + switch (subPhase) + { + case SUBPHASE_PORTAL: return uint32(m_sunsReachReclamationCounters[COUNTER_INTERCEPTING_THE_MANA_CELLS] * 100 / COUNTER_MAX_VAL_REQ); + case SUBPHASE_ANVIL: return uint32(m_sunsReachReclamationCounters[COUNTER_MAKING_READY] * 100 / COUNTER_MAX_VAL_REQ); + case SUBPHASE_ALCHEMY_LAB: return uint32(m_sunsReachReclamationCounters[COUNTER_DISCOVERING_YOUR_ROOTS] * 100 / COUNTER_MAX_VAL_REQ); + case SUBPHASE_MONUMENT: return uint32(m_sunsReachReclamationCounters[COUNTER_A_CHARITABLE_DONATION] * 100 / COUNTER_MAX_VAL_REQ); + default: return 0; + } +} + void WorldState::StartExpansionEvent() { if (m_expansion == EXPANSION_NONE) @@ -967,43 +1359,72 @@ void WorldState::StartExpansionEvent() void WorldState::FillInitialWorldStates(ByteBuffer& data, uint32& count, uint32 zoneId, uint32 areaId) { - if (sGameEventMgr.IsActiveHoliday(HOLIDAY_LOVE_IS_IN_THE_AIR)) + switch (zoneId) { - switch (zoneId) + case ZONEID_STORMWIND_CITY: + case ZONEID_DARNASSUS: + case ZONEID_IRONFORGE: + case ZONEID_ORGRIMMAR: + case ZONEID_THUNDER_BLUFF: + case ZONEID_UNDERCITY: { - case ZONEID_STORMWIND_CITY: - case ZONEID_DARNASSUS: - case ZONEID_IRONFORGE: - case ZONEID_ORGRIMMAR: - case ZONEID_THUNDER_BLUFF: - case ZONEID_UNDERCITY: + if (sGameEventMgr.IsActiveHoliday(HOLIDAY_LOVE_IS_IN_THE_AIR)) { - if (sGameEventMgr.IsActiveHoliday(HOLIDAY_LOVE_IS_IN_THE_AIR)) - { - uint32 allianceSum = GetLoveIsInTheAirCounter(LOVE_LEADER_BOLVAR) + GetLoveIsInTheAirCounter(LOVE_LEADER_TYRANDE) + GetLoveIsInTheAirCounter(LOVE_LEADER_MAGNI); - uint32 hordeSum = GetLoveIsInTheAirCounter(LOVE_LEADER_CAIRNE) + GetLoveIsInTheAirCounter(LOVE_LEADER_THRALL) + GetLoveIsInTheAirCounter(LOVE_LEADER_SYLVANAS); - FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_BOLVAR, GetLoveIsInTheAirCounter(LOVE_LEADER_BOLVAR)); - FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_TYRANDE, GetLoveIsInTheAirCounter(LOVE_LEADER_TYRANDE)); - FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_MAGNI, GetLoveIsInTheAirCounter(LOVE_LEADER_MAGNI)); - FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_TOTAL_ALLIANCE, allianceSum); - FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_CAIRNE, GetLoveIsInTheAirCounter(LOVE_LEADER_CAIRNE)); - FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_THRALL, GetLoveIsInTheAirCounter(LOVE_LEADER_THRALL)); - FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_SYLVANAS, GetLoveIsInTheAirCounter(LOVE_LEADER_SYLVANAS)); - FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_TOTAL_HORDE, hordeSum); - } + uint32 allianceSum = GetLoveIsInTheAirCounter(LOVE_LEADER_BOLVAR) + GetLoveIsInTheAirCounter(LOVE_LEADER_TYRANDE) + GetLoveIsInTheAirCounter(LOVE_LEADER_MAGNI); + uint32 hordeSum = GetLoveIsInTheAirCounter(LOVE_LEADER_CAIRNE) + GetLoveIsInTheAirCounter(LOVE_LEADER_THRALL) + GetLoveIsInTheAirCounter(LOVE_LEADER_SYLVANAS); + FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_BOLVAR, GetLoveIsInTheAirCounter(LOVE_LEADER_BOLVAR)); + FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_TYRANDE, GetLoveIsInTheAirCounter(LOVE_LEADER_TYRANDE)); + FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_MAGNI, GetLoveIsInTheAirCounter(LOVE_LEADER_MAGNI)); + FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_TOTAL_ALLIANCE, allianceSum); + FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_CAIRNE, GetLoveIsInTheAirCounter(LOVE_LEADER_CAIRNE)); + FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_THRALL, GetLoveIsInTheAirCounter(LOVE_LEADER_THRALL)); + FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_SYLVANAS, GetLoveIsInTheAirCounter(LOVE_LEADER_SYLVANAS)); + FillInitialWorldStateData(data, count, WORLD_STATE_LOVE_IS_IN_THE_AIR_TOTAL_HORDE, hordeSum); + } - if (m_aqData.m_phase == PHASE_1_GATHERING_RESOURCES) - { - // totals first - for (auto itr = aqWorldStateTotalsMap.begin(); itr != aqWorldStateTotalsMap.end(); ++itr) - FillInitialWorldStateData(data, count, (*itr).first, (*itr).second); - for (auto itr = aqWorldstateMap.begin(); itr != aqWorldstateMap.end(); ++itr) - FillInitialWorldStateData(data, count, m_aqData.m_WarEffortCounters[(*itr).first], (*itr).second); - } - else if (m_aqData.m_phase == PHASE_2_TRANSPORTING_RESOURCES) - FillInitialWorldStateData(data, count, WORLD_STATE_AQ_DAYS_LEFT, uint32(m_aqData.m_timer / DAY * IN_MILLISECONDS)); - break; + if (m_aqData.m_phase == PHASE_1_GATHERING_RESOURCES) + { + // totals first + for (auto itr = aqWorldStateTotalsMap.begin(); itr != aqWorldStateTotalsMap.end(); ++itr) + FillInitialWorldStateData(data, count, (*itr).first, (*itr).second); + for (auto itr = aqWorldstateMap.begin(); itr != aqWorldstateMap.end(); ++itr) + FillInitialWorldStateData(data, count, m_aqData.m_WarEffortCounters[(*itr).first], (*itr).second); + } + else if (m_aqData.m_phase == PHASE_2_TRANSPORTING_RESOURCES) + FillInitialWorldStateData(data, count, WORLD_STATE_AQ_DAYS_LEFT, uint32(m_aqData.m_timer / DAY * IN_MILLISECONDS)); + break; + } + case ZONEID_ISLE_OF_QUEL_DANAS: + case ZONEID_MAGISTERS_TERRACE: + case ZONEID_SUNWELL_PLATEAU: + case ZONEID_SHATTRATH: + { + switch (m_sunsReachData.m_phase) + { + case SUNS_REACH_PHASE_1_STAGING_AREA: + FillInitialWorldStateData(data, count, WORLD_STATE_QUEL_DANAS_SANCTUM, m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase)); + break; + case SUNS_REACH_PHASE_2_SANCTUM: + FillInitialWorldStateData(data, count, WORLD_STATE_QUEL_DANAS_ARMORY, m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase)); + break; + case SUNS_REACH_PHASE_3_ARMORY: + FillInitialWorldStateData(data, count, WORLD_STATE_QUEL_DANAS_HARBOR, m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase)); + break; + case SUNS_REACH_PHASE_4_HARBOR: + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALCHEMY_LAB) == 0) + FillInitialWorldStateData(data, count, WORLD_STATE_QUEL_DANAS_ALCHEMY_LAB, m_sunsReachData.GetSubPhasePercentage(SUBPHASE_ALCHEMY_LAB)); + if ((m_sunsReachData.m_subphaseMask & SUBPHASE_MONUMENT) == 0) + FillInitialWorldStateData(data, count, WORLD_STATE_QUEL_DANAS_MONUMENT, m_sunsReachData.GetSubPhasePercentage(SUBPHASE_MONUMENT)); + break; } + if (m_sunsReachData.m_phase >= SUNS_REACH_PHASE_3_ARMORY && (m_sunsReachData.m_subphaseMask & SUBPHASE_ANVIL) == 0) + FillInitialWorldStateData(data, count, WORLD_STATE_QUEL_DANAS_ANVIL, m_sunsReachData.GetSubPhasePercentage(SUBPHASE_ANVIL)); + + FillInitialWorldStateData(data, count, WORLD_STATE_QUEL_DANAS_MUSIC, m_sunsReachData.m_phase); + + if (m_sunsReachData.m_phase >= SUNS_REACH_PHASE_2_SANCTUM && (m_sunsReachData.m_subphaseMask & SUBPHASE_PORTAL) == 0) + FillInitialWorldStateData(data, count, WORLD_STATE_QUEL_DANAS_PORTAL, m_sunsReachData.GetSubPhasePercentage(SUBPHASE_PORTAL)); + break; } } -} +} \ No newline at end of file diff --git a/src/game/World/WorldState.h b/src/game/World/WorldState.h index da6f2214f5b..0748e9c61d5 100644 --- a/src/game/World/WorldState.h +++ b/src/game/World/WorldState.h @@ -55,6 +55,10 @@ enum ZoneIds ZONEID_BOTANICA = 3847, ZONEID_ARCATRAZ = 3848, ZONEID_MECHANAR = 3849, + + ZONEID_ISLE_OF_QUEL_DANAS = 4080, + ZONEID_MAGISTERS_TERRACE = 4131, + ZONEID_SUNWELL_PLATEAU = 4075, }; enum AreaIds @@ -78,6 +82,8 @@ enum SpellId SPELL_NAZGRELS_FAVOR = 39913, SPELL_ADAL_SONG_OF_BATTLE = 39953, + + SPELL_KIRU_SONG_OF_VICTORY = 46302, }; enum GoId @@ -127,16 +133,6 @@ enum GameEvents // Prepatch event GAME_EVENT_BEFORE_THE_STORM = 100, - // Isle phases - GAME_EVENT_QUEL_DANAS_PHASE_1 = 101, - GAME_EVENT_QUEL_DANAS_PHASE_2 = 102, - GAME_EVENT_QUEL_DANAS_PHASE_2_PORTAL = 103, - GAME_EVENT_QUEL_DANAS_PHASE_3 = 104, - GAME_EVENT_QUEL_DANAS_PHASE_3_ANVIL = 105, - GAME_EVENT_QUEL_DANAS_PHASE_4 = 106, - GAME_EVENT_QUEL_DANAS_PHASE_4_MONUMENT = 107, - GAME_EVENT_QUEL_DANAS_PHASE_4_ALCHEMY_LAB = 108, - // AQ // giving items GAME_EVENT_AHN_QIRAJ_EFFORT_PHASE_1 = 120, @@ -149,8 +145,30 @@ enum GameEvents // base perpetual state GAME_EVENT_AHN_QIRAJ_EFFORT_PHASE_5 = 124, + // Isle phases + GAME_EVENT_QUEL_DANAS_PHASE_1 = 301, + GAME_EVENT_QUEL_DANAS_PHASE_2_ONLY = 302, + GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT = 303, + GAME_EVENT_QUEL_DANAS_PHASE_2_NO_PORTAL = 304, + GAME_EVENT_QUEL_DANAS_PHASE_2_PORTAL = 305, + GAME_EVENT_QUEL_DANAS_PHASE_3_ONLY = 306, + GAME_EVENT_QUEL_DANAS_PHASE_3_PERMANENT = 307, + GAME_EVENT_QUEL_DANAS_PHASE_3_NO_ANVIL = 308, + GAME_EVENT_QUEL_DANAS_PHASE_3_ANVIL = 309, + GAME_EVENT_QUEL_DANAS_PHASE_4 = 310, + GAME_EVENT_QUEL_DANAS_PHASE_4_NO_MONUMENT = 311, + GAME_EVENT_QUEL_DANAS_PHASE_4_MONUMENT = 312, + GAME_EVENT_QUEL_DANAS_PHASE_4_NO_ALCHEMY_LAB= 313, + GAME_EVENT_QUEL_DANAS_PHASE_4_ALCHEMY_LAB = 314, + GAME_EVENT_QUEL_DANAS_PHASE_4_KIRU = 315, + // SWP Phases + GAME_EVENT_SWP_GATES_PHASE_0 = 316, + GAME_EVENT_SWP_GATES_PHASE_1 = 317, + GAME_EVENT_SWP_GATES_PHASE_2 = 318, + GAME_EVENT_SWP_GATES_PHASE_3 = 319, + // wotlk range for events - GAME_EVENT_ECHOES_OF_DOOM = 401, + GAME_EVENT_ECHOES_OF_DOOM = 401, }; enum AQResources @@ -217,9 +235,52 @@ struct AhnQirajData std::string GetData(); }; -struct QuelDanasData +enum SunsReachPhases { - std::string GetData() { return ""; } + SUNS_REACH_PHASE_1_STAGING_AREA, + SUNS_REACH_PHASE_2_SANCTUM, + SUNS_REACH_PHASE_3_ARMORY, + SUNS_REACH_PHASE_4_HARBOR, +}; + +enum SunsReachSubPhases +{ + SUBPHASE_PORTAL = 0x01, + SUBPHASE_ANVIL = 0x02, + SUBPHASE_ALCHEMY_LAB = 0x04, + SUBPHASE_MONUMENT = 0x08, + SUBPHASE_ALL = SUBPHASE_PORTAL + SUBPHASE_ANVIL + SUBPHASE_ALCHEMY_LAB + SUBPHASE_MONUMENT, +}; + +enum SunsReachCounters +{ + COUNTER_ERRATIC_BEHAVIOR, + COUNTER_SANCTUM_WARDS, + COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY, + COUNTER_DISTRACTION_AT_THE_DEAD_SCAR, + COUNTER_INTERCEPTING_THE_MANA_CELLS, + COUNTER_INTERCEPT_THE_REINFORCEMENTS, + COUNTER_TAKING_THE_HARBOR, + COUNTER_MAKING_READY, + COUNTER_DISCOVERING_YOUR_ROOTS, + COUNTER_A_CHARITABLE_DONATION, + COUNTERS_MAX, +}; + +struct SunsReachReclamationData +{ + uint32 m_phase; + uint32 m_subphaseMask; + uint32 m_sunsReachReclamationCounters[COUNTERS_MAX]; + GuidVector m_sunsReachReclamationPlayers; + std::mutex m_sunsReachReclamationMutex; + SunsReachReclamationData() : m_phase(SUNS_REACH_PHASE_1_STAGING_AREA), m_subphaseMask(0) + { + memset(m_sunsReachReclamationCounters, 0, sizeof(m_sunsReachReclamationCounters)); + } + std::string GetData(); + uint32 GetPhasePercentage(uint32 phase); + uint32 GetSubPhasePercentage(uint32 subPhase); }; enum LoveIsInTheAirLeaders @@ -272,7 +333,7 @@ class WorldState void SendWorldstateUpdate(std::mutex& mutex, uint32 value, uint32 worldStateId); // vanilla section - void SendLoveIsInTheAirWorldstateUpdate(uint32 value, uint32 worldStateId); + uint32 GetLoveIsInTheAirCounter(LoveIsInTheAirLeaders leader) { return m_loveIsInTheAirData.counters[leader]; } void AddWarEffortProgress(AQResources resource, uint32 count); @@ -292,6 +353,15 @@ class WorldState uint8 GetExpansion() const { return m_expansion; } bool SetExpansion(uint8 expansion); + // Suns reach reclamation + void AddSunsReachProgress(uint32 questId); + void HandleSunsReachPhaseTransition(uint32 newPhase); + void HandleSunsReachSubPhaseTransition(int32 subPhaseMask, bool initial = false); + void SetSunsReachCounter(SunsReachCounters index, uint32 value); + void StopSunsReachPhase(bool forward); + void StartSunsReachPhase(bool initial = false); + std::string GetSunsReachPrintout(); + void FillInitialWorldStates(ByteBuffer& data, uint32& count, uint32 zoneId, uint32 areaId); // helper functions for world state list fill @@ -339,7 +409,7 @@ class WorldState GuidVector m_adalSongOfBattlePlayers; uint32 m_adalSongOfBattleTimer; - QuelDanasData m_quelDanasData; + SunsReachReclamationData m_sunsReachData; // Release Events void StartExpansionEvent();