2023-04-23 10:12:53 +02:00
|
|
|
/*
|
|
|
|
* QuestArtifact.cpp, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "StdInc.h"
|
|
|
|
#include "QuestArtifactPlacer.h"
|
2023-05-20 10:17:37 +02:00
|
|
|
#include "../CMapGenerator.h"
|
|
|
|
#include "../RmgMap.h"
|
2023-04-23 10:12:53 +02:00
|
|
|
#include "TreasurePlacer.h"
|
2023-05-20 10:17:37 +02:00
|
|
|
#include "../CZonePlacer.h"
|
|
|
|
#include "../../VCMI_Lib.h"
|
2023-06-02 20:47:37 +02:00
|
|
|
#include "../../mapObjectConstructors/AObjectTypeHandler.h"
|
|
|
|
#include "../../mapObjectConstructors/CObjectClassesHandler.h"
|
2024-06-01 17:28:17 +02:00
|
|
|
#include "../../mapObjects/MapObjects.h"
|
|
|
|
|
|
|
|
#include <vstd/RNG.h>
|
2023-04-23 10:12:53 +02:00
|
|
|
|
2023-05-20 14:00:03 +02:00
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
2023-04-23 10:12:53 +02:00
|
|
|
void QuestArtifactPlacer::process()
|
|
|
|
{
|
|
|
|
findZonesForQuestArts();
|
2023-05-20 11:46:32 +02:00
|
|
|
placeQuestArtifacts(zone.getRand());
|
2023-04-23 10:12:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QuestArtifactPlacer::init()
|
|
|
|
{
|
|
|
|
DEPENDENCY_ALL(TreasurePlacer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QuestArtifactPlacer::addQuestArtZone(std::shared_ptr<Zone> otherZone)
|
|
|
|
{
|
2023-05-19 20:30:15 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
2023-04-23 10:12:53 +02:00
|
|
|
questArtZones.push_back(otherZone);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QuestArtifactPlacer::addQuestArtifact(const ArtifactID& id)
|
|
|
|
{
|
2024-02-25 12:40:01 +02:00
|
|
|
logGlobal->trace("Need to place quest artifact %s", VLC->artifacts()->getById(id)->getNameTranslated());
|
2023-05-19 20:30:15 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
2023-04-23 10:12:53 +02:00
|
|
|
questArtifactsToPlace.emplace_back(id);
|
|
|
|
}
|
|
|
|
|
2024-01-16 18:15:35 +02:00
|
|
|
void QuestArtifactPlacer::removeQuestArtifact(const ArtifactID& id)
|
|
|
|
{
|
2024-02-25 12:40:01 +02:00
|
|
|
logGlobal->trace("Will not try to place quest artifact %s", VLC->artifacts()->getById(id)->getNameTranslated());
|
2024-01-16 18:15:35 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
|
|
|
vstd::erase_if_present(questArtifactsToPlace, id);
|
|
|
|
}
|
|
|
|
|
2023-04-23 10:12:53 +02:00
|
|
|
void QuestArtifactPlacer::rememberPotentialArtifactToReplace(CGObjectInstance* obj)
|
|
|
|
{
|
2023-05-19 20:30:15 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
2023-04-23 10:12:53 +02:00
|
|
|
artifactsToReplace.push_back(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<CGObjectInstance*> QuestArtifactPlacer::getPossibleArtifactsToReplace() const
|
|
|
|
{
|
2023-05-19 20:30:15 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
2023-04-23 10:12:53 +02:00
|
|
|
return artifactsToReplace;
|
|
|
|
}
|
|
|
|
|
2024-06-24 20:06:50 +02:00
|
|
|
CGObjectInstance * QuestArtifactPlacer::drawObjectToReplace()
|
|
|
|
{
|
|
|
|
RecursiveLock lock(externalAccessMutex);
|
|
|
|
|
|
|
|
if (artifactsToReplace.empty())
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto ret = *RandomGeneratorUtil::nextItem(artifactsToReplace, zone.getRand());
|
|
|
|
vstd::erase_if_present(artifactsToReplace, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-23 10:12:53 +02:00
|
|
|
void QuestArtifactPlacer::findZonesForQuestArts()
|
|
|
|
{
|
2023-04-29 11:46:03 +02:00
|
|
|
const auto& distances = generator.getZonePlacer()->getDistanceMap().at(zone.getId());
|
2023-04-23 10:12:53 +02:00
|
|
|
for (auto const& connectedZone : distances)
|
|
|
|
{
|
|
|
|
// Choose zones that are 1 or 2 connections away
|
|
|
|
if (vstd::iswithin(connectedZone.second, 1, 2))
|
|
|
|
{
|
|
|
|
addQuestArtZone(map.getZones().at(connectedZone.first));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-25 12:40:01 +02:00
|
|
|
logGlobal->trace("Number of nearby zones suitable for quest artifacts: %d", questArtZones.size());
|
2023-04-23 10:12:53 +02:00
|
|
|
}
|
|
|
|
|
2024-06-01 17:28:17 +02:00
|
|
|
void QuestArtifactPlacer::placeQuestArtifacts(vstd::RNG & rand)
|
2023-04-23 10:12:53 +02:00
|
|
|
{
|
|
|
|
for (const auto & artifactToPlace : questArtifactsToPlace)
|
|
|
|
{
|
2023-05-20 11:46:32 +02:00
|
|
|
RandomGeneratorUtil::randomShuffle(questArtZones, rand);
|
2023-04-23 10:12:53 +02:00
|
|
|
for (auto zone : questArtZones)
|
|
|
|
{
|
|
|
|
auto* qap = zone->getModificator<QuestArtifactPlacer>();
|
2024-06-24 20:06:50 +02:00
|
|
|
|
|
|
|
auto objectToReplace = qap->drawObjectToReplace();
|
|
|
|
if (!objectToReplace)
|
2023-04-23 10:12:53 +02:00
|
|
|
continue;
|
|
|
|
|
2024-02-25 12:40:01 +02:00
|
|
|
logGlobal->trace("Replacing %s at %s with the quest artifact %s",
|
2024-06-24 20:06:50 +02:00
|
|
|
objectToReplace->getObjectName(),
|
|
|
|
objectToReplace->getPosition().toString(),
|
2023-04-25 16:20:36 +02:00
|
|
|
VLC->artifacts()->getById(artifactToPlace)->getNameTranslated());
|
2023-04-23 10:12:53 +02:00
|
|
|
|
|
|
|
//Update appearance. Terrain is irrelevant.
|
|
|
|
auto handler = VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, artifactToPlace);
|
2024-01-01 16:37:48 +02:00
|
|
|
auto newObj = handler->create(map.mapInstance->cb, nullptr);
|
2023-04-23 10:12:53 +02:00
|
|
|
auto templates = handler->getTemplates();
|
2023-08-11 20:13:25 +02:00
|
|
|
//artifactToReplace->appearance = templates.front();
|
|
|
|
newObj->appearance = templates.front();
|
2024-06-24 20:06:50 +02:00
|
|
|
newObj->pos = objectToReplace->pos;
|
2023-08-11 20:13:25 +02:00
|
|
|
mapProxy->insertObject(newObj);
|
2024-06-24 20:06:50 +02:00
|
|
|
mapProxy->removeObject(objectToReplace);
|
2023-04-23 10:12:53 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-24 20:06:50 +02:00
|
|
|
// TODO: Unused?
|
2023-04-23 10:12:53 +02:00
|
|
|
void QuestArtifactPlacer::dropReplacedArtifact(CGObjectInstance* obj)
|
|
|
|
{
|
2023-05-19 20:30:15 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
2023-04-23 10:12:53 +02:00
|
|
|
boost::remove(artifactsToReplace, obj);
|
2023-04-29 11:46:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t QuestArtifactPlacer::getMaxQuestArtifactCount() const
|
|
|
|
{
|
2023-05-19 20:30:15 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
2023-04-29 11:46:03 +02:00
|
|
|
return questArtifacts.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
ArtifactID QuestArtifactPlacer::drawRandomArtifact()
|
|
|
|
{
|
2023-05-19 20:30:15 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
2023-04-29 11:46:03 +02:00
|
|
|
if (!questArtifacts.empty())
|
|
|
|
{
|
2023-12-11 08:37:23 +02:00
|
|
|
RandomGeneratorUtil::randomShuffle(questArtifacts, zone.getRand());
|
2023-04-29 11:46:03 +02:00
|
|
|
ArtifactID ret = questArtifacts.back();
|
|
|
|
questArtifacts.pop_back();
|
2023-12-11 08:37:23 +02:00
|
|
|
generator.banQuestArt(ret);
|
2023-04-29 11:46:03 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw rmgException("No quest artifacts left for this zone!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-16 18:15:35 +02:00
|
|
|
void QuestArtifactPlacer::addRandomArtifact(const ArtifactID & artid)
|
2023-04-29 11:46:03 +02:00
|
|
|
{
|
2023-05-19 20:30:15 +02:00
|
|
|
RecursiveLock lock(externalAccessMutex);
|
2023-04-29 11:46:03 +02:00
|
|
|
questArtifacts.push_back(artid);
|
2024-01-16 18:15:35 +02:00
|
|
|
generator.unbanQuestArt(artid);
|
2023-04-29 11:46:03 +02:00
|
|
|
}
|
2023-05-20 14:00:03 +02:00
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_END
|