Browse Source

Further work on bonus system.

Michał W. Urbańczyk 15 years ago
parent
commit
27f83ea8c3
12 changed files with 326 additions and 251 deletions
  1. 4 4
      hch/CArtHandler.cpp
  2. 11 11
      hch/CCreatureHandler.cpp
  3. 60 60
      hch/CObjectHandler.cpp
  4. 2 17
      lib/CGameState.cpp
  5. 9 9
      lib/CGameState.h
  6. 13 0
      lib/Connection.h
  7. 110 54
      lib/HeroBonus.cpp
  8. 71 16
      lib/HeroBonus.h
  9. 6 6
      lib/NetPacksLib.cpp
  10. 4 0
      lib/RegisterTypes.cpp
  11. 3 1
      lib/map.h
  12. 33 73
      server/CGameHandler.cpp

+ 4 - 4
hch/CArtHandler.cpp

@@ -484,11 +484,11 @@ void CArtHandler::getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArti
 }
 void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int subtype, int valType, ILimiter * limiter )
 {
-	Bonus added(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
-	added.valType = valType;
-	added.limiter = limiter;
+	Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
+	added->valType = valType;
+	added->limiter.reset(limiter);
 	if(type == Bonus::MORALE || Bonus::LUCK)
-		added.description = "\n" + artifacts[aid]->Name()  + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
+		added->description = "\n" + artifacts[aid]->Name()  + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
 	artifacts[aid]->addNewBonus(added);
 }
 

+ 11 - 11
hch/CCreatureHandler.cpp

@@ -126,7 +126,7 @@ CCreature::CCreature()
 }
 void CCreature::addBonus(int val, int type, int subtype /*= -1*/)
 {
-	Bonus added(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER);
+	Bonus *added = new Bonus(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER);
 	addNewBonus(added);
 }
 // void CCreature::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const
@@ -364,7 +364,7 @@ void CCreatureHandler::loadCreatures()
 		case '+': //add new ability
 			{
 				int creatureID;
-				Bonus nsf;
+				Bonus *nsf = new Bonus();
 				si32 buf;
 				std::string type;
 
@@ -392,15 +392,15 @@ void CCreatureHandler::loadCreatures()
 						tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl;
 					break;
 				}
-				nsf.type = it->second;
-
-				reader >> buf; nsf.val = buf;
-				reader >> buf; nsf.subtype = buf;
-				reader >> buf; nsf.additionalInfo = buf;
-				nsf.source = Bonus::CREATURE_ABILITY;
-				nsf.id = cre->idNumber;
-				nsf.duration = Bonus::ONE_BATTLE;
-				nsf.turnsRemain = 0;
+				nsf->type = it->second;
+
+				reader >> buf; nsf->val = buf;
+				reader >> buf; nsf->subtype = buf;
+				reader >> buf; nsf->additionalInfo = buf;
+				nsf->source = Bonus::CREATURE_ABILITY;
+				nsf->id = cre->idNumber;
+				nsf->duration = Bonus::ONE_BATTLE;
+				nsf->turnsRemain = 0;
 
 				cre->addNewBonus(nsf);
 				break;

+ 60 - 60
hch/CObjectHandler.cpp

@@ -979,17 +979,17 @@ void CGHeroInstance::initObj()
 {
 	blockVisit = true;
 	speciality.growthsWithLevel = false;
-	Bonus bonus;
 
 	if(!type)
 		return; //TODO support prison
 
 	for (std::vector<SSpecialtyInfo>::const_iterator it = type->spec.begin(); it != type->spec.end(); it++)
 	{
-		bonus.val = it->val;
-		bonus.id = id; //from the hero, speciality has no unique id
-		bonus.duration = Bonus::PERMANENT;
-		bonus.source = Bonus::HERO_SPECIAL;
+		Bonus *bonus = new Bonus();
+		bonus->val = it->val;
+		bonus->id = id; //from the hero, speciality has no unique id
+		bonus->duration = Bonus::PERMANENT;
+		bonus->source = Bonus::HERO_SPECIAL;
 		switch (it->type)
 		{
 			case 1:// creature speciality
@@ -1010,139 +1010,139 @@ void CGHeroInstance::initObj()
 						}
 					}
 
-					bonus.limiter = new CCreatureTypeLimiter (specCreature, true); //with upgrades
-					bonus.type = Bonus::PRIMARY_SKILL; 
-					bonus.additionalInfo = it->additionalinfo;
-					bonus.valType = Bonus::ADDITIVE_VALUE;
+					bonus->limiter.reset(new CCreatureTypeLimiter (specCreature, true)); //with upgrades
+					bonus->type = Bonus::PRIMARY_SKILL; 
+					bonus->additionalInfo = it->additionalinfo;
+					bonus->valType = Bonus::ADDITIVE_VALUE;
 
-					bonus.subtype = PrimarySkill::ATTACK;
+					bonus->subtype = PrimarySkill::ATTACK;
 					speciality.addNewBonus(bonus);
 
-					bonus.subtype = PrimarySkill::DEFENSE;
+					bonus->subtype = PrimarySkill::DEFENSE;
 					speciality.addNewBonus(bonus);
 					//values will be calculated later
 
-					bonus.type = Bonus::STACKS_SPEED;
-					bonus.val = 1; //+1 speed
+					bonus->type = Bonus::STACKS_SPEED;
+					bonus->val = 1; //+1 speed
 					speciality.addNewBonus(bonus);
 				}
 				break;
 			case 2://secondary skill
 				speciality.growthsWithLevel = true;
-				bonus.type = Bonus::SPECIAL_SECONDARY_SKILL; //needs to be recalculated with level, based on this value
-				bonus.valType = Bonus::BASE_NUMBER; // to receive nonzero value
-				bonus.subtype = it->subtype; //skill id
-				bonus.val = it->val; //value per level, in percent
+				bonus->type = Bonus::SPECIAL_SECONDARY_SKILL; //needs to be recalculated with level, based on this value
+				bonus->valType = Bonus::BASE_NUMBER; // to receive nonzero value
+				bonus->subtype = it->subtype; //skill id
+				bonus->val = it->val; //value per level, in percent
 				speciality.addNewBonus(bonus);
 				switch (it->additionalinfo)
 				{
 					case 0: //normal
-						bonus.valType = Bonus::PERCENT_TO_BASE;
+						bonus->valType = Bonus::PERCENT_TO_BASE;
 						break;
 					case 1: //when it's navigation or there's no 'base' at all
-						bonus.valType = Bonus::PERCENT_TO_ALL;
+						bonus->valType = Bonus::PERCENT_TO_ALL;
 						break;
 				}
-				bonus.type = Bonus::SECONDARY_SKILL_PREMY; //value will be calculated later
+				bonus->type = Bonus::SECONDARY_SKILL_PREMY; //value will be calculated later
 				speciality.addNewBonus(bonus);
 				break;
 			case 3://spell damage bonus, level dependant but calculated elsehwere
-				bonus.type = Bonus::SPECIAL_SPELL_LEV;
-				bonus.subtype = it->subtype;
+				bonus->type = Bonus::SPECIAL_SPELL_LEV;
+				bonus->subtype = it->subtype;
 				speciality.addNewBonus(bonus);
 				break;
 			case 4://creature stat boost
 				switch (it->subtype)
 				{
 					case 1://attack
-						bonus.type = Bonus::PRIMARY_SKILL;
-						bonus.subtype = PrimarySkill::ATTACK;
+						bonus->type = Bonus::PRIMARY_SKILL;
+						bonus->subtype = PrimarySkill::ATTACK;
 						break;
 					case 2://defense
-						bonus.type = Bonus::PRIMARY_SKILL;
-						bonus.subtype = PrimarySkill::DEFENSE;
+						bonus->type = Bonus::PRIMARY_SKILL;
+						bonus->subtype = PrimarySkill::DEFENSE;
 						break;
 					case 3:
-						bonus.type = Bonus::CREATURE_DAMAGE;
-						bonus.subtype = 0; //both min and max
+						bonus->type = Bonus::CREATURE_DAMAGE;
+						bonus->subtype = 0; //both min and max
 						break;
 					case 4://hp
-						bonus.type = Bonus::STACK_HEALTH;
+						bonus->type = Bonus::STACK_HEALTH;
 						break;
 					case 5:
-						bonus.type = Bonus::STACKS_SPEED;
+						bonus->type = Bonus::STACKS_SPEED;
 						break;
 					default:
 						continue;
 				}
-				bonus.valType = Bonus::ADDITIVE_VALUE;
-				bonus.limiter = new CCreatureTypeLimiter (*VLC->creh->creatures[it->additionalinfo], true);
+				bonus->valType = Bonus::ADDITIVE_VALUE;
+				bonus->limiter.reset(new CCreatureTypeLimiter (*VLC->creh->creatures[it->additionalinfo], true));
 				speciality.addNewBonus(bonus);
 				break;
 			case 5://spell damage bonus in percent
-				bonus.type = Bonus::SPECIFIC_SPELL_DAMAGE;
-				bonus.valType = Bonus::BASE_NUMBER; // current spell system is screwed
-				bonus.subtype = it->subtype; //spell id
+				bonus->type = Bonus::SPECIFIC_SPELL_DAMAGE;
+				bonus->valType = Bonus::BASE_NUMBER; // current spell system is screwed
+				bonus->subtype = it->subtype; //spell id
 				speciality.addNewBonus(bonus);
 				break;
 			case 6://damage bonus for bless (Adela)
-				bonus.type = Bonus::SPECIAL_BLESS_DAMAGE;
-				bonus.subtype = it->subtype; //spell id if you ever wanted to use it otherwise
-				bonus.additionalInfo = it->additionalinfo; //damage factor
+				bonus->type = Bonus::SPECIAL_BLESS_DAMAGE;
+				bonus->subtype = it->subtype; //spell id if you ever wanted to use it otherwise
+				bonus->additionalInfo = it->additionalinfo; //damage factor
 				speciality.addNewBonus(bonus);
 				break;
 			case 7://maxed mastery for spell
-				bonus.type = Bonus::MAXED_SPELL;
-				bonus.subtype = it->subtype; //spell i
+				bonus->type = Bonus::MAXED_SPELL;
+				bonus->subtype = it->subtype; //spell i
 				speciality.addNewBonus(bonus);
 				break;
 			case 8://peculiar spells - enchantments
-				bonus.type = Bonus::SPECIAL_PECULIAR_ENCHANT;
-				bonus.subtype = it->subtype; //spell id
-				bonus.additionalInfo = it->additionalinfo;//0, 1 for Coronius
+				bonus->type = Bonus::SPECIAL_PECULIAR_ENCHANT;
+				bonus->subtype = it->subtype; //spell id
+				bonus->additionalInfo = it->additionalinfo;//0, 1 for Coronius
 				speciality.addNewBonus(bonus);
 				break;
 			case 9://upgrade creatures
 			{
 				std::vector<CCreature*>* creatures = &VLC->creh->creatures;
-				bonus.type = Bonus::SPECIAL_UPGRADE;
-				bonus.subtype = it->subtype; //base id
-				bonus.additionalInfo = it->additionalinfo; //target id
+				bonus->type = Bonus::SPECIAL_UPGRADE;
+				bonus->subtype = it->subtype; //base id
+				bonus->additionalInfo = it->additionalinfo; //target id
 				speciality.addNewBonus(bonus);
 
 				for (std::set<ui32>::iterator i = (*creatures)[it->subtype]->upgrades.begin();
 					i != (*creatures)[it->subtype]->upgrades.end(); i++)
 				{
-					bonus.subtype = *i; //propagate for regular upgrades of base creature
+					bonus->subtype = *i; //propagate for regular upgrades of base creature
 					speciality.addNewBonus(bonus);
 				}
 				break;
 			}
 			case 10://resource generation
-				bonus.type = Bonus::GENERATE_RESOURCE;
-				bonus.subtype = it->subtype;
+				bonus->type = Bonus::GENERATE_RESOURCE;
+				bonus->subtype = it->subtype;
 				speciality.addNewBonus(bonus);
 				break;
 			case 11://starting skill with mastery (Adrienne)
 				cb->changeSecSkill(id, it->val, it->additionalinfo); //simply give it and forget
 				break;
 			case 12://army speed
-				bonus.type = Bonus::STACKS_SPEED;
+				bonus->type = Bonus::STACKS_SPEED;
 				speciality.addNewBonus(bonus);
 				break;
 			case 13://Dragon bonuses (Mutare)
-				bonus.type = Bonus::PRIMARY_SKILL;
-				bonus.valType = Bonus::ADDITIVE_VALUE;
+				bonus->type = Bonus::PRIMARY_SKILL;
+				bonus->valType = Bonus::ADDITIVE_VALUE;
 				switch (it->subtype)
 				{
 					case 1:
-						bonus.subtype = PrimarySkill::ATTACK;
+						bonus->subtype = PrimarySkill::ATTACK;
 						break;
 					case 2:
-						bonus.subtype = PrimarySkill::DEFENSE;
+						bonus->subtype = PrimarySkill::DEFENSE;
 						break;
 				}
-				bonus.limiter = new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE);
+				bonus->limiter.reset(new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE));
 				speciality.addNewBonus(bonus);
 				break;
 			default:
@@ -1247,9 +1247,9 @@ void CGHeroInstance::updateSkill(int which, int val)
 		}
 		else
 		{
-			Bonus bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, id, skillVal, ID, which, Bonus::BASE_NUMBER);
-			bonus.source = Bonus::SECONDARY_SKILL;
-			addNewBonus (bonus);
+			Bonus *bonus = new Bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, id, skillVal, ID, which, Bonus::BASE_NUMBER);
+			bonus->source = Bonus::SECONDARY_SKILL;
+			addNewBonus(bonus);
 		}
 	}
 }
@@ -1506,7 +1506,7 @@ int CGHeroInstance::getSpellCost(const CSpell *sp) const
 
 void CGHeroInstance::pushPrimSkill(int which, int val)
 {
-	addNewBonus(Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id, which));
+	addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id, which));
 }
 
 // void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
@@ -2132,7 +2132,7 @@ void CGTownInstance::initObj()
 	//add special bonuses from buildings
 	if(subID == 4 && vstd::contains(builtBuildings, 17))
 	{
-		addNewBonus( Bonus(Bonus::PERMANENT, Bonus::DARKNESS, Bonus::TOWN_STRUCTURE, 20, 17) );
+		addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::DARKNESS, Bonus::TOWN_STRUCTURE, 20, 17) );
 	}
 }
 

