mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-29 21:56:54 +02:00
Merge pull request #2981 from Nordsoft91/rmg-template
Select random object template instead of first
This commit is contained in:
commit
80be1e9f4c
@ -111,18 +111,18 @@ void Object::Instance::setPositionRaw(const int3 & position)
|
|||||||
dObject.pos = dPosition + dParent.getPosition();
|
dObject.pos = dPosition + dParent.getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::Instance::setAnyTemplate()
|
void Object::Instance::setAnyTemplate(CRandomGenerator & rng)
|
||||||
{
|
{
|
||||||
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates();
|
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates();
|
||||||
if(templates.empty())
|
if(templates.empty())
|
||||||
throw rmgException(boost::str(boost::format("Did not find any graphics for object (%d,%d)") % dObject.ID % dObject.subID));
|
throw rmgException(boost::str(boost::format("Did not find any graphics for object (%d,%d)") % dObject.ID % dObject.subID));
|
||||||
|
|
||||||
dObject.appearance = templates.front();
|
dObject.appearance = *RandomGeneratorUtil::nextItem(templates, rng);
|
||||||
dAccessibleAreaCache.clear();
|
dAccessibleAreaCache.clear();
|
||||||
setPosition(getPosition(false));
|
setPosition(getPosition(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::Instance::setTemplate(TerrainId terrain)
|
void Object::Instance::setTemplate(TerrainId terrain, CRandomGenerator & rng)
|
||||||
{
|
{
|
||||||
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
|
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
|
||||||
if (templates.empty())
|
if (templates.empty())
|
||||||
@ -130,7 +130,8 @@ void Object::Instance::setTemplate(TerrainId terrain)
|
|||||||
auto terrainName = VLC->terrainTypeHandler->getById(terrain)->getNameTranslated();
|
auto terrainName = VLC->terrainTypeHandler->getById(terrain)->getNameTranslated();
|
||||||
throw rmgException(boost::str(boost::format("Did not find graphics for object (%d,%d) at %s") % dObject.ID % dObject.subID % terrainName));
|
throw rmgException(boost::str(boost::format("Did not find graphics for object (%d,%d) at %s") % dObject.ID % dObject.subID % terrainName));
|
||||||
}
|
}
|
||||||
dObject.appearance = templates.front();
|
|
||||||
|
dObject.appearance = *RandomGeneratorUtil::nextItem(templates, rng);
|
||||||
dAccessibleAreaCache.clear();
|
dAccessibleAreaCache.clear();
|
||||||
setPosition(getPosition(false));
|
setPosition(getPosition(false));
|
||||||
}
|
}
|
||||||
@ -280,10 +281,10 @@ void Object::setPosition(const int3 & position)
|
|||||||
i.setPositionRaw(i.getPosition());
|
i.setPositionRaw(i.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::setTemplate(const TerrainId & terrain)
|
void Object::setTemplate(const TerrainId & terrain, CRandomGenerator & rng)
|
||||||
{
|
{
|
||||||
for(auto& i : dInstances)
|
for(auto& i : dInstances)
|
||||||
i.setTemplate(terrain);
|
i.setTemplate(terrain, rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Area & Object::getArea() const
|
const Area & Object::getArea() const
|
||||||
@ -325,7 +326,7 @@ void rmg::Object::setGuardedIfMonster(const Instance& object)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::Instance::finalize(RmgMap & map)
|
void Object::Instance::finalize(RmgMap & map, CRandomGenerator & rng)
|
||||||
{
|
{
|
||||||
if(!map.isOnMap(getPosition(true)))
|
if(!map.isOnMap(getPosition(true)))
|
||||||
throw rmgException(boost::str(boost::format("Position of object %d at %s is outside the map") % dObject.id % getPosition(true).toString()));
|
throw rmgException(boost::str(boost::format("Position of object %d at %s is outside the map") % dObject.id % getPosition(true).toString()));
|
||||||
@ -341,7 +342,7 @@ void Object::Instance::finalize(RmgMap & map)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setTemplate(terrainType->getId());
|
setTemplate(terrainType->getId(), rng);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,14 +363,14 @@ void Object::Instance::finalize(RmgMap & map)
|
|||||||
map.getMapProxy()->insertObject(&dObject);
|
map.getMapProxy()->insertObject(&dObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::finalize(RmgMap & map)
|
void Object::finalize(RmgMap & map, CRandomGenerator & rng)
|
||||||
{
|
{
|
||||||
if(dInstances.empty())
|
if(dInstances.empty())
|
||||||
throw rmgException("Cannot finalize object without instances");
|
throw rmgException("Cannot finalize object without instances");
|
||||||
|
|
||||||
for(auto & dInstance : dInstances)
|
for(auto & dInstance : dInstances)
|
||||||
{
|
{
|
||||||
dInstance.finalize(map);
|
dInstance.finalize(map, rng);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class CGObjectInstance;
|
class CGObjectInstance;
|
||||||
|
class CRandomGenerator;
|
||||||
class RmgMap;
|
class RmgMap;
|
||||||
|
|
||||||
namespace rmg {
|
namespace rmg {
|
||||||
@ -35,8 +36,8 @@ public:
|
|||||||
int3 getVisitablePosition() const;
|
int3 getVisitablePosition() const;
|
||||||
bool isVisitableFrom(const int3 & tile) const;
|
bool isVisitableFrom(const int3 & tile) const;
|
||||||
const Area & getAccessibleArea() const;
|
const Area & getAccessibleArea() const;
|
||||||
void setTemplate(TerrainId terrain); //cache invalidation
|
void setTemplate(TerrainId terrain, CRandomGenerator &); //cache invalidation
|
||||||
void setAnyTemplate(); //cache invalidation
|
void setAnyTemplate(CRandomGenerator &); //cache invalidation
|
||||||
|
|
||||||
int3 getTopTile() const;
|
int3 getTopTile() const;
|
||||||
int3 getPosition(bool isAbsolute = false) const;
|
int3 getPosition(bool isAbsolute = false) const;
|
||||||
@ -45,7 +46,7 @@ public:
|
|||||||
const CGObjectInstance & object() const;
|
const CGObjectInstance & object() const;
|
||||||
CGObjectInstance & object();
|
CGObjectInstance & object();
|
||||||
|
|
||||||
void finalize(RmgMap & map); //cache invalidation
|
void finalize(RmgMap & map, CRandomGenerator &); //cache invalidation
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -73,7 +74,7 @@ public:
|
|||||||
|
|
||||||
const int3 & getPosition() const;
|
const int3 & getPosition() const;
|
||||||
void setPosition(const int3 & position);
|
void setPosition(const int3 & position);
|
||||||
void setTemplate(const TerrainId & terrain);
|
void setTemplate(const TerrainId & terrain, CRandomGenerator &);
|
||||||
|
|
||||||
const Area & getArea() const; //lazy cache invalidation
|
const Area & getArea() const; //lazy cache invalidation
|
||||||
const int3 getVisibleTop() const;
|
const int3 getVisibleTop() const;
|
||||||
@ -81,7 +82,7 @@ public:
|
|||||||
bool isGuarded() const;
|
bool isGuarded() const;
|
||||||
void setGuardedIfMonster(const Instance & object);
|
void setGuardedIfMonster(const Instance & object);
|
||||||
|
|
||||||
void finalize(RmgMap & map);
|
void finalize(RmgMap & map, CRandomGenerator &);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -316,8 +316,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
|
|||||||
auto * gate2 = factory->create();
|
auto * gate2 = factory->create();
|
||||||
rmg::Object rmgGate1(*gate1);
|
rmg::Object rmgGate1(*gate1);
|
||||||
rmg::Object rmgGate2(*gate2);
|
rmg::Object rmgGate2(*gate2);
|
||||||
rmgGate1.setTemplate(zone.getTerrainType());
|
rmgGate1.setTemplate(zone.getTerrainType(), zone.getRand());
|
||||||
rmgGate2.setTemplate(otherZone->getTerrainType());
|
rmgGate2.setTemplate(otherZone->getTerrainType(), zone.getRand());
|
||||||
bool guarded1 = manager.addGuard(rmgGate1, connection.getGuardStrength(), true);
|
bool guarded1 = manager.addGuard(rmgGate1, connection.getGuardStrength(), true);
|
||||||
bool guarded2 = managerOther.addGuard(rmgGate2, connection.getGuardStrength(), true);
|
bool guarded2 = managerOther.addGuard(rmgGate2, connection.getGuardStrength(), true);
|
||||||
int minDist = 3;
|
int minDist = 3;
|
||||||
|
@ -79,25 +79,14 @@ void ObjectDistributor::distributeLimitedObjects()
|
|||||||
|
|
||||||
for (auto& zone : matchingZones)
|
for (auto& zone : matchingZones)
|
||||||
{
|
{
|
||||||
//We already know there are some templates
|
oi.generateObject = [primaryID, secondaryID]() -> CGObjectInstance *
|
||||||
auto templates = handler->getTemplates(zone->getTerrainType());
|
|
||||||
|
|
||||||
//FIXME: Templates empty?! Maybe zone changed terrain type over time?
|
|
||||||
|
|
||||||
//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
|
|
||||||
{
|
{
|
||||||
return lhs->getAllowedTerrains().size() < rhs->getAllowedTerrains().size();
|
return VLC->objtypeh->getHandlerFor(primaryID, secondaryID)->create();
|
||||||
});
|
|
||||||
|
|
||||||
oi.generateObject = [temp]() -> CGObjectInstance *
|
|
||||||
{
|
|
||||||
return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
oi.value = rmgInfo.value;
|
oi.value = rmgInfo.value;
|
||||||
oi.probability = rmgInfo.rarity;
|
oi.probability = rmgInfo.rarity;
|
||||||
oi.templ = temp;
|
oi.setTemplates(primaryID, secondaryID, zone->getTerrainType());
|
||||||
|
|
||||||
//Rounding up will make sure all possible objects are exhausted
|
//Rounding up will make sure all possible objects are exhausted
|
||||||
uint32_t mapLimit = rmgInfo.mapLimit.value();
|
uint32_t mapLimit = rmgInfo.mapLimit.value();
|
||||||
@ -109,7 +98,7 @@ void ObjectDistributor::distributeLimitedObjects()
|
|||||||
|
|
||||||
rmgInfo.setMapLimit(mapLimit - oi.maxPerZone);
|
rmgInfo.setMapLimit(mapLimit - oi.maxPerZone);
|
||||||
//Don't add objects with 0 count remaining
|
//Don't add objects with 0 count remaining
|
||||||
if (oi.maxPerZone)
|
if(oi.maxPerZone && !oi.templates.empty())
|
||||||
{
|
{
|
||||||
zone->getModificator<TreasurePlacer>()->addObjectToRandomPool(oi);
|
zone->getModificator<TreasurePlacer>()->addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
|
@ -354,7 +354,7 @@ bool ObjectManager::createRequiredObjects()
|
|||||||
for(const auto & objInfo : requiredObjects)
|
for(const auto & objInfo : requiredObjects)
|
||||||
{
|
{
|
||||||
rmg::Object rmgObject(*objInfo.obj);
|
rmg::Object rmgObject(*objInfo.obj);
|
||||||
rmgObject.setTemplate(zone.getTerrainType());
|
rmgObject.setTemplate(zone.getTerrainType(), zone.getRand());
|
||||||
bool guarded = addGuard(rmgObject, objInfo.guardStrength, (objInfo.obj->ID == Obj::MONOLITH_TWO_WAY));
|
bool guarded = addGuard(rmgObject, objInfo.guardStrength, (objInfo.obj->ID == Obj::MONOLITH_TWO_WAY));
|
||||||
|
|
||||||
Zone::Lock lock(zone.areaMutex);
|
Zone::Lock lock(zone.areaMutex);
|
||||||
@ -394,7 +394,7 @@ bool ObjectManager::createRequiredObjects()
|
|||||||
auto possibleArea = zone.areaPossible();
|
auto possibleArea = zone.areaPossible();
|
||||||
|
|
||||||
rmg::Object rmgObject(*objInfo.obj);
|
rmg::Object rmgObject(*objInfo.obj);
|
||||||
rmgObject.setTemplate(zone.getTerrainType());
|
rmgObject.setTemplate(zone.getTerrainType(), zone.getRand());
|
||||||
bool guarded = addGuard(rmgObject, objInfo.guardStrength, (objInfo.obj->ID == Obj::MONOLITH_TWO_WAY));
|
bool guarded = addGuard(rmgObject, objInfo.guardStrength, (objInfo.obj->ID == Obj::MONOLITH_TWO_WAY));
|
||||||
auto path = placeAndConnectObject(zone.areaPossible(), rmgObject,
|
auto path = placeAndConnectObject(zone.areaPossible(), rmgObject,
|
||||||
[this, &rmgObject](const int3 & tile)
|
[this, &rmgObject](const int3 & tile)
|
||||||
@ -480,7 +480,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
|||||||
if (!monster->object().appearance)
|
if (!monster->object().appearance)
|
||||||
{
|
{
|
||||||
//Needed to determine visitable offset
|
//Needed to determine visitable offset
|
||||||
monster->setAnyTemplate();
|
monster->setAnyTemplate(zone.getRand());
|
||||||
}
|
}
|
||||||
object.getPosition();
|
object.getPosition();
|
||||||
auto visitableOffset = monster->object().getVisitableOffset();
|
auto visitableOffset = monster->object().getVisitableOffset();
|
||||||
@ -492,7 +492,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
|||||||
int3 parentOffset = monster->getPosition(true) - monster->getPosition(false);
|
int3 parentOffset = monster->getPosition(true) - monster->getPosition(false);
|
||||||
monster->setPosition(fixedPos - parentOffset);
|
monster->setPosition(fixedPos - parentOffset);
|
||||||
}
|
}
|
||||||
object.finalize(map);
|
object.finalize(map, zone.getRand());
|
||||||
|
|
||||||
Zone::Lock lock(zone.areaMutex);
|
Zone::Lock lock(zone.areaMutex);
|
||||||
zone.areaPossible().subtract(object.getArea());
|
zone.areaPossible().subtract(object.getArea());
|
||||||
@ -689,7 +689,7 @@ bool ObjectManager::addGuard(rmg::Object & object, si32 strength, bool zoneGuard
|
|||||||
});
|
});
|
||||||
|
|
||||||
auto & instance = object.addInstance(*guard);
|
auto & instance = object.addInstance(*guard);
|
||||||
instance.setAnyTemplate(); //terrain is irrelevant for monsters, but monsters need some template now
|
instance.setAnyTemplate(zone.getRand()); //terrain is irrelevant for monsters, but monsters need some template now
|
||||||
|
|
||||||
//Fix HoTA monsters with offset template
|
//Fix HoTA monsters with offset template
|
||||||
auto visitableOffset = instance.object().getVisitableOffset();
|
auto visitableOffset = instance.object().getVisitableOffset();
|
||||||
|
@ -397,7 +397,7 @@ void RiverPlacer::connectRiver(const int3 & tile)
|
|||||||
{
|
{
|
||||||
auto * obj = handler->create(templ);
|
auto * obj = handler->create(templ);
|
||||||
rmg::Object deltaObj(*obj, deltaPositions[pos]);
|
rmg::Object deltaObj(*obj, deltaPositions[pos]);
|
||||||
deltaObj.finalize(map);
|
deltaObj.finalize(map, zone.getRand());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ int3 TownPlacer::placeMainTown(ObjectManager & manager, CGTownInstance & town)
|
|||||||
{
|
{
|
||||||
//towns are big objects and should be centered around visitable position
|
//towns are big objects and should be centered around visitable position
|
||||||
rmg::Object rmgObject(town);
|
rmg::Object rmgObject(town);
|
||||||
rmgObject.setTemplate(zone.getTerrainType());
|
rmgObject.setTemplate(zone.getTerrainType(), zone.getRand());
|
||||||
|
|
||||||
int3 position(-1, -1, -1);
|
int3 position(-1, -1, -1);
|
||||||
{
|
{
|
||||||
|
@ -72,26 +72,16 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto templates = handler->getTemplates(zone.getTerrainType());
|
oi.generateObject = [primaryID, secondaryID]() -> CGObjectInstance *
|
||||||
if (templates.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//TODO: Reuse chooseRandomAppearance (eg. WoG treasure chests)
|
|
||||||
//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
|
|
||||||
{
|
{
|
||||||
return lhs->getAllowedTerrains().size() < rhs->getAllowedTerrains().size();
|
return VLC->objtypeh->getHandlerFor(primaryID, secondaryID)->create();
|
||||||
});
|
|
||||||
|
|
||||||
oi.generateObject = [temp]() -> CGObjectInstance *
|
|
||||||
{
|
|
||||||
return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp);
|
|
||||||
};
|
};
|
||||||
oi.value = rmgInfo.value;
|
oi.value = rmgInfo.value;
|
||||||
oi.probability = rmgInfo.rarity;
|
oi.probability = rmgInfo.rarity;
|
||||||
oi.templ = temp;
|
oi.setTemplates(primaryID, secondaryID, zone.getTerrainType());
|
||||||
oi.maxPerZone = rmgInfo.zoneLimit;
|
oi.maxPerZone = rmgInfo.zoneLimit;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,18 +115,18 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
obj->exp = generator.getConfig().prisonExperience[i];
|
obj->exp = generator.getConfig().prisonExperience[i];
|
||||||
obj->setOwner(PlayerColor::NEUTRAL);
|
obj->setOwner(PlayerColor::NEUTRAL);
|
||||||
generator.banHero(hid);
|
generator.banHero(hid);
|
||||||
obj->appearance = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0)->getTemplates(zone.getTerrainType()).front(); //can't init template with hero subID
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.setTemplate(Obj::PRISON, 0, zone.getTerrainType());
|
oi.setTemplates(Obj::PRISON, 0, zone.getTerrainType());
|
||||||
oi.value = generator.getConfig().prisonValues[i];
|
oi.value = generator.getConfig().prisonValues[i];
|
||||||
oi.probability = 30;
|
oi.probability = 30;
|
||||||
|
|
||||||
//Distribute all allowed prisons, starting from the most valuable
|
//Distribute all allowed prisons, starting from the most valuable
|
||||||
oi.maxPerZone = (std::ceil((float)prisonsLeft / (i + 1)));
|
oi.maxPerZone = (std::ceil((float)prisonsLeft / (i + 1)));
|
||||||
prisonsLeft -= oi.maxPerZone;
|
prisonsLeft -= oi.maxPerZone;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,22 +173,16 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
auto nativeZonesCount = static_cast<float>(map.getZoneCount(cre->getFaction()));
|
auto nativeZonesCount = static_cast<float>(map.getZoneCount(cre->getFaction()));
|
||||||
oi.value = static_cast<ui32>(cre->getAIValue() * cre->getGrowth() * (1 + (nativeZonesCount / map.getTotalZoneCount()) + (nativeZonesCount / 2)));
|
oi.value = static_cast<ui32>(cre->getAIValue() * cre->getGrowth() * (1 + (nativeZonesCount / map.getTotalZoneCount()) + (nativeZonesCount / 2)));
|
||||||
oi.probability = 40;
|
oi.probability = 40;
|
||||||
|
|
||||||
for(const auto & tmplate : dwellingHandler->getTemplates())
|
oi.generateObject = [secondaryID, dwellingType]() -> CGObjectInstance *
|
||||||
{
|
{
|
||||||
if(tmplate->canBePlacedAt(zone.getTerrainType()))
|
auto * obj = VLC->objtypeh->getHandlerFor(dwellingType, secondaryID)->create();
|
||||||
{
|
obj->tempOwner = PlayerColor::NEUTRAL;
|
||||||
oi.generateObject = [tmplate, secondaryID, dwellingType]() -> CGObjectInstance *
|
return obj;
|
||||||
{
|
};
|
||||||
auto * obj = VLC->objtypeh->getHandlerFor(dwellingType, secondaryID)->create(tmplate);
|
oi.setTemplates(dwellingType, secondaryID, zone.getTerrainType());
|
||||||
obj->tempOwner = PlayerColor::NEUTRAL;
|
if(!oi.templates.empty())
|
||||||
return obj;
|
addObjectToRandomPool(oi);
|
||||||
};
|
|
||||||
|
|
||||||
oi.templ = tmplate;
|
|
||||||
addObjectToRandomPool(oi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,10 +206,11 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
obj->storedArtifact = a;
|
obj->storedArtifact = a;
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.setTemplate(Obj::SPELL_SCROLL, 0, zone.getTerrainType());
|
oi.setTemplates(Obj::SPELL_SCROLL, 0, zone.getTerrainType());
|
||||||
oi.value = generator.getConfig().scrollValues[i];
|
oi.value = generator.getConfig().scrollValues[i];
|
||||||
oi.probability = 30;
|
oi.probability = 30;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
//pandora box with gold
|
//pandora box with gold
|
||||||
@ -243,10 +228,11 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
||||||
oi.value = i * generator.getConfig().pandoraMultiplierGold;
|
oi.value = i * generator.getConfig().pandoraMultiplierGold;
|
||||||
oi.probability = 5;
|
oi.probability = 5;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
//pandora box with experience
|
//pandora box with experience
|
||||||
@ -264,10 +250,11 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
||||||
oi.value = i * generator.getConfig().pandoraMultiplierExperience;
|
oi.value = i * generator.getConfig().pandoraMultiplierExperience;
|
||||||
oi.probability = 20;
|
oi.probability = 20;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
//pandora box with creatures
|
//pandora box with creatures
|
||||||
@ -325,10 +312,11 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
||||||
oi.value = static_cast<ui32>((2 * (creature->getAIValue()) * creaturesAmount * (1 + static_cast<float>(map.getZoneCount(creature->getFaction())) / map.getTotalZoneCount())) / 3);
|
oi.value = static_cast<ui32>((2 * (creature->getAIValue()) * creaturesAmount * (1 + static_cast<float>(map.getZoneCount(creature->getFaction())) / map.getTotalZoneCount())) / 3);
|
||||||
oi.probability = 3;
|
oi.probability = 3;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Pandora with 12 spells of certain level
|
//Pandora with 12 spells of certain level
|
||||||
@ -357,10 +345,11 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
||||||
oi.value = (i + 1) * generator.getConfig().pandoraMultiplierSpells; //5000 - 15000
|
oi.value = (i + 1) * generator.getConfig().pandoraMultiplierSpells; //5000 - 15000
|
||||||
oi.probability = 2;
|
oi.probability = 2;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Pandora with 15 spells of certain school
|
//Pandora with 15 spells of certain school
|
||||||
@ -389,10 +378,11 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
||||||
oi.value = generator.getConfig().pandoraSpellSchool;
|
oi.value = generator.getConfig().pandoraSpellSchool;
|
||||||
oi.probability = 2;
|
oi.probability = 2;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pandora box with 60 random spells
|
// Pandora box with 60 random spells
|
||||||
@ -420,10 +410,11 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
oi.setTemplates(Obj::PANDORAS_BOX, 0, zone.getTerrainType());
|
||||||
oi.value = generator.getConfig().pandoraSpell60;
|
oi.value = generator.getConfig().pandoraSpell60;
|
||||||
oi.probability = 2;
|
oi.probability = 2;
|
||||||
addObjectToRandomPool(oi);
|
if(!oi.templates.empty())
|
||||||
|
addObjectToRandomPool(oi);
|
||||||
|
|
||||||
//Seer huts with creatures or generic rewards
|
//Seer huts with creatures or generic rewards
|
||||||
|
|
||||||
@ -483,7 +474,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
oi.probability = 3;
|
oi.probability = 3;
|
||||||
oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
|
oi.setTemplates(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);
|
||||||
if (oi.value > zone.getMaxTreasureValue())
|
if (oi.value > zone.getMaxTreasureValue())
|
||||||
{
|
{
|
||||||
@ -491,7 +482,8 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
possibleSeerHuts.push_back(oi);
|
if(!oi.templates.empty())
|
||||||
|
possibleSeerHuts.push_back(oi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,7 +492,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
{
|
{
|
||||||
int randomAppearance = chooseRandomAppearance(zone.getRand(), Obj::SEER_HUT, zone.getTerrainType());
|
int randomAppearance = chooseRandomAppearance(zone.getRand(), Obj::SEER_HUT, zone.getTerrainType());
|
||||||
|
|
||||||
oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
|
oi.setTemplates(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
|
||||||
oi.value = generator.getConfig().questValues[i];
|
oi.value = generator.getConfig().questValues[i];
|
||||||
if (oi.value > zone.getMaxTreasureValue())
|
if (oi.value > zone.getMaxTreasureValue())
|
||||||
{
|
{
|
||||||
@ -533,7 +525,8 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
possibleSeerHuts.push_back(oi);
|
if(!oi.templates.empty())
|
||||||
|
possibleSeerHuts.push_back(oi);
|
||||||
|
|
||||||
oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
|
oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
|
||||||
{
|
{
|
||||||
@ -557,7 +550,8 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
possibleSeerHuts.push_back(oi);
|
if(!oi.templates.empty())
|
||||||
|
possibleSeerHuts.push_back(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (possibleSeerHuts.empty())
|
if (possibleSeerHuts.empty())
|
||||||
@ -610,7 +604,12 @@ std::vector<ObjectInfo*> TreasurePlacer::prepareTreasurePile(const CTreasureInfo
|
|||||||
if(!oi) //fail
|
if(!oi) //fail
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(oi->templ->isVisitableFromTop())
|
bool visitableFromTop = true;
|
||||||
|
for(auto & t : oi->templates)
|
||||||
|
if(!t->isVisitableFromTop())
|
||||||
|
visitableFromTop = false;
|
||||||
|
|
||||||
|
if(visitableFromTop)
|
||||||
{
|
{
|
||||||
objectInfos.push_back(oi);
|
objectInfos.push_back(oi);
|
||||||
}
|
}
|
||||||
@ -641,7 +640,10 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
|||||||
accessibleArea.add(int3());
|
accessibleArea.add(int3());
|
||||||
|
|
||||||
auto * object = oi->generateObject();
|
auto * object = oi->generateObject();
|
||||||
object->appearance = oi->templ;
|
if(oi->templates.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
object->appearance = *RandomGeneratorUtil::nextItem(oi->templates, zone.getRand());
|
||||||
auto & instance = rmgObject.addInstance(*object);
|
auto & instance = rmgObject.addInstance(*object);
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -717,7 +719,12 @@ ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValu
|
|||||||
if(oi.value > maxVal)
|
if(oi.value > maxVal)
|
||||||
break; //this assumes values are sorted in ascending order
|
break; //this assumes values are sorted in ascending order
|
||||||
|
|
||||||
if(!oi.templ->isVisitableFromTop() && !allowLargeObjects)
|
bool visitableFromTop = true;
|
||||||
|
for(auto & t : oi.templates)
|
||||||
|
if(!t->isVisitableFromTop())
|
||||||
|
visitableFromTop = false;
|
||||||
|
|
||||||
|
if(!visitableFromTop && !allowLargeObjects)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(oi.value >= minValue && oi.maxPerZone > 0)
|
if(oi.value >= minValue && oi.maxPerZone > 0)
|
||||||
@ -921,17 +928,13 @@ char TreasurePlacer::dump(const int3 & t)
|
|||||||
return Modificator::dump(t);
|
return Modificator::dump(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectInfo::setTemplate(si32 type, si32 subtype, TerrainId terrainType)
|
void ObjectInfo::setTemplates(si32 type, si32 subtype, TerrainId terrainType)
|
||||||
{
|
{
|
||||||
auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
|
auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
|
||||||
if(!templHandler)
|
if(!templHandler)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto templates = templHandler->getTemplates(terrainType);
|
templates = templHandler->getTemplates(terrainType);
|
||||||
if(templates.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
templ = templates.front();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -22,16 +22,14 @@ class CRandomGenerator;
|
|||||||
|
|
||||||
struct ObjectInfo
|
struct ObjectInfo
|
||||||
{
|
{
|
||||||
std::shared_ptr<const ObjectTemplate> templ;
|
std::vector<std::shared_ptr<const ObjectTemplate>> templates;
|
||||||
ui32 value = 0;
|
ui32 value = 0;
|
||||||
ui16 probability = 0;
|
ui16 probability = 0;
|
||||||
ui32 maxPerZone = 1;
|
ui32 maxPerZone = 1;
|
||||||
//ui32 maxPerMap; //unused
|
//ui32 maxPerMap; //unused
|
||||||
std::function<CGObjectInstance *()> generateObject;
|
std::function<CGObjectInstance *()> generateObject;
|
||||||
|
|
||||||
void setTemplate(si32 type, si32 subtype, TerrainId terrain);
|
void setTemplates(si32 type, si32 subtype, TerrainId terrain);
|
||||||
|
|
||||||
bool operator==(const ObjectInfo& oi) const { return (templ == oi.templ); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TreasurePlacer: public Modificator
|
class TreasurePlacer: public Modificator
|
||||||
|
@ -254,7 +254,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, bool createRoad, Rout
|
|||||||
auto * boat = dynamic_cast<CGBoat *>(VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(sailingBoatTypes, zone.getRand()))->create());
|
auto * boat = dynamic_cast<CGBoat *>(VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(sailingBoatTypes, zone.getRand()))->create());
|
||||||
|
|
||||||
rmg::Object rmgObject(*boat);
|
rmg::Object rmgObject(*boat);
|
||||||
rmgObject.setTemplate(zone.getTerrainType());
|
rmgObject.setTemplate(zone.getTerrainType(), zone.getRand());
|
||||||
|
|
||||||
auto waterAvailable = zone.areaPossible() + zone.freePaths();
|
auto waterAvailable = zone.areaPossible() + zone.freePaths();
|
||||||
rmg::Area coast = lake.neighbourZones.at(land.getId()); //having land tiles
|
rmg::Area coast = lake.neighbourZones.at(land.getId()); //having land tiles
|
||||||
@ -319,7 +319,7 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, bool
|
|||||||
shipyard->tempOwner = PlayerColor::NEUTRAL;
|
shipyard->tempOwner = PlayerColor::NEUTRAL;
|
||||||
|
|
||||||
rmg::Object rmgObject(*shipyard);
|
rmg::Object rmgObject(*shipyard);
|
||||||
rmgObject.setTemplate(land.getTerrainType());
|
rmgObject.setTemplate(land.getTerrainType(), zone.getRand());
|
||||||
bool guarded = manager->addGuard(rmgObject, guard);
|
bool guarded = manager->addGuard(rmgObject, guard);
|
||||||
|
|
||||||
auto waterAvailable = zone.areaPossible() + zone.freePaths();
|
auto waterAvailable = zone.areaPossible() + zone.freePaths();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user