From ce83db0f4392fcb8a1f4a93decda4830b4762fd0 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Thu, 30 Oct 2014 13:03:53 +0100 Subject: [PATCH] - Option to configure monster types spawning in a zone - 25% chance to get neutral faction in zone with no town --- lib/CTownHandler.cpp | 13 +++++++-- lib/CTownHandler.h | 2 +- lib/GameConstants.h | 2 +- lib/rmg/CRmgTemplateStorage.cpp | 52 ++++++++++++++++++++------------- lib/rmg/CRmgTemplateZone.cpp | 52 ++++++++++++++++++++++++++++----- lib/rmg/CRmgTemplateZone.h | 2 ++ 6 files changed, 90 insertions(+), 33 deletions(-) diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index d7e9973e4..5ca0d4f55 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -767,10 +767,19 @@ std::vector CTownHandler::getDefaultAllowed() const } return allowedFactions; } -std::set CTownHandler::getAllowedFactions() const +std::set CTownHandler::getAllowedFactions(bool withTown /*=true*/) const { std::set allowedFactions; - auto allowed = getDefaultAllowed(); + std::vector allowed; + if (withTown) + allowed = getDefaultAllowed(); + else + { + for (auto town : factions) + { + allowed.push_back (true); + } + } for (size_t i=0; i getDefaultAllowed() const override; - std::set getAllowedFactions() const; + std::set getAllowedFactions(bool withTown = true) const; template void serialize(Handler &h, const int version) { diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 3e036cb49..20f7eaa5f 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -299,7 +299,7 @@ namespace ETownType enum ETownType { ANY = -1, - CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX + CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX, NEUTRAL }; } diff --git a/lib/rmg/CRmgTemplateStorage.cpp b/lib/rmg/CRmgTemplateStorage.cpp index e211f4be7..b45c67a27 100644 --- a/lib/rmg/CRmgTemplateStorage.cpp +++ b/lib/rmg/CRmgTemplateStorage.cpp @@ -47,7 +47,7 @@ void CJsonRmgTemplateLoader::loadTemplates() // Parse zones std::map zones; - for(const auto & zonePair : templateNode["zones"].Struct()) + for (const auto & zonePair : templateNode["zones"].Struct()) { auto zone = new CRmgTemplateZone(); auto zoneId = boost::lexical_cast(zonePair.first); @@ -56,7 +56,7 @@ void CJsonRmgTemplateLoader::loadTemplates() const auto & zoneNode = zonePair.second; zone->setType(parseZoneType(zoneNode["type"].String())); 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->setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"])); @@ -65,32 +65,42 @@ void CJsonRmgTemplateLoader::loadTemplates() zone->setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone->getDefaultTerrainTypes())); zone->setTownsAreSameType((zoneNode["townsAreSameType"].Bool())); - std::set allowedTownTypes; - if (zoneNode["allowedTowns"].isNull()) - allowedTownTypes = zone->getDefaultTownTypes(); - else + for (int i = 0; i < 2; ++i) { - for (const JsonNode & allowedTown : zoneNode["allowedTowns"].Vector()) + std::set allowedTownTypes; + if (zoneNode[i ? "allowedTowns" : "allowedMonsters"].isNull()) { - //complain if the town type is not present in our game - boost::optional id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false); - if (id.is_initialized()) - allowedTownTypes.insert (id.get()); + if (i) + allowedTownTypes = zone->getDefaultTownTypes(); + else + 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 id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false); + if (id.is_initialized()) + allowedTownTypes.insert(id.get()); + } } - } - if (!zoneNode["bannedTowns"].isNull()) - { - for (const JsonNode & bannedTown : zoneNode["bannedTowns"].Vector()) + if (!zoneNode[i ? "bannedTowns" : "bannedMonsters"].isNull()) { - //erase unindentified towns silently - boost::optional id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true); - if (id.is_initialized()) - vstd::erase_if_present(allowedTownTypes, id.get()); + for (const JsonNode & bannedTown : zoneNode[i ? "bannedTowns" : "bannedMonsters"].Vector()) + { + //erase unindentified towns silently + boost::optional 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(); if (monsterStrength == "weak") diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 9f3c49a26..06f699da7 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -136,7 +136,7 @@ CRmgTemplateZone::CRmgTemplateZone() : size(1), townsAreSameType(false), matchTerrainToTown(true), - townType(0), + townType(ETownType::NEUTRAL), terrainType (ETerrainType::GRASS), zoneMonsterStrength(EMonsterStrength::ZONE_NORMAL), totalDensity(0) @@ -228,6 +228,10 @@ void CRmgTemplateZone::setTownTypes(const std::set & value) { townTypes = value; } +void CRmgTemplateZone::setMonsterTypes(const std::set & value) +{ + monsterTypes = value; +} std::set CRmgTemplateZone::getDefaultTownTypes() const { @@ -635,6 +639,8 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength, { if (cre->special) 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 { possibleCreatures.push_back(cre->idNumber); @@ -950,7 +956,12 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen) if (this->townsAreSameType) town->subID = townType; 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; if (hasFort) @@ -992,7 +1003,12 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen) townType = gen->mapGenOptions->getPlayersSettings().find(player)->second.getStartingTown(); 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(); town->ID = Obj::TOWN; @@ -1044,12 +1060,29 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen) addNewTowns (neutralTowns.getCastleCount(), true, 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) { - if (matchTerrainToTown) + if (matchTerrainToTown && townType != ETownType::NEUTRAL) terrainType = VLC->townh->factions[townType]->nativeTerrain; else terrainType = *RandomGeneratorUtil::nextItem(terrainTypes, gen->rand); @@ -1945,12 +1978,15 @@ void CRmgTemplateZone::addAllPossibleObjects (CMapGenerator* gen) 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 creaturesAmount = tierValues[actualTier] / creature->AIValue; + float creaturesAmount = tierValues[actualTier] / creature->AIValue; if (creaturesAmount <= 5) { + creaturesAmount = boost::math::round(creaturesAmount); //allow single monsters + if (creaturesAmount < 1) + continue; } else if (creaturesAmount <= 12) { @@ -1958,11 +1994,11 @@ void CRmgTemplateZone::addAllPossibleObjects (CMapGenerator* gen) } else if (creaturesAmount <= 50) { - creaturesAmount = boost::math::round((float)creaturesAmount / 5) * 5; + creaturesAmount = boost::math::round(creaturesAmount / 5) * 5; } else if (creaturesAmount <= 12) { - creaturesAmount = boost::math::round((float)creaturesAmount / 10) * 10; + creaturesAmount = boost::math::round(creaturesAmount / 10) * 10; } oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance * diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index 891ba9ab2..2ce38b095 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -129,6 +129,7 @@ public: void setTownsAreSameType(bool value); const std::set & getTownTypes() const; /// Default: all void setTownTypes(const std::set & value); + void setMonsterTypes(const std::set & value); std::set getDefaultTownTypes() const; bool getMatchTerrainToTown() const; /// Default: true void setMatchTerrainToTown(bool value); @@ -186,6 +187,7 @@ private: CTownInfo playerTowns, neutralTowns; bool townsAreSameType; std::set townTypes; + std::set monsterTypes; bool matchTerrainToTown; std::set terrainTypes; std::map mines; //obligatory mines to spawn in this zone