+ 2 - 17
lib/CGameState.cpp

@@ -3435,25 +3435,10 @@ int BattleInfo::calculateSpellDuration( const CSpell * spell, const CGHeroInstan
 	}
 }
 
-CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const
+CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int position) const
 {
 	CStack * ret = new CStack(&base, attackerOwned ? side1 : side2, stackID, attackerOwned, slot);
-
-	//TODO: bonus na bitwê z limiterem
-
-//////////////////////////////////////////////////////////////////////////
-
-	//native terrain bonuses
-// 	int faction = ret->type->faction;
-// 	if(faction >= 0 && VLC->heroh->nativeTerrains[faction] == terrain)
-// 	{
-// 		ret->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE));
-// 		ret->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE));
-// 		ret->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE));
-// 	}
-// 
-// 	ret->position = position;
-
+ 	ret->position = position;
 	return ret;
 }
 

+ 9 - 9
lib/CGameState.h

@@ -236,7 +236,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
 	void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
 	std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile); //calculates stack affected by given spell
 	static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster, int usedSpellPower);
-	CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
+	CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
 	ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
 	int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
 	int lineToWallHex(int line) const; //returns hex with wall in given line
@@ -278,19 +278,19 @@ public:
 	void stackEffectToFeature(BonusList & sf, const Bonus & sse);
 	std::vector<si32> activeSpells() const; //returns vector of active spell IDs sorted by time of cast
 
-	static inline Bonus featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
+	static inline Bonus *featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
 	{
-		Bonus hb(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo));
-		hb.effectRange = limit;
-		hb.source = Bonus::CASTED_SPELL; //right?
+		Bonus *hb = makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo);
+		hb->effectRange = limit;
+		hb->source = Bonus::CASTED_SPELL; //right?
 		return hb;
 	}
 
-	static inline Bonus featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType)
+	static inline Bonus *featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType)
 	{
-		Bonus ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain));
-		ret.valType = valType;
-		ret.source = Bonus::CASTED_SPELL; //right?
+		Bonus *ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain));
+		ret->valType = valType;
+		ret->source = Bonus::CASTED_SPELL; //right?
 		return ret;
 	}
 

+ 13 - 0
lib/Connection.h

@@ -488,6 +488,12 @@ public:
 		const_cast<T&>(data).serialize(*this,version);
 	}
 	template <typename T>
+	void saveSerializable(const boost::shared_ptr<T> &data)
+	{
+		T *internalPtr = data.get();
+		*this << internalPtr;
+	}
+	template <typename T>
 	void saveSerializable(const std::vector<T> &data)
 	{
 		boost::uint32_t length = data.size();
@@ -735,6 +741,13 @@ public:
 	};
 
 
+	template <typename T>
+	void loadSerializable(boost::shared_ptr<T> &data)
+	{
+		T *internalPtr;
+		*this >> internalPtr;
+		data.reset(internalPtr);
+	}
 	template <typename T>
 	void loadSerializable(std::vector<T> &data)
 	{

+ 110 - 54
lib/HeroBonus.cpp

@@ -8,6 +8,8 @@
 #include <boost/assign/list_of.hpp>
 #include "CCreatureSet.h"
 #include <boost/algorithm/string/trim.hpp>
+#include <boost/bind.hpp>
+#include "../hch/CHeroHandler.h"
 
 #define FOREACH_CONST_PARENT(pname) 	TCNodes parents; getParents(parents); BOOST_FOREACH(const CBonusSystemNode *pname, parents)
 #define FOREACH_PARENT(pname) 	TNodes parents; getParents(parents); BOOST_FOREACH(CBonusSystemNode *pname, parents)
@@ -99,49 +101,15 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector,
 			out.push_back(i);
 }
 
-namespace HHLP
-{
-	class SourceComp
-	{
-	public:
-		Bonus::BonusSource src;
-		SourceComp(Bonus::BonusSource _src) : src(_src)
-		{
-		}
-		bool operator()(const Bonus * bon)
-		{
-			return bon->source == src;
-		}
-	};
-}
-
 
 void DLL_EXPORT BonusList::removeSpells(Bonus::BonusSource sourceType)
 {
-	std::remove_if(begin(), end(), HHLP::SourceComp(sourceType));
+	remove_if(Selector::sourceType(sourceType));
 }
 
 void BonusList::limit(const CBonusSystemNode &node)
 {
-limit_start:
-	for(iterator i = begin(); i != end(); i++)
-	{
-		Bonus *b = *i;
-		if(b->limiter && b->limiter->limit(b, node))
-		{
-			iterator toErase = i;
-			if(i != begin())
-			{
-				i--;
-				erase(toErase);
-			}
-			else
-			{
-				erase(toErase);
-				goto limit_start;
-			}
-		}
-	}
+	remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, node, _1));
 }
 
 int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
