mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-27 22:49:25 +02:00
Add specific objects and configure their frequency / value
This commit is contained in:
@@ -40,6 +40,8 @@
|
|||||||
#include "../texts/CGeneralTextHandler.h"
|
#include "../texts/CGeneralTextHandler.h"
|
||||||
#include "../texts/CLegacyConfigParser.h"
|
#include "../texts/CLegacyConfigParser.h"
|
||||||
|
|
||||||
|
#include <vstd/StringUtils.h>
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
CObjectClassesHandler::CObjectClassesHandler()
|
CObjectClassesHandler::CObjectClassesHandler()
|
||||||
@@ -396,6 +398,9 @@ CompoundMapObjectID CObjectClassesHandler::getCompoundIdentifier(const std::stri
|
|||||||
|
|
||||||
if(id)
|
if(id)
|
||||||
{
|
{
|
||||||
|
if (subtype.empty())
|
||||||
|
return CompoundMapObjectID(id.value(), 0);
|
||||||
|
|
||||||
const auto & object = objects.at(id.value());
|
const auto & object = objects.at(id.value());
|
||||||
std::optional<si32> subID = VLC->identifiers()->getIdentifier(scope, object->getJsonKey(), subtype);
|
std::optional<si32> subID = VLC->identifiers()->getIdentifier(scope, object->getJsonKey(), subtype);
|
||||||
|
|
||||||
@@ -410,45 +415,32 @@ CompoundMapObjectID CObjectClassesHandler::getCompoundIdentifier(const std::stri
|
|||||||
|
|
||||||
CompoundMapObjectID CObjectClassesHandler::getCompoundIdentifier(const std::string & objectName) const
|
CompoundMapObjectID CObjectClassesHandler::getCompoundIdentifier(const std::string & objectName) const
|
||||||
{
|
{
|
||||||
// FIXME: Crash with no further log
|
// TODO: Use existing utilities for parsing id:
|
||||||
|
// CIdentifierStorage::ObjectCallback::fromNameAndType
|
||||||
|
|
||||||
// TODO: Use existing utilities for parsing id?
|
std::string subtype = "object"; //Default for objects with no subIds
|
||||||
JsonNode node(objectName);
|
std::string type;
|
||||||
auto modScope = node.getModScope();
|
|
||||||
|
|
||||||
std::string scope, type, subtype;
|
auto scopeAndFullName = vstd::splitStringToPair(objectName, ':');
|
||||||
size_t firstColon = objectName.find(':');
|
logGlobal->debug("scopeAndFullName: %s, %s", scopeAndFullName.first, scopeAndFullName.second);
|
||||||
size_t lastDot = objectName.find_last_of('.');
|
|
||||||
|
|
||||||
// TODO: Ignore object class, there should not be objects with same names within one scope anyway
|
auto typeAndName = vstd::splitStringToPair(scopeAndFullName.second, '.');
|
||||||
|
logGlobal->debug("typeAndName: %s, %s", typeAndName.first, typeAndName.second);
|
||||||
|
|
||||||
if(firstColon != std::string::npos)
|
auto nameAndSubtype = vstd::splitStringToPair(typeAndName.second, '.');
|
||||||
|
logGlobal->debug("nameAndSubtype: %s, %s", nameAndSubtype.first, nameAndSubtype.second);
|
||||||
|
|
||||||
|
if (!nameAndSubtype.first.empty())
|
||||||
{
|
{
|
||||||
scope = objectName.substr(0, firstColon);
|
type = nameAndSubtype.first;
|
||||||
if(lastDot != std::string::npos && lastDot > firstColon)
|
subtype = nameAndSubtype.second;
|
||||||
{
|
|
||||||
type = objectName.substr(firstColon + 1, lastDot - firstColon - 1);
|
|
||||||
subtype = objectName.substr(lastDot + 1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
type = objectName.substr(firstColon + 1);
|
type = typeAndName.second;
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(lastDot != std::string::npos)
|
|
||||||
{
|
|
||||||
type = objectName.substr(0, lastDot);
|
|
||||||
subtype = objectName.substr(lastDot + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
type = objectName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return getCompoundIdentifier(scope, type, subtype);
|
return getCompoundIdentifier(scopeAndFullName.first, type, subtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<MapObjectID> CObjectClassesHandler::knownObjects() const
|
std::set<MapObjectID> CObjectClassesHandler::knownObjects() const
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ public:
|
|||||||
/// H3 ID/subID of this object
|
/// H3 ID/subID of this object
|
||||||
MapObjectID id;
|
MapObjectID id;
|
||||||
MapObjectSubID subid;
|
MapObjectSubID subid;
|
||||||
|
|
||||||
|
// TODO: get compound id
|
||||||
/// print priority, objects with higher priority will be print first, below everything else
|
/// print priority, objects with higher priority will be print first, below everything else
|
||||||
si32 printPriority;
|
si32 printPriority;
|
||||||
/// animation file that should be used to display object
|
/// animation file that should be used to display object
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ ObjectInfo & ObjectInfo::operator=(const ObjectInfo & other)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectInfo::setAllTemplates(MapObjectID type, MapObjectSubID subtype)
|
||||||
|
{
|
||||||
|
auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
|
||||||
|
if(!templHandler)
|
||||||
|
return;
|
||||||
|
|
||||||
|
templates = templHandler->getTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectInfo::setTemplates(MapObjectID type, MapObjectSubID subtype, TerrainId terrainType)
|
void ObjectInfo::setTemplates(MapObjectID type, MapObjectSubID subtype, TerrainId terrainType)
|
||||||
{
|
{
|
||||||
auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
|
auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
|
||||||
@@ -68,6 +77,20 @@ void ObjectConfig::addBannedObject(const CompoundMapObjectID & objid)
|
|||||||
logGlobal->info("Banned object of type %d.%d", objid.primaryID, objid.secondaryID);
|
logGlobal->info("Banned object of type %d.%d", objid.primaryID, objid.secondaryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectConfig::addCustomObject(const ObjectInfo & object, const CompoundMapObjectID & objid)
|
||||||
|
{
|
||||||
|
// FIXME: Need id / subId
|
||||||
|
|
||||||
|
// FIXME: Add templates and possibly other info
|
||||||
|
customObjects.push_back(object);
|
||||||
|
auto & lastObject = customObjects.back();
|
||||||
|
lastObject.setAllTemplates(objid.primaryID, objid.secondaryID);
|
||||||
|
|
||||||
|
assert(lastObject.templates.size() > 0);
|
||||||
|
auto temp = lastObject.templates.front();
|
||||||
|
logGlobal->info("Added custom object of type %d.%d", temp->id, temp->subid);
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
|
void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
|
||||||
{
|
{
|
||||||
// TODO: We need serializer utility for list of enum values
|
// TODO: We need serializer utility for list of enum values
|
||||||
@@ -87,6 +110,9 @@ void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
|
|||||||
(EObjectCategory::QUEST_ARTIFACT, "questArtifact")
|
(EObjectCategory::QUEST_ARTIFACT, "questArtifact")
|
||||||
(EObjectCategory::SEER_HUT, "seerHut");
|
(EObjectCategory::SEER_HUT, "seerHut");
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Separate into individual methods to enforce RAII destruction?
|
||||||
|
{
|
||||||
auto categories = handler.enterArray("bannedCategories");
|
auto categories = handler.enterArray("bannedCategories");
|
||||||
if (handler.saving)
|
if (handler.saving)
|
||||||
{
|
{
|
||||||
@@ -110,7 +136,11 @@ void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Doesn't seem to use this field at all
|
||||||
|
|
||||||
|
{
|
||||||
auto bannedObjectData = handler.enterArray("bannedObjects");
|
auto bannedObjectData = handler.enterArray("bannedObjects");
|
||||||
if (handler.saving)
|
if (handler.saving)
|
||||||
{
|
{
|
||||||
@@ -134,17 +164,6 @@ void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
auto zonesData = handler.enterStruct("zones");
|
|
||||||
for(const auto & idAndZone : zonesData->getCurrent().Struct())
|
|
||||||
{
|
|
||||||
auto guard = handler.enterStruct(idAndZone.first);
|
|
||||||
auto zone = std::make_shared<ZoneOptions>();
|
|
||||||
zone->setId(decodeZoneId(idAndZone.first));
|
|
||||||
zone->serializeJson(handler);
|
|
||||||
zones[zone->getId()] = zone;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::vector<std::string> objectNames;
|
std::vector<std::string> objectNames;
|
||||||
bannedObjectData.serializeArray(objectNames);
|
bannedObjectData.serializeArray(objectNames);
|
||||||
|
|
||||||
@@ -161,6 +180,42 @@ void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto commonObjectData = handler.getCurrent()["commonObjects"].Vector();
|
||||||
|
if (handler.saving)
|
||||||
|
{
|
||||||
|
|
||||||
|
//TODO?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto & objectConfig : commonObjectData)
|
||||||
|
{
|
||||||
|
auto objectName = objectConfig["id"].String();
|
||||||
|
auto rmg = objectConfig["rmg"].Struct();
|
||||||
|
|
||||||
|
// TODO: Use common code with default rmg config
|
||||||
|
auto objectValue = rmg["value"].Integer();
|
||||||
|
auto objectProbability = rmg["rarity"].Integer();
|
||||||
|
auto objectMaxPerZone = rmg["zoneLimit"].Integer();
|
||||||
|
|
||||||
|
VLC->objtypeh->resolveObjectCompoundId(objectName,
|
||||||
|
[this, objectValue, objectProbability, objectMaxPerZone](CompoundMapObjectID objid)
|
||||||
|
{
|
||||||
|
ObjectInfo object;
|
||||||
|
|
||||||
|
// TODO: Configure basic generateObject function
|
||||||
|
|
||||||
|
object.value = objectValue;
|
||||||
|
object.probability = objectProbability;
|
||||||
|
object.maxPerZone = objectMaxPerZone;
|
||||||
|
addCustomObject(object, objid);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<ObjectInfo> & ObjectConfig::getConfiguredObjects() const
|
const std::vector<ObjectInfo> & ObjectConfig::getConfiguredObjects() const
|
||||||
{
|
{
|
||||||
return customObjects;
|
return customObjects;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ struct DLL_LINKAGE ObjectInfo
|
|||||||
std::function<CGObjectInstance *()> generateObject;
|
std::function<CGObjectInstance *()> generateObject;
|
||||||
std::function<void(CGObjectInstance *)> destroyObject;
|
std::function<void(CGObjectInstance *)> destroyObject;
|
||||||
|
|
||||||
|
void setAllTemplates(MapObjectID type, MapObjectSubID subtype);
|
||||||
void setTemplates(MapObjectID type, MapObjectSubID subtype, TerrainId terrain);
|
void setTemplates(MapObjectID type, MapObjectSubID subtype, TerrainId terrain);
|
||||||
|
|
||||||
//bool matchesId(const CompoundMapObjectID & id) const;
|
//bool matchesId(const CompoundMapObjectID & id) const;
|
||||||
@@ -61,7 +62,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void addBannedObject(const CompoundMapObjectID & objid);
|
void addBannedObject(const CompoundMapObjectID & objid);
|
||||||
void addCustomObject(const ObjectInfo & object);
|
void addCustomObject(const ObjectInfo & object, const CompoundMapObjectID & objid);
|
||||||
void clearBannedObjects();
|
void clearBannedObjects();
|
||||||
void clearCustomObjects();
|
void clearCustomObjects();
|
||||||
const std::vector<CompoundMapObjectID> & getBannedObjects() const;
|
const std::vector<CompoundMapObjectID> & getBannedObjects() const;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ void TreasurePlacer::process()
|
|||||||
// Get default objects
|
// Get default objects
|
||||||
addAllPossibleObjects();
|
addAllPossibleObjects();
|
||||||
// Override with custom objects
|
// Override with custom objects
|
||||||
objects.patchWithZoneConfig(zone);
|
objects.patchWithZoneConfig(zone, this);
|
||||||
|
|
||||||
auto * m = zone.getModificator<ObjectManager>();
|
auto * m = zone.getModificator<ObjectManager>();
|
||||||
if(m)
|
if(m)
|
||||||
@@ -65,6 +65,8 @@ void TreasurePlacer::init()
|
|||||||
DEPENDENCY_ALL(PrisonHeroPlacer);
|
DEPENDENCY_ALL(PrisonHeroPlacer);
|
||||||
DEPENDENCY(RoadPlacer);
|
DEPENDENCY(RoadPlacer);
|
||||||
|
|
||||||
|
// FIXME: Starting zones get Pandoras with neutral creatures
|
||||||
|
|
||||||
// Add all native creatures
|
// Add all native creatures
|
||||||
for(auto const & cre : VLC->creh->objects)
|
for(auto const & cre : VLC->creh->objects)
|
||||||
{
|
{
|
||||||
@@ -79,7 +81,6 @@ void TreasurePlacer::init()
|
|||||||
|
|
||||||
void TreasurePlacer::addObjectToRandomPool(const ObjectInfo& oi)
|
void TreasurePlacer::addObjectToRandomPool(const ObjectInfo& oi)
|
||||||
{
|
{
|
||||||
// FIXME: It is never the case - objects must be erased or badly copied after this
|
|
||||||
if (oi.templates.empty())
|
if (oi.templates.empty())
|
||||||
{
|
{
|
||||||
logGlobal->error("Attempt to add ObjectInfo with no templates! Value: %d", oi.value);
|
logGlobal->error("Attempt to add ObjectInfo with no templates! Value: %d", oi.value);
|
||||||
@@ -126,14 +127,11 @@ void TreasurePlacer::addCommonObjects()
|
|||||||
//Skip objects with per-map limit here
|
//Skip objects with per-map limit here
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
setBasicProperties(oi, CompoundMapObjectID(primaryID, secondaryID));
|
||||||
|
|
||||||
oi.generateObject = [this, primaryID, secondaryID]() -> CGObjectInstance *
|
|
||||||
{
|
|
||||||
return VLC->objtypeh->getHandlerFor(primaryID, secondaryID)->create(map.mapInstance->cb, nullptr);
|
|
||||||
};
|
|
||||||
oi.value = rmgInfo.value;
|
oi.value = rmgInfo.value;
|
||||||
oi.probability = rmgInfo.rarity;
|
oi.probability = rmgInfo.rarity;
|
||||||
oi.setTemplates(primaryID, secondaryID, zone.getTerrainType());
|
|
||||||
oi.maxPerZone = rmgInfo.zoneLimit;
|
oi.maxPerZone = rmgInfo.zoneLimit;
|
||||||
if(!oi.templates.empty())
|
if(!oi.templates.empty())
|
||||||
addObjectToRandomPool(oi);
|
addObjectToRandomPool(oi);
|
||||||
@@ -142,6 +140,15 @@ void TreasurePlacer::addCommonObjects()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TreasurePlacer::setBasicProperties(ObjectInfo & oi, CompoundMapObjectID objid) const
|
||||||
|
{
|
||||||
|
oi.generateObject = [this, objid]() -> CGObjectInstance *
|
||||||
|
{
|
||||||
|
return VLC->objtypeh->getHandlerFor(objid)->create(map.mapInstance->cb, nullptr);
|
||||||
|
};
|
||||||
|
oi.setTemplates(objid.primaryID, objid.secondaryID, zone.getTerrainType());
|
||||||
|
}
|
||||||
|
|
||||||
void TreasurePlacer::addPrisons()
|
void TreasurePlacer::addPrisons()
|
||||||
{
|
{
|
||||||
//Generate Prison on water only if it has a template
|
//Generate Prison on water only if it has a template
|
||||||
@@ -1116,7 +1123,7 @@ void TreasurePlacer::ObjectPool::updateObject(MapObjectID id, MapObjectSubID sub
|
|||||||
customObjects[CompoundMapObjectID(id, subid)] = info;
|
customObjects[CompoundMapObjectID(id, subid)] = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
|
void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone, TreasurePlacer * tp)
|
||||||
{
|
{
|
||||||
// FIXME: Wycina wszystkie obiekty poza pandorami i dwellami :?
|
// FIXME: Wycina wszystkie obiekty poza pandorami i dwellami :?
|
||||||
|
|
||||||
@@ -1145,18 +1152,27 @@ void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
|
|||||||
if (categoriesSet.count(category))
|
if (categoriesSet.count(category))
|
||||||
{
|
{
|
||||||
logGlobal->info("Removing object %s from possible objects", oi.templates.front()->stringID);
|
logGlobal->info("Removing object %s from possible objects", oi.templates.front()->stringID);
|
||||||
|
/* FIXME:
|
||||||
|
Removing object normal from possible objects
|
||||||
|
Removing object base from possible objects
|
||||||
|
Removing object default from possible objects
|
||||||
|
*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
vstd::erase_if(possibleObjects, [&zone](const ObjectInfo & object)
|
auto bannedObjects = zone.getBannedObjects();
|
||||||
|
auto bannedObjectsSet = std::set<CompoundMapObjectID>(bannedObjects.begin(), bannedObjects.end());
|
||||||
|
vstd::erase_if(possibleObjects, [&bannedObjectsSet](const ObjectInfo & object)
|
||||||
{
|
{
|
||||||
for (const auto & templ : object.templates)
|
for (const auto & templ : object.templates)
|
||||||
{
|
{
|
||||||
CompoundMapObjectID key(templ->id, templ->subid);
|
CompoundMapObjectID key(templ->id, templ->subid);
|
||||||
if (vstd::contains(zone.getBannedObjects(), key))
|
if (bannedObjectsSet.count(key))
|
||||||
{
|
{
|
||||||
|
// FIXME: Stopped working, nothing is banned
|
||||||
|
logGlobal->info("Banning object %s from possible objects", templ->stringID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1164,6 +1180,15 @@ void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
|
|||||||
});
|
});
|
||||||
|
|
||||||
auto configuredObjects = zone.getConfiguredObjects();
|
auto configuredObjects = zone.getConfiguredObjects();
|
||||||
|
|
||||||
|
// FIXME: Access TreasurePlacer from ObjectPool
|
||||||
|
for (auto & object : configuredObjects)
|
||||||
|
{
|
||||||
|
auto temp = object.templates.front();
|
||||||
|
tp->setBasicProperties(object, CompoundMapObjectID(temp->id, temp->subid));
|
||||||
|
addObject(object);
|
||||||
|
logGlobal->info("Added custom object of type %d.%d", temp->id, temp->subid);
|
||||||
|
}
|
||||||
// TODO: Overwrite or add to possibleObjects
|
// TODO: Overwrite or add to possibleObjects
|
||||||
|
|
||||||
// FIXME: Protect with mutex as well?
|
// FIXME: Protect with mutex as well?
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public:
|
|||||||
|
|
||||||
void createTreasures(ObjectManager & manager);
|
void createTreasures(ObjectManager & manager);
|
||||||
void addObjectToRandomPool(const ObjectInfo& oi);
|
void addObjectToRandomPool(const ObjectInfo& oi);
|
||||||
|
void setBasicProperties(ObjectInfo & oi, CompoundMapObjectID objid) const;
|
||||||
|
|
||||||
// TODO: Can be defaulted to addAllPossibleObjects, but then each object will need to be configured
|
// TODO: Can be defaulted to addAllPossibleObjects, but then each object will need to be configured
|
||||||
void addCommonObjects();
|
void addCommonObjects();
|
||||||
@@ -69,7 +70,7 @@ protected:
|
|||||||
void addObject(const ObjectInfo & info);
|
void addObject(const ObjectInfo & info);
|
||||||
void updateObject(MapObjectID id, MapObjectSubID subid, ObjectInfo info);
|
void updateObject(MapObjectID id, MapObjectSubID subid, ObjectInfo info);
|
||||||
std::vector<ObjectInfo> & getPossibleObjects();
|
std::vector<ObjectInfo> & getPossibleObjects();
|
||||||
void patchWithZoneConfig(const Zone & zone);
|
void patchWithZoneConfig(const Zone & zone, TreasurePlacer * tp);
|
||||||
void sortPossibleObjects();
|
void sortPossibleObjects();
|
||||||
void discardObjectsAboveValue(ui32 value);
|
void discardObjectsAboveValue(ui32 value);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user