mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
- Option to configure monster types spawning in a zone
- 25% chance to get neutral faction in zone with no town
This commit is contained in:
@@ -767,10 +767,19 @@ std::vector<bool> CTownHandler::getDefaultAllowed() const
|
|||||||
}
|
}
|
||||||
return allowedFactions;
|
return allowedFactions;
|
||||||
}
|
}
|
||||||
std::set<TFaction> CTownHandler::getAllowedFactions() const
|
std::set<TFaction> CTownHandler::getAllowedFactions(bool withTown /*=true*/) const
|
||||||
{
|
{
|
||||||
std::set<TFaction> allowedFactions;
|
std::set<TFaction> allowedFactions;
|
||||||
auto allowed = getDefaultAllowed();
|
std::vector<bool> allowed;
|
||||||
|
if (withTown)
|
||||||
|
allowed = getDefaultAllowed();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto town : factions)
|
||||||
|
{
|
||||||
|
allowed.push_back (true);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (size_t i=0; i<allowed.size(); i++)
|
for (size_t i=0; i<allowed.size(); i++)
|
||||||
if (allowed[i])
|
if (allowed[i])
|
||||||
allowedFactions.insert(i);
|
allowedFactions.insert(i);
|
||||||
|
@@ -266,7 +266,7 @@ public:
|
|||||||
void afterLoadFinalization() override;
|
void afterLoadFinalization() override;
|
||||||
|
|
||||||
std::vector<bool> getDefaultAllowed() const override;
|
std::vector<bool> getDefaultAllowed() const override;
|
||||||
std::set<TFaction> getAllowedFactions() const;
|
std::set<TFaction> getAllowedFactions(bool withTown = true) const;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
|
@@ -299,7 +299,7 @@ namespace ETownType
|
|||||||
enum ETownType
|
enum ETownType
|
||||||
{
|
{
|
||||||
ANY = -1,
|
ANY = -1,
|
||||||
CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX
|
CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX, NEUTRAL
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -47,7 +47,7 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
|||||||
|
|
||||||
// Parse zones
|
// Parse zones
|
||||||
std::map<TRmgTemplateZoneId, CRmgTemplateZone *> zones;
|
std::map<TRmgTemplateZoneId, CRmgTemplateZone *> zones;
|
||||||
for(const auto & zonePair : templateNode["zones"].Struct())
|
for (const auto & zonePair : templateNode["zones"].Struct())
|
||||||
{
|
{
|
||||||
auto zone = new CRmgTemplateZone();
|
auto zone = new CRmgTemplateZone();
|
||||||
auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
|
auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
|
||||||
@@ -56,7 +56,7 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
|||||||
const auto & zoneNode = zonePair.second;
|
const auto & zoneNode = zonePair.second;
|
||||||
zone->setType(parseZoneType(zoneNode["type"].String()));
|
zone->setType(parseZoneType(zoneNode["type"].String()));
|
||||||
zone->setSize(zoneNode["size"].Float());
|
zone->setSize(zoneNode["size"].Float());
|
||||||
if(!zoneNode["owner"].isNull()) zone->setOwner(zoneNode["owner"].Float());
|
if (!zoneNode["owner"].isNull()) zone->setOwner(zoneNode["owner"].Float());
|
||||||
|
|
||||||
zone->setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
|
zone->setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
|
||||||
zone->setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
|
zone->setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
|
||||||
@@ -65,23 +65,30 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
|||||||
zone->setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone->getDefaultTerrainTypes()));
|
zone->setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone->getDefaultTerrainTypes()));
|
||||||
zone->setTownsAreSameType((zoneNode["townsAreSameType"].Bool()));
|
zone->setTownsAreSameType((zoneNode["townsAreSameType"].Bool()));
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
std::set<TFaction> allowedTownTypes;
|
std::set<TFaction> allowedTownTypes;
|
||||||
if (zoneNode["allowedTowns"].isNull())
|
if (zoneNode[i ? "allowedTowns" : "allowedMonsters"].isNull())
|
||||||
|
{
|
||||||
|
if (i)
|
||||||
allowedTownTypes = zone->getDefaultTownTypes();
|
allowedTownTypes = zone->getDefaultTownTypes();
|
||||||
|
else
|
||||||
|
allowedTownTypes = VLC->townh->getAllowedFactions(false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (const JsonNode & allowedTown : zoneNode["allowedTowns"].Vector())
|
for (const JsonNode & allowedTown : zoneNode[i ? "allowedTowns" : "allowedMonsters"].Vector())
|
||||||
{
|
{
|
||||||
//complain if the town type is not present in our game
|
//complain if the town type is not present in our game
|
||||||
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false);
|
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false);
|
||||||
if (id.is_initialized())
|
if (id.is_initialized())
|
||||||
allowedTownTypes.insert (id.get());
|
allowedTownTypes.insert(id.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!zoneNode["bannedTowns"].isNull())
|
if (!zoneNode[i ? "bannedTowns" : "bannedMonsters"].isNull())
|
||||||
{
|
{
|
||||||
for (const JsonNode & bannedTown : zoneNode["bannedTowns"].Vector())
|
for (const JsonNode & bannedTown : zoneNode[i ? "bannedTowns" : "bannedMonsters"].Vector())
|
||||||
{
|
{
|
||||||
//erase unindentified towns silently
|
//erase unindentified towns silently
|
||||||
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true);
|
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true);
|
||||||
@@ -89,8 +96,11 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
|||||||
vstd::erase_if_present(allowedTownTypes, id.get());
|
vstd::erase_if_present(allowedTownTypes, id.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(allowedTownTypes.size());
|
if (i)
|
||||||
zone->setTownTypes (allowedTownTypes);
|
zone->setTownTypes(allowedTownTypes);
|
||||||
|
else
|
||||||
|
zone->setMonsterTypes(allowedTownTypes);
|
||||||
|
}
|
||||||
|
|
||||||
const std::string monsterStrength = zoneNode["monsters"].String();
|
const std::string monsterStrength = zoneNode["monsters"].String();
|
||||||
if (monsterStrength == "weak")
|
if (monsterStrength == "weak")
|
||||||
|
@@ -136,7 +136,7 @@ CRmgTemplateZone::CRmgTemplateZone() :
|
|||||||
size(1),
|
size(1),
|
||||||
townsAreSameType(false),
|
townsAreSameType(false),
|
||||||
matchTerrainToTown(true),
|
matchTerrainToTown(true),
|
||||||
townType(0),
|
townType(ETownType::NEUTRAL),
|
||||||
terrainType (ETerrainType::GRASS),
|
terrainType (ETerrainType::GRASS),
|
||||||
zoneMonsterStrength(EMonsterStrength::ZONE_NORMAL),
|
zoneMonsterStrength(EMonsterStrength::ZONE_NORMAL),
|
||||||
totalDensity(0)
|
totalDensity(0)
|
||||||
@@ -228,6 +228,10 @@ void CRmgTemplateZone::setTownTypes(const std::set<TFaction> & value)
|
|||||||
{
|
{
|
||||||
townTypes = value;
|
townTypes = value;
|
||||||
}
|
}
|
||||||
|
void CRmgTemplateZone::setMonsterTypes(const std::set<TFaction> & value)
|
||||||
|
{
|
||||||
|
monsterTypes = value;
|
||||||
|
}
|
||||||
|
|
||||||
std::set<TFaction> CRmgTemplateZone::getDefaultTownTypes() const
|
std::set<TFaction> CRmgTemplateZone::getDefaultTownTypes() const
|
||||||
{
|
{
|
||||||
@@ -635,6 +639,8 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength,
|
|||||||
{
|
{
|
||||||
if (cre->special)
|
if (cre->special)
|
||||||
continue;
|
continue;
|
||||||
|
if (!vstd::contains(monsterTypes, cre->faction))
|
||||||
|
continue;
|
||||||
if ((cre->AIValue * (cre->ammMin + cre->ammMax) / 2 < strength) && (strength < cre->AIValue * 100)) //at least one full monster. size between minimum size of given stack and 100
|
if ((cre->AIValue * (cre->ammMin + cre->ammMax) / 2 < strength) && (strength < cre->AIValue * 100)) //at least one full monster. size between minimum size of given stack and 100
|
||||||
{
|
{
|
||||||
possibleCreatures.push_back(cre->idNumber);
|
possibleCreatures.push_back(cre->idNumber);
|
||||||
@@ -950,7 +956,12 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
|
|||||||
if (this->townsAreSameType)
|
if (this->townsAreSameType)
|
||||||
town->subID = townType;
|
town->subID = townType;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (townTypes.size())
|
||||||
town->subID = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
|
town->subID = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
|
||||||
|
else
|
||||||
|
town->subID = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed
|
||||||
|
}
|
||||||
|
|
||||||
town->tempOwner = player;
|
town->tempOwner = player;
|
||||||
if (hasFort)
|
if (hasFort)
|
||||||
@@ -992,7 +1003,12 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
|
|||||||
townType = gen->mapGenOptions->getPlayersSettings().find(player)->second.getStartingTown();
|
townType = gen->mapGenOptions->getPlayersSettings().find(player)->second.getStartingTown();
|
||||||
|
|
||||||
if (townType == CMapGenOptions::CPlayerSettings::RANDOM_TOWN)
|
if (townType == CMapGenOptions::CPlayerSettings::RANDOM_TOWN)
|
||||||
|
{
|
||||||
|
if (townTypes.size())
|
||||||
townType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
|
townType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
|
||||||
|
else
|
||||||
|
townType = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed
|
||||||
|
}
|
||||||
|
|
||||||
auto town = new CGTownInstance();
|
auto town = new CGTownInstance();
|
||||||
town->ID = Obj::TOWN;
|
town->ID = Obj::TOWN;
|
||||||
@@ -1044,12 +1060,29 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
|
|||||||
|
|
||||||
addNewTowns (neutralTowns.getCastleCount(), true, PlayerColor::NEUTRAL);
|
addNewTowns (neutralTowns.getCastleCount(), true, PlayerColor::NEUTRAL);
|
||||||
addNewTowns (neutralTowns.getTownCount(), false, PlayerColor::NEUTRAL);
|
addNewTowns (neutralTowns.getTownCount(), false, PlayerColor::NEUTRAL);
|
||||||
|
|
||||||
|
if (!totalTowns) //if there's no town present, get random faction for dwellings and pandoras
|
||||||
|
{
|
||||||
|
//25% chance for neutral
|
||||||
|
if (gen->rand.nextInt(1, 100) <= 25)
|
||||||
|
{
|
||||||
|
townType = ETownType::NEUTRAL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (townTypes.size())
|
||||||
|
townType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
|
||||||
|
else if (monsterTypes.size())
|
||||||
|
townType = *RandomGeneratorUtil::nextItem(monsterTypes, gen->rand); //this happens in Clash of Dragons in treasure zones, where all towns are banned
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRmgTemplateZone::initTerrainType (CMapGenerator* gen)
|
void CRmgTemplateZone::initTerrainType (CMapGenerator* gen)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (matchTerrainToTown)
|
if (matchTerrainToTown && townType != ETownType::NEUTRAL)
|
||||||
terrainType = VLC->townh->factions[townType]->nativeTerrain;
|
terrainType = VLC->townh->factions[townType]->nativeTerrain;
|
||||||
else
|
else
|
||||||
terrainType = *RandomGeneratorUtil::nextItem(terrainTypes, gen->rand);
|
terrainType = *RandomGeneratorUtil::nextItem(terrainTypes, gen->rand);
|
||||||
@@ -1945,12 +1978,15 @@ void CRmgTemplateZone::addAllPossibleObjects (CMapGenerator* gen)
|
|||||||
|
|
||||||
for (auto creature : VLC->creh->creatures)
|
for (auto creature : VLC->creh->creatures)
|
||||||
{
|
{
|
||||||
if (!creature->special && VLC->townh->factions[creature->faction]->nativeTerrain == terrainType)
|
if (!creature->special && creature->faction == townType)
|
||||||
{
|
{
|
||||||
int actualTier = creature->level > 7 ? 6 : creature->level-1;
|
int actualTier = creature->level > 7 ? 6 : creature->level-1;
|
||||||
int creaturesAmount = tierValues[actualTier] / creature->AIValue;
|
float creaturesAmount = tierValues[actualTier] / creature->AIValue;
|
||||||
if (creaturesAmount <= 5)
|
if (creaturesAmount <= 5)
|
||||||
{
|
{
|
||||||
|
creaturesAmount = boost::math::round(creaturesAmount); //allow single monsters
|
||||||
|
if (creaturesAmount < 1)
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (creaturesAmount <= 12)
|
else if (creaturesAmount <= 12)
|
||||||
{
|
{
|
||||||
@@ -1958,11 +1994,11 @@ void CRmgTemplateZone::addAllPossibleObjects (CMapGenerator* gen)
|
|||||||
}
|
}
|
||||||
else if (creaturesAmount <= 50)
|
else if (creaturesAmount <= 50)
|
||||||
{
|
{
|
||||||
creaturesAmount = boost::math::round((float)creaturesAmount / 5) * 5;
|
creaturesAmount = boost::math::round(creaturesAmount / 5) * 5;
|
||||||
}
|
}
|
||||||
else if (creaturesAmount <= 12)
|
else if (creaturesAmount <= 12)
|
||||||
{
|
{
|
||||||
creaturesAmount = boost::math::round((float)creaturesAmount / 10) * 10;
|
creaturesAmount = boost::math::round(creaturesAmount / 10) * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance *
|
oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance *
|
||||||
|
@@ -129,6 +129,7 @@ public:
|
|||||||
void setTownsAreSameType(bool value);
|
void setTownsAreSameType(bool value);
|
||||||
const std::set<TFaction> & getTownTypes() const; /// Default: all
|
const std::set<TFaction> & getTownTypes() const; /// Default: all
|
||||||
void setTownTypes(const std::set<TFaction> & value);
|
void setTownTypes(const std::set<TFaction> & value);
|
||||||
|
void setMonsterTypes(const std::set<TFaction> & value);
|
||||||
std::set<TFaction> getDefaultTownTypes() const;
|
std::set<TFaction> getDefaultTownTypes() const;
|
||||||
bool getMatchTerrainToTown() const; /// Default: true
|
bool getMatchTerrainToTown() const; /// Default: true
|
||||||
void setMatchTerrainToTown(bool value);
|
void setMatchTerrainToTown(bool value);
|
||||||
@@ -186,6 +187,7 @@ private:
|
|||||||
CTownInfo playerTowns, neutralTowns;
|
CTownInfo playerTowns, neutralTowns;
|
||||||
bool townsAreSameType;
|
bool townsAreSameType;
|
||||||
std::set<TFaction> townTypes;
|
std::set<TFaction> townTypes;
|
||||||
|
std::set<TFaction> monsterTypes;
|
||||||
bool matchTerrainToTown;
|
bool matchTerrainToTown;
|
||||||
std::set<ETerrainType> terrainTypes;
|
std::set<ETerrainType> terrainTypes;
|
||||||
std::map<TResource, ui16> mines; //obligatory mines to spawn in this zone
|
std::map<TResource, ui16> mines; //obligatory mines to spawn in this zone
|
||||||
|
Reference in New Issue
Block a user