diff --git a/docs/modders/Map_Objects/Rewardable.md b/docs/modders/Map_Objects/Rewardable.md index 1694b7e7a..3aa316327 100644 --- a/docs/modders/Map_Objects/Rewardable.md +++ b/docs/modders/Map_Objects/Rewardable.md @@ -72,7 +72,7 @@ Rewardable object is defined similarly to other objects, with key difference bei // additional list of conditions. Limiter will be valid if any of these conditions are true "anyOf" : [ { - // See "Configurable Properties" section for additiona parameters + // See "Configurable Properties" section for additional parameters } ] @@ -80,12 +80,12 @@ Rewardable object is defined similarly to other objects, with key difference bei // additional list of conditions. Limiter will be valid only if none of these conditions are true "noneOf" : [ { - // See "Configurable Properties" section for additiona parameters + // See "Configurable Properties" section for additional parameters } ] - // See "Configurable Properties" section for additiona parameters + // See "Configurable Properties" section for additional parameters } @@ -95,7 +95,7 @@ Rewardable object is defined similarly to other objects, with key difference bei // object will be disappeared after taking reward is set to true "removeObject": false - // See "Configurable Properties" section for additiona parameters + // See "Configurable Properties" section for additional parameters } ], @@ -450,4 +450,32 @@ Keep in mind, that all randomization is performed on map load and on object rese "spell" : "townPortal", "schoolLevel": 3 } +``` + +### Player color +- Can be used as limiter +- Can NOT be used as reward +- Only players with specific color can pass the limiter +- If not specified or empty all colors may pass the limiter + +```jsonc +"colors" : [ "red", "blue", "tan", "green", "orange", "purple", "teal", "pink" ] +``` + +### Hero types +- Can be used as limiter +- Can NOT be used as reward +- Only specific heroes can pass the limiter + +```jsonc +"heroes" : [ "orrin" ] +``` + +### Hero classes +- Can be used as limiter +- Can NOT be used as reward +- Only heroes belonging to specific classes can pass the limiter + +```jsonc +"heroClasses" : [ "battlemage" ] ``` \ No newline at end of file diff --git a/lib/JsonRandom.cpp b/lib/JsonRandom.cpp index 270c47b80..95ce1f4f4 100644 --- a/lib/JsonRandom.cpp +++ b/lib/JsonRandom.cpp @@ -22,6 +22,7 @@ #include "CCreatureSet.h" #include "spells/CSpellHandler.h" #include "CSkillHandler.h" +#include "CHeroHandler.h" #include "IGameCallback.h" #include "mapObjects/IObjectInterface.h" #include "modding/IdentifierStorage.h" @@ -282,6 +283,46 @@ namespace JsonRandom return ret; } + std::vector loadColors(const JsonNode & value, CRandomGenerator & rng) + { + std::vector ret; + std::set def; + + for(auto & color : GameConstants::PLAYER_COLOR_NAMES) + def.insert(color); + + for(auto & entry : value.Vector()) + { + auto key = loadKey(entry, rng, def); + auto pos = vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, key); + if(pos < 0) + logMod->warn("Unable to determine player color %s", key); + else + ret.emplace_back(pos); + } + return ret; + } + + std::vector loadHeroes(const JsonNode & value, CRandomGenerator & rng) + { + std::vector ret; + for(auto & entry : value.Vector()) + { + ret.push_back(VLC->heroTypes()->getByIndex(VLC->identifiers()->getIdentifier("hero", entry.String()).value())->getId()); + } + return ret; + } + + std::vector loadHeroClasses(const JsonNode & value, CRandomGenerator & rng) + { + std::vector ret; + for(auto & entry : value.Vector()) + { + ret.push_back(VLC->heroClasses()->getByIndex(VLC->identifiers()->getIdentifier("heroClass", entry.String()).value())->getId()); + } + return ret; + } + CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng) { CStackBasicDescriptor stack; diff --git a/lib/JsonRandom.h b/lib/JsonRandom.h index 2ac9e1d65..ef066d14e 100644 --- a/lib/JsonRandom.h +++ b/lib/JsonRandom.h @@ -48,6 +48,10 @@ namespace JsonRandom DLL_LINKAGE std::vector loadCreatures(const JsonNode & value, CRandomGenerator & rng); DLL_LINKAGE std::vector evaluateCreatures(const JsonNode & value); + DLL_LINKAGE std::vector loadColors(const JsonNode & value, CRandomGenerator & rng); + DLL_LINKAGE std::vector loadHeroes(const JsonNode & value, CRandomGenerator & rng); + DLL_LINKAGE std::vector loadHeroClasses(const JsonNode & value, CRandomGenerator & rng); + DLL_LINKAGE std::vector loadBonuses(const JsonNode & value); //DLL_LINKAGE std::vector loadComponents(const JsonNode & value); } diff --git a/lib/rewardable/Info.cpp b/lib/rewardable/Info.cpp index c82fca352..b9a8f1b2b 100644 --- a/lib/rewardable/Info.cpp +++ b/lib/rewardable/Info.cpp @@ -122,6 +122,10 @@ void Rewardable::Info::configureLimiter(Rewardable::Configuration & object, CRan limiter.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng); limiter.spells = JsonRandom::loadSpells(source["spells"], rng, spells); limiter.creatures = JsonRandom::loadCreatures(source["creatures"], rng); + + limiter.players = JsonRandom::loadColors(source["colors"], rng); + limiter.heroes = JsonRandom::loadHeroes(source["heroes"], rng); + limiter.heroClasses = JsonRandom::loadHeroClasses(source["heroClasses"], rng); limiter.allOf = configureSublimiters(object, rng, source["allOf"] ); limiter.anyOf = configureSublimiters(object, rng, source["anyOf"] ); diff --git a/lib/rewardable/Limiter.cpp b/lib/rewardable/Limiter.cpp index 9611f67aa..8167da026 100644 --- a/lib/rewardable/Limiter.cpp +++ b/lib/rewardable/Limiter.cpp @@ -16,6 +16,7 @@ #include "../mapObjects/CGHeroInstance.h" #include "../serializer/JsonSerializeFormat.h" #include "../constants/StringConstants.h" +#include "../CHeroHandler.h" #include "../CSkillHandler.h" #include "../ArtifactUtils.h" @@ -112,6 +113,16 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const return false; } + if(!players.empty() && !vstd::contains(players, hero->getOwner())) + return false; + + if(!heroes.empty() && !vstd::contains(heroes, hero->type->getId())) + return false; + + if(!heroClasses.empty() && !vstd::contains(heroClasses, hero->type->heroClass->getId())) + return false; + + for(const auto & sublimiter : noneOf) { if (sublimiter->heroAllowed(hero)) @@ -143,6 +154,9 @@ void Rewardable::Limiter::serializeJson(JsonSerializeFormat & handler) handler.serializeInt("manaPercentage", manaPercentage); handler.serializeInt("heroExperience", heroExperience); handler.serializeInt("heroLevel", heroLevel); + handler.serializeIdArray("hero", heroes); + handler.serializeIdArray("heroClass", heroClasses); + handler.serializeIdArray("color", players); handler.serializeInt("manaPoints", manaPoints); handler.serializeIdArray("artifacts", artifacts); handler.enterArray("creatures").serializeStruct(creatures); diff --git a/lib/rewardable/Limiter.h b/lib/rewardable/Limiter.h index 1f92cf4f0..300e572ae 100644 --- a/lib/rewardable/Limiter.h +++ b/lib/rewardable/Limiter.h @@ -60,6 +60,13 @@ struct DLL_LINKAGE Limiter /// creatures that hero needs to have std::vector creatures; + + /// only heroes/hero classes from list could pass limiter + std::vector heroes; + std::vector heroClasses; + + /// only player colors can pass limiter + std::vector players; /// sub-limiters, all must pass for this limiter to pass LimitersList allOf; @@ -91,6 +98,9 @@ struct DLL_LINKAGE Limiter h & allOf; h & anyOf; h & noneOf; + h & heroes; + h & heroClasses; + h & players; } void serializeJson(JsonSerializeFormat & handler);