فهرست منبع

* Bonus system caching updated, partially rewritten, much more robust, thread-safe
* Adjusted projectile speed, trebuchet canon speed

beegee1 14 سال پیش
والد
کامیت
55e7959fd9

+ 11 - 11
client/CBattleInterface.cpp

@@ -631,8 +631,8 @@ bool CBattleStackMoved::init()
 	}
 	//unit reversed
 
-	if(owner->moveSh <= 0)
-		owner->moveSh = CCS->soundh->playSound(battle_sound(movedStack->getCreature(), move), -1);
+//	if(owner->moveSh <= 0)
+//		owner->moveSh = CCS->soundh->playSound(battle_sound(movedStack->getCreature(), move), -1);
 
 	//step shift calculation
 	posX = owner->creAnims[stack->ID]->pos.x, posY = owner->creAnims[stack->ID]->pos.y; // for precise calculations ;]
@@ -1008,7 +1008,7 @@ bool CShootingAnim::init()
 
 	Point xycoord = CBattleHex::getXYUnitAnim(shooter->position, true, shooter, owner);
 	Point destcoord;
-	int animSpeed = 40; // flight speed of projectile
+	
 	
 	// The "master" point where all projectile positions relate to.
 	static const Point projectileOrigin(181, 252);
@@ -1037,7 +1037,8 @@ bool CShootingAnim::init()
 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->rightMissleOffsetX;
 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->rightMissleOffsetY;
 		}
-
+	
+		double animSpeed = 23.0 * owner->getAnimSpeed(); // flight speed of projectile
 		spi.lastStep = sqrt((float)((destcoord.x - spi.x)*(destcoord.x - spi.x) + (destcoord.y - spi.y) * (destcoord.y - spi.y))) / animSpeed;
 		if(spi.lastStep == 0)
 			spi.lastStep = 1;
@@ -1069,12 +1070,12 @@ bool CShootingAnim::init()
 		{
 			int curveID = it->second;
 			spi.catapultInfo = trajectoryCurves[curveID];
-			animSpeed /= 2;
+			double animSpeed = 3.318 * owner->getAnimSpeed();
 			spi.lastStep = (spi.catapultInfo->toX - spi.catapultInfo->fromX) / animSpeed;
 			spi.dx = animSpeed;
 			spi.dy = 0;
-			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->rightMissleOffsetX + 17;
-			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->rightMissleOffsetY + 10;
+			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->rightMissleOffsetX + 17.;
+			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->rightMissleOffsetY + 10.;
 
 			// Add explosion anim
 			int xEnd = spi.x + spi.lastStep * spi.dx;
@@ -3333,7 +3334,6 @@ void CBattleInterface::setAnimSpeed(int set)
 int CBattleInterface::getAnimSpeed() const
 {
 	return curInt->sysOpts.animSpeed;
-	curInt->sysOpts.settingsChanged();
 }
 
 void CBattleInterface::activateStack()
@@ -3654,8 +3654,8 @@ void CBattleInterface::projectileShowHelper(SDL_Surface * to)
 		// of it for drawing
 		if (it->catapultInfo)
 		{
-			dst.x -= 17;
-			dst.y -= 10;
+			dst.x -= 17.;
+			dst.y -= 10.;
 		}
 
 		if(it->reverse)
@@ -4790,7 +4790,7 @@ void CStackQueue::StackBox::hover( bool on )
 
 }
 
-int CatapultProjectileInfo::calculateY(int x)
+double CatapultProjectileInfo::calculateY(double x)
 {
 	return (facA * pow(10., -3.)) * pow(x, 2.0) + facB * x + facC;
 }

+ 3 - 3
client/CBattleInterface.h

@@ -51,8 +51,8 @@ struct SStackAttackedInfo
 /// Small struct which contains information about the position and the velocity of a projectile
 struct SProjectileInfo
 {
-	int x, y; //position on the screen
-	int dx, dy; //change in position in one step
+	double x, y; //position on the screen
+	double dx, dy; //change in position in one step
 	int step, lastStep; //to know when finish showing this projectile
 	int creID; //ID of creature that shot this projectile
 	int stackID; //ID of stack
@@ -407,7 +407,7 @@ struct CatapultProjectileInfo
 	CatapultProjectileInfo(double factorA, double factorB, double factorC, int fromXX, int toXX) : facA(factorA), facB(factorB), facC(factorC),
 		fromX(fromXX), toX(toXX) { };
 
-	int calculateY(int x);
+	double calculateY(double x);
 };
 
 /// Big class which handles the overall battle interface actions and it is also responsible for

+ 1 - 1
client/CCastleInterface.cpp

@@ -1147,7 +1147,7 @@ void CCreaInfo::clickRight(tribool down, bool previousState)
 			{
 				boost::shared_ptr<BonusList> blAppend = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level) 
 					&& Selector::sourceType(Bonus::ARTIFACT), 0, hero);
-				bl->insert(bl->end(), blAppend->begin(), blAppend->end()) ;
+				bl->insert(bl->size(), blAppend->begin(), blAppend->end()) ;
 			}
 			
 			if (bl->size())

+ 7 - 7
client/CCreatureWindow.cpp

@@ -131,17 +131,17 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
 
 	//Basic graphics - need to calculate size
 
-	CBonusSystemNode node = CBonusSystemNode() ;
-	node.bonuses = *(stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT)));
-	BonusList bl;
+	BonusList bl, blTemp;
+	blTemp = (*(stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT))));
+	
 
-	while (node.bonuses.size())
+	while (blTemp.size())
 	{
-		Bonus * b = node.bonuses.front();
+		Bonus * b = blTemp.front();
 
 		bl.push_back (new Bonus(*b));
-		bl.back()->val = node.valOfBonuses(Selector::typeSubtype(b->type, b->subtype)); //merge multiple bonuses into one
-		node.bonuses.remove_if (Selector::typeSubtype(b->type, b->subtype)); //remove used bonuses
+		bl.back()->val = blTemp.valOfBonuses(Selector::typeSubtype(b->type, b->subtype)); //merge multiple bonuses into one
+		blTemp.remove_if (Selector::typeSubtype(b->type, b->subtype)); //remove used bonuses
 	}
 
 	std::string text;

+ 1 - 1
client/CHeroWindow.cpp

@@ -44,7 +44,7 @@
 extern SDL_Surface * screen;
 using namespace boost::assign;
 
-const boost::shared_ptr<BonusList> CHeroWithMaybePickedArtifact::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
+const boost::shared_ptr<BonusList> CHeroWithMaybePickedArtifact::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const std::string &cachingStr /*= ""*/) const
 {
 	boost::shared_ptr<BonusList> out(new BonusList);
 	boost::shared_ptr<BonusList> heroBonuses = hero->getAllBonuses(selector, limit, hero);

+ 1 - 1
client/CHeroWindow.h

@@ -46,7 +46,7 @@ public:
 	CWindowWithArtifacts *cww;
 
 	CHeroWithMaybePickedArtifact(CWindowWithArtifacts *Cww, const CGHeroInstance *Hero);
-	const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const OVERRIDE;
+	const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const std::string &cachingStr = "") const OVERRIDE;
 };
 
 class CHeroWindow: public CWindowWithGarrison, public CWindowWithArtifacts

