1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

It is now possible to copy object settings between zones

This commit is contained in:
Tomasz Zieliński 2024-08-24 20:18:36 +02:00
parent 64fc2e5ed0
commit bfe75a6a02
7 changed files with 139 additions and 85 deletions

View File

@ -22,6 +22,7 @@
"minesLikeZone" : { "type" : "number" },
"terrainTypeLikeZone" : { "type" : "number" },
"treasureLikeZone" : { "type" : "number" },
"customObjectsLikeZone" : { "type" : "number" },
"terrainTypes": {"$ref" : "#/definitions/stringArray"},
"bannedTerrains": {"$ref" : "#/definitions/stringArray"},

View File

@ -157,7 +157,7 @@ std::optional<int> ZoneOptions::getOwner() const
return owner;
}
const std::set<TerrainId> ZoneOptions::getTerrainTypes() const
std::set<TerrainId> ZoneOptions::getTerrainTypes() const
{
if (terrainTypes.empty())
{
@ -192,7 +192,7 @@ std::set<FactionID> ZoneOptions::getDefaultTownTypes() const
return VLC->townh->getDefaultAllowed();
}
const std::set<FactionID> ZoneOptions::getTownTypes() const
std::set<FactionID> ZoneOptions::getTownTypes() const
{
if (townTypes.empty())
{
@ -215,7 +215,7 @@ void ZoneOptions::setMonsterTypes(const std::set<FactionID> & value)
monsterTypes = value;
}
const std::set<FactionID> ZoneOptions::getMonsterTypes() const
std::set<FactionID> ZoneOptions::getMonsterTypes() const
{
return vstd::difference(monsterTypes, bannedMonsters);
}
@ -251,7 +251,7 @@ void ZoneOptions::addTreasureInfo(const CTreasureInfo & value)
vstd::amax(maxTreasureValue, value.max);
}
const std::vector<CTreasureInfo> & ZoneOptions::getTreasureInfo() const
std::vector<CTreasureInfo> ZoneOptions::getTreasureInfo() const
{
return treasureInfo;
}
@ -273,7 +273,22 @@ TRmgTemplateZoneId ZoneOptions::getTerrainTypeLikeZone() const
TRmgTemplateZoneId ZoneOptions::getTreasureLikeZone() const
{
return treasureLikeZone;
return treasureLikeZone;
}
ObjectConfig ZoneOptions::getCustomObjects() const
{
return objectConfig;
}
void ZoneOptions::setCustomObjects(const ObjectConfig & value)
{
objectConfig = value;
}
TRmgTemplateZoneId ZoneOptions::getCustomObjectsLikeZone() const
{
return customObjectsLikeZone;
}
void ZoneOptions::addConnection(const ZoneConnection & connection)
@ -335,7 +350,7 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
SERIALIZE_ZONE_LINK(minesLikeZone);
SERIALIZE_ZONE_LINK(terrainTypeLikeZone);
SERIALIZE_ZONE_LINK(treasureLikeZone);
SERIALIZE_ZONE_LINK(customObjectsLikeZone);
#undef SERIALIZE_ZONE_LINK
if(terrainTypeLikeZone == NO_ZONE)
@ -751,53 +766,29 @@ void CRmgTemplate::serializeJson(JsonSerializeFormat & handler)
}
}
std::set<TerrainId> CRmgTemplate::inheritTerrainType(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
template<typename T>
T CRmgTemplate::inheritZoneProperty(std::shared_ptr<rmg::ZoneOptions> zone,
T (rmg::ZoneOptions::*getter)() const,
void (rmg::ZoneOptions::*setter)(const T&),
TRmgTemplateZoneId (rmg::ZoneOptions::*inheritFrom)() const,
const std::string& propertyString,
uint32_t iteration)
{
if (iteration >= 50)
{
logGlobal->error("Infinite recursion for terrain types detected in template %s", name);
return std::set<TerrainId>();
logGlobal->error("Infinite recursion for %s detected in template %s", propertyString, name);
return T();
}
if (zone->getTerrainTypeLikeZone() != ZoneOptions::NO_ZONE)
{
iteration++;
const auto otherZone = zones.at(zone->getTerrainTypeLikeZone());
zone->setTerrainTypes(inheritTerrainType(otherZone, iteration));
}
//This implicitly excludes banned terrains
return zone->getTerrainTypes();
}
std::map<TResource, ui16> CRmgTemplate::inheritMineTypes(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
{
if (iteration >= 50)
{
logGlobal->error("Infinite recursion for mine types detected in template %s", name);
return std::map<TResource, ui16>();
}
if (zone->getMinesLikeZone() != ZoneOptions::NO_ZONE)
if (((*zone).*inheritFrom)() != rmg::ZoneOptions::NO_ZONE)
{
iteration++;
const auto otherZone = zones.at(zone->getMinesLikeZone());
zone->setMinesInfo(inheritMineTypes(otherZone, iteration));
const auto otherZone = zones.at(((*zone).*inheritFrom)());
T inheritedValue = inheritZoneProperty(otherZone, getter, setter, inheritFrom, propertyString, iteration);
((*zone).*setter)(inheritedValue);
}
return zone->getMinesInfo();
}
std::vector<CTreasureInfo> CRmgTemplate::inheritTreasureInfo(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
{
if (iteration >= 50)
{
logGlobal->error("Infinite recursion for treasures detected in template %s", name);
return std::vector<CTreasureInfo>();
}
if (zone->getTreasureLikeZone() != ZoneOptions::NO_ZONE)
{
iteration++;
const auto otherZone = zones.at(zone->getTreasureLikeZone());
zone->setTreasureInfo(inheritTreasureInfo(otherZone, iteration));
}
return zone->getTreasureInfo();
return ((*zone).*getter)();
}
void CRmgTemplate::afterLoad()
@ -806,12 +797,32 @@ void CRmgTemplate::afterLoad()
{
auto zone = idAndZone.second;
//Inherit properties recursively.
inheritTerrainType(zone);
inheritMineTypes(zone);
inheritTreasureInfo(zone);
// Inherit properties recursively
inheritZoneProperty(zone,
&rmg::ZoneOptions::getTerrainTypes,
&rmg::ZoneOptions::setTerrainTypes,
&rmg::ZoneOptions::getTerrainTypeLikeZone,
"terrain types");
//TODO: Inherit monster types as well
inheritZoneProperty(zone,
&rmg::ZoneOptions::getMinesInfo,
&rmg::ZoneOptions::setMinesInfo,
&rmg::ZoneOptions::getMinesLikeZone,
"mine types");
inheritZoneProperty(zone,
&rmg::ZoneOptions::getTreasureInfo,
&rmg::ZoneOptions::setTreasureInfo,
&rmg::ZoneOptions::getTreasureLikeZone,
"treasure info");
inheritZoneProperty(zone,
&rmg::ZoneOptions::getCustomObjects,
&rmg::ZoneOptions::setCustomObjects,
&rmg::ZoneOptions::getCustomObjectsLikeZone,
"custom objects");
//TODO: Inherit monster types as well
auto monsterTypes = zone->getMonsterTypes();
if (monsterTypes.empty())
{
@ -919,9 +930,9 @@ const std::vector<ObjectConfig::EObjectCategory> & ZoneOptions::getBannedObjectC
return objectConfig.getBannedObjectCategories();
}
const std::vector<ObjectInfo> & ZoneOptions::getCustomObjects() const
const std::vector<ObjectInfo> & ZoneOptions::getConfiguredObjects() const
{
return objectConfig.getCustomObjects();
return objectConfig.getConfiguredObjects();
}
VCMI_LIB_NAMESPACE_END

View File

@ -151,15 +151,15 @@ public:
void setSize(int value);
std::optional<int> getOwner() const;
const std::set<TerrainId> getTerrainTypes() const;
std::set<TerrainId> getTerrainTypes() const;
void setTerrainTypes(const std::set<TerrainId> & value);
std::set<TerrainId> getDefaultTerrainTypes() const;
const CTownInfo & getPlayerTowns() const;
const CTownInfo & getNeutralTowns() const;
std::set<FactionID> getDefaultTownTypes() const;
const std::set<FactionID> getTownTypes() const;
const std::set<FactionID> getMonsterTypes() const;
std::set<FactionID> getTownTypes() const;
std::set<FactionID> getMonsterTypes() const;
void setTownTypes(const std::set<FactionID> & value);
void setMonsterTypes(const std::set<FactionID> & value);
@ -169,7 +169,7 @@ public:
void setTreasureInfo(const std::vector<CTreasureInfo> & value);
void addTreasureInfo(const CTreasureInfo & value);
const std::vector<CTreasureInfo> & getTreasureInfo() const;
std::vector<CTreasureInfo> getTreasureInfo() const;
ui32 getMaxTreasureValue() const;
void recalculateMaxTreasureValue();
@ -188,9 +188,15 @@ public:
bool areTownsSameType() const;
bool isMatchTerrainToTown() const;
// Get a group of configured objects
const std::vector<CompoundMapObjectID> & getBannedObjects() const;
const std::vector<ObjectConfig::EObjectCategory> & getBannedObjectCategories() const;
const std::vector<ObjectInfo> & getCustomObjects() const;
const std::vector<ObjectInfo> & getConfiguredObjects() const;
// Copy whole custom object config from another zone
ObjectConfig getCustomObjects() const;
void setCustomObjects(const ObjectConfig & value);
TRmgTemplateZoneId getCustomObjectsLikeZone() const;
protected:
TRmgTemplateZoneId id;
@ -222,6 +228,7 @@ protected:
TRmgTemplateZoneId minesLikeZone;
TRmgTemplateZoneId terrainTypeLikeZone;
TRmgTemplateZoneId treasureLikeZone;
TRmgTemplateZoneId customObjectsLikeZone;
};
}
@ -294,6 +301,15 @@ private:
void serializeSize(JsonSerializeFormat & handler, int3 & value, const std::string & fieldName);
void serializePlayers(JsonSerializeFormat & handler, CPlayerCountRange & value, const std::string & fieldName);
template<typename T>
T inheritZoneProperty(std::shared_ptr<rmg::ZoneOptions> zone,
T (rmg::ZoneOptions::*getter)() const,
void (rmg::ZoneOptions::*setter)(const T&),
TRmgTemplateZoneId (rmg::ZoneOptions::*inheritFrom)() const,
const std::string& propertyString,
uint32_t iteration = 0);
};
VCMI_LIB_NAMESPACE_END

View File

@ -77,15 +77,15 @@ void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
(EObjectCategory::ALL, "all")
(EObjectCategory::NONE, "none")
(EObjectCategory::CREATURE_BANK, "creatureBank")
(EObjectCategory::PERMANENT_BONUS, "permanentBonus")
(EObjectCategory::NEXT_BATTLE_BONUS, "nextBattleBonus")
(EObjectCategory::BONUS, "bonus")
(EObjectCategory::DWELLING, "dwelling")
(EObjectCategory::RESOURCE, "resource")
(EObjectCategory::RESOURCE_GENERATOR, "resourceGenerator")
(EObjectCategory::SPELL_SCROLL, "spellScroll")
(EObjectCategory::RANDOM_ARTIFACT, "randomArtifact")
(EObjectCategory::PANDORAS_BOX, "pandorasBox")
(EObjectCategory::QUEST_ARTIFACT, "questArtifact");
(EObjectCategory::QUEST_ARTIFACT, "questArtifact")
(EObjectCategory::SEER_HUT, "seerHut");
auto categories = handler.enterArray("bannedCategories");
if (handler.saving)
@ -161,7 +161,7 @@ void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
}
}
const std::vector<ObjectInfo> & ObjectConfig::getCustomObjects() const
const std::vector<ObjectInfo> & ObjectConfig::getConfiguredObjects() const
{
return customObjects;
}

