瀏覽代碼

vcmi: slightly rework limiters

1. Add vector to aggregates
2. Rework CreatureFactionLimiter to FactionLimiter
Konstantin 2 年之前
父節點
當前提交
dd196f2aa8
共有 7 個文件被更改,包括 75 次插入36 次删除
  1. 2 2
      lib/CTownHandler.cpp
  2. 2 2
      lib/GameConstants.cpp
  3. 1 1
      lib/GameConstants.h
  4. 49 22
      lib/HeroBonus.cpp
  5. 18 6
      lib/HeroBonus.h
  6. 2 2
      lib/JsonNode.cpp
  7. 1 1
      lib/registerTypes/RegisterTypes.h

+ 2 - 2
lib/CTownHandler.cpp

@@ -569,9 +569,9 @@ void CTownHandler::loadSpecialBuildingBonuses(const JsonNode & source, BonusList
 
 		if(bonus->limiter != nullptr)
 		{
-			auto * limPtr = dynamic_cast<CreatureFactionLimiter *>(bonus->limiter.get());
+			auto * limPtr = dynamic_cast<FactionLimiter *>(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.

+ 2 - 2
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)

+ 1 - 1
lib/GameConstants.h

@@ -443,7 +443,7 @@ class FactionID : public BaseForID<FactionID, int32_t>
 	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;

+ 49 - 22
lib/HeroBonus.cpp

@@ -75,7 +75,8 @@ const std::map<std::string, TLimiterPtr> bonusLimiterMap =
 	{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
 	{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)},
 	{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()},
-	{"CREATURE_FACTION", std::make_shared<CreatureFactionLimiter>()},
+	{"CREATURE_FACTION", std::make_shared<AllOfLimiter>(std::initializer_list<TLimiterPtr>{std::make_shared<CreatureLevelLimiter>(), std::make_shared<FactionLimiter>()})},
+	{"SAME_FACTION", std::make_shared<FactionLimiter>()},
 	{"CREATURES_ONLY", std::make_shared<CreatureLevelLimiter>()},
 	{"OPPOSITE_SIDE", std::make_shared<OppositeSideLimiter>()},
 };
@@ -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<const INativeTerrainProvider*>(&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<TLimiterPtr> 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<TLimiterPtr> 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<TLimiterPtr> 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<TLimiterPtr> limiters):
+	AggregateLimiter(limiters)
+{
+}
+
 ILimiter::EDecision NoneOfLimiter::limit(const BonusLimitationContext & context) const
 {
 	bool wasntSure = false;

+ 18 - 6
lib/HeroBonus.h

@@ -523,6 +523,16 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
 		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<si32> 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<TLimiterPtr> limiters;
 	virtual const std::string & getAggregator() const = 0;
+	AggregateLimiter(std::vector<TLimiterPtr> 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<TLimiterPtr> 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<TLimiterPtr> 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<TLimiterPtr> 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;
 

+ 2 - 2
lib/JsonNode.cpp

@@ -749,9 +749,9 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
 				else
 					return std::make_shared<CreatureAlignmentLimiter>(static_cast<EAlignment>(alignment));
 			}
-			else if(limiterType == "CREATURE_FACTION_LIMITER")
+			else if(limiterType == "FACTION_LIMITER")
 			{
-				std::shared_ptr<CreatureFactionLimiter> factionLimiter = std::make_shared<CreatureFactionLimiter>();
+				std::shared_ptr<FactionLimiter> factionLimiter = std::make_shared<FactionLimiter>();
 				VLC->modh->identifiers.requestIdentifier("faction", parameters[0], [=](si32 faction)
 				{
 					factionLimiter->faction = FactionID(faction);

+ 1 - 1
lib/registerTypes/RegisterTypes.h

@@ -179,7 +179,7 @@ void registerTypesMapObjects2(Serializer &s)
 	s.template registerType<ILimiter, CCreatureTypeLimiter>();
 	s.template registerType<ILimiter, HasAnotherBonusLimiter>();
 	s.template registerType<ILimiter, CreatureTerrainLimiter>();
-	s.template registerType<ILimiter, CreatureFactionLimiter>();
+	s.template registerType<ILimiter, FactionLimiter>();
 	s.template registerType<ILimiter, CreatureLevelLimiter>();
 	s.template registerType<ILimiter, CreatureAlignmentLimiter>();
 	s.template registerType<ILimiter, RankRangeLimiter>();