@@ -358,27 +326,36 @@ void CBonusSystemNode::popBonuses(const CSelector &s)
 		child->popBonuses(s);
 }
 
-void CBonusSystemNode::addNewBonus(const Bonus &b)
-{
-	addNewBonus(new Bonus(b));
-}
+// void CBonusSystemNode::addNewBonus(const Bonus &b)
+// {
+// 	addNewBonus(new Bonus(b));
+// }
 
 void CBonusSystemNode::addNewBonus(Bonus *b)
 {
 	exportedBonuses.push_back(b);
-
-	if(!b->propagator)
-		bonuses.push_back(b);
-	else
-	{
-		//prop
-	}
+	whereToPropagate(b)->bonuses.push_back(b);
 }
 
 void CBonusSystemNode::removeBonus(Bonus *b)
 {
 	exportedBonuses -= b;
-	//TODO: prop
+	CBonusSystemNode *whereIsOurBonus = whereToPropagate(b);
+	whereIsOurBonus->bonuses -= b;
+	delNull(b);
+}
+
+CBonusSystemNode * CBonusSystemNode::whereToPropagate(Bonus *b)
+{
+	if(b->propagator)
+		return b->propagator->getDestNode(this);
+	else
+		return this;
+}
+
+bool CBonusSystemNode::isLimitedOnUs(Bonus *b) const
+{
+	return b->limiter && b->limiter->limit(b, *this);
 }
 
 int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
@@ -445,8 +422,6 @@ Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si
 	turnsRemain = 0;
 	valType = ADDITIVE_VALUE;
 	effectRange = NO_LIMIT;
-	limiter = NULL;
-	propagator = NULL;
 	boost::algorithm::trim(description);
 }
 
@@ -456,8 +431,6 @@ Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype/*=-1*/,
 	additionalInfo = -1;
 	turnsRemain = 0;
 	effectRange = NO_LIMIT;
-	limiter = NULL;
-	propagator = NULL;
 }
 
 Bonus::Bonus()
@@ -467,8 +440,16 @@ Bonus::Bonus()
 	turnsRemain = 0;
 	valType = ADDITIVE_VALUE;
 	effectRange = NO_LIMIT;
-	limiter = NULL;
-	propagator = NULL;
+}
+
+Bonus::~Bonus()
+{
+}
+
+Bonus * Bonus::addLimiter(ILimiter *Limiter)
+{
+	limiter.reset(Limiter);
+	return this;
 }
 
 CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second)
@@ -525,6 +506,19 @@ namespace Selector
 	}
 }
 
+const CCreature * retrieveCreature(const CBonusSystemNode *node)
+{
+	switch(node->nodeType)
+	{
+	case CBonusSystemNode::CREATURE:
+		return (static_cast<const CCreature *>(node));
+	case CBonusSystemNode::STACK:
+		return (static_cast<const CStackInstance *>(node))->type;
+	default:
+		return NULL;
+	}
+}
+
 DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
 {
 	int i = 0;
@@ -621,4 +615,66 @@ bool HasAnotherBonusLimiter::limit( const Bonus *b, const CBonusSystemNode &node
 IPropagator::~IPropagator()
 {
 
+}
+
+CBonusSystemNode * IPropagator::getDestNode(CBonusSystemNode *source)
+{
+	return source;
+}
+
+CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter(int TerrainType) 
+	: terrainType(TerrainType)
+{
+}
+
+CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter()
+{
+
+}
+bool CreatureNativeTerrainLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const
+{
+	const CCreature *c = retrieveCreature(&node);
+	return !c || VLC->heroh->nativeTerrains[c->faction] != terrainType; //drop bonus for non-creatures or non-native residents
+}
+
+CreatureFactionLimiter::CreatureFactionLimiter(int Faction)
+	: faction(Faction)
+{
+}
+
+CreatureFactionLimiter::CreatureFactionLimiter()
+{
+}
+bool CreatureFactionLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const
+{
+	const CCreature *c = retrieveCreature(&node);
+	return !c || c->faction != faction; //drop bonus for non-creatures or non-native residents
+}
+
+CreatureAlignmentLimiter::CreatureAlignmentLimiter()
+{
+}
+
+CreatureAlignmentLimiter::CreatureAlignmentLimiter(si8 Alignment)
+	: alignment(Alignment)
+{
+}
+
+bool CreatureAlignmentLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const
+{
+	const CCreature *c = retrieveCreature(&node);
+	if(!c) 
+		return true;
+	switch(alignment)
+	{
+	case GOOD:
+		return !c->isGood(); //if not good -> return true (drop bonus)
+	case NEUTRAL:
+		return c->isEvil() || c->isGood();
+	case EVIL:
+		return !c->isEvil();
+	default:
+		tlog1 << "Warning: illegal alignment in limiter!\n";
+		return true;
+	}
 }

+ 71 - 16
lib/HeroBonus.h

@@ -4,6 +4,7 @@
 #include <list>
 #include <set>
 #include <boost/function.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
 
 /*
  * HeroBonus.h, part of VCMI engine
@@ -229,14 +230,15 @@ struct DLL_EXPORT Bonus
 	si32 additionalInfo;
 	ui8 effectRange; //if not NO_LIMIT, bonus will be ommitted by default
 
-	ILimiter *limiter;
-	IPropagator *propagator;
+	boost::shared_ptr<ILimiter> limiter;
+	boost::shared_ptr<IPropagator> propagator;
 
 	std::string description; 
 
 	Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1);
 	Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1, ui8 ValType = ADDITIVE_VALUE);
 	Bonus();
+	~Bonus();
 
 // 	//comparison
 // 	bool operator==(const HeroBonus &other)
@@ -294,6 +296,8 @@ struct DLL_EXPORT Bonus
 	const CSpell * sourceSpell() const;
 
 	std::string Description() const;
+
+	Bonus *addLimiter(ILimiter *Limiter); //returns this for convenient chain-calls
 };
 
 struct DLL_EXPORT stackExperience : public Bonus
@@ -337,6 +341,7 @@ class DLL_EXPORT IPropagator
 {
 public:
 	virtual ~IPropagator();
+	virtual CBonusSystemNode *getDestNode(CBonusSystemNode *source);
 };
 	
 class DLL_EXPORT ILimiter
@@ -405,9 +410,12 @@ public:
 	void attachTo(const CBonusSystemNode *parent);
 	void detachFrom(const CBonusSystemNode *parent);
 	void addNewBonus(Bonus *b); //b will be deleted with destruction of node
-	void addNewBonus(const Bonus &b); //b will copied
+	//void addNewBonus(const Bonus &b); //b will copied
 	void removeBonus(Bonus *b);
 
+	bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node
+	CBonusSystemNode *whereToPropagate(Bonus *b);
+
 	void popBonuses(const CSelector &s);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -432,16 +440,16 @@ namespace NBonus
 };
 
 //generates HeroBonus from given data
-inline Bonus makeFeature(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
+inline Bonus* makeFeature(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
 {
-	Bonus sf;
-	sf.type = type;
-	sf.duration = duration;
-	sf.source = source;
-	sf.turnsRemain = turnsRemain;
-	sf.subtype = subtype;
-	sf.val = value;
-	sf.additionalInfo = additionalInfo;
+	Bonus* sf = new Bonus();
+	sf->type = type;
+	sf->duration = duration;
+	sf->source = source;
+	sf->turnsRemain = turnsRemain;
+	sf->subtype = subtype;
+	sf->val = value;
+	sf->additionalInfo = additionalInfo;
 
 	return sf;
 }
@@ -497,7 +505,7 @@ public:
 	}
 };
 
-class CWillLastTurns
+class DLL_EXPORT CWillLastTurns
 {
 public:
 	int turnsRequested;
@@ -515,7 +523,7 @@ public:
 	}
 };
 
-class CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades)
+class DLL_EXPORT CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades)
 {
 public:
 	const CCreature *creature;
@@ -532,14 +540,14 @@ public:
 	}
 };
 
-class HasAnotherBonusLimiter : public ILimiter //applies only to nodes that have another bonus working
+class DLL_EXPORT HasAnotherBonusLimiter : public ILimiter //applies only to nodes that have another bonus working
 {
 public:
 	TBonusType type;
 	TBonusSubtype subtype;
 	ui8 isSubtypeRelevant; //check for subtype only if this is true
 
-	HasAnotherBonusLimiter(TBonusType bonus);
+	HasAnotherBonusLimiter(TBonusType bonus = Bonus::NONE);
 	HasAnotherBonusLimiter(TBonusType bonus, TBonusSubtype _subtype);
 
 	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE;
@@ -550,6 +558,53 @@ public:
 	}
 };
 
+class DLL_EXPORT CreatureNativeTerrainLimiter : public ILimiter //applies only to creatures that are on their native terrain 
+{
+public:
+	si8 terrainType;
+	CreatureNativeTerrainLimiter();
+	CreatureNativeTerrainLimiter(int TerrainType);
+
+	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & terrainType;
+	}
+};
+
+class DLL_EXPORT CreatureFactionLimiter : public ILimiter //applies only to creatures of given faction
+{
+public:
+	si8 faction;
+	CreatureFactionLimiter();
+	CreatureFactionLimiter(int TerrainType);
+
+	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & faction;
+	}
+};
+
+class DLL_EXPORT CreatureAlignmentLimiter : public ILimiter //applies only to creatures of given alignment
+{
+public:
+	si8 alignment;
+	CreatureAlignmentLimiter();
+	CreatureAlignmentLimiter(si8 Alignment);
+
+	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & alignment;
+	}
+};
+
+const CCreature *retrieveCreature(const CBonusSystemNode *node);
+
 namespace Selector
 {
 	extern DLL_EXPORT CSelectFieldEqual<TBonusType> type;

+ 6 - 6
lib/NetPacksLib.cpp

@@ -664,17 +664,17 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs )
 				case DOUBLE_GROWTH:
 					b->val = 100;
 					b->type = Bonus::CREATURE_GROWTH_PERCENT;
-					b->limiter = new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false);
+					b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false));
 					break;
 				case BONUS_GROWTH:
 					b->val = 5;
 					b->type = Bonus::CREATURE_GROWTH;
-					b->limiter = new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false);
+					b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false));
 					break;
 				case DEITYOFFIRE:
 					b->val = 15;
 					b->type = Bonus::CREATURE_GROWTH;
-					b->limiter = new CCreatureTypeLimiter(*VLC->creh->creatures[42], true);
+					b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[42], true));
 					break;
 				case PLAGUE:
 					b->val = -100; //no basic creatures
@@ -985,8 +985,8 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
 			creID = 112; //air elemental
 			break;
 		}
-		const int3 & tile = gs->curB->tile;
-		TerrainTile::EterrainType ter = gs->map->terrain[tile.x][tile.y][tile.z].tertype;
+// 		const int3 & tile = gs->curB->tile;
+// 		TerrainTile::EterrainType ter = gs->map->terrain[tile.x][tile.y][tile.z].tertype;
 
 		int pos; //position of stack on the battlefield - to be calculated
 
@@ -1004,7 +1004,7 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
 			}
 		}
 
-		CStack * summonedStack = gs->curB->generateNewStack(CStackInstance(creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], h), gs->curB->stacks.size(), !side, 255, ter, pos);
+		CStack * summonedStack = gs->curB->generateNewStack(CStackInstance(creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], h), gs->curB->stacks.size(), !side, 255, pos);
 		summonedStack->state.insert(SUMMONED);
 		//summonedStack->addNewBonus( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) );
 

+ 4 - 0
lib/RegisterTypes.cpp

@@ -75,6 +75,10 @@ void registerTypes1(Serializer &s)
 	//end of objects
 	s.template registerType<ILimiter>();
 	s.template registerType<CCreatureTypeLimiter>();
+	s.template registerType<HasAnotherBonusLimiter>();
+	s.template registerType<CreatureNativeTerrainLimiter>();
+	s.template registerType<CreatureFactionLimiter>();
+	s.template registerType<CreatureAlignmentLimiter>();
 }
 
 template<typename Serializer> DLL_EXPORT 

+ 3 - 1
lib/map.h

@@ -314,7 +314,9 @@ struct DLL_EXPORT Mapa : public CMapHeader
 	{
 		h & static_cast<CMapHeader&>(*this);
 		h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos;
-		h & monsters & heroesToBeat & artInstances; //hopefully serialization is now automagical?
+		h & monsters;
+		h & heroesToBeat;
+		h & artInstances; //hopefully serialization is now automagical?
 
 		//TODO: viccondetails
 		if(h.saving)

+ 33 - 73
server/CGameHandler.cpp

@@ -1478,7 +1478,7 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
 		else
 			pos = attackerLoose[army1->stacksCount()-1][k];
 
-		CStack * stack = curB->generateNewStack(i->second, stacks.size(), true, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos);
+		CStack * stack = curB->generateNewStack(i->second, stacks.size(), true, i->first, pos);
 		stacks.push_back(stack);
 	}
 	
@@ -1493,7 +1493,7 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
 		else
 			pos = defenderLoose[army2->stacksCount()-1][k];
 
-		CStack * stack = curB->generateNewStack(i->second, stacks.size(), false, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos);
+		CStack * stack = curB->generateNewStack(i->second, stacks.size(), false, i->first, pos);
 		stacks.push_back(stack);
 	}
 
@@ -1514,17 +1514,17 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
 	{
 		if(hero1->getArt(13)) //ballista
 		{
-			CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 52);
+			CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero1), stacks.size(), true, 255, 52);
 			stacks.push_back(stack);
 		}
 		if(hero1->getArt(14)) //ammo cart
 		{
-			CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 18);
+			CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), true, 255, 18);
 			stacks.push_back(stack);
 		}
 		if(hero1->getArt(15)) //first aid tent
 		{
-			CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 154);
+			CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero1), stacks.size(), true, 255, 154);
 			stacks.push_back(stack);
 		}
 	}
@@ -1533,23 +1533,23 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
 		//defending hero shouldn't receive ballista (bug #551)
 		if(hero2->getArt(13) && !town) //ballista
 		{
-			CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero2),  stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 66);
+			CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero2),  stacks.size(), false, 255, 66);
 			stacks.push_back(stack);
 		}
 		if(hero2->getArt(14)) //ammo cart
 		{
-			CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 32);
+			CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), false, 255, 32);
 			stacks.push_back(stack);
 		}
 		if(hero2->getArt(15)) //first aid tent
 		{
-			CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 168);
+			CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero2), stacks.size(), false, 255, 168);
 			stacks.push_back(stack);
 		}
 	}
 	if(town && hero1 && town->hasFort()) //catapult
 	{
-		CStack * stack = curB->generateNewStack(CStackInstance(145, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 120);
+		CStack * stack = curB->generateNewStack(CStackInstance(145, 1, hero1), stacks.size(), true, 255, 120);
 		stacks.push_back(stack);
 	}
 	//war machines added
@@ -1559,14 +1559,14 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
 		
 	case 3: //castle
 		{//lower tower / upper tower
-			CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -4);
+			CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, -4);
 			stacks.push_back(stack);
-			stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -3);
+			stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, -3);
 			stacks.push_back(stack);
 		}
 	case 2: //citadel
 		{//main tower
-			CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -2);
+			CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, -2);
 			stacks.push_back(stack);
 		}
 	}
@@ -1676,8 +1676,7 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
 		}
 	}
 
-	//giving terrain premies for heroes & stacks
-
+	//giving terrain overalay premies
 	int bonusSubtype = -1;
 	switch(terType)
 	{
@@ -1703,86 +1702,47 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
 		}
 
 		{ //common part for cases 9, 14, 15, 16, 17
-			const CGHeroInstance * cHero = NULL;
-			for(int i=0; i<2; ++i)
-			{
-				if(i == 0) cHero = hero1;
-				else cHero = hero2;
-
-				if(cHero == NULL) continue;
-
-				GiveBonus gs;
-				gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::OBJECT, 3, -1, "", bonusSubtype);
-				gs.id = cHero->id;
-
-				sendAndApply(&gs);
-			}
-
+			curB->addNewBonus(new Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::TERRAIN_OVERLAY, 3, -1, "", bonusSubtype));
 			break;
 		}
 
 	case 18: //holy ground
 		{
-			for(int g=0; g<stacks.size(); ++g) //+1 morale bonus for good creatures, -1 morale bonus for evil creatures
-			{
-				if (stacks[g]->type->isGood())
-					stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY));
-				else if (stacks[g]->type->isEvil())
-					stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY));
-			}
+			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(GOOD)));
+			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EVIL)));
 			break;
 		}
 	case 19: //clover field
-		{
-			for(int g=0; g<stacks.size(); ++g)
-			{
-				if(stacks[g]->type->faction == -1) //+2 luck bonus for neutral creatures
-				{
-					stacks[g]->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TERRAIN_OVERLAY));
-				}
-			}
+		{ //+2 luck bonus for neutral creatures
+			curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureFactionLimiter(-1)));
 			break;
 		}
 	case 20: //evil fog
 		{
-			for(int g=0; g<stacks.size(); ++g) //-1 morale bonus for good creatures, +1 morale bonus for evil creatures
-			{
-				if (stacks[g]->type->isGood())
-					stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY));
-				else if (stacks[g]->type->isEvil())
-					stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY));
-			}
+			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(GOOD)));
+			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EVIL)));
 			break;
 		}
 	case 22: //cursed ground
 		{
-			for(int g=0; g<stacks.size(); ++g) //no luck nor morale
-			{
-				stacks[g]->addNewBonus(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
-				stacks[g]->addNewBonus(makeFeature(Bonus::NO_LUCK, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
-			}
-
-			const CGHeroInstance * cHero = NULL;
-			for(int i=0; i<2; ++i) //blocking spells above level 1
-			{
-				if(i == 0) cHero = hero1;
-				else cHero = hero2;
-
-				if(cHero == NULL) continue;
-
-				GiveBonus gs;
-				gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::OBJECT, 1, -1, "", bonusSubtype);
-				gs.id = cHero->id;
-
-				sendAndApply(&gs);
-			}
-
+			curB->addNewBonus(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
+			curB->addNewBonus(makeFeature(Bonus::NO_LUCK, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
+			curB->addNewBonus(makeFeature(Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY));
 			break;
 		}
 	}
+	//overlay premies given
 
-	//premies given
+	//native terrain bonuses
+	int terrain = this->getTile(tile)->tertype;
+	if(town) //during siege always take premies for native terrain of faction
+		terrain = VLC->heroh->nativeTerrains[town->town->typeID];
 
+	ILimiter *nativeTerrain = new CreatureNativeTerrainLimiter(terrain);
+	curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
+	curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
+	curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
+	//////////////////////////////////////////////////////////////////////////
 
 	//send info about battles
 	BattleStart bs;