View File

@ -49,16 +49,15 @@ public:
ALL = -1,
NONE = 0,
CREATURE_BANK = 1,
PERMANENT_BONUS,
NEXT_BATTLE_BONUS,
BONUS,
DWELLING,
RESOURCE,
RESOURCE_GENERATOR,
SPELL_SCROLL,
RANDOM_ARTIFACT,
PANDORAS_BOX,
QUEST_ARTIFACT
// TODO: Seer huts?
QUEST_ARTIFACT,
SEER_HUT
};
void addBannedObject(const CompoundMapObjectID & objid);
@ -67,9 +66,8 @@ public:
void clearCustomObjects();
const std::vector<CompoundMapObjectID> & getBannedObjects() const;
const std::vector<EObjectCategory> & getBannedObjectCategories() const;
const std::vector<ObjectInfo> & getCustomObjects() const;
const std::vector<ObjectInfo> & getConfiguredObjects() const;
// TODO: Separate serializer
void serializeJson(JsonSerializeFormat & handler);
private:
// TODO: Add convenience method for banning objects by name

View File

@ -25,6 +25,7 @@
#include "../../mapObjectConstructors/AObjectTypeHandler.h"
#include "../../mapObjectConstructors/CObjectClassesHandler.h"
#include "../../mapObjectConstructors/DwellingInstanceConstructor.h"
#include "../../rewardable/Info.h"
#include "../../mapObjects/CGHeroInstance.h"
#include "../../mapObjects/CGPandoraBox.h"
#include "../../mapObjects/CQuest.h"
@ -1139,7 +1140,8 @@ void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
vstd::erase_if(possibleObjects, [this, &categoriesSet](const ObjectInfo & oi) -> bool
{
auto category = getObjectCategory(oi.templates.front()->id);
auto temp = oi.templates.front();
auto category = getObjectCategory(CompoundMapObjectID(temp->id, temp->subid));
if (categoriesSet.count(category))
{
logGlobal->info("Removing object %s from possible objects", oi.templates.front()->stringID);
@ -1161,10 +1163,11 @@ void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
return false;
});
// Now copy back modified list
auto configuredObjects = zone.getConfiguredObjects();
// TODO: Overwrite or add to possibleObjects
// FIXME: Protect with mutex as well?
/*
possibleObjects.clear();
for (const auto & customObject : customObjects)
{
addObject(customObject.second);
@ -1194,15 +1197,35 @@ void TreasurePlacer::ObjectPool::discardObjectsAboveValue(ui32 value)
});
}
ObjectConfig::EObjectCategory TreasurePlacer::ObjectPool::getObjectCategory(MapObjectID id)
ObjectConfig::EObjectCategory TreasurePlacer::ObjectPool::getObjectCategory(CompoundMapObjectID id)
{
auto name = VLC->objtypeh->getObjectHandlerName(id);
auto name = VLC->objtypeh->getObjectHandlerName(id.primaryID);
if (name == "configurable")
{
// TODO: Need to check configuration here.
// Possible otions: PERMANENT_BONUS, NEXT_BATTLE_BONUS, RESOURCE
return ObjectConfig::EObjectCategory::RESOURCE;
// TODO: Access Rewardable::Info by ID
auto handler = VLC->objtypeh->getHandlerFor(id.primaryID, id.secondaryID);
if (!handler)
{
return ObjectConfig::EObjectCategory::NONE;
}
auto temp = handler->getTemplates().front();
auto info = handler->getObjectInfo(temp);
if (info->givesResources())
{
return ObjectConfig::EObjectCategory::RESOURCE;
}
else if (info->givesArtifacts())
{
return ObjectConfig::EObjectCategory::RANDOM_ARTIFACT;
}
else if (info->givesBonuses())
{
return ObjectConfig::EObjectCategory::BONUS;
}
return ObjectConfig::EObjectCategory::OTHER;
}
else if (name == "dwelling" || name == "randomDwelling")
{
@ -1223,28 +1246,33 @@ ObjectConfig::EObjectCategory TreasurePlacer::ObjectPool::getObjectCategory(MapO
return ObjectConfig::EObjectCategory::OTHER;
else if (name == "lighthouse")
{
// TODO: So far Lighthouse is not generated
// Also, it gives global bonus as long as owned
return ObjectConfig::EObjectCategory::PERMANENT_BONUS;
return ObjectConfig::EObjectCategory::BONUS;
}
else if (name == "magi")
{
// TODO: By default, both eye and hut are banned in every zone
return ObjectConfig::EObjectCategory::OTHER;
}
else if (name == "mine")
return ObjectConfig::EObjectCategory::RESOURCE_GENERATOR;
else if (name == "pandora")
return ObjectConfig::EObjectCategory::PANDORAS_BOX;
else if (name == "prison")
{
// TODO: Prisons are configurable
// TODO: Prisons should be configurable
return ObjectConfig::EObjectCategory::OTHER;
}
else if (name == "questArtifact")
{
// TODO: There are no dedicated quest artifacts, needs extra logic
return ObjectConfig::EObjectCategory::QUEST_ARTIFACT;
}
else if (name == "seerHut")
{
// quest artifacts are configurable, but what about seer huts?
return ObjectConfig::EObjectCategory::QUEST_ARTIFACT;
return ObjectConfig::EObjectCategory::SEER_HUT;
}
else if (name == "siren")
return ObjectConfig::EObjectCategory::NEXT_BATTLE_BONUS;
return ObjectConfig::EObjectCategory::BONUS;
else if (name == "obelisk")
return ObjectConfig::EObjectCategory::OTHER;

View File

@ -73,7 +73,7 @@ protected:
void sortPossibleObjects();
void discardObjectsAboveValue(ui32 value);
ObjectConfig::EObjectCategory getObjectCategory(MapObjectID id);
ObjectConfig::EObjectCategory getObjectCategory(CompoundMapObjectID id);
private: