mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Fixed #1176.
This commit is contained in:
		| @@ -956,6 +956,7 @@ void CGHeroInstance::initObj() //TODO: use bonus system | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					bonus->additionalInfo = spec.additionalinfo; //creature id | ||||
| 					bonus->limiter.reset(new CCreatureTypeLimiter (specCreature, true)); //with upgrades | ||||
| 					bonus->type = Bonus::PRIMARY_SKILL; | ||||
| 					bonus->valType = Bonus::ADDITIVE_VALUE; | ||||
| @@ -1024,6 +1025,7 @@ void CGHeroInstance::initObj() //TODO: use bonus system | ||||
| 					default: | ||||
| 						continue; | ||||
| 				} | ||||
| 				bonus->additionalInfo = spec.additionalinfo; //creature id | ||||
| 				bonus->valType = Bonus::ADDITIVE_VALUE; | ||||
| 				bonus->limiter.reset(new CCreatureTypeLimiter (*VLC->creh->creatures[spec.additionalinfo], true)); | ||||
| 				hs->addNewBonus(bonus); | ||||
| @@ -1143,33 +1145,21 @@ void CGHeroInstance::Updatespecialty() //TODO: calculate special value of bonuse | ||||
| 						break; //use only hero skills as bonuses to avoid feedback loop | ||||
| 					case Bonus::PRIMARY_SKILL: //for creatures, that is | ||||
| 					{ | ||||
| 						CCreatureTypeLimiter * foundLimiter = NULL; | ||||
| 						CCreature * cre = NULL; | ||||
| 						int creLevel = 0; | ||||
| 						TLimiterPtr limiterNode (b); | ||||
| 						while (limiterNode->limiter) | ||||
| 						if (auto creatureLimiter = std::dynamic_pointer_cast<CCreatureTypeLimiter>(b->limiter)) //TODO: more general eveluation of bonuses? | ||||
| 						{ | ||||
| 							limiterNode = limiterNode->limiter; //search list | ||||
| 							if (foundLimiter = dynamic_cast<CCreatureTypeLimiter*>(limiterNode.get())) //TODO: more general eveluation of bonuses? | ||||
| 							creLevel = creatureLimiter->creature->level; | ||||
| 							if(!creLevel) | ||||
| 							{ | ||||
| 								cre = const_cast<CCreature*>(foundLimiter->creature); | ||||
| 								creLevel = cre->level; | ||||
| 								break; | ||||
| 								creLevel = 5; //treat ballista as tier 5 | ||||
| 							} | ||||
| 						} | ||||
| 						if (!foundLimiter) | ||||
| 						else | ||||
| 						{ | ||||
| 							tlog2 << "Primary skill specialty growth supported only with creature type limiters\n"; | ||||
| 							break; | ||||
| 						} | ||||
| 						if (cre) | ||||
| 						{ | ||||
| 							creLevel = cre->level; | ||||
| 						} | ||||
| 						if(!creLevel) | ||||
| 						{ | ||||
| 							creLevel = 5; //treat ballista as tier 5 | ||||
| 						} | ||||
|  | ||||
| 						double primSkillModifier = (int)(level / creLevel) / 20.0; | ||||
| 						int param; | ||||
| 						switch (b->subtype) | ||||
|   | ||||
| @@ -96,7 +96,6 @@ BonusList& BonusList::operator=(const BonusList &bonusList) | ||||
|  | ||||
| int BonusList::totalValue() const | ||||
| { | ||||
| 	int tempVal = 0; | ||||
| 	int base = 0; | ||||
| 	int percentToBase = 0; | ||||
| 	int percentToAll = 0; | ||||
| @@ -110,15 +109,6 @@ int BonusList::totalValue() const | ||||
| 	{ | ||||
| 		Bonus *b = bonuses[i]; | ||||
|  | ||||
| 		if (b->calculator) | ||||
| 		{ | ||||
| 			assert (false); | ||||
| 			BonusCalculationContext bcc = {b, CBonusSystemNode()}; | ||||
| 			tempVal = b->calculator->val (bcc); | ||||
| 		} | ||||
| 		else | ||||
| 			tempVal = b->val; | ||||
|  | ||||
| 		switch(b->valType) | ||||
| 		{ | ||||
| 		case Bonus::BASE_NUMBER: | ||||
| @@ -471,7 +461,9 @@ ui32 IBonusBearer::getMaxDamage() const | ||||
|  | ||||
| si32 IBonusBearer::manaLimit() const | ||||
| { | ||||
| 	return si32(getPrimSkillLevel(3) * (100.0 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 24)) / 10.0); | ||||
| 	return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE)  | ||||
| 		* (100.0 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, CGHeroInstance::INTELLIGENCE))  | ||||
| 		/ 10.0); | ||||
| } | ||||
|  | ||||
| int IBonusBearer::getPrimSkillLevel(int id) const | ||||
| @@ -1042,7 +1034,7 @@ void CBonusSystemNode::limitBonuses(const BonusList &allBonuses, BonusList &out) | ||||
| 		{ | ||||
| 			Bonus *b = undecided[i]; | ||||
| 			BonusLimitationContext context = {b, *this, out}; | ||||
| 			int decision = b->limit(context); //bonuses without limiters will be accepted by default | ||||
| 			int decision = b->limiter ? b->limiter->limit(context) : ILimiter::ACCEPT; //bonuses without limiters will be accepted by default | ||||
| 			if(decision == ILimiter::DISCARD) | ||||
| 			{ | ||||
| 				undecided.erase(i); | ||||
| @@ -1173,14 +1165,6 @@ 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); | ||||
| @@ -1319,25 +1303,28 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus) | ||||
|  | ||||
| 	return out; | ||||
| } | ||||
|  | ||||
| Bonus * Bonus::addLimiter(TLimiterPtr Limiter) | ||||
| { | ||||
| 	if (limiter) //insert at the beginning of list | ||||
| 	if (limiter) | ||||
| 	{ | ||||
| 		TLimiterPtr temp = limiter; | ||||
| 		limiter = Limiter; | ||||
| 		limiter->limiter = temp; | ||||
| 		//If we already have limiter list, retreive it | ||||
| 		auto limiterList = std::dynamic_pointer_cast<LimiterList>(limiter); | ||||
| 		if(!limiterList) | ||||
| 		{ | ||||
| 			//Create a new limiter list with old limiter and the new one will be pushed later | ||||
| 			limiterList = make_shared<LimiterList>(); | ||||
| 			limiterList->add(limiter); | ||||
| 			limiter = limiterList; | ||||
| 		} | ||||
|  | ||||
| 		limiterList->add(Limiter); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		limiter = Limiter; | ||||
| 	} | ||||
| 	return this; | ||||
|  | ||||
| } | ||||
|  | ||||
| int LimiterDecorator::limit(const BonusLimitationContext &context) const /*return true to drop the bonus */ | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| ILimiter::~ILimiter() | ||||
| @@ -1434,16 +1421,6 @@ bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest) | ||||
| 	return nodeType == dest->getNodeType(); | ||||
| } | ||||
|  | ||||
| int LimiterDecorator::callNext(const BonusLimitationContext &context) const | ||||
| { | ||||
| 	if (limiter) | ||||
| 	{ | ||||
| 		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) | ||||
| { | ||||
| @@ -1547,3 +1524,32 @@ StackOwnerLimiter::StackOwnerLimiter(ui8 Owner) | ||||
| 	: owner(Owner) | ||||
| { | ||||
| } | ||||
| // int Bonus::limit(const BonusLimitationContext &context) const  | ||||
| //  	1162	{  | ||||
| //  	1163	        if (limiter)  | ||||
| //  	1164	                return limiter->callNext(context);  | ||||
| //  	1165	        else  | ||||
| //  	1166	                return ILimiter::ACCEPT; //accept if there's no limiter  | ||||
| //  	1167	}  | ||||
|  	//1168	  | ||||
|  | ||||
| int LimiterList::limit( const BonusLimitationContext &context ) const  | ||||
| { | ||||
| 	bool wasntSure = false; | ||||
|  | ||||
| 	BOOST_FOREACH(auto limiter, limiters) | ||||
| 	{ | ||||
| 		auto result = limiter->limit(context); | ||||
| 		if(result == ILimiter::DISCARD) | ||||
| 			return result; | ||||
| 		if(result == ILimiter::NOT_SURE) | ||||
| 			wasntSure = true; | ||||
| 	} | ||||
|  | ||||
| 	return wasntSure ? ILimiter::NOT_SURE : ILimiter::ACCEPT; | ||||
| } | ||||
|  | ||||
| void LimiterList::add( TLimiterPtr limiter ) | ||||
| { | ||||
| 	limiters.push_back(limiter); | ||||
| } | ||||
|   | ||||
| @@ -20,12 +20,10 @@ class ILimiter; | ||||
| class IPropagator; | ||||
| class ICalculator; | ||||
| class BonusList; | ||||
| class LimiterDecorator; | ||||
| struct BonusLimitationContext; | ||||
| struct BonusCalculationContext; | ||||
|  | ||||
| typedef shared_ptr<BonusList> TBonusListPtr; | ||||
| typedef shared_ptr<LimiterDecorator> TLimiterPtr; | ||||
| typedef shared_ptr<ILimiter> TLimiterPtr; | ||||
| typedef shared_ptr<IPropagator> TPropagatorPtr; | ||||
| typedef shared_ptr<ICalculator> TCalculatorPtr; | ||||
| typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions | ||||
| @@ -34,22 +32,7 @@ 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 limiter; //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; | ||||
|  | ||||
| 	virtual ~LimiterDecorator() | ||||
| 	{} | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & limiter; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| #define BONUS_TREE_DESERIALIZATION_FIX if(!h.saving && h.smartPointerSerialization) deserializationFix(); | ||||
|  | ||||
| @@ -227,7 +210,7 @@ public: | ||||
| 	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 : public LimiterDecorator | ||||
| struct DLL_LINKAGE Bonus | ||||
| { | ||||
| 	enum BonusType | ||||
| 	{ | ||||
| @@ -283,6 +266,7 @@ struct DLL_LINKAGE Bonus : public LimiterDecorator | ||||
| 	si32 additionalInfo; | ||||
| 	ui8 effectRange; //if not NO_LIMIT, bonus will be omitted by default | ||||
|  | ||||
| 	TLimiterPtr limiter; | ||||
| 	TPropagatorPtr propagator; | ||||
| 	TCalculatorPtr calculator; | ||||
|  | ||||
| @@ -307,8 +291,7 @@ struct DLL_LINKAGE Bonus : public LimiterDecorator | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<LimiterDecorator&>(*this); | ||||
| 		h & duration & type & subtype & source & val & sid & description & additionalInfo & turnsRemain & valType & effectRange & propagator; | ||||
| 		h & duration & type & subtype & source & val & sid & description & additionalInfo & turnsRemain & valType & effectRange & limiter & propagator; | ||||
| 	} | ||||
|  | ||||
| 	static bool compareByAdditionalInfo(const Bonus *a, const Bonus *b) | ||||
| @@ -363,9 +346,8 @@ struct DLL_LINKAGE Bonus : public LimiterDecorator | ||||
|  | ||||
| 	std::string Description() const; | ||||
|  | ||||
| 	Bonus * addLimiter(TLimiterPtr Limiter); | ||||
| 	Bonus * addPropagator(TPropagatorPtr Propagator); //returns this for convenient chain-calls | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; //for backward compatibility | ||||
| 	Bonus *addLimiter(TLimiterPtr Limiter); //returns this for convenient chain-calls | ||||
| 	Bonus *addPropagator(TPropagatorPtr Propagator); //returns this for convenient chain-calls | ||||
| }; | ||||
|  | ||||
| DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus); | ||||
| @@ -509,24 +491,17 @@ struct BonusLimitationContext | ||||
| 	const BonusList &alreadyAccepted; | ||||
| }; | ||||
|  | ||||
| struct BonusCalculationContext | ||||
| { | ||||
| 	const Bonus *b; | ||||
| 	const CBonusSystemNode &node; | ||||
| }; | ||||
|  | ||||
|  | ||||
| class DLL_LINKAGE ILimiter : public LimiterDecorator | ||||
| class DLL_LINKAGE ILimiter | ||||
| { | ||||
| public: | ||||
| 	enum EDecision {ACCEPT, DISCARD, NOT_SURE}; | ||||
|  | ||||
| 	virtual int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
| 	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) | ||||
| 	{ | ||||
| 		h & static_cast<LimiterDecorator&>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -776,6 +751,16 @@ public: | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| //Stores multiple limiters. If any of them fails -> bonus is dropped. | ||||
| class DLL_LINKAGE LimiterList : public ILimiter | ||||
| { | ||||
| 	std::vector<TLimiterPtr> limiters; | ||||
|  | ||||
| public: | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
| 	void add(TLimiterPtr limiter); | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades) | ||||
| { | ||||
| public: | ||||
|   | ||||
| @@ -76,8 +76,8 @@ void registerTypes1(Serializer &s) | ||||
| 	s.template registerType<IPropagator>(); | ||||
| 	s.template registerType<CPropagatorNodeType>(); | ||||
|  | ||||
| 	s.template registerType<LimiterDecorator>(); | ||||
| 	s.template registerType<ILimiter>(); | ||||
| 	s.template registerType<LimiterList>(); | ||||
| 	s.template registerType<CCreatureTypeLimiter>(); | ||||
| 	s.template registerType<HasAnotherBonusLimiter>(); | ||||
| 	s.template registerType<CreatureNativeTerrainLimiter>(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user