/*
* 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 .
*/
#include "InstanceScenario.h"
#include "DatabaseEnv.h"
#include "DB2Stores.h"
#include "GameTime.h"
#include "InstanceSaveMgr.h"
#include "Log.h"
#include "Map.h"
#include "Player.h"
InstanceScenario::InstanceScenario(Map const* map, ScenarioData const* scenarioData) : Scenario(scenarioData), _map(map)
{
ASSERT(_map);
LoadInstanceData(_map->GetInstanceId());
Map::PlayerList const& players = map->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource()->ToPlayer())
SendScenarioState(player);
}
void InstanceScenario::SaveToDB()
{
if (_criteriaProgress.empty())
return;
DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(_map->GetDifficultyID());
if (!difficultyEntry || difficultyEntry->Flags & DIFFICULTY_FLAG_CHALLENGE_MODE) // Map should have some sort of "CanSave" boolean that returns whether or not the map is savable. (Challenge modes cannot be saved for example)
return;
uint32 id = _map->GetInstanceId();
if (!id)
{
TC_LOG_DEBUG("scenario", "Scenario::SaveToDB: Can not save scenario progress without an instance save. Map::GetInstanceId() did not return an instance save.");
return;
}
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
for (auto iter = _criteriaProgress.begin(); iter != _criteriaProgress.end(); ++iter)
{
if (!iter->second.Changed)
continue;
Criteria const* criteria = sCriteriaMgr->GetCriteria(iter->first);
switch (CriteriaType(criteria->Entry->Type))
{
// Blizzard only appears to store creature kills
case CriteriaType::KillCreature:
break;
default:
continue;
}
if (iter->second.Counter)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_SCENARIO_INSTANCE_CRITERIA);
stmt->setUInt32(0, id);
stmt->setUInt32(1, iter->first);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_SCENARIO_INSTANCE_CRITERIA);
stmt->setUInt32(0, id);
stmt->setUInt32(1, iter->first);
stmt->setUInt64(2, iter->second.Counter);
stmt->setInt64(3, iter->second.Date);
trans->Append(stmt);
}
iter->second.Changed = false;
}
CharacterDatabase.CommitTransaction(trans);
}
void InstanceScenario::LoadInstanceData(uint32 instanceId)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE);
stmt->setUInt32(0, instanceId);
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (result)
{
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
time_t now = GameTime::GetGameTime();
std::vector criteriaTrees;
do
{
Field* fields = result->Fetch();
uint32 id = fields[0].GetUInt32();
uint64 counter = fields[1].GetUInt64();
time_t date = fields[2].GetInt64();
Criteria const* criteria = sCriteriaMgr->GetCriteria(id);
if (!criteria)
{
// Removing non-existing criteria data for all instances
TC_LOG_ERROR("criteria.instancescenarios", "Removing scenario criteria %u data from the table `instance_scenario_progress`.", id);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_SCENARIO_INSTANCE_CRITERIA);
stmt->setUInt32(0, instanceId);
stmt->setUInt32(1, uint32(id));
trans->Append(stmt);
continue;
}
if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now)
continue;
switch (CriteriaType(criteria->Entry->Type))
{
// Blizzard appears to only stores creatures killed progress for unknown reasons. Either technical shortcoming or intentional
case CriteriaType::KillCreature:
break;
default:
continue;
}
SetCriteriaProgress(criteria, counter, nullptr, PROGRESS_SET);
if (CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID))
for (CriteriaTree const* tree : *trees)
criteriaTrees.push_back(tree);
}
while (result->NextRow());
CharacterDatabase.CommitTransaction(trans);
for (CriteriaTree const* tree : criteriaTrees)
{
ScenarioStepEntry const* step = tree->ScenarioStep;
if (!step)
continue;
if (IsCompletedCriteriaTree(tree))
SetStepState(step, SCENARIO_STEP_DONE);
}
}
}
std::string InstanceScenario::GetOwnerInfo() const
{
return Trinity::StringFormat("Instance ID %u", _map->GetInstanceId());
}
void InstanceScenario::SendPacket(WorldPacket const* data) const
{
_map->SendToPlayers(data);
}