mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +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/CLegacyConfigParser.h"
|
||||
|
||||
#include <vstd/StringUtils.h>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
CObjectClassesHandler::CObjectClassesHandler()
|
||||
@@ -396,6 +398,9 @@ CompoundMapObjectID CObjectClassesHandler::getCompoundIdentifier(const std::stri
|
||||
|
||||
if(id)
|
||||
{
|
||||
if (subtype.empty())
|
||||
return CompoundMapObjectID(id.value(), 0);
|
||||
|
||||
const auto & object = objects.at(id.value());
|
||||
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
|
||||
{
|
||||
// FIXME: Crash with no further log
|
||||
// TODO: Use existing utilities for parsing id:
|
||||
// CIdentifierStorage::ObjectCallback::fromNameAndType
|
||||
|
||||
// TODO: Use existing utilities for parsing id?
|
||||
JsonNode node(objectName);
|
||||
auto modScope = node.getModScope();
|
||||
std::string subtype = "object"; //Default for objects with no subIds
|
||||
std::string type;
|
||||
|
||||
std::string scope, type, subtype;
|
||||
size_t firstColon = objectName.find(':');
|
||||
size_t lastDot = objectName.find_last_of('.');
|
||||
|
||||
// TODO: Ignore object class, there should not be objects with same names within one scope anyway
|
||||
auto scopeAndFullName = vstd::splitStringToPair(objectName, ':');
|
||||
logGlobal->debug("scopeAndFullName: %s, %s", scopeAndFullName.first, scopeAndFullName.second);
|
||||
|
||||
if(firstColon != std::string::npos)
|
||||
auto typeAndName = vstd::splitStringToPair(scopeAndFullName.second, '.');
|
||||
logGlobal->debug("typeAndName: %s, %s", typeAndName.first, typeAndName.second);
|
||||
|
||||
auto nameAndSubtype = vstd::splitStringToPair(typeAndName.second, '.');
|
||||
logGlobal->debug("nameAndSubtype: %s, %s", nameAndSubtype.first, nameAndSubtype.second);
|
||||
|
||||
if (!nameAndSubtype.first.empty())
|
||||
{
|
||||
scope = objectName.substr(0, firstColon);
|
||||
if(lastDot != std::string::npos && lastDot > firstColon)
|
||||
{
|
||||
type = objectName.substr(firstColon + 1, lastDot - firstColon - 1);
|
||||
subtype = objectName.substr(lastDot + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = objectName.substr(firstColon + 1);
|
||||
}
|
||||
type = nameAndSubtype.first;
|
||||
subtype = nameAndSubtype.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(lastDot != std::string::npos)
|
||||
{
|
||||
type = objectName.substr(0, lastDot);
|
||||
subtype = objectName.substr(lastDot + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = objectName;
|
||||
}
|
||||
type = typeAndName.second;
|
||||
}
|
||||
|
||||
return getCompoundIdentifier(scope, type, subtype);
|
||||
|
||||
return getCompoundIdentifier(scopeAndFullName.first, type, subtype);
|
||||
}
|
||||
|
||||
std::set<MapObjectID> CObjectClassesHandler::knownObjects() const
|
||||
|
@@ -46,6 +46,8 @@ public:
|
||||
/// H3 ID/subID of this object
|
||||
MapObjectID id;
|
||||
MapObjectSubID subid;
|
||||
|
||||
// TODO: get compound id
|
||||
/// print priority, objects with higher priority will be print first, below everything else
|
||||
si32 printPriority;
|
||||
/// animation file that should be used to display object
|
||||
|
@@ -50,6 +50,15 @@ ObjectInfo & ObjectInfo::operator=(const ObjectInfo & other)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO: We need serializer utility for list of enum values
|
||||
@@ -87,73 +110,105 @@ void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
|
||||
(EObjectCategory::QUEST_ARTIFACT, "questArtifact")
|
||||
(EObjectCategory::SEER_HUT, "seerHut");
|
||||
|
||||
auto categories = handler.enterArray("bannedCategories");
|
||||
if (handler.saving)
|
||||
{
|
||||
for (const auto& category : bannedObjectCategories)
|
||||
{
|
||||
auto str = OBJECT_CATEGORY_STRINGS.left.at(category);
|
||||
categories.serializeString(categories.size(), str);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> categoryNames;
|
||||
categories.serializeArray(categoryNames);
|
||||
|
||||
for (const auto & categoryName : categoryNames)
|
||||
// TODO: Separate into individual methods to enforce RAII destruction?
|
||||
{
|
||||
auto categories = handler.enterArray("bannedCategories");
|
||||
if (handler.saving)
|
||||
{
|
||||
auto it = OBJECT_CATEGORY_STRINGS.right.find(categoryName);
|
||||
if (it != OBJECT_CATEGORY_STRINGS.right.end())
|
||||
for (const auto& category : bannedObjectCategories)
|
||||
{
|
||||
bannedObjectCategories.push_back(it->second);
|
||||
auto str = OBJECT_CATEGORY_STRINGS.left.at(category);
|
||||
categories.serializeString(categories.size(), str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto bannedObjectData = handler.enterArray("bannedObjects");
|
||||
if (handler.saving)
|
||||
{
|
||||
|
||||
// FIXME: Do we even need to serialize / store banned objects?
|
||||
/*
|
||||
for (const auto & object : bannedObjects)
|
||||
else
|
||||
{
|
||||
// TODO: Translate id back to string?
|
||||
std::vector<std::string> categoryNames;
|
||||
categories.serializeArray(categoryNames);
|
||||
|
||||
|
||||
JsonNode node;
|
||||
node.String() = VLC->objtypeh->getHandlerFor(object.primaryID, object.secondaryID);
|
||||
// TODO: Check if AI-generated code is right
|
||||
|
||||
|
||||
}
|
||||
// handler.serializeRaw("bannedObjects", node, std::nullopt);
|
||||
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
auto zonesData = handler.enterStruct("zones");
|
||||
for(const auto & idAndZone : zonesData->getCurrent().Struct())
|
||||
for (const auto & categoryName : categoryNames)
|
||||
{
|
||||
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;
|
||||
bannedObjectData.serializeArray(objectNames);
|
||||
|
||||
for (const auto & objectName : objectNames)
|
||||
{
|
||||
VLC->objtypeh->resolveObjectCompoundId(objectName,
|
||||
[this](CompoundMapObjectID objid)
|
||||
auto it = OBJECT_CATEGORY_STRINGS.right.find(categoryName);
|
||||
if (it != OBJECT_CATEGORY_STRINGS.right.end())
|
||||
{
|
||||
addBannedObject(objid);
|
||||
bannedObjectCategories.push_back(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Doesn't seem to use this field at all
|
||||
|
||||
{
|
||||
auto bannedObjectData = handler.enterArray("bannedObjects");
|
||||
if (handler.saving)
|
||||
{
|
||||
|
||||
// FIXME: Do we even need to serialize / store banned objects?
|
||||
/*
|
||||
for (const auto & object : bannedObjects)
|
||||
{
|
||||
// TODO: Translate id back to string?
|
||||
|
||||
|
||||
JsonNode node;
|
||||
node.String() = VLC->objtypeh->getHandlerFor(object.primaryID, object.secondaryID);
|
||||
// TODO: Check if AI-generated code is right
|
||||
|
||||
|
||||
}
|
||||
// handler.serializeRaw("bannedObjects", node, std::nullopt);
|
||||
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> objectNames;
|
||||
bannedObjectData.serializeArray(objectNames);
|
||||
|
||||
for (const auto & objectName : objectNames)
|
||||
{
|
||||
VLC->objtypeh->resolveObjectCompoundId(objectName,
|
||||
[this](CompoundMapObjectID objid)
|
||||
{
|
||||
addBannedObject(objid);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
);
|
||||
|
||||
|
@@ -32,6 +32,7 @@ struct DLL_LINKAGE ObjectInfo
|
||||
std::function<CGObjectInstance *()> generateObject;
|
||||
std::function<void(CGObjectInstance *)> destroyObject;
|
||||
|
||||
void setAllTemplates(MapObjectID type, MapObjectSubID subtype);
|
||||
void setTemplates(MapObjectID type, MapObjectSubID subtype, TerrainId terrain);
|
||||
|
||||
//bool matchesId(const CompoundMapObjectID & id) const;
|
||||
@@ -61,7 +62,7 @@ public:
|
||||
};
|
||||
|
||||
void addBannedObject(const CompoundMapObjectID & objid);
|
||||
void addCustomObject(const ObjectInfo & object);
|
||||
void addCustomObject(const ObjectInfo & object, const CompoundMapObjectID & objid);
|
||||
void clearBannedObjects();
|
||||
void clearCustomObjects();
|
||||
const std::vector<CompoundMapObjectID> & getBannedObjects() const;
|
||||
|
@@ -50,7 +50,7 @@ void TreasurePlacer::process()
|
||||
// Get default objects
|
||||
addAllPossibleObjects();
|
||||
// Override with custom objects
|
||||
objects.patchWithZoneConfig(zone);
|
||||
objects.patchWithZoneConfig(zone, this);
|
||||
|
||||
auto * m = zone.getModificator<ObjectManager>();
|
||||
if(m)
|
||||
@@ -65,6 +65,8 @@ void TreasurePlacer::init()
|
||||
DEPENDENCY_ALL(PrisonHeroPlacer);
|
||||
DEPENDENCY(RoadPlacer);
|
||||
|
||||
// FIXME: Starting zones get Pandoras with neutral creatures
|
||||
|
||||
// Add all native creatures
|
||||
for(auto const & cre : VLC->creh->objects)
|
||||
{
|
||||
@@ -79,7 +81,6 @@ void TreasurePlacer::init()
|
||||
|
||||
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())
|
||||
{
|
||||
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
|
||||
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.probability = rmgInfo.rarity;
|
||||
oi.setTemplates(primaryID, secondaryID, zone.getTerrainType());
|
||||
|
||||
oi.maxPerZone = rmgInfo.zoneLimit;
|
||||
if(!oi.templates.empty())
|
||||
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()
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
|
||||
void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone, TreasurePlacer * tp)
|
||||
{
|
||||
// FIXME: Wycina wszystkie obiekty poza pandorami i dwellami :?
|
||||
|
||||
@@ -1145,18 +1152,27 @@ void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
|
||||
if (categoriesSet.count(category))
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1164,6 +1180,15 @@ void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
|
||||
});
|
||||
|
||||
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
|
||||
|
||||
// FIXME: Protect with mutex as well?
|
||||
|
@@ -34,6 +34,7 @@ public:
|
||||
|
||||
void createTreasures(ObjectManager & manager);
|
||||
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
|
||||
void addCommonObjects();
|
||||
@@ -69,7 +70,7 @@ protected:
|
||||
void addObject(const ObjectInfo & info);
|
||||
void updateObject(MapObjectID id, MapObjectSubID subid, ObjectInfo info);
|
||||
std::vector<ObjectInfo> & getPossibleObjects();
|
||||
void patchWithZoneConfig(const Zone & zone);
|
||||
void patchWithZoneConfig(const Zone & zone, TreasurePlacer * tp);
|
||||
void sortPossibleObjects();
|
||||
void discardObjectsAboveValue(ui32 value);
|
||||
|
||||
|
Reference in New Issue
Block a user