TrinityCore
Scenario.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Scenario.h"
19#include "Log.h"
20#include "Map.h"
21#include "ObjectAccessor.h"
22#include "ObjectMgr.h"
23#include "Player.h"
24#include "ScenarioMgr.h"
25#include "ScenarioPackets.h"
26#include "WorldSession.h"
27
28Scenario::Scenario(Map* map, ScenarioData const* scenarioData) : _map(map), _data(scenarioData),
29 _guid(ObjectGuid::Create<HighGuid::Scenario>(map->GetId(), scenarioData->Entry->ID, map->GenerateLowGuid<HighGuid::Scenario>())),
30 _currentstep(nullptr)
31{
33
34 for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps)
35 SetStepState(scenarioStep.second, SCENARIO_STEP_NOT_STARTED);
36
37 if (ScenarioStepEntry const* step = GetFirstStep())
38 SetStep(step);
39 else
40 TC_LOG_ERROR("scenario", "Scenario::Scenario: Could not launch Scenario (id: {}), found no valid scenario step", _data->Entry->ID);
41}
42
44{
45 for (ObjectGuid guid : _players)
46 if (Player* player = ObjectAccessor::GetPlayer(_map, guid))
47 SendBootPlayer(player);
48
49 _players.clear();
50}
51
53{
56}
57
59{
60 if (Quest const* quest = sObjectMgr->GetQuestTemplate(step->RewardQuestID))
61 for (ObjectGuid guid : _players)
62 if (Player* player = ObjectAccessor::GetPlayer(_map, guid))
63 player->RewardQuest(quest, LootItemType::Item, 0, nullptr, false);
64
65 if (step->IsBonusObjective())
66 return;
67
68 ScenarioStepEntry const* newStep = nullptr;
69 for (auto const& _step : _data->Steps)
70 {
71 if (_step.second->IsBonusObjective())
72 continue;
73
74 if (GetStepState(_step.second) == SCENARIO_STEP_DONE)
75 continue;
76
77 if (!newStep || _step.second->OrderIndex < newStep->OrderIndex)
78 newStep = _step.second;
79 }
80
81 SetStep(newStep);
82 if (IsComplete())
84 else
85 TC_LOG_ERROR("scenario", "Scenario::CompleteStep: Scenario (id: {}, step: {}) was completed, but could not determine new step, or validate scenario completion.", step->ScenarioID, step->ID);
86}
87
89{
91}
92
94{
95 _currentstep = step;
96 if (step)
97 {
99 for (ObjectGuid const& guid : _players)
100 if (Player* player = ObjectAccessor::GetPlayer(_map, guid))
101 player->StartCriteria(CriteriaStartEvent::BeginScenarioStep, step->ID);
102 }
103
104 DoForAllPlayers([&](Player const* receiver)
105 {
107 BuildScenarioStateFor(receiver, &scenarioState);
108 receiver->SendDirectMessage(scenarioState.Write());
109 });
110}
111
113{
114 _players.insert(player->GetGUID());
115 SendScenarioState(player);
116}
117
119{
120 _players.erase(player->GetGUID());
121 SendBootPlayer(player);
122}
123
125{
126 for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps)
127 {
128 if (scenarioStep.second->IsBonusObjective())
129 continue;
130
131 if (GetStepState(scenarioStep.second) != SCENARIO_STEP_DONE)
132 return false;
133 }
134
135 return true;
136}
137
139{
140 return _data->Entry;
141}
142
144{
145 auto itr = _stepStates.find(step);
146 if (itr == _stepStates.end())
148
149 return itr->second;
150}
151
152void Scenario::SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, Seconds timeElapsed, bool timedCompleted) const
153{
154 DoForAllPlayers([=](Player const* receiver)
155 {
157 progressUpdate.CriteriaProgress.Id = criteria->ID;
158 progressUpdate.CriteriaProgress.Quantity = progress->Counter;
159 progressUpdate.CriteriaProgress.Player = progress->PlayerGUID;
160 progressUpdate.CriteriaProgress.Date.SetUtcTimeFromUnixTime(progress->Date);
161 progressUpdate.CriteriaProgress.Date += receiver->GetSession()->GetTimezoneOffset();
162 if (criteria->Entry->StartTimer)
163 progressUpdate.CriteriaProgress.Flags = timedCompleted ? 1 : 0;
164
165 progressUpdate.CriteriaProgress.TimeFromStart = timeElapsed;
166 progressUpdate.CriteriaProgress.TimeFromCreate = Seconds::zero();
167
168 receiver->SendDirectMessage(progressUpdate.Write());
169 });
170}
171
172bool Scenario::CanUpdateCriteriaTree(Criteria const * /*criteria*/, CriteriaTree const * tree, Player * /*referencePlayer*/) const
173{
174 ScenarioStepEntry const* step = tree->ScenarioStep;
175 if (!step)
176 return false;
177
178 if (step->ScenarioID != _data->Entry->ID)
179 return false;
180
181 ScenarioStepEntry const* currentStep = GetStep();
182 if (!currentStep)
183 return false;
184
185 if (step->IsBonusObjective())
186 return true;
187
188 return currentStep == step;
189}
190
192{
193 ScenarioStepEntry const* step = tree->ScenarioStep;
194 if (!step)
195 return false;
196
197 ScenarioStepState const state = GetStepState(step);
198 if (state == SCENARIO_STEP_DONE)
199 return false;
200
201 ScenarioStepEntry const* currentStep = GetStep();
202 if (!currentStep)
203 return false;
204
205 if (!step->IsBonusObjective())
206 if (step != currentStep)
207 return false;
208
210}
211
212void Scenario::CompletedCriteriaTree(CriteriaTree const* tree, Player* /*referencePlayer*/)
213{
214 ScenarioStepEntry const* step = ASSERT_NOTNULL(tree->ScenarioStep);
215 if (!IsCompletedStep(step))
216 return;
217
219 CompleteStep(step);
220}
221
223{
224 CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(step->Criteriatreeid);
225 if (!tree)
226 return false;
227
228 return IsCompletedCriteriaTree(tree);
229}
230
231void Scenario::DoForAllPlayers(std::function<void(Player*)> const& worker) const
232{
233 for (ObjectGuid guid : _players)
234 if (Player* player = ObjectAccessor::GetPlayer(_map, guid))
235 worker(player);
236}
237
238void Scenario::SendPacket(WorldPacket const* data) const
239{
240 DoForAllPlayers([data](Player const* player)
241 {
242 player->SendDirectMessage(data);
243 });
244}
245
247{
248 scenarioState->ScenarioGUID = _guid;
249 scenarioState->ScenarioID = _data->Entry->ID;
250 if (ScenarioStepEntry const* step = GetStep())
251 scenarioState->CurrentStep = step->ID;
252 scenarioState->CriteriaProgress = GetCriteriasProgressFor(player);
253 scenarioState->BonusObjectives = GetBonusObjectivesData();
254 // 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
255 for (std::pair<ScenarioStepEntry const* const, ScenarioStepState> const& state : _stepStates)
256 {
257 if (state.first->IsBonusObjective())
258 continue;
259
260 switch (state.second)
261 {
264 break;
266 default:
267 continue;
268 }
269
270 scenarioState->PickedSteps.push_back(state.first->ID);
271 }
272 scenarioState->ScenarioComplete = IsComplete();
273}
274
276{
277 // Do it like this because we don't know what order they're in inside the container.
278 ScenarioStepEntry const* firstStep = nullptr;
279 for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps)
280 {
281 if (scenarioStep.second->IsBonusObjective())
282 continue;
283
284 if (!firstStep || scenarioStep.second->OrderIndex < firstStep->OrderIndex)
285 firstStep = scenarioStep.second;
286 }
287
288 return firstStep;
289}
290
292{
293 // Do it like this because we don't know what order they're in inside the container.
294 ScenarioStepEntry const* lastStep = nullptr;
295 for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps)
296 {
297 if (scenarioStep.second->IsBonusObjective())
298 continue;
299
300 if (!lastStep || scenarioStep.second->OrderIndex > lastStep->OrderIndex)
301 lastStep = scenarioStep.second;
302 }
303
304 return lastStep;
305}
306
307void Scenario::SendScenarioState(Player const* player) const
308{
310 BuildScenarioStateFor(player, &scenarioState);
311 player->SendDirectMessage(scenarioState.Write());
312}
313
314std::vector<WorldPackets::Scenario::BonusObjectiveData> Scenario::GetBonusObjectivesData() const
315{
316 std::vector<WorldPackets::Scenario::BonusObjectiveData> bonusObjectivesData;
317 for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps)
318 {
319 if (!scenarioStep.second->IsBonusObjective())
320 continue;
321
322 if (sCriteriaMgr->GetCriteriaTree(scenarioStep.second->Criteriatreeid))
323 {
325 bonusObjectiveData.BonusObjectiveID = scenarioStep.second->ID;
326 bonusObjectiveData.ObjectiveComplete = GetStepState(scenarioStep.second) == SCENARIO_STEP_DONE;
327 bonusObjectivesData.push_back(bonusObjectiveData);
328 }
329 }
330
331 return bonusObjectivesData;
332}
333
334std::vector<WorldPackets::Achievement::CriteriaProgress> Scenario::GetCriteriasProgressFor(Player const* player) const
335{
336 std::vector<WorldPackets::Achievement::CriteriaProgress> criteriasProgress;
337
338 for (auto const& [criteriaId, progress] : _criteriaProgress)
339 {
340 WorldPackets::Achievement::CriteriaProgress& criteriaProgress = criteriasProgress.emplace_back();
341 criteriaProgress.Id = criteriaId;
342 criteriaProgress.Quantity = progress.Counter;
343 criteriaProgress.Date.SetUtcTimeFromUnixTime(progress.Date);
344 criteriaProgress.Date += player->GetSession()->GetTimezoneOffset();
345 criteriaProgress.Player = progress.PlayerGUID;
346 }
347
348 return criteriasProgress;
349}
350
352{
353 return sCriteriaMgr->GetScenarioCriteriaByTypeAndScenario(type, _data->Entry->ID);
354}
355
356void Scenario::SendBootPlayer(Player const* player) const
357{
359 scenarioBoot.ScenarioGUID = _guid;
360 scenarioBoot.ScenarioID = _data->Entry->ID;
361 player->SendDirectMessage(scenarioBoot.Write());
362}
#define sCriteriaMgr
std::vector< Criteria const * > CriteriaList
CriteriaType
Definition: DBCEnums.h:503
uint32_t uint32
Definition: Define.h:142
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition: Duration.h:32
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
HighGuid
Definition: ObjectGuid.h:75
#define sObjectMgr
Definition: ObjectMgr.h:1946
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
ScenarioStepState
Definition: Scenario.h:45
@ SCENARIO_STEP_IN_PROGRESS
Definition: Scenario.h:48
@ SCENARIO_STEP_INVALID
Definition: Scenario.h:46
@ SCENARIO_STEP_DONE
Definition: Scenario.h:49
@ SCENARIO_STEP_NOT_STARTED
Definition: Scenario.h:47
uint32 const Entry[5]
virtual void Reset()
CriteriaProgressMap _criteriaProgress
virtual bool CanCompleteCriteriaTree(CriteriaTree const *tree)
bool IsCompletedCriteriaTree(CriteriaTree const *tree)
Definition: Map.h:189
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
WorldSession * GetSession() const
Definition: Player.h:2101
void SendScenarioState(Player const *player) const
Definition: Scenario.cpp:307
ScenarioEntry const * GetEntry() const
Definition: Scenario.cpp:138
std::vector< WorldPackets::Achievement::CriteriaProgress > GetCriteriasProgressFor(Player const *player) const
Definition: Scenario.cpp:334
virtual void OnPlayerExit(Player *player)
Definition: Scenario.cpp:118
void SendPacket(WorldPacket const *data) const override
Definition: Scenario.cpp:238
void SendBootPlayer(Player const *player) const
Definition: Scenario.cpp:356
ScenarioData const * _data
Definition: Scenario.h:103
virtual void OnPlayerEnter(Player *player)
Definition: Scenario.cpp:112
ScenarioStepEntry const * GetLastStep() const
Definition: Scenario.cpp:291
ScenarioStepEntry const * GetFirstStep() const
Definition: Scenario.cpp:275
bool IsComplete() const
Definition: Scenario.cpp:124
void Reset() override
Definition: Scenario.cpp:52
std::vector< WorldPackets::Scenario::BonusObjectiveData > GetBonusObjectivesData() const
Definition: Scenario.cpp:314
bool CanUpdateCriteriaTree(Criteria const *criteria, CriteriaTree const *tree, Player *referencePlayer) const override
Definition: Scenario.cpp:172
virtual void CompleteStep(ScenarioStepEntry const *step)
Definition: Scenario.cpp:58
Map const * _map
Definition: Scenario.h:81
ScenarioStepState GetStepState(ScenarioStepEntry const *step) const
Definition: Scenario.cpp:143
std::map< ScenarioStepEntry const *, ScenarioStepState > _stepStates
Definition: Scenario.h:108
Scenario(Map *map, ScenarioData const *scenarioData)
Definition: Scenario.cpp:28
ObjectGuid const _guid
Definition: Scenario.h:106
bool CanCompleteCriteriaTree(CriteriaTree const *tree) override
Definition: Scenario.cpp:191
GuidUnorderedSet _players
Definition: Scenario.h:82
void DoForAllPlayers(std::function< void(Player *)> const &worker) const
Definition: Scenario.cpp:231
void BuildScenarioStateFor(Player const *player, WorldPackets::Scenario::ScenarioState *scenarioState) const
Definition: Scenario.cpp:246
ScenarioStepEntry const * _currentstep
Definition: Scenario.h:107
~Scenario()
Definition: Scenario.cpp:43
virtual void CompleteScenario()
Definition: Scenario.cpp:88
void SetStepState(ScenarioStepEntry const *step, ScenarioStepState state)
Definition: Scenario.h:70
ScenarioStepEntry const * GetStep() const
Definition: Scenario.h:73
void SetStep(ScenarioStepEntry const *step)
Definition: Scenario.cpp:93
bool IsCompletedStep(ScenarioStepEntry const *step)
Definition: Scenario.cpp:222
CriteriaList const & GetCriteriaByType(CriteriaType type, uint32 asset) const override
Definition: Scenario.cpp:351
void CompletedCriteriaTree(CriteriaTree const *tree, Player *referencePlayer) override
Definition: Scenario.cpp:212
void SendCriteriaUpdate(Criteria const *criteria, CriteriaProgress const *progress, Seconds timeElapsed, bool timedCompleted) const override
Definition: Scenario.cpp:152
WorldPacket const * Write() override
Achievement::CriteriaProgress CriteriaProgress
std::vector< Achievement::CriteriaProgress > CriteriaProgress
WorldPacket const * Write() override
std::vector< BonusObjectiveData > BonusObjectives
WorldPacket const * Write() override
Minutes GetTimezoneOffset() const
void SetUtcTimeFromUnixTime(std::time_t unixTime)
Definition: WowTime.cpp:86
TC_GAME_API uint32 GetId(std::string_view username)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
std::unique_ptr< VignetteData > Create(VignetteEntry const *vignetteData, WorldObject const *owner)
Definition: Vignette.cpp:72
std::time_t Date
ObjectGuid PlayerGUID
ScenarioStepEntry const * ScenarioStep
CriteriaEntry const * Entry
std::map< uint8, ScenarioStepEntry const * > Steps
Definition: ScenarioMgr.h:36
ScenarioEntry const * Entry
Definition: ScenarioMgr.h:35
bool IsBonusObjective() const