+ 2 - 2
client/CMT.cpp

@@ -469,14 +469,14 @@ void processCommand(const std::string &message)
 	else if(cn == "bonuses")
 	{
 		tlog0 << "Bonuses of " << adventureInt->selection->getHoverText() << std::endl
-			<< adventureInt->selection->bonuses << std::endl;
+			<< adventureInt->selection->getBonusList() << std::endl;
 
 		tlog0 << "\nInherited bonuses:\n";
 		TCNodes parents;
 		adventureInt->selection->getParents(parents);
 		BOOST_FOREACH(const CBonusSystemNode *parent, parents)
 		{
-			tlog0 << "\nBonuses from " << typeid(*parent).name() << std::endl << parent->bonuses << std::endl;
+			tlog0 << "\nBonuses from " << typeid(*parent).name() << std::endl << parent->getBonusList() << std::endl;
 		}
 	}
 	else if(cn == "not dialog")

+ 2 - 2
client/NetPacksClient.cpp

@@ -249,13 +249,13 @@ void GiveBonus::applyCl( CClient *cl )
 	case HERO:
 		{
 			const CGHeroInstance *h = GS(cl)->getHero(id);
-			INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroBonusChanged, h, *h->bonuses.back(),true);
+			INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroBonusChanged, h, *h->getBonusList().back(),true);
 		}
 		break;
 	case PLAYER:
 		{
 			const PlayerState *p = GS(cl)->getPlayer(id);
-			INTERFACE_CALL_IF_PRESENT(id, playerBonusChanged, *p->bonuses.back(), true);
+			INTERFACE_CALL_IF_PRESENT(id, playerBonusChanged, *p->getBonusList().back(), true);
 		}
 		break;
 	}

+ 14 - 13
lib/BattleState.cpp

