diff options
author | Krudor <erikstrandberg93@hotmail.com> | 2016-11-06 23:30:49 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2016-11-06 23:30:49 +0100 |
commit | 8444ab736568667cb6425757ce5f832cb6068379 (patch) | |
tree | 375c6a9d25b9d5a4d351f4e3a7c0b52526dd816f /src/server/game/Scenarios/Scenario.cpp | |
parent | 9d88e78961cc92c2914ffb25333f35433a0c9682 (diff) |
Core/Instances: Implemented base scenario system and objectives in dungeons
Closes #17905
Closes #18034
Diffstat (limited to 'src/server/game/Scenarios/Scenario.cpp')
-rw-r--r-- | src/server/game/Scenarios/Scenario.cpp | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/src/server/game/Scenarios/Scenario.cpp b/src/server/game/Scenarios/Scenario.cpp new file mode 100644 index 00000000000..a4e39b2caa6 --- /dev/null +++ b/src/server/game/Scenarios/Scenario.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Scenario.h" +#include "Player.h" +#include "ScenarioMgr.h" +#include "InstanceSaveMgr.h" +#include "ObjectMgr.h" +#include "ScenarioPackets.h" + +Scenario::Scenario(ScenarioData const* scenarioData) : _data(scenarioData), _currentstep(nullptr) +{ + ASSERT(_data); + + for (auto step : _data->Steps) + SetStepState(step.second, SCENARIO_STEP_NOT_STARTED); + + if (ScenarioStepEntry const* step = GetFirstStep()) + SetStep(step); + else + TC_LOG_ERROR("scenario", "Scenario::Scenario: Could not launch Scenario (id: %u), found no valid scenario step", _data->Entry->ID); +} + +Scenario::~Scenario() +{ + for (ObjectGuid guid : _players) + if (Player* player = ObjectAccessor::FindPlayer(guid)) + SendBootPlayer(player); + + _players.clear(); +} + +void Scenario::Reset() +{ + CriteriaHandler::Reset(); + SetStep(GetFirstStep()); +} + +void Scenario::CompleteStep(ScenarioStepEntry const* step) +{ + if (Quest const* quest = sObjectMgr->GetQuestTemplate(step->QuestRewardID)) + for (ObjectGuid guid : _players) + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->RewardQuest(quest, 0, nullptr, false); + + if (step->IsBonusObjective()) + return; + + ScenarioStepEntry const* newStep = nullptr; + for (auto _step : _data->Steps) + { + if (_step.second->IsBonusObjective()) + continue; + + if (GetStepState(_step.second) == SCENARIO_STEP_DONE) + continue; + + if (!newStep || _step.second->Step < newStep->Step) + newStep = _step.second; + } + + SetStep(newStep); + if (IsComplete()) + CompleteScenario(); + else + TC_LOG_ERROR("scenario", "Scenario::CompleteStep: Scenario (id: %u, step: %u) was completed, but could not determine new step, or validate scenario completion.", step->ScenarioID, step->ID); +} + +void Scenario::CompleteScenario() +{ + return SendPacket(WorldPackets::Scenario::ScenarioCompleted(_data->Entry->ID).Write()); +} + +void Scenario::SetStep(ScenarioStepEntry const* step) +{ + _currentstep = step; + if (step) + SetStepState(step, SCENARIO_STEP_IN_PROGRESS); + + WorldPackets::Scenario::ScenarioState scenarioState; + BuildScenarioState(&scenarioState); + SendPacket(scenarioState.Write()); +} + +void Scenario::OnPlayerEnter(Player* player) +{ + _players.insert(player->GetGUID()); + SendScenarioState(player); +} + +void Scenario::OnPlayerExit(Player* player) +{ + _players.erase(player->GetGUID()); + SendBootPlayer(player); +} + +bool Scenario::IsComplete() +{ + for (auto step : _data->Steps) + { + if (step.second->IsBonusObjective()) + continue; + + if (GetStepState(step.second) != SCENARIO_STEP_DONE) + return false; + } + + return true; +} + +ScenarioStepState Scenario::GetStepState(ScenarioStepEntry const* step) +{ + std::map<ScenarioStepEntry const*, ScenarioStepState>::const_iterator itr = _stepStates.find(step); + if (itr == _stepStates.end()) + return SCENARIO_STEP_INVALID; + + return itr->second; +} + +void Scenario::SendCriteriaUpdate(Criteria const * criteria, CriteriaProgress const * progress, uint32 timeElapsed, bool timedCompleted) const +{ + WorldPackets::Scenario::ScenarioProgressUpdate progressUpdate; + progressUpdate.CriteriaProgress.Id = criteria->ID; + progressUpdate.CriteriaProgress.Quantity = progress->Counter; + progressUpdate.CriteriaProgress.Player = progress->PlayerGUID; + progressUpdate.CriteriaProgress.Date = progress->Date; + if (criteria->Entry->StartTimer) + progressUpdate.CriteriaProgress.Flags = timedCompleted ? 1 : 0; + + progressUpdate.CriteriaProgress.TimeFromStart = timeElapsed; + progressUpdate.CriteriaProgress.TimeFromCreate = 0; + + SendPacket(progressUpdate.Write()); +} + +bool Scenario::CanUpdateCriteriaTree(Criteria const * /*criteria*/, CriteriaTree const * tree, Player * /*referencePlayer*/) const +{ + ScenarioStepEntry const* step = tree->ScenarioStep; + if (!step) + return false; + + if (step->ScenarioID != _data->Entry->ID) + return false; + + ScenarioStepEntry const* currentStep = GetStep(); + if (!currentStep) + return false; + + if (step->IsBonusObjective()) + return true; + + return currentStep == step; +} + +bool Scenario::CanCompleteCriteriaTree(CriteriaTree const* tree) +{ + ScenarioStepEntry const* step = tree->ScenarioStep; + if (!step) + return false; + + if (step->ScenarioID != _data->Entry->ID) + return false; + + if (step->IsBonusObjective()) + return !IsComplete(); + + if (step != GetStep()) + return false; + + return true; +} + +void Scenario::CompletedCriteriaTree(CriteriaTree const* tree, Player* /*referencePlayer*/) +{ + ScenarioStepEntry const* step = tree->ScenarioStep; + if (!step) + return; + + if (!step->IsBonusObjective() && step != GetStep()) + return; + + if (GetStepState(step) == SCENARIO_STEP_DONE) + return; + + SetStepState(step, SCENARIO_STEP_DONE); + CompleteStep(step); +} + +void Scenario::SendPacket(WorldPacket const* data) const +{ + for (ObjectGuid guid : _players) + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->SendDirectMessage(data); +} + +void Scenario::BuildScenarioState(WorldPackets::Scenario::ScenarioState* scenarioState) +{ + scenarioState->ScenarioID = _data->Entry->ID; + if (ScenarioStepEntry const* step = GetStep()) + scenarioState->CurrentStep = step->ID; + scenarioState->CriteriaProgress = GetCriteriasProgress(); + scenarioState->BonusObjectives = GetBonusObjectivesData(); + // Don't know exactly what this is for, but seems to contain list of scenario steps that we're either on or that are completed + for (auto state : _stepStates) + { + if (state.first->IsBonusObjective()) + continue; + + switch (state.second) + { + case SCENARIO_STEP_IN_PROGRESS: + case SCENARIO_STEP_DONE: + break; + case SCENARIO_STEP_NOT_STARTED: + default: + continue; + } + + scenarioState->PickedSteps.push_back(state.first->ID); + } + scenarioState->ScenarioComplete = IsComplete(); +} + +ScenarioStepEntry const* Scenario::GetFirstStep() const +{ + // Do it like this because we don't know what order they're in inside the container. + ScenarioStepEntry const* firstStep = nullptr; + for (auto scenarioStep : _data->Steps) + { + if (scenarioStep.second->IsBonusObjective()) + continue; + + if (!firstStep || scenarioStep.second->Step < firstStep->Step) + firstStep = scenarioStep.second; + } + + return firstStep; +} + +void Scenario::SendScenarioState(Player* player) +{ + WorldPackets::Scenario::ScenarioState scenarioState; + BuildScenarioState(&scenarioState); + player->SendDirectMessage(scenarioState.Write()); +} + +std::vector<WorldPackets::Scenario::BonusObjectiveData> Scenario::GetBonusObjectivesData() +{ + std::vector<WorldPackets::Scenario::BonusObjectiveData> bonusObjectivesData; + for (auto itr = _data->Steps.begin(); itr != _data->Steps.end(); ++itr) + { + if (!itr->second->IsBonusObjective()) + continue; + + if (CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(itr->second->CriteriaTreeID)) + { + WorldPackets::Scenario::BonusObjectiveData bonusObjectiveData; + bonusObjectiveData.BonusObjectiveID = itr->second->ID; + bonusObjectiveData.ObjectiveComplete = GetStepState(itr->second) == SCENARIO_STEP_DONE; + bonusObjectivesData.push_back(bonusObjectiveData); + } + } + + return bonusObjectivesData; +} + +std::vector<WorldPackets::Achievement::CriteriaProgress> Scenario::GetCriteriasProgress() +{ + std::vector<WorldPackets::Achievement::CriteriaProgress> criteriasProgress; + + if (!_criteriaProgress.empty()) + { + for (auto critItr = _criteriaProgress.begin(); critItr != _criteriaProgress.end(); ++critItr) + { + WorldPackets::Achievement::CriteriaProgress criteriaProgress; + criteriaProgress.Id = critItr->first; + criteriaProgress.Quantity = critItr->second.Counter; + criteriaProgress.Date = critItr->second.Date; + criteriaProgress.Player = critItr->second.PlayerGUID; + criteriasProgress.push_back(criteriaProgress); + } + } + + return criteriasProgress; +} + +CriteriaList const& Scenario::GetCriteriaByType(CriteriaTypes type) const +{ + return sCriteriaMgr->GetScenarioCriteriaByType(type); +} + +void Scenario::SendBootPlayer(Player* player) +{ + WorldPackets::Scenario::ScenarioBoot scenarioBoot; + scenarioBoot.ScenarioID = _data->Entry->ID; + player->SendDirectMessage(scenarioBoot.Write()); +} |