浏览代码

Bonus limiters are now implemented using Decorator design pattern, which allows to chain them.

DjWarmonger 13 年之前
父节点
当前提交
71cbde7bbc
共有 2 个文件被更改,包括 37 次插入5 次删除
  1. 24 1
      lib/HeroBonus.cpp
  2. 13 4
      lib/HeroBonus.h

+ 24 - 1
lib/HeroBonus.cpp

@@ -1021,7 +1021,7 @@ void CBonusSystemNode::limitBonuses(const BonusList &allBonuses, BonusList &out)
 		{
 			Bonus *b = undecided[i];
 			BonusLimitationContext context = {b, *this, out};
-			int decision = b->limiter ? b->limiter->limit(context) : ILimiter::ACCEPT; //bonuses without limiters will be accepted by default
+			int decision = b->limit(context); //bonuses without limiters will be accepted by default
 			if(decision == ILimiter::DISCARD)
 			{
 				undecided.erase(i);
@@ -1158,6 +1158,14 @@ Bonus * Bonus::addPropagator(TPropagatorPtr Propagator)
 	return this;
 }
 
+int Bonus::limit(const BonusLimitationContext &context) const
+{
+	if (limiter)
+		return limiter->callNext(context);
+	else
+		return ILimiter::ACCEPT; //accept if there's no limiter
+}
+
 CSelector DLL_LINKAGE operator&&(const CSelector &first, const CSelector &second)
 {
 	return CSelectorsConjunction(first, second);
@@ -1297,6 +1305,11 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
 	return out;
 }
 
+int LimiterDecorator::limit(const BonusLimitationContext &context) const /*return true to drop the bonus */
+{
+	return false;
+}
+
 ILimiter::~ILimiter()
 {
 }
@@ -1386,6 +1399,16 @@ bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
 	return nodeType == dest->getNodeType();
 }
 
+int LimiterDecorator::callNext(const BonusLimitationContext &context) const
+{
+	if (next)
+	{
+		return (limit(context) || callNext(context)); //either of limiters will cause bonus to drop
+	}
+	else //we are last on the list
+		return limit (context);
+}
+
 CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter(int TerrainType) 
 	: terrainType(TerrainType)
 {

+ 13 - 4
lib/HeroBonus.h

@@ -19,6 +19,8 @@ class CBonusSystemNode;
 class ILimiter;
 class IPropagator;
 class BonusList;
+class LimiterDecorator;
+struct BonusLimitationContext;
 
 typedef shared_ptr<BonusList> TBonusListPtr;
 typedef shared_ptr<ILimiter> TLimiterPtr;
@@ -29,7 +31,14 @@ typedef std::set<const CBonusSystemNode*> TCNodes;
 typedef std::vector<CBonusSystemNode *> TNodesVector;
 typedef boost::function<bool(const Bonus*)> CSelector;
 
+class DLL_LINKAGE LimiterDecorator //follows decorator design pattern
+{
+public:
+	TLimiterPtr next; //forms a list
 
+	virtual int limit(const BonusLimitationContext &context) const; //0 - accept bonus; 1 - drop bonus; 2 - delay (drops eventually)
+	virtual int callNext(const BonusLimitationContext &context) const;
+};
 
 #define BONUS_TREE_DESERIALIZATION_FIX if(!h.saving && h.smartPointerSerialization) deserializationFix();
 
@@ -207,7 +216,7 @@ typedef boost::function<bool(const Bonus*)> CSelector;
 	BONUS_VALUE(INDEPENDENT_MIN) //used for SECONDARY_SKILL_PREMY bonus
 
 /// Struct for handling bonuses of several types. Can be transferred to any hero
-struct DLL_LINKAGE Bonus
+struct DLL_LINKAGE Bonus : public LimiterDecorator
 {
 	enum BonusType
 	{
@@ -344,6 +353,7 @@ struct DLL_LINKAGE Bonus
 
 	Bonus *addLimiter(TLimiterPtr Limiter); //returns this for convenient chain-calls
 	Bonus *addPropagator(TPropagatorPtr Propagator); //returns this for convenient chain-calls
+	int limit(const BonusLimitationContext &context) const; //for backward compatibility
 };
 
 DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
@@ -487,15 +497,14 @@ struct BonusLimitationContext
 	const BonusList &alreadyAccepted;
 };
 
-class DLL_LINKAGE ILimiter
+class DLL_LINKAGE ILimiter : public LimiterDecorator
 {
 public:
 	enum EDecision {ACCEPT, DISCARD, NOT_SURE};
 
+	virtual int limit(const BonusLimitationContext &context) const;
 	virtual ~ILimiter();
 
-	virtual int limit(const BonusLimitationContext &context) const; //0 - accept bonus; 1 - drop bonus; 2 - delay (drops eventually)
-
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{}
 };