@@ -490,7 +490,7 @@ TDmgRange BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* d
 
 		for(int g = 0; g < VLC->creh->creatures.size(); ++g)
 		{
-			BOOST_FOREACH(const Bonus *b, VLC->creh->creatures[g]->bonuses)
+			BOOST_FOREACH(const Bonus *b, VLC->creh->creatures[g]->getBonusList())
 			{
 				if ( (b->type == Bonus::KING3 && spLevel >= 3) || //expert
 					(b->type == Bonus::KING2 && spLevel >= 2) || //adv +
@@ -602,7 +602,7 @@ TDmgRange BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* d
 		static bool hasAdvancedAirShield(const CStack * stack)
 		{
 
-			BOOST_FOREACH(const Bonus *it, stack->bonuses)
+			BOOST_FOREACH(const Bonus *it, stack->getBonusList())
 			{
 				if (it->source == Bonus::SPELL_EFFECT && it->sid == 28 && it->val >= 2)
 				{
@@ -1718,7 +1718,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
 		curB->belligerents[i]->getRedAncestors(nodes);
 		BOOST_FOREACH(CBonusSystemNode *n, nodes)
 		{
-			BOOST_FOREACH(Bonus *b, n->exportedBonuses)
+			BOOST_FOREACH(Bonus *b, n->getExportedBonusList())
 			{
 				if(b->effectRange == Bonus::ONLY_ENEMY_ARMY/* && b->propagator && b->propagator->shouldBeAttached(curB)*/)
 				{
@@ -1944,7 +1944,8 @@ SpellCasting::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInstance
 		boost::shared_ptr<BonusList> immunities = subject->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
 		if(subject->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES))
 		{
-			std::remove_if(immunities->begin(), immunities->end(), NegateRemover);
+			//std::remove_if(immunities->begin(), immunities->end(), NegateRemover);
+			immunities->remove_if(NegateRemover);
 		}
 
 		if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) ||
@@ -2074,13 +2075,13 @@ CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
 	assert(base);
 	type = base->type;
 	count = baseAmount = base->count;
-	nodeType = STACK_BATTLE;
+	setNodeType(STACK_BATTLE);
 }
 
 CStack::CStack()
 {
 	init();
-	nodeType = STACK_BATTLE;
+	setNodeType(STACK_BATTLE);
 }
 
 CStack::CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S)
@@ -2088,7 +2089,7 @@ CStack::CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S)
 {
 	type = stack->type;
 	count = baseAmount = stack->count;
-	nodeType = STACK_BATTLE;
+	setNodeType(STACK_BATTLE);
 }
 
 void CStack::init()
@@ -2108,7 +2109,7 @@ void CStack::init()
 void CStack::postInit()
 {
 	assert(type);
-	assert(parents.size());
+	assert(getParentNodes().size());
 
 	firstHPleft = valOfBonuses(Bonus::STACK_HEALTH);
 	shots = getCreature()->valOfBonuses(Bonus::SHOTS);
@@ -2127,7 +2128,7 @@ ui32 CStack::Speed( int turn /*= 0*/ ) const
 	int speed = valOfBonuses(Selector::type(Bonus::STACKS_SPEED) && Selector::turns(turn));
 
 	int percentBonus = 0;
-	BOOST_FOREACH(const Bonus *b, bonuses)
+	BOOST_FOREACH(const Bonus *b, getBonusList())
 	{
 		if(b->type == Bonus::STACKS_SPEED)
 		{
@@ -2148,7 +2149,7 @@ ui32 CStack::Speed( int turn /*= 0*/ ) const
 
 const Bonus * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
 {
-	BOOST_FOREACH(Bonus *it, bonuses)
+	BOOST_FOREACH(Bonus *it, getBonusList())
 	{
 		if(it->source == Bonus::SPELL_EFFECT && it->sid == id)
 		{
@@ -2328,7 +2329,7 @@ void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
 ui8 CStack::howManyEffectsSet(ui16 id) const
 {
 	ui8 ret = 0;
-	BOOST_FOREACH(const Bonus *it, bonuses)
+	BOOST_FOREACH(const Bonus *it, getBonusList())
 		if(it->source == Bonus::SPELL_EFFECT && it->sid == id) //effect found
 		{
 			++ret;
@@ -2453,8 +2454,8 @@ const CGHeroInstance * CStack::getMyHero() const
 	if(base)
 		return dynamic_cast<const CGHeroInstance *>(base->armyObj);
 	else //we are attached directly?
-		BOOST_FOREACH(const CBonusSystemNode *n, parents)
-		if(n->nodeType == HERO)
+		BOOST_FOREACH(const CBonusSystemNode *n, getParentNodes())
+		if(n->getNodeType() == HERO)
 			dynamic_cast<const CGHeroInstance *>(n);
 
 	return NULL;

+ 2 - 2
lib/CArtHandler.cpp

@@ -147,7 +147,7 @@ bool CArtifact::isBig () const
 
 CArtifact::CArtifact()
 {
-	nodeType = ARTIFACT;
+	setNodeType(ARTIFACT);
 }
 
 CArtifact::~CArtifact()
@@ -1116,7 +1116,7 @@ void CCombinedArtifactInstance::createConstituents()
 void CCombinedArtifactInstance::addAsConstituent(CArtifactInstance *art, int slot)
 {
 	assert(vstd::contains(*artType->constituents, art->artType->id));
-	assert(art->parents.size() == 1  &&  art->parents.front() == art->artType);
+	assert(art->getParentNodes().size() == 1  &&  art->getParentNodes().front() == art->artType);
 	constituentsInfo.push_back(ConstituentInfo(art, slot));
 	attachTo(art);
 }

+ 12 - 12
lib/CCreatureHandler.cpp

@@ -49,10 +49,10 @@ CCreatureHandler::CCreatureHandler()
 	factionAlignments += 1, 1, 1, -1, -1, -1, 0, 0, 0;
 	doubledCreatures +=  4, 14, 20, 28, 42, 44, 60, 70, 72, 85, 86, 100, 104; //according to Strategija
 
-	allCreatures.description = "All creatures";
-	creaturesOfLevel[0].description = "Creatures of unnormalized tier";
+	allCreatures.setDescription("All creatures");
+	creaturesOfLevel[0].setDescription("Creatures of unnormalized tier");
 	for(int i = 1; i < ARRAY_COUNT(creaturesOfLevel); i++)
-		creaturesOfLevel[i].description = "Creatures of tier " + boost::lexical_cast<std::string>(i);
+		creaturesOfLevel[i].setDescription("Creatures of tier " + boost::lexical_cast<std::string>(i));
 }
 
 int CCreature::getQuantityID(const int & quantity)
@@ -129,7 +129,7 @@ si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatur
 CCreature::CCreature()
 {
 	doubleWide = false;
-	nodeType = CBonusSystemNode::CREATURE;
+	setNodeType(CBonusSystemNode::CREATURE);
 }
 void CCreature::addBonus(int val, int type, int subtype /*= -1*/)
 {
@@ -330,12 +330,12 @@ void CCreatureHandler::loadCreatures()
 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_raises_morale"))
 			{
 				ncre.addBonus(+1, Bonus::MORALE);;
-				ncre.bonuses.back()->addPropagator(new CPropagatorNodeType(CBonusSystemNode::HERO));
+				ncre.getBonusList().back()->addPropagator(new CPropagatorNodeType(CBonusSystemNode::HERO));
 			}
 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale"))
 			{
 				ncre.addBonus(-1, Bonus::MORALE);;
-				ncre.bonuses.back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
+				ncre.getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
 			}
 			if(boost::algorithm::find_first(ncre.abilityRefs, "KING_1"))
 				ncre.addBonus(0, Bonus::KING1);
@@ -399,12 +399,12 @@ void CCreatureHandler::loadCreatures()
 					else if(type == "ENEMY_MORALE_DECREASING")
 					{
 						cre->addBonus(-1, Bonus::MORALE);
-						cre->bonuses.back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
+						cre->getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
 					}
 					else if(type == "ENEMY_LUCK_DECREASING")
 					{
 						cre->addBonus(-1, Bonus::LUCK);
-						cre->bonuses.back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
+						cre->getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
 					}
 					else
 						tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl;
@@ -678,7 +678,7 @@ void CCreatureHandler::loadCreatures()
 		{
 			loadToIt(creid, buf, it, 4); //get index
 			b.sid = creid; //id = this particular creature ID
-			loadStackExp(b, creatures[creid]->bonuses, buf, it); //add directly to CCreature Node
+			loadStackExp(b, creatures[creid]->getBonusList(), buf, it); //add directly to CCreature Node
 			loadToIt (dump2, buf, it, 3); //crop comment
 		} while (it < buf.size());
 
@@ -1110,7 +1110,7 @@ void CCreatureHandler::loadMindImmunity(Bonus & b, BonusList & bl, std::string &
 	for (int g=0; g < mindSpells.size(); ++g)
 	{
 		b.subtype = mindSpells[g];
-		cre->bonuses.push_back(new Bonus(b));
+		cre->getBonusList().push_back(new Bonus(b));
 	}
 }
 
@@ -1151,9 +1151,9 @@ int CCreatureHandler::pickRandomMonster(const boost::function<int()> &randGen, i
 	{
 		assert(iswith(tier, 1, 7));
 		std::vector<int> allowed;
-		BOOST_FOREACH(const CBonusSystemNode *b, creaturesOfLevel[tier].children)
+		BOOST_FOREACH(const CBonusSystemNode *b, creaturesOfLevel[tier].getChildrenNodes())
 		{
-			assert(b->nodeType == CBonusSystemNode::CREATURE);
+			assert(b->getNodeType() == CBonusSystemNode::CREATURE);
 			int creid = static_cast<const CCreature*>(b)->idNumber;
 			if(!vstd::contains(notUsedMonsters, creid))
 

+ 1 - 1
lib/CCreatureSet.cpp

@@ -469,7 +469,7 @@ void CStackInstance::init()
 	type = NULL;
 	idRand = -1;
 	_armyObj = NULL;
-	nodeType = STACK_INSTANCE;
+	setNodeType(STACK_INSTANCE);	
 }
 
 int CStackInstance::getQuantityID() const 

+ 3 - 3
lib/CGameState.cpp

@@ -799,7 +799,7 @@ CGameState::CGameState()
 	applierGs = new CApplier<CBaseForGSApply>;
 	registerTypes2(*applierGs);
 	objCaller = new CObjectCallersHandler;
-	globalEffects.description = "Global effects";
+	globalEffects.setDescription("Global effects");
 }
 CGameState::~CGameState()
 {
@@ -2900,7 +2900,7 @@ PlayerState::PlayerState()
  : color(-1), currentSelection(0xffffffff), enteredWinningCheatCode(0), 
    enteredLosingCheatCode(0), status(INGAME), daysWithoutCastle(0)
 {
-	nodeType = PLAYER;
+	setNodeType(PLAYER);
 }
 
 std::string PlayerState::nodeName() const
@@ -3022,5 +3022,5 @@ DuelParameters::DuelParameters()
 
 TeamState::TeamState()
 {
-	nodeType = TEAM;
+	setNodeType(TEAM);
 }

+ 1 - 1
lib/CGameState.h

@@ -182,7 +182,7 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & color & human & currentSelection & team & resources & status;
-		h & heroes & towns & availableHeroes & dwellings & bonuses;
+		h & heroes & towns & availableHeroes & dwellings & getBonusList();
 		h & status & daysWithoutCastle;
 		h & enteredLosingCheatCode & enteredWinningCheatCode;
 		h & static_cast<CBonusSystemNode&>(*this);

+ 8 - 8
lib/CObjectHandler.cpp

@@ -722,7 +722,7 @@ int CGHeroInstance::maxMovePoints(bool onLand) const
 CGHeroInstance::CGHeroInstance()
  : IBoatGenerator(this)
 {
-	nodeType = HERO;
+	setNodeType(HERO);
 	ID = HEROI_TYPE;
 	tacticFormationEnabled = inTownGarrison = false;
 	mana = movement = portrait = level = -1;
@@ -733,7 +733,7 @@ CGHeroInstance::CGHeroInstance()
 	type = NULL;
 	boat = NULL;
 	secSkills.push_back(std::make_pair(-1, -1));
-	speciality.nodeType = CBonusSystemNode::SPECIALITY;
+	speciality.setNodeType(CBonusSystemNode::SPECIALITY);
 	attachTo(&speciality); //do we evert need to detach it?
 }
 
@@ -1124,7 +1124,7 @@ void CGHeroInstance::UpdateSpeciality()
 	{
 		std::vector< ConstTransitivePtr<CCreature> > & creatures = VLC->creh->creatures;
 
-		BOOST_FOREACH(Bonus *it, speciality.bonuses)
+		BOOST_FOREACH(Bonus *it, speciality.getBonusList())
 		{
 			switch (it->type)
 			{
@@ -1230,7 +1230,7 @@ void CGHeroInstance::updateSkill(int which, int val)
 	
 
 	int skillValType = skillVal ? Bonus::BASE_NUMBER : Bonus::INDEPENDENT_MIN;
-	if(Bonus * b = bonuses.getFirst(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, which) && Selector::sourceType(Bonus::SECONDARY_SKILL))) //only local hero bonus
+	if(Bonus * b = getBonusList().getFirst(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, which) && Selector::sourceType(Bonus::SECONDARY_SKILL))) //only local hero bonus
 	{
 		b->val = skillVal;
 		b->valType = skillValType;
@@ -2262,7 +2262,7 @@ void CGTownInstance::deserializationFix()
 void CGTownInstance::recreateBuildingsBonuses()
 {
 	boost::shared_ptr<BonusList> bl(new BonusList);
-	exportedBonuses.getBonuses(bl, Selector::sourceType(Bonus::TOWN_STRUCTURE));
+	getExportedBonusList().getBonuses(bl, Selector::sourceType(Bonus::TOWN_STRUCTURE));
 	BOOST_FOREACH(Bonus *b, *bl)
 		removeBonus(b);
 
@@ -3704,7 +3704,7 @@ void CGArtifact::initObj()
 		subID = 1;
 
 	assert(storedArtifact->artType);
-	assert(storedArtifact->parents.size());
+	assert(storedArtifact->getParentNodes().size());
 }
 
 void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
@@ -6692,7 +6692,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
 	if(!validTypes(false)) //object not randomized, don't bother
 		return;
 
-	Bonus *b = bonuses.getFirst(Selector::sourceType(Bonus::ARMY) && Selector::type(Bonus::MORALE));
+	Bonus *b = getBonusList().getFirst(Selector::sourceType(Bonus::ARMY) && Selector::type(Bonus::MORALE));
 	if(!b)
 	{
 		b = new Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
@@ -6731,7 +6731,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
 	 
 	//-1 modifier for any Necropolis unit in army
 	const ui8 UNDEAD_MODIFIER_ID = -2;
-	Bonus *undeadModifier = bonuses.getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
+	Bonus *undeadModifier = getBonusList().getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
  	if(vstd::contains(factions,4))
 	{
 		if(!undeadModifier)

+ 178 - 55
lib/HeroBonus.cpp

@@ -25,9 +25,29 @@
 #define BONUS_LOG_LINE(x) tlog5 << x << std::endl
 
 int CBonusSystemNode::treeChanged = 1;
-const bool CBonusSystemNode::cachingEnabled = false;
+const bool CBonusSystemNode::cachingEnabled = true;
 
-int DLL_EXPORT BonusList::totalValue() const
+BonusList::BonusList(bool BelongsToTree /* =false */) : belongsToTree(BelongsToTree)
+{
+
+}
+
+BonusList::BonusList(const BonusList &bonusList)
+{
+	bonuses.resize(bonusList.size());
+	std::copy(bonusList.begin(), bonusList.end(), bonuses.begin());
+	belongsToTree = false;
+}
+
+BonusList& BonusList::operator=(const BonusList &bonusList)
+{
+	bonuses.resize(bonusList.size());
+	std::copy(bonusList.begin(), bonusList.end(), bonuses.begin());
+	belongsToTree = false;
+	return *this;
+}
+
+int BonusList::totalValue() const
 {
 	int base = 0;
 	int percentToBase = 0;
@@ -38,7 +58,7 @@ int DLL_EXPORT BonusList::totalValue() const
 	int indepMin = 0;
 	bool hasIndepMin = false;
 
-	BOOST_FOREACH(Bonus *i, *this)
+	BOOST_FOREACH(Bonus *i, bonuses)
 	{
 		switch(i->valType)
 		{
@@ -93,35 +113,35 @@ int DLL_EXPORT BonusList::totalValue() const
 
 	return valFirst;
 }
-const DLL_EXPORT Bonus * BonusList::getFirst(const CSelector &selector) const
+const Bonus * BonusList::getFirst(const CSelector &selector) const
 {
-	for (int i = 0; i < this->size(); i++)
+	for (unsigned int i = 0; i < bonuses.size(); i++)
 	{
-		const Bonus *b = (*this)[i];
+		const Bonus *b = bonuses[i];
 		if(selector(b))
 			return &*b;
 	}
 	return NULL;
 }
 
-DLL_EXPORT Bonus * BonusList::getFirst(const CSelector &select)
+Bonus * BonusList::getFirst(const CSelector &select)
 {
-	for (int i = 0; i < this->size(); i++)
+	for (unsigned int i = 0; i < bonuses.size(); i++)
 	{
-		Bonus *b = (*this)[i];
+		Bonus *b = bonuses[i];
 		if(select(b))
 			return &*b;
 	}
 	return NULL;
 }
 
-void DLL_EXPORT BonusList::getModifiersWDescr(TModDescr &out) const
+void BonusList::getModifiersWDescr(TModDescr &out) const
 {
-	BOOST_FOREACH(Bonus *i, *this)
+	BOOST_FOREACH(Bonus *i, bonuses)
 		out.push_back(std::make_pair(i->val, i->Description()));
 }
 
-void DLL_EXPORT BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector) const
+void BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector) const
 {
 // 	BOOST_FOREACH(Bonus *i, *this)
 // 		if(selector(i) && i->effectRange == Bonus::NO_LIMIT)
@@ -130,11 +150,11 @@ void DLL_EXPORT BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CS
 	getBonuses(out, selector, 0);
 }
 
-void DLL_EXPORT BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const bool caching /*= false*/) const
+void BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const bool caching /*= false*/) const
 {
-	for (int i = 0; i < this->size(); i++)
+	for (unsigned int i = 0; i < bonuses.size(); i++)
 	{
-		Bonus *b = (*this)[i];
+		Bonus *b = bonuses[i];
 
 		//add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate
 		if(caching || (selector(b) && ((!limit && b->effectRange == Bonus::NO_LIMIT) || (limit && limit(b)))))
@@ -142,16 +162,76 @@ void DLL_EXPORT BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CS
 	}
 }
 
+int BonusList::valOfBonuses(const CSelector &select) const
+{
+	boost::shared_ptr<BonusList> ret(new BonusList());
+	CSelector limit = 0;
+	getBonuses(ret, select, limit, false);
+	ret->eliminateDuplicates();
+	return ret->totalValue();
+}
+
 void BonusList::limit(const CBonusSystemNode &node)
 {
 	remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, boost::ref(node), _1));
 }
 
 
-void DLL_EXPORT BonusList::eliminateDuplicates()
+void BonusList::eliminateDuplicates()
+{
+	sort( bonuses.begin(), bonuses.end() );
+	bonuses.erase( unique( bonuses.begin(), bonuses.end() ), bonuses.end() );
+}
+
+void BonusList::push_back(Bonus* const &x)
+{
+	bonuses.push_back(x);
+	
+	if (belongsToTree)
+		CBonusSystemNode::incrementTreeChangedNum();
+}
+
+std::vector<Bonus*>::iterator BonusList::erase(std::vector<Bonus*>::const_iterator position)
+{
+	if (belongsToTree)
+		CBonusSystemNode::incrementTreeChangedNum();
+	return bonuses.erase(position);
+}
+
+void BonusList::clear()
 {
-	sort( begin(), end() );
-	erase( unique( begin(), end() ), end() );
+	bonuses.clear();
+
+	if (belongsToTree)
+		CBonusSystemNode::incrementTreeChangedNum();
+}
+
+std::vector<BonusList*>::size_type BonusList::operator-=(Bonus* const &i)
+{
+	std::vector<Bonus*>::iterator itr = std::find(bonuses.begin(), bonuses.end(), i);
+	if(itr == bonuses.end())
+		return false;
+	bonuses.erase(itr);
+
+	if (belongsToTree)
+		CBonusSystemNode::incrementTreeChangedNum();
+	return true;
+}
+
+void BonusList::resize(std::vector<Bonus*>::size_type sz, Bonus* c )
+{
+	bonuses.resize(sz, c);
+
+	if (belongsToTree)
+		CBonusSystemNode::incrementTreeChangedNum();
+}
+
+void BonusList::insert(std::vector<Bonus*>::iterator position, std::vector<Bonus*>::size_type n, Bonus* const &x)
+{
+	bonuses.insert(position, n, x);
+
+	if (belongsToTree)
+		CBonusSystemNode::incrementTreeChangedNum();
 }
 
 int IBonusBearer::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
@@ -174,24 +254,24 @@ int IBonusBearer::valOfBonuses(const CSelector &selector) const
 	boost::shared_ptr<BonusList> hlp = getAllBonuses(selector, limit, NULL);
 	return hlp->totalValue();
 }
-bool IBonusBearer::hasBonus(const CSelector &selector) const
+bool IBonusBearer::hasBonus(const CSelector &selector, const std::string &cachingStr /*= ""*/) const
 {
-	return getBonuses(selector)->size() > 0;
+	return getBonuses(selector, cachingStr)->size() > 0;
 }
 
 bool IBonusBearer::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*/) const
 {
 	CSelector s = Selector::type(type);
+	std::string cachingStr = "";
 	if(subtype != -1)
 		s = s && Selector::subtype(subtype);
 	else
 	{
-		std::string str = "type_";
-		str += ((char) type);
-		setCachingStr(str);
+		cachingStr = "type_";
+		cachingStr += ((char) type);
 	}
 
-	return hasBonus(s);
+	return hasBonus(s, cachingStr);
 }
 
 void IBonusBearer::getModifiersWDescr(TModDescr &out, Bonus::BonusType type, int subtype /*= -1 */) const
@@ -213,14 +293,14 @@ int IBonusBearer::getBonusesCount(const CSelector &selector) const
 	return getBonuses(selector)->size();
 }
 
-const boost::shared_ptr<BonusList> IBonusBearer::getBonuses(const CSelector &selector) const
+const boost::shared_ptr<BonusList> IBonusBearer::getBonuses(const CSelector &selector, const std::string &cachingStr /*= ""*/) const
 {
-	return getAllBonuses(selector, 0, NULL);
+	return getAllBonuses(selector, 0, NULL, cachingStr);
 }
 
-const boost::shared_ptr<BonusList> IBonusBearer::getBonuses(const CSelector &selector, const CSelector &limit) const
+const boost::shared_ptr<BonusList> IBonusBearer::getBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr /*= ""*/) const
 {
-	return getAllBonuses(selector, limit, NULL);
+	return getAllBonuses(selector, limit, NULL, cachingStr);
 }
 
 bool IBonusBearer::hasBonusFrom(ui8 source, ui32 sourceID) const
@@ -324,21 +404,11 @@ bool IBonusBearer::isLiving() const //TODO: theoreticaly there exists "LIVING" b
 	return(!hasBonus(Selector::type(Bonus::UNDEAD) || Selector::type(Bonus::NON_LIVING)));
 }
 
-void IBonusBearer::setCachingStr(const std::string &request) const
-{
-}
-
 const boost::shared_ptr<BonusList> IBonusBearer::getSpellBonuses() const
 {
-	std::string str = "source_";
-	str += (char) Bonus::SPELL_EFFECT;
-	setCachingStr(str);
-	return getBonuses(Selector::sourceType(Bonus::SPELL_EFFECT));
-}
-
-void CBonusSystemNode::setCachingStr(const std::string &request) const
-{
-	cachingStr = request;
+	std::string cachingStr = "source_";
+	cachingStr += (char) Bonus::SPELL_EFFECT;
+	return getBonuses(Selector::sourceType(Bonus::SPELL_EFFECT), cachingStr);
 }
 
 Bonus * CBonusSystemNode::getBonus(const CSelector &selector)
@@ -364,7 +434,7 @@ const Bonus * CBonusSystemNode::getBonus( const CSelector &selector ) const
 
 void CBonusSystemNode::getParents(TCNodes &out) const /*retreives list of parent nodes (nodes to inherit bonuses from) */
 {
-	for (int i = 0; i < parents.size(); i++)
+	for (unsigned int i = 0; i < parents.size(); i++)
 	{
 		const CBonusSystemNode *parent = parents[i];
 		out.insert(parent);
@@ -373,7 +443,7 @@ void CBonusSystemNode::getParents(TCNodes &out) const /*retreives list of parent
 
 void CBonusSystemNode::getParents(TNodes &out)
 {
-	for (int i = 0; i < parents.size(); i++)
+	for (unsigned int i = 0; i < parents.size(); i++)
 	{
 		const CBonusSystemNode *parent = parents[i];
 		out.insert(const_cast<CBonusSystemNode*>(parent));
@@ -393,11 +463,14 @@ void CBonusSystemNode::getAllBonusesRec(boost::shared_ptr<BonusList> out, const
 		out->limit(*this);
 }
 
-const boost::shared_ptr<BonusList> CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
+const boost::shared_ptr<BonusList> CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const std::string &cachingStr /*= ""*/) const
 {
 	boost::shared_ptr<BonusList> ret(new BonusList());
 	if (CBonusSystemNode::cachingEnabled)
 	{
+		static boost::mutex m;
+		boost::mutex::scoped_lock lock(m);
+
 		if (cachedLast != treeChanged)
 		{
 			getAllBonusesRec(ret, selector, limit, this, true);
@@ -414,11 +487,10 @@ const boost::shared_ptr<BonusList> CBonusSystemNode::getAllBonuses(const CSelect
 			if (cachedRequests.size() > 0 && it != cachedRequests.end())
 			{
 				ret = it->second;
-				cachingStr = "";
 				return ret;
 			}
 		}
-
+	
 		cachedBonuses.getBonuses(ret, selector, limit, false);
 		if (!root)
 			ret->limit(*this);
@@ -426,7 +498,6 @@ const boost::shared_ptr<BonusList> CBonusSystemNode::getAllBonuses(const CSelect
 		if (cachingStr != "")
 			cachedRequests[cachingStr] = ret;
 
-		cachingStr = "";
 
 		return ret;
 	}
@@ -438,7 +509,7 @@ const boost::shared_ptr<BonusList> CBonusSystemNode::getAllBonuses(const CSelect
 	}
 }
 
-CBonusSystemNode::CBonusSystemNode() : cachedLast(0), nodeType(UNKNOWN)
+CBonusSystemNode::CBonusSystemNode() : bonuses(true), exportedBonuses(true), nodeType(UNKNOWN), cachedLast(0)
 {
 }
 
@@ -452,7 +523,7 @@ CBonusSystemNode::~CBonusSystemNode()
 		while(children.size())
 			children.front()->detachFrom(this);
 	}
-
+	
 	BOOST_FOREACH(Bonus *b, exportedBonuses)
 		delete b;
 }
@@ -675,7 +746,7 @@ void CBonusSystemNode::getRedDescendants(TNodes &out)
 void CBonusSystemNode::battleTurnPassed()
 {
 	BonusList bonusesCpy = exportedBonuses; //copy, because removing bonuses invalidates iters
-	for (int i = 0; i < bonusesCpy.size(); i++)
+	for (unsigned int i = 0; i < bonusesCpy.size(); i++)
 	{
 		Bonus *b = bonusesCpy[i];
 
@@ -694,6 +765,8 @@ void CBonusSystemNode::exportBonus(Bonus * b)
 		propagateBonus(b);
 	else
 		bonuses.push_back(b);
+
+	CBonusSystemNode::treeChanged++;
 }
 
 void CBonusSystemNode::exportBonuses()
@@ -702,6 +775,56 @@ void CBonusSystemNode::exportBonuses()
 		exportBonus(b);
 }
 
+const ui8 CBonusSystemNode::getNodeType() const
+{
+	return nodeType;
+}
+
+BonusList& CBonusSystemNode::getBonusList()
+{
+	return bonuses;
+}
+
+const BonusList& CBonusSystemNode::getBonusList() const
+{
+	return bonuses;
+}
+
+const TNodesVector& CBonusSystemNode::getParentNodes() const
+{
+	return parents;
+}
+
+const TNodesVector& CBonusSystemNode::getChildrenNodes() const
+{
+	return children;
+}
+
+void CBonusSystemNode::setNodeType(ui8 type)
+{
+	nodeType = type;
+}
+
+BonusList& CBonusSystemNode::getExportedBonusList()
+{
+	return exportedBonuses;
+}
+
+const std::string& CBonusSystemNode::getDescription() const
+{
+	return description;
+}
+
+void CBonusSystemNode::setDescription(const std::string &description)
+{
+	this->description = description;
+}
+
+void CBonusSystemNode::incrementTreeChangedNum()
+{
+	treeChanged++;
+}
+
 int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
 {
 	if(obj)
@@ -888,7 +1011,7 @@ namespace Selector
 
 const CStack * retreiveStackBattle(const CBonusSystemNode *node)
 {
-	switch(node->nodeType)
+	switch(node->getNodeType())
 	{
 	case CBonusSystemNode::STACK_BATTLE:
 		return static_cast<const CStack*>(node);
@@ -899,7 +1022,7 @@ const CStack * retreiveStackBattle(const CBonusSystemNode *node)
 
 const CStackInstance * retreiveStackInstance(const CBonusSystemNode *node)
 {
-	switch(node->nodeType)
+	switch(node->getNodeType())
 	{
 	case CBonusSystemNode::STACK_INSTANCE:
 		return (static_cast<const CStackInstance *>(node));
@@ -912,7 +1035,7 @@ const CStackInstance * retreiveStackInstance(const CBonusSystemNode *node)
 
 const CCreature * retrieveCreature(const CBonusSystemNode *node)
 {
-	switch(node->nodeType)
+	switch(node->getNodeType())
 	{
 	case CBonusSystemNode::CREATURE:
 		return (static_cast<const CCreature *>(node));
@@ -926,7 +1049,7 @@ const CCreature * retrieveCreature(const CBonusSystemNode *node)
 
 DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
 {
-	for (int i = 0; i < bonusList.size(); i++)
+	for (unsigned int i = 0; i < bonusList.size(); i++)
 	{
 		Bonus *b = bonusList[i];
 		out << "Bonus " << i << "\n" << *b << std::endl;
@@ -1039,7 +1162,7 @@ CPropagatorNodeType::CPropagatorNodeType(ui8 NodeType)
 
 bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
 {
-	return nodeType == dest->nodeType;
+	return nodeType == dest->getNodeType();
 }
 
 CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter(int TerrainType) 

+ 123 - 31
lib/HeroBonus.h

@@ -4,6 +4,8 @@
 #include <set>
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/range.hpp>
+#include <boost/thread/mutex.hpp>
 
 /*
  * HeroBonus.h, part of VCMI engine
@@ -320,44 +322,107 @@ struct DLL_EXPORT Bonus
 
 DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
 
-class BonusList : public std::vector<Bonus*>
+
+class DLL_EXPORT BonusList
 {
-public:
-	int DLL_EXPORT totalValue() const; //subtype -> subtype of bonus, if -1 then any
-	void DLL_EXPORT getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const bool caching = false) const;
-	void DLL_EXPORT getModifiersWDescr(TModDescr &out) const;
+private:
+	std::vector<Bonus*> bonuses;
+	bool belongsToTree;
 
-	void DLL_EXPORT getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector) const;
+public:
+	BonusList(bool BelongsToTree = false);
+	BonusList(const BonusList &bonusList);
+	BonusList& operator=(const BonusList &bonusList); 
+
+	// wrapper functions of the STL vector container
+	std::vector<Bonus*>::size_type size() const { return bonuses.size(); }
+	void push_back(Bonus* const &x);
+	std::vector<Bonus*>::iterator erase (std::vector<Bonus*>::const_iterator position);
+	void clear();
+	void resize(std::vector<Bonus*>::size_type sz, Bonus* c = NULL );
+	void insert(std::vector<Bonus*>::iterator position, std::vector<Bonus*>::size_type n, Bonus* const &x);
+	(Bonus *const) &operator[] (std::vector<Bonus*>::size_type n) { return bonuses[n]; }
+	(Bonus *const) &operator[] (std::vector<Bonus*>::size_type n) const { return bonuses[n]; }
+	(Bonus *const) &back() { return bonuses.back(); }
+	(Bonus *const) &front() { return bonuses.front(); }
+	(Bonus *const) &back() const { return bonuses.back(); }
+	(Bonus *const) &front() const { return bonuses.front(); }
+	std::vector<Bonus*>::const_iterator begin() { return bonuses.begin(); }
+	std::vector<Bonus*>::const_iterator end() { return bonuses.end(); }
+	std::vector<Bonus*>::const_iterator begin() const { return bonuses.begin(); }
+	std::vector<Bonus*>::const_iterator end() const { return bonuses.end(); }
+	std::vector<Bonus*>::size_type operator-=(Bonus* const &i);
+
+	// BonusList functions
+	int totalValue() const; //subtype -> subtype of bonus, if -1 then any
+	void getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const bool caching = false) const;
+	void getModifiersWDescr(TModDescr &out) const;
+
+	void getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector) const;
 
 	//special find functions
-	DLL_EXPORT Bonus * getFirst(const CSelector &select);
-	DLL_EXPORT const Bonus * getFirst(const CSelector &select) const;
+	Bonus *getFirst(const CSelector &select);
+	const Bonus *getFirst(const CSelector &select) const;
+	int valOfBonuses(const CSelector &select) const;
 
 	void limit(const CBonusSystemNode &node); //erases bonuses using limitor
-	void DLL_EXPORT eliminateDuplicates();
+	void eliminateDuplicates();
 	
 	// remove_if implementation for STL vector types
 	template <class Predicate>
 	void remove_if(Predicate pred)
 	{
 		BonusList newList;
-		for (int i = 0; i < this->size(); i++)
+		for (unsigned int i = 0; i < bonuses.size(); i++)
 		{
-			Bonus *b = (*this)[i];
+			Bonus *b = bonuses[i];
 			if (!pred(b))
 				newList.push_back(b);
 		}
-		this->clear();
-		this->resize(newList.size());
-		std::copy(newList.begin(), newList.end(), this->begin());
+		bonuses.clear();
+		bonuses.resize(newList.size());
+		std::copy(newList.begin(), newList.end(), bonuses.begin());
+	}
+	
+	template <class InputIterator>
+	void insert(const int position, InputIterator first, InputIterator last)
+	{
+		bonuses.insert(bonuses.begin() + position, first, last);
+
+		if (belongsToTree)
+			CBonusSystemNode::incrementTreeChangedNum();
 	}
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<std::vector<Bonus*>&>(*this);
+		h & static_cast<std::vector<Bonus*>&>(bonuses);
 	}
+
+	friend inline std::vector<Bonus*>::iterator range_begin(BonusList & x);
+	friend inline std::vector<Bonus*>::iterator range_end(BonusList & x);
 };
 
+// Extensions for BOOST_FOREACH to enable iterating of BonusList objects
+inline std::vector<Bonus*>::iterator range_begin(BonusList & x)
+{
+	return x.bonuses.begin();
+}
+
+inline std::vector<Bonus*>::iterator range_end(BonusList & x)
+{
+	return x.bonuses.end();
+}
+
+inline std::vector<Bonus*>::const_iterator range_begin(BonusList const &x)
+{
+	return x.begin();
+}
+
+inline std::vector<Bonus*>::const_iterator range_end(BonusList const &x)
+{
+	return x.end();
+}
+
 DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
 
 class DLL_EXPORT IPropagator
@@ -404,14 +469,13 @@ public:
 	// * selector is predicate that tests if HeroBonus matches our criteria
 	// * root is node on which call was made (NULL will be replaced with this)
 	//interface
-	virtual const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const = 0; 
-	virtual void setCachingStr(const std::string &request) const;
+	virtual const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const std::string &cachingStr = "") const = 0; 
 	void getModifiersWDescr(TModDescr &out, const CSelector &selector) const;  //out: pairs<modifier value, modifier description>
 	int getBonusesCount(const CSelector &selector) const;
 	int valOfBonuses(const CSelector &selector) const;
-	bool hasBonus(const CSelector &selector) const;
-	const boost::shared_ptr<BonusList> getBonuses(const CSelector &selector, const CSelector &limit) const;
-	const boost::shared_ptr<BonusList> getBonuses(const CSelector &selector) const;
+	bool hasBonus(const CSelector &selector, const std::string &cachingStr = "") const;
+	const boost::shared_ptr<BonusList> getBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr = "") const;
+	const boost::shared_ptr<BonusList> getBonuses(const CSelector &selector, const std::string &cachingStr = "") const;
 
 	//legacy interface 
 	int valOfBonuses(Bonus::BonusType type, const CSelector &selector) const;
@@ -439,6 +503,16 @@ public:
 
 class DLL_EXPORT CBonusSystemNode : public IBonusBearer
 {
+private:
+	BonusList bonuses; //wielded bonuses (local or up-propagated here)
+	BonusList exportedBonuses; //bonuses coming from this node (wielded or propagated away)
+
+	TNodesVector parents; //parents -> we inherit bonuses from them, we may attach our bonuses to them
+	TNodesVector children;
+	
+	ui8 nodeType;
+	std::string description;
+	
 	static const bool cachingEnabled; 
 	mutable BonusList cachedBonuses;
 	mutable int cachedLast;	
@@ -447,26 +521,16 @@ class DLL_EXPORT CBonusSystemNode : public IBonusBearer
 	// Setting a value to cachingStr before getting any bonuses caches the result for later requests. 
 	// This string needs to be unique, that's why it has to be setted in the following manner:
 	// [property key]_[value] => only for selector
-	mutable std::string cachingStr;
 	mutable std::map<std::string, boost::shared_ptr<BonusList> > cachedRequests;
 
 	void getAllBonusesRec(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const bool caching = false) const;
 
 public:
-	BonusList bonuses; //wielded bonuses (local or up-propagated here)
-	BonusList exportedBonuses; //bonuses coming from this node (wielded or propagated away)
-
-	TNodesVector parents; //parents -> we inherit bonuses from them, we may attach our bonuses to them
-	TNodesVector children;
-
-	ui8 nodeType;
-	std::string description;
 
 	explicit CBonusSystemNode();
 	virtual ~CBonusSystemNode();
 	
-	const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const;
-	void setCachingStr(const std::string &request) const;
+	const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const std::string &cachingStr = "") const;
 	void getParents(TCNodes &out) const;  //retrieves list of parent nodes (nodes to inherit bonuses from),
 	const Bonus *getBonus(const CSelector &selector) const;
 
@@ -504,6 +568,17 @@ public:
 	void deserializationFix();
 	void exportBonus(Bonus * b);
 	void exportBonuses();
+	
+	static void incrementTreeChangedNum();
+	BonusList &getBonusList();
+	const BonusList &getBonusList() const;
+	BonusList &getExportedBonusList();
+	const ui8 getNodeType() const;
+	void setNodeType(ui8 type);
+	const TNodesVector &getParentNodes() const;
+	const TNodesVector &getChildrenNodes() const;
+	const std::string &getDescription() const;
+	void setDescription(const std::string &description);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -754,3 +829,20 @@ namespace Selector
 }
 
 extern DLL_EXPORT const std::map<std::string, int> bonusNameMap;
+
+
+// Extensions for BOOST_FOREACH to enable iterating of BonusList objects
+namespace boost
+{
+	template<>
+	struct range_mutable_iterator<BonusList>
+	{
+		typedef std::vector<Bonus*>::iterator type;
+	};
+
+	template<>
+	struct range_const_iterator<::BonusList>
+	{
+		typedef std::vector<Bonus*>::const_iterator type;
+	};
+}

+ 4 - 4
lib/IGameCallback.cpp

@@ -515,7 +515,7 @@ void CPrivilagedInfoCallback::getAllowedSpells(std::vector<ui16> &out, ui16 leve
 {
 
 	CSpell *spell;
-	for (int i = 0; i < gs->map->allowedSpell.size(); i++) //spellh size appears to be greater (?)
+	for (unsigned int i = 0; i < gs->map->allowedSpell.size(); i++) //spellh size appears to be greater (?)
 	{
 		spell = VLC->spellh->spells[i];
 		if (isAllowed (0, spell->id) && spell->level == level)
@@ -974,7 +974,7 @@ int CGameInfoCallback::getHeroCount( int player, bool includeGarrisoned ) const
 	if(includeGarrisoned)
 		return p->heroes.size();
 	else
-		for(int i=0; i < p->heroes.size(); i++)
+		for(unsigned int i = 0; i < p->heroes.size(); i++)
 			if(!p->heroes[i]->inTownGarrison)
 				ret++;
 	return ret;
@@ -1018,7 +1018,7 @@ std::vector < const CGTownInstance *> CPlayerSpecificInfoCallback::getTownsInfo(
 	std::vector < const CGTownInstance *> ret = std::vector < const CGTownInstance *>();
 	for ( std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end();i++)
 	{
-		for (size_t j=0; j < (*i).second.towns.size(); ++j)
+		for (size_t j = 0; j < (*i).second.towns.size(); ++j)
 		{
 			if ((*i).first==player  
 				|| (isVisible((*i).second.towns[j],player) && !onlyOur))
@@ -1205,7 +1205,7 @@ void IGameEventRealizer::setObjProperty(int objid, int prop, si64 val)
 	SetObjectProperty sob;
 	sob.id = objid;
 	sob.what = prop;
-	sob.val = val;
+	sob.val = static_cast<ui32>(val);
 	commitPackage(&sob);
 }
 

+ 21 - 14
lib/NetPacksLib.cpp

@@ -217,14 +217,21 @@ DLL_EXPORT void PlayerEndsGame::applyGs( CGameState *gs )
 
 DLL_EXPORT void RemoveBonus::applyGs( CGameState *gs )
 {
-	BonusList &bonuses = (who == HERO ? gs->getHero(whoID)->bonuses : gs->getPlayer(whoID)->bonuses);
+	CBonusSystemNode *node;
+	if (who == HERO)
+		node = gs->getHero(whoID);
+	else
+		node = gs->getPlayer(whoID);
 
-	for(BonusList::iterator i = bonuses.begin(); i != bonuses.end(); i++)
+	BonusList &bonuses = node->getBonusList();
+	
+	for (int i = 0; i < bonuses.size(); i++)
 	{
-		if((*i)->source == source && (*i)->sid == id)
+		Bonus *b = bonuses[i];
+		if(b->source == source && b->sid == id)
 		{
-			bonus = **i; //backup bonus (to show to interfaces later)
-			bonuses.erase(i);
+			bonus = *b; //backup bonus (to show to interfaces later)
+			bonuses.erase(bonuses.begin() + i);
 			break;
 		}
 	}
@@ -513,7 +520,7 @@ DLL_EXPORT void NewArtifact::applyGs( CGameState *gs )
 	assert(!vstd::contains(gs->map->artInstances, art));
 	gs->map->addNewArtifactInstance(art);
 
-	assert(!art->parents.size());
+	assert(!art->getParentNodes().size());
 	art->setType(art->artType);
 	if (CCombinedArtifactInstance* cart = dynamic_cast<CCombinedArtifactInstance*>(art.get()))
 		cart->createConstituents();
@@ -922,7 +929,7 @@ DLL_EXPORT void BattleSetActiveStack::applyGs( CGameState *gs )
 		}
 
 	//remove bonuses that last until when stack gets new turn
-	st->bonuses.remove_if(Bonus::UntilGetsTurn);
+	st->getBonusList().remove_if(Bonus::UntilGetsTurn);
 
 	if(vstd::contains(st->state,MOVED)) //if stack is moving second time this turn it must had a high morale bonus
 		st->state.insert(HAD_MORALE);
@@ -946,11 +953,11 @@ void BattleResult::applyGs( CGameState *gs )
 	CGHeroInstance *h;
 	h = gs->curB->heroes[0];
 	if(h)
-		h->bonuses.remove_if(Bonus::OneBattle);
+		h->getBonusList().remove_if(Bonus::OneBattle);
 
 	h = gs->curB->heroes[1];
 	if(h) 
-		h->bonuses.remove_if(Bonus::OneBattle);
+		h->getBonusList().remove_if(Bonus::OneBattle);
 
 	if (STACK_EXP)
 	{
@@ -1018,12 +1025,12 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
 	BOOST_FOREACH(BattleStackAttacked stackAttacked, bsa)
 		stackAttacked.applyGs(gs);
 
-	attacker->bonuses.remove_if(Bonus::UntilAttack);
+	attacker->getBonusList().remove_if(Bonus::UntilAttack);
 
 	for(std::vector<BattleStackAttacked>::const_iterator it = bsa.begin(); it != bsa.end(); ++it)
 	{
 		CStack * stack = gs->curB->getStack(it->stackAttacked, false);
-		stack->bonuses.remove_if(Bonus::UntilBeingAttacked);
+		stack->getBonusList().remove_if(Bonus::UntilBeingAttacked);
 	}
 }
 
@@ -1160,7 +1167,7 @@ void actualizeEffect(CStack * s, const std::vector<Bonus> & ef)
 
 	BOOST_FOREACH(const Bonus &fromEffect, ef)
 	{
-		BOOST_FOREACH(Bonus *stackBonus, s->bonuses) //TODO: optimize
+		BOOST_FOREACH(Bonus *stackBonus, s->getBonusList()) //TODO: optimize
 		{
 			if(stackBonus->source == Bonus::SPELL_EFFECT && stackBonus->type == fromEffect.type && stackBonus->subtype == fromEffect.subtype)
 			{
@@ -1171,7 +1178,7 @@ void actualizeEffect(CStack * s, const std::vector<Bonus> & ef)
 }
 void actualizeEffect(CStack * s, const Bonus & ef)
 {
-	BOOST_FOREACH(Bonus *stackBonus, s->bonuses) //TODO: optimize
+	BOOST_FOREACH(Bonus *stackBonus, s->getBonusList()) //TODO: optimize
 	{
 		if(stackBonus->source == Bonus::SPELL_EFFECT && stackBonus->type == ef.type && stackBonus->subtype == ef.subtype)
 		{
@@ -1279,7 +1286,7 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
 // 			}
 			
 			//removing all features from negative spells
-			BonusList tmpFeatures = changedStack->bonuses;
+			const BonusList tmpFeatures = changedStack->getBonusList();
 			//changedStack->bonuses.clear();
 
 			BOOST_FOREACH(Bonus *b, tmpFeatures)