mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-21 21:17:49 +02:00
Some working version, needs corrections still.
This commit is contained in:
parent
3c9599657b
commit
d325051213
@ -113,7 +113,8 @@ void CMapGenerator::initQuestArtsRemaining()
|
|||||||
//TODO: Move to QuestArtifactPlacer?
|
//TODO: Move to QuestArtifactPlacer?
|
||||||
for (auto art : VLC->arth->objects)
|
for (auto art : VLC->arth->objects)
|
||||||
{
|
{
|
||||||
if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->getId()) && art->constituentOf.empty()) //don't use parts of combined artifacts
|
//Don't use parts of combined artifacts
|
||||||
|
if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->getId()) && art->constituentOf.empty())
|
||||||
questArtifacts.push_back(art->getId());
|
questArtifacts.push_back(art->getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,7 @@ int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, TerrainId t
|
|||||||
auto factories = VLC->objtypeh->knownSubObjects(ObjID);
|
auto factories = VLC->objtypeh->knownSubObjects(ObjID);
|
||||||
vstd::erase_if(factories, [ObjID, &terrain](si32 f)
|
vstd::erase_if(factories, [ObjID, &terrain](si32 f)
|
||||||
{
|
{
|
||||||
|
//TODO: Use templates with lowest number of terrains (most specific)
|
||||||
return VLC->objtypeh->getHandlerFor(ObjID, f)->getTemplates(terrain).empty();
|
return VLC->objtypeh->getHandlerFor(ObjID, f)->getTemplates(terrain).empty();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "RmgMap.h"
|
#include "RmgMap.h"
|
||||||
#include "CMapGenerator.h"
|
#include "CMapGenerator.h"
|
||||||
#include "TreasurePlacer.h"
|
#include "TreasurePlacer.h"
|
||||||
|
#include "QuestArtifactPlacer.h"
|
||||||
#include "TownPlacer.h"
|
#include "TownPlacer.h"
|
||||||
#include "TerrainPainter.h"
|
#include "TerrainPainter.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.h"
|
#include "../mapObjects/CObjectClassesHandler.h"
|
||||||
@ -29,7 +30,8 @@ void ObjectDistributor::process()
|
|||||||
//Firts call will add objects to ALL zones, once they were added skip it
|
//Firts call will add objects to ALL zones, once they were added skip it
|
||||||
if (zone.getModificator<TreasurePlacer>()->getPossibleObjectsSize() == 0)
|
if (zone.getModificator<TreasurePlacer>()->getPossibleObjectsSize() == 0)
|
||||||
{
|
{
|
||||||
ObjectDistributor::distributeLimitedObjects();
|
distributeLimitedObjects();
|
||||||
|
distributeSeerHuts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,4 +120,33 @@ void ObjectDistributor::distributeLimitedObjects()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectDistributor::distributeSeerHuts()
|
||||||
|
{
|
||||||
|
//TODO: Move typedef outside the class?
|
||||||
|
|
||||||
|
//Copy by value to random shuffle
|
||||||
|
const auto & zoneMap = map.getZones();
|
||||||
|
RmgMap::ZoneVector zones(zoneMap.begin(), zoneMap.end());
|
||||||
|
|
||||||
|
RandomGeneratorUtil::randomShuffle(zones, generator.rand);
|
||||||
|
|
||||||
|
const auto & possibleQuestArts = generator.getQuestArtsRemaning();
|
||||||
|
size_t availableArts = possibleQuestArts.size();
|
||||||
|
auto artIt = possibleQuestArts.begin();
|
||||||
|
for (int i = zones.size() - 1; i >= 0 ; i--)
|
||||||
|
{
|
||||||
|
size_t localArts = std::ceil((float)availableArts / (i + 1));
|
||||||
|
availableArts -= localArts;
|
||||||
|
|
||||||
|
auto * qap = zones[i].second->getModificator<QuestArtifactPlacer>();
|
||||||
|
if (qap)
|
||||||
|
{
|
||||||
|
for (;localArts > 0 && artIt != possibleQuestArts.end(); artIt++, localArts--)
|
||||||
|
{
|
||||||
|
qap->addRandomArtifact(*artIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
@ -21,6 +21,7 @@ class ObjectTemplate;
|
|||||||
class ObjectDistributor : public Modificator
|
class ObjectDistributor : public Modificator
|
||||||
{
|
{
|
||||||
void distributeLimitedObjects();
|
void distributeLimitedObjects();
|
||||||
|
void distributeSeerHuts();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MODIFICATOR(ObjectDistributor);
|
MODIFICATOR(ObjectDistributor);
|
||||||
|
@ -54,8 +54,6 @@ std::vector<CGObjectInstance*> QuestArtifactPlacer::getPossibleArtifactsToReplac
|
|||||||
|
|
||||||
void QuestArtifactPlacer::findZonesForQuestArts()
|
void QuestArtifactPlacer::findZonesForQuestArts()
|
||||||
{
|
{
|
||||||
//FIXME: Store and access CZonePlacer from CMapGenerator
|
|
||||||
|
|
||||||
const auto& distances = generator.getZonePlacer()->getDistanceMap().at(zone.getId());
|
const auto& distances = generator.getZonePlacer()->getDistanceMap().at(zone.getId());
|
||||||
for (auto const& connectedZone : distances)
|
for (auto const& connectedZone : distances)
|
||||||
{
|
{
|
||||||
@ -96,6 +94,8 @@ void QuestArtifactPlacer::placeQuestArtifacts(CRandomGenerator * rand)
|
|||||||
artifactToReplace->appearance = templates.front();
|
artifactToReplace->appearance = templates.front();
|
||||||
//FIXME: Instance name is still "randomArtifact"
|
//FIXME: Instance name is still "randomArtifact"
|
||||||
|
|
||||||
|
//FIXME: Every qap has its OWN collection of artifacts,
|
||||||
|
//which means different qaps can replace the same object many times
|
||||||
qap->dropReplacedArtifact(artifactToReplace);
|
qap->dropReplacedArtifact(artifactToReplace);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -107,3 +107,28 @@ void QuestArtifactPlacer::dropReplacedArtifact(CGObjectInstance* obj)
|
|||||||
{
|
{
|
||||||
boost::remove(artifactsToReplace, obj);
|
boost::remove(artifactsToReplace, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t QuestArtifactPlacer::getMaxQuestArtifactCount() const
|
||||||
|
{
|
||||||
|
return questArtifacts.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArtifactID QuestArtifactPlacer::drawRandomArtifact()
|
||||||
|
{
|
||||||
|
if (!questArtifacts.empty())
|
||||||
|
{
|
||||||
|
ArtifactID ret = questArtifacts.back();
|
||||||
|
questArtifacts.pop_back();
|
||||||
|
RandomGeneratorUtil::randomShuffle(questArtifacts, generator.rand);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw rmgException("No quest artifacts left for this zone!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuestArtifactPlacer::addRandomArtifact(ArtifactID artid)
|
||||||
|
{
|
||||||
|
questArtifacts.push_back(artid);
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Zone.h"
|
#include "Zone.h"
|
||||||
|
#include "Functions.h"
|
||||||
#include "../mapObjects/ObjectTemplate.h"
|
#include "../mapObjects/ObjectTemplate.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
@ -33,11 +34,18 @@ public:
|
|||||||
void placeQuestArtifacts(CRandomGenerator* rand);
|
void placeQuestArtifacts(CRandomGenerator* rand);
|
||||||
void dropReplacedArtifact(CGObjectInstance* obj);
|
void dropReplacedArtifact(CGObjectInstance* obj);
|
||||||
|
|
||||||
|
size_t getMaxQuestArtifactCount() const;
|
||||||
|
ArtifactID drawRandomArtifact();
|
||||||
|
void addRandomArtifact(ArtifactID artid);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Zone>> questArtZones; //artifacts required for Seer Huts will be placed here - or not if null
|
std::vector<std::shared_ptr<Zone>> questArtZones; //artifacts required for Seer Huts will be placed here - or not if null
|
||||||
std::vector<ArtifactID> questArtifactsToPlace;
|
std::vector<ArtifactID> questArtifactsToPlace;
|
||||||
std::vector<CGObjectInstance*> artifactsToReplace; //Common artifacts which may be replaced by quest artifacts from other zones
|
std::vector<CGObjectInstance*> artifactsToReplace; //Common artifacts which may be replaced by quest artifacts from other zones
|
||||||
|
|
||||||
|
size_t maxQuestArtifacts;
|
||||||
|
std::vector<ArtifactID> questArtifacts;
|
||||||
};
|
};
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
@ -57,6 +57,8 @@ public:
|
|||||||
void setZoneID(const int3& tile, TRmgTemplateZoneId zid);
|
void setZoneID(const int3& tile, TRmgTemplateZoneId zid);
|
||||||
|
|
||||||
using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
|
using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
|
||||||
|
using ZonePair = std::pair<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
|
||||||
|
using ZoneVector = std::vector<ZonePair>;
|
||||||
|
|
||||||
Zones & getZones();
|
Zones & getZones();
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
if (templates.empty())
|
if (templates.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
//TODO: Reuse chooseRandomAppearance (eg. WoG treasure chests)
|
||||||
//Assume the template with fewest terrains is the most suitable
|
//Assume the template with fewest terrains is the most suitable
|
||||||
auto temp = *boost::min_element(templates, [](std::shared_ptr<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> rhs) -> bool
|
auto temp = *boost::min_element(templates, [](std::shared_ptr<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> rhs) -> bool
|
||||||
{
|
{
|
||||||
@ -385,44 +386,28 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
oi.probability = 2;
|
oi.probability = 2;
|
||||||
addObjectToRandomPool(oi);
|
addObjectToRandomPool(oi);
|
||||||
|
|
||||||
//seer huts with creatures or generic rewards
|
//Seer huts with creatures or generic rewards
|
||||||
|
|
||||||
if(zone.getConnections().size()) //Unlikely, but...
|
if(zone.getConnections().size()) //Unlikely, but...
|
||||||
{
|
{
|
||||||
static const int genericSeerHuts = 8;
|
auto * qap = zone.getModificator<QuestArtifactPlacer>();
|
||||||
int seerHutsPerType = 0;
|
if(!qap)
|
||||||
const int questArtsRemaining = static_cast<int>(generator.getQuestArtsRemaning().size());
|
|
||||||
|
|
||||||
//general issue is that not many artifact types are available for quests
|
|
||||||
|
|
||||||
if(questArtsRemaining >= genericSeerHuts + static_cast<int>(creatures.size()))
|
|
||||||
{
|
{
|
||||||
seerHutsPerType = questArtsRemaining / (genericSeerHuts + static_cast<int>(creatures.size()));
|
return; //TODO: throw?
|
||||||
}
|
}
|
||||||
else if(questArtsRemaining >= genericSeerHuts)
|
|
||||||
{
|
const int questArtsRemaining = qap->getMaxQuestArtifactCount();
|
||||||
seerHutsPerType = 1;
|
|
||||||
}
|
//Generate Seer Hut one by one. Duplicated oi possible and should work fine.
|
||||||
oi.maxPerZone = seerHutsPerType;
|
oi.maxPerZone = 1;
|
||||||
|
|
||||||
|
std::vector<ObjectInfo> possibleSeerHuts;
|
||||||
|
//14 creatures per town + 4 for each of gold / exp reward
|
||||||
|
possibleSeerHuts.reserve(14 + 4 + 4);
|
||||||
|
|
||||||
RandomGeneratorUtil::randomShuffle(creatures, generator.rand);
|
RandomGeneratorUtil::randomShuffle(creatures, generator.rand);
|
||||||
|
|
||||||
auto generateArtInfo = [this](const ArtifactID & id) -> ObjectInfo
|
for(int i = 0; i < static_cast<int>(creatures.size()); i++)
|
||||||
{
|
|
||||||
ObjectInfo artInfo;
|
|
||||||
artInfo.probability = std::numeric_limits<ui16>::max(); //99,9% to spawn that art in first treasure pile
|
|
||||||
artInfo.maxPerZone = 1;
|
|
||||||
artInfo.value = 2000; //treasure art
|
|
||||||
artInfo.setTemplate(Obj::ARTIFACT, id, this->zone.getTerrainType());
|
|
||||||
artInfo.generateObject = [id]() -> CGObjectInstance *
|
|
||||||
{
|
|
||||||
auto handler = VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, id);
|
|
||||||
return handler->create(handler->getTemplates().front());
|
|
||||||
};
|
|
||||||
return artInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
for(int i = 0; i < std::min(static_cast<int>(creatures.size()), questArtsRemaining - genericSeerHuts); i++)
|
|
||||||
{
|
{
|
||||||
auto * creature = creatures[i];
|
auto * creature = creatures[i];
|
||||||
int creaturesAmount = creatureToCount(creature);
|
int creaturesAmount = creatureToCount(creature);
|
||||||
@ -432,7 +417,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
int randomAppearance = chooseRandomAppearance(generator.rand, Obj::SEER_HUT, zone.getTerrainType());
|
int randomAppearance = chooseRandomAppearance(generator.rand, Obj::SEER_HUT, zone.getTerrainType());
|
||||||
|
|
||||||
oi.generateObject = [creature, creaturesAmount, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
oi.generateObject = [creature, creaturesAmount, randomAppearance, this, qap]() -> CGObjectInstance *
|
||||||
{
|
{
|
||||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||||
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
||||||
@ -441,7 +426,8 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
obj->rVal = creaturesAmount;
|
obj->rVal = creaturesAmount;
|
||||||
|
|
||||||
obj->quest->missionType = CQuest::MISSION_ART;
|
obj->quest->missionType = CQuest::MISSION_ART;
|
||||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
|
|
||||||
|
ArtifactID artid = qap->drawRandomArtifact();
|
||||||
obj->quest->addArtifactID(artid);
|
obj->quest->addArtifactID(artid);
|
||||||
obj->quest->lastDay = -1;
|
obj->quest->lastDay = -1;
|
||||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||||
@ -451,10 +437,17 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
oi.probability = 3;
|
||||||
oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
|
oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
|
||||||
oi.value = static_cast<ui32>(((2 * (creature->getAIValue()) * creaturesAmount * (1 + static_cast<float>(map.getZoneCount(creature->getFaction())) / map.getTotalZoneCount())) - 4000) / 3);
|
oi.value = static_cast<ui32>(((2 * (creature->getAIValue()) * creaturesAmount * (1 + static_cast<float>(map.getZoneCount(creature->getFaction())) / map.getTotalZoneCount())) - 4000) / 3);
|
||||||
oi.probability = 3;
|
if (oi.value > zone.getMaxTreasureValue())
|
||||||
addObjectToRandomPool(oi);
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
possibleSeerHuts.push_back(oi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int seerLevels = std::min(generator.getConfig().questValues.size(), generator.getConfig().questRewardValues.size());
|
static int seerLevels = std::min(generator.getConfig().questValues.size(), generator.getConfig().questRewardValues.size());
|
||||||
@ -464,9 +457,15 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
|
oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
|
||||||
oi.value = generator.getConfig().questValues[i];
|
oi.value = generator.getConfig().questValues[i];
|
||||||
|
if (oi.value > zone.getMaxTreasureValue())
|
||||||
|
{
|
||||||
|
//Both variants have same value
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
oi.probability = 10;
|
oi.probability = 10;
|
||||||
|
|
||||||
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
|
||||||
{
|
{
|
||||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||||
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
||||||
@ -476,7 +475,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
obj->rVal = generator.getConfig().questRewardValues[i];
|
obj->rVal = generator.getConfig().questRewardValues[i];
|
||||||
|
|
||||||
obj->quest->missionType = CQuest::MISSION_ART;
|
obj->quest->missionType = CQuest::MISSION_ART;
|
||||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
|
ArtifactID artid = qap->drawRandomArtifact();
|
||||||
obj->quest->addArtifactID(artid);
|
obj->quest->addArtifactID(artid);
|
||||||
obj->quest->lastDay = -1;
|
obj->quest->lastDay = -1;
|
||||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||||
@ -487,9 +486,9 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
addObjectToRandomPool(oi);
|
possibleSeerHuts.push_back(oi);
|
||||||
|
|
||||||
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
|
||||||
{
|
{
|
||||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||||
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
||||||
@ -498,7 +497,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
obj->rVal = generator.getConfig().questRewardValues[i];
|
obj->rVal = generator.getConfig().questRewardValues[i];
|
||||||
|
|
||||||
obj->quest->missionType = CQuest::MISSION_ART;
|
obj->quest->missionType = CQuest::MISSION_ART;
|
||||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
|
ArtifactID artid = qap->drawRandomArtifact();
|
||||||
obj->quest->addArtifactID(artid);
|
obj->quest->addArtifactID(artid);
|
||||||
obj->quest->lastDay = -1;
|
obj->quest->lastDay = -1;
|
||||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||||
@ -509,7 +508,12 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
addObjectToRandomPool(oi);
|
possibleSeerHuts.push_back(oi);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < questArtsRemaining; i++)
|
||||||
|
{
|
||||||
|
addObjectToRandomPool(*RandomGeneratorUtil::nextItem(possibleSeerHuts, generator.rand));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user