1
0
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:
DjWarmonger
2014-10-30 13:03:53 +01:00
parent 530a3e69bf
commit ce83db0f43
6 changed files with 90 additions and 33 deletions

View File

@@ -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);

View File

@@ -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)
{ {

View File

@@ -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
}; };
} }

View File

@@ -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,32 +65,42 @@ 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()));
std::set<TFaction> allowedTownTypes; for (int i = 0; i < 2; ++i)
if (zoneNode["allowedTowns"].isNull())
allowedTownTypes = zone->getDefaultTownTypes();
else
{ {
for (const JsonNode & allowedTown : zoneNode["allowedTowns"].Vector()) std::set<TFaction> allowedTownTypes;
if (zoneNode[i ? "allowedTowns" : "allowedMonsters"].isNull())
{ {
//complain if the town type is not present in our game if (i)
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false); allowedTownTypes = zone->getDefaultTownTypes();
if (id.is_initialized()) else
allowedTownTypes.insert (id.get()); allowedTownTypes = VLC->townh->getAllowedFactions(false);
}
else
{
for (const JsonNode & allowedTown : zoneNode[i ? "allowedTowns" : "allowedMonsters"].Vector())
{
//complain if the town type is not present in our game
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false);
if (id.is_initialized())
allowedTownTypes.insert(id.get());
}
} }
}
if (!zoneNode["bannedTowns"].isNull()) if (!zoneNode[i ? "bannedTowns" : "bannedMonsters"].isNull())
{
for (const JsonNode & bannedTown : zoneNode["bannedTowns"].Vector())
{ {
//erase unindentified towns silently for (const JsonNode & bannedTown : zoneNode[i ? "bannedTowns" : "bannedMonsters"].Vector())
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true); {
if (id.is_initialized()) //erase unindentified towns silently
vstd::erase_if_present(allowedTownTypes, id.get()); boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true);
if (id.is_initialized())
vstd::erase_if_present(allowedTownTypes, id.get());
}
} }
if (i)
zone->setTownTypes(allowedTownTypes);
else
zone->setMonsterTypes(allowedTownTypes);
} }
assert(allowedTownTypes.size());
zone->setTownTypes (allowedTownTypes);
const std::string monsterStrength = zoneNode["monsters"].String(); const std::string monsterStrength = zoneNode["monsters"].String();
if (monsterStrength == "weak") if (monsterStrength == "weak")

View File

@@ -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
town->subID = *RandomGeneratorUtil::nextItem(townTypes, gen->rand); {
if (townTypes.size())
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)
townType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand); {
if (townTypes.size())
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 *

View File

@@ -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