From dd196f2aa8b3dffdb4f92e73d8c2eaf040bcc5f9 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sun, 9 Apr 2023 04:36:16 +0300 Subject: [PATCH] vcmi: slightly rework limiters 1. Add vector to aggregates 2. Rework CreatureFactionLimiter to FactionLimiter --- lib/CTownHandler.cpp | 4 +- lib/GameConstants.cpp | 4 +- lib/GameConstants.h | 2 +- lib/HeroBonus.cpp | 71 +++++++++++++++++++++---------- lib/HeroBonus.h | 24 ++++++++--- lib/JsonNode.cpp | 4 +- lib/registerTypes/RegisterTypes.h | 2 +- 7 files changed, 75 insertions(+), 36 deletions(-) diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index c351db9a6..f59674cc2 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -569,9 +569,9 @@ void CTownHandler::loadSpecialBuildingBonuses(const JsonNode & source, BonusList if(bonus->limiter != nullptr) { - auto * limPtr = dynamic_cast(bonus->limiter.get()); + auto * limPtr = dynamic_cast(bonus->limiter.get()); - if(limPtr != nullptr && limPtr->faction == FactionID::ANY) + if(limPtr != nullptr && limPtr->faction == FactionID::DEFAULT) limPtr->faction = building->town->faction->getId(); } //JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty. diff --git a/lib/GameConstants.cpp b/lib/GameConstants.cpp index c9b42702d..5839ebb61 100644 --- a/lib/GameConstants.cpp +++ b/lib/GameConstants.cpp @@ -188,7 +188,7 @@ std::string PlayerColor::getStrCap(bool L10n) const } const FactionID FactionID::NONE = FactionID(-2); -const FactionID FactionID::ANY = FactionID(-1); +const FactionID FactionID::DEFAULT = FactionID(-1); const FactionID FactionID::CASTLE = FactionID(0); const FactionID FactionID::RAMPART = FactionID(1); const FactionID FactionID::TOWER = FactionID(2); @@ -206,7 +206,7 @@ si32 FactionID::decode(const std::string & identifier) if(rawId) return rawId.get(); else - return FactionID::ANY; + return FactionID::DEFAULT; } std::string FactionID::encode(const si32 index) diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 73216bb37..8cca0edc6 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -443,7 +443,7 @@ class FactionID : public BaseForID INSTID_LIKE_CLASS_COMMON(FactionID, si32) DLL_LINKAGE static const FactionID NONE; - DLL_LINKAGE static const FactionID ANY; + DLL_LINKAGE static const FactionID DEFAULT; DLL_LINKAGE static const FactionID CASTLE; DLL_LINKAGE static const FactionID RAMPART; DLL_LINKAGE static const FactionID TOWER; diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index aa6200ba1..65f0b11f1 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -75,7 +75,8 @@ const std::map bonusLimiterMap = {"DRAGON_NATURE", std::make_shared(Bonus::DRAGON_NATURE)}, {"IS_UNDEAD", std::make_shared(Bonus::UNDEAD)}, {"CREATURE_NATIVE_TERRAIN", std::make_shared()}, - {"CREATURE_FACTION", std::make_shared()}, + {"CREATURE_FACTION", std::make_shared(std::initializer_list{std::make_shared(), std::make_shared()})}, + {"SAME_FACTION", std::make_shared()}, {"CREATURES_ONLY", std::make_shared()}, {"OPPOSITE_SIDE", std::make_shared()}, }; @@ -2366,30 +2367,46 @@ JsonNode CreatureTerrainLimiter::toJsonNode() const return root; } -CreatureFactionLimiter::CreatureFactionLimiter(FactionID creatureFaction) +FactionLimiter::FactionLimiter(FactionID creatureFaction) : faction(creatureFaction) { } -ILimiter::EDecision CreatureFactionLimiter::limit(const BonusLimitationContext &context) const +ILimiter::EDecision FactionLimiter::limit(const BonusLimitationContext &context) const { - const CCreature *c = retrieveCreature(&context.node); - auto accept = c && (c->getFactionIndex() == faction || faction == FactionID::ANY); - return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD; //drop bonus for non-creatures or non-native residents + const auto * bearer = dynamic_cast(&context.node); + + if(bearer) + { + if(faction != FactionID::DEFAULT) + return bearer->getFaction() == faction ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD; + + switch(context.b->source) + { + case Bonus::CREATURE_ABILITY: + return faction == CreatureID(context.b->sid).toCreature()->getFaction() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD; + + case Bonus::TOWN_STRUCTURE: + return faction == FactionID(Bonus::getHighFromSid32(context.b->sid)) ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD; + + //TODO: other sources of bonuses + } + } + return ILimiter::EDecision::DISCARD; //Discard by default } -std::string CreatureFactionLimiter::toString() const +std::string FactionLimiter::toString() const { - boost::format fmt("CreatureFactionLimiter(faction=%s)"); + boost::format fmt("FactionLimiter(faction=%s)"); fmt % VLC->factions()->getByIndex(faction)->getJsonKey(); return fmt.str(); } -JsonNode CreatureFactionLimiter::toJsonNode() const +JsonNode FactionLimiter::toJsonNode() const { JsonNode root(JsonNode::JsonType::DATA_STRUCT); - root["type"].String() = "CREATURE_FACTION_LIMITER"; + root["type"].String() = "FACTION_LIMITER"; root["parameters"].Vector().push_back(JsonUtils::stringNode(VLC->factions()->getByIndex(faction)->getJsonKey())); return root; @@ -2498,23 +2515,13 @@ ILimiter::EDecision StackOwnerLimiter::limit(const BonusLimitationContext &conte return ILimiter::EDecision::DISCARD; } -StackOwnerLimiter::StackOwnerLimiter() - : owner(-1) -{ -} - StackOwnerLimiter::StackOwnerLimiter(const PlayerColor & Owner): owner(Owner) { } -OppositeSideLimiter::OppositeSideLimiter(): - owner(PlayerColor::CANNOT_DETERMINE) -{ -} - -OppositeSideLimiter::OppositeSideLimiter(const PlayerColor & Owner): - owner(Owner) +OppositeSideLimiter::OppositeSideLimiter(PlayerColor Owner): + owner(std::move(Owner)) { } @@ -2527,6 +2534,11 @@ ILimiter::EDecision OppositeSideLimiter::limit(const BonusLimitationContext & co // Aggregate/Boolean Limiters +AggregateLimiter::AggregateLimiter(std::vector limiters): + limiters(std::move(limiters)) +{ +} + void AggregateLimiter::add(const TLimiterPtr & limiter) { if(limiter) @@ -2548,6 +2560,11 @@ const std::string & AllOfLimiter::getAggregator() const return aggregator; } +AllOfLimiter::AllOfLimiter(std::vector limiters): + AggregateLimiter(limiters) +{ +} + ILimiter::EDecision AllOfLimiter::limit(const BonusLimitationContext & context) const { bool wasntSure = false; @@ -2570,6 +2587,11 @@ const std::string & AnyOfLimiter::getAggregator() const return aggregator; } +AnyOfLimiter::AnyOfLimiter(std::vector limiters): + AggregateLimiter(limiters) +{ +} + ILimiter::EDecision AnyOfLimiter::limit(const BonusLimitationContext & context) const { bool wasntSure = false; @@ -2592,6 +2614,11 @@ const std::string & NoneOfLimiter::getAggregator() const return aggregator; } +NoneOfLimiter::NoneOfLimiter(std::vector limiters): + AggregateLimiter(limiters) +{ +} + ILimiter::EDecision NoneOfLimiter::limit(const BonusLimitationContext & context) const { bool wasntSure = false; diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 80fd6298b..60d1f21b8 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -523,6 +523,16 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this return (high << 16) + low; } + STRONG_INLINE static ui32 getHighFromSid32(ui32 sid) + { + return sid >> 16; + } + + STRONG_INLINE static ui32 getLowFromSid32(ui32 sid) + { + return sid & 0x0000FFFF; + } + std::string Description(boost::optional customValue = {}) const; JsonNode toJsonNode() const; std::string nameForBonus() const; // generate suitable name for bonus - e.g. for storing in json struct @@ -996,6 +1006,7 @@ class DLL_LINKAGE AggregateLimiter : public ILimiter protected: std::vector limiters; virtual const std::string & getAggregator() const = 0; + AggregateLimiter(std::vector limiters = {}); public: void add(const TLimiterPtr & limiter); JsonNode toJsonNode() const override; @@ -1012,6 +1023,7 @@ class DLL_LINKAGE AllOfLimiter : public AggregateLimiter protected: const std::string & getAggregator() const override; public: + AllOfLimiter(std::vector limiters = {}); static const std::string aggregator; EDecision limit(const BonusLimitationContext & context) const override; }; @@ -1021,6 +1033,7 @@ class DLL_LINKAGE AnyOfLimiter : public AggregateLimiter protected: const std::string & getAggregator() const override; public: + AnyOfLimiter(std::vector limiters = {}); static const std::string aggregator; EDecision limit(const BonusLimitationContext & context) const override; }; @@ -1030,6 +1043,7 @@ class DLL_LINKAGE NoneOfLimiter : public AggregateLimiter protected: const std::string & getAggregator() const override; public: + NoneOfLimiter(std::vector limiters = {}); static const std::string aggregator; EDecision limit(const BonusLimitationContext & context) const override; }; @@ -1127,11 +1141,11 @@ public: } }; -class DLL_LINKAGE CreatureFactionLimiter : public ILimiter //applies only to creatures of given faction +class DLL_LINKAGE FactionLimiter : public ILimiter //applies only to creatures of given faction { public: FactionID faction; - CreatureFactionLimiter(FactionID faction = FactionID::ANY); + FactionLimiter(FactionID faction = FactionID::DEFAULT); EDecision limit(const BonusLimitationContext &context) const override; std::string toString() const override; @@ -1165,8 +1179,7 @@ class DLL_LINKAGE StackOwnerLimiter : public ILimiter //applies only to creature { public: PlayerColor owner; - StackOwnerLimiter(); - StackOwnerLimiter(const PlayerColor & Owner); + StackOwnerLimiter(const PlayerColor & Owner = PlayerColor::NEUTRAL); EDecision limit(const BonusLimitationContext &context) const override; @@ -1181,8 +1194,7 @@ class DLL_LINKAGE OppositeSideLimiter : public ILimiter //applies only to creatu { public: PlayerColor owner; - OppositeSideLimiter(); - OppositeSideLimiter(const PlayerColor & Owner); + OppositeSideLimiter(PlayerColor Owner = PlayerColor::CANNOT_DETERMINE); EDecision limit(const BonusLimitationContext &context) const override; diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index 8609738f9..20cc9a77e 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -749,9 +749,9 @@ std::shared_ptr JsonUtils::parseLimiter(const JsonNode & limiter) else return std::make_shared(static_cast(alignment)); } - else if(limiterType == "CREATURE_FACTION_LIMITER") + else if(limiterType == "FACTION_LIMITER") { - std::shared_ptr factionLimiter = std::make_shared(); + std::shared_ptr factionLimiter = std::make_shared(); VLC->modh->identifiers.requestIdentifier("faction", parameters[0], [=](si32 faction) { factionLimiter->faction = FactionID(faction); diff --git a/lib/registerTypes/RegisterTypes.h b/lib/registerTypes/RegisterTypes.h index 8e670cd00..4082e988c 100644 --- a/lib/registerTypes/RegisterTypes.h +++ b/lib/registerTypes/RegisterTypes.h @@ -179,7 +179,7 @@ void registerTypesMapObjects2(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); - s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType();