1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

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

This commit is contained in:
DjWarmonger 2012-12-13 10:49:12 +00:00
parent a1c7beeb83
commit 71cbde7bbc
2 changed files with 37 additions and 5 deletions

View File

@ -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)
{

View File

@ -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)
{}
};