Browse Source

* fixed crash on calculating dmg dealt by stack under Curse
* fixed crash on sea battles (obstacles data got corrupted during conversion)
* fixed crash when StupidAI had a catapult
* minor fixes and refactorings (typename for bonus list under shared ptr)

Michał W. Urbańczyk 14 years ago
parent
commit
9621cbcaa7

+ 6 - 0
AI/StupidAI/StupidAI.cpp

@@ -250,6 +250,12 @@ BattleAction CStupidAI::goTowards(const CStack * stack, THex hex)
 	dists = cb->battleGetDistances(stack, realDest, predecessors);
 	std::vector<THex> avHexes = cb->battleGetAvailableHexes(stack, false);
 
+	if(!avHexes.size())
+	{
+		print("goTowards: Stack cannot move! That's " + stack->nodeName());
+		return BattleAction::makeDefend(stack);
+	}
+
 	while(1)
 	{
 		assert(realDest.isValid());

+ 2 - 2
client/CBattleInterface.cpp

@@ -3179,7 +3179,7 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
 						boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin())->type->nameSing);
 					}
 					//The %s shrivel with age, and lose %d hit points."	
-					boost::shared_ptr<BonusList> bl = curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getBonuses(Selector::type(Bonus::STACK_HEALTH));
+					TBonusListPtr bl = curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getBonuses(Selector::type(Bonus::STACK_HEALTH));
 					bl->remove_if(Selector::source(Bonus::SPELL_EFFECT, 75));
 					boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bl->totalValue()/2));
 				}
@@ -3542,7 +3542,7 @@ void CBattleInterface::showAliveStack(const CStack *stack, SDL_Surface * to)
         int yAdd = 260 + ((stack->attackerOwned || moveInside) ? 0 : -15);
 		//blitting amount background box
 		SDL_Surface *amountBG = NULL;
-		boost::shared_ptr<BonusList> spellEffects = stack->getSpellBonuses();
+		TBonusListPtr spellEffects = stack->getSpellBonuses();
 		if(!spellEffects->size())
 		{
 			amountBG = amountNormal;

+ 5 - 5
client/CHeroWindow.cpp

@@ -44,11 +44,11 @@
 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 std::string &cachingStr /*= ""*/) const
+const TBonusListPtr 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);
-	boost::shared_ptr<BonusList> bonusesFromPickedUpArtifact;
+	TBonusListPtr out(new BonusList);
+	TBonusListPtr heroBonuses = hero->getAllBonuses(selector, limit, hero);
+	TBonusListPtr bonusesFromPickedUpArtifact;
 
 	CArtifactsOfHero::SCommonPart *cp = cww->artSets.size() ? cww->artSets.front()->commonInfo : NULL;
 	if(cp && cp->src.art && cp->src.valid() && cp->src.AOH && cp->src.AOH->getHero() == hero)
@@ -56,7 +56,7 @@ const boost::shared_ptr<BonusList> CHeroWithMaybePickedArtifact::getAllBonuses(c
 		bonusesFromPickedUpArtifact = cp->src.art->getAllBonuses(selector, limit, hero);
 	}
 	else
-		bonusesFromPickedUpArtifact = boost::shared_ptr<BonusList>(new BonusList);
+		bonusesFromPickedUpArtifact = TBonusListPtr(new BonusList);
 
 	BOOST_FOREACH(Bonus *b, *bonusesFromPickedUpArtifact)
 		*heroBonuses -= b;

+ 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 std::string &cachingStr = "") const OVERRIDE;
+	const TBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const std::string &cachingStr = "") const OVERRIDE;
 };
 
 class CHeroWindow: public CWindowWithGarrison, public CWindowWithArtifacts

+ 16 - 16
config/obstacles.json

@@ -17,7 +17,7 @@
 		{ "id": 56, "defname": "OBBHS02.DEF", "blockmap": "XXLNX", "terrains": "1100000000000000000000100", "shift_x": -8, "shift_y": 0 },
 		{ "id": 57, "defname": "OBBHS03.DEF", "blockmap": "LXXX", "terrains": "1111100000000000000000100", "shift_x": -8, "shift_y": 0 },
 		{ "id": 91, "defname": "OBBHS04.DEF", "blockmap": "XXLNXX", "terrains": "1100000000000000000000000", "shift_x": -40, "shift_y": -20 },
-		{ "id": 58, "defname": "OBBHS11A.DEF", "blockmap": "XXXLNXXX", "terrains": "100000000000000000000000", "shift_x": -8, "shift_y": 0 },
+		{ "id": 58, "defname": "OBBHS11A.DEF", "blockmap": "XXXLNXXX", "terrains": "1100000000000000000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 59, "defname": "OBBHS12B.DEF", "blockmap": "NXXLNXX", "terrains": "1100000000000000000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 60, "defname": "OBBHS14B.DEF", "blockmap": "NXLNXX", "terrains": "1111100000000000000000100", "shift_x": 36, "shift_y": 0 },
 		{ "id": 92, "defname": "OBBHS16A.DEF", "blockmap": "XLNXX", "terrains": "1100000000000000000000000", "shift_x": -8, "shift_y": -28 },
@@ -34,7 +34,7 @@
 		{ "id": 8, "defname": "OBDRK03.DEF", "blockmap": "X", "terrains": "1111110000000000000000100", "shift_x": -8, "shift_y": -8 },
 		{ "id": 9, "defname": "OBDRK04.DEF", "blockmap": "LXX", "terrains": "1111110000000000000000100", "shift_x": -8, "shift_y": 0 },
 		{ "id": 10, "defname": "OBDSH01.DEF", "blockmap": "LXX", "terrains": "1111110000000000000000100", "shift_x": -8, "shift_y": 0 },
-		{ "id": 93, "defname": "OBDSM01.DEF", "blockmap": "NNXXXLNNXXXLNNXX", "terrains": "00000000000000000000000", "shift_x": 36, "shift_y": 0 },
+		{ "id": 93, "defname": "OBDSM01.DEF", "blockmap": "NNXXXLNNXXXLNNXX", "terrains": "1100000000000000000000000", "shift_x": 36, "shift_y": 0 },
 		{ "id": 17, "defname": "OBDSM02.DEF", "blockmap": "XXLNX", "terrains": "1111100000000000000000100", "shift_x": -9, "shift_y": -2 },
 		{ "id": 18, "defname": "OBDSS17.DEF", "blockmap": "XXLNXXX", "terrains": "1111100000000000000000100", "shift_x": -8, "shift_y": 0 },
 		{ "id": 11, "defname": "OBDTF03.DEF", "blockmap": "XX", "terrains": "1111100000000000000001100", "shift_x": 14, "shift_y": 0 },
@@ -46,17 +46,17 @@
 		{ "id": 67, "defname": "OBEFS01.DEF", "blockmap": "XX", "terrains": "0000000000000000000100000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 68, "defname": "OBEFS02.DEF", "blockmap": "NXLXXX", "terrains": "0000000000000000000100000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 69, "defname": "OBEFS03.DEF", "blockmap": "LNXX", "terrains": "0000000000000000000100000", "shift_x": 0, "shift_y": 0 },
-		{ "id": 70, "defname": "OBEFS04.DEF", "blockmap": "NNXXXLNXXX", "terrains": "000000000000000000100000", "shift_x": -8, "shift_y": 0 },
+		{ "id": 70, "defname": "OBEFS04.DEF", "blockmap": "NNXXXLNXXX", "terrains": "0000000000000000000100000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 79, "defname": "OBFFS00.DEF", "blockmap": "X", "terrains": "0000000000000100000000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 80, "defname": "OBFFS01.DEF", "blockmap": "XX", "terrains": "0000000000000100000000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 81, "defname": "OBFFS02.DEF", "blockmap": "NXLXXX", "terrains": "0000000000000100000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 82, "defname": "OBFFS03.DEF", "blockmap": "XXLNXXX", "terrains": "0000000000000100000000000", "shift_x": -8, "shift_y": 0 },
-		{ "id": 83, "defname": "OBFFS04.DEF", "blockmap": "XXXLXXXX", "terrains": "000000000000100000000000", "shift_x": -8, "shift_y": -42 },
+		{ "id": 83, "defname": "OBFFS04.DEF", "blockmap": "XXXLXXXX", "terrains": "0000000000000100000000000", "shift_x": -8, "shift_y": -42 },
 		{ "id": 19, "defname": "OBGLG01.DEF", "blockmap": "XX", "terrains": "0000000000001000000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 94, "defname": "OBGRK01.DEF", "blockmap": "XX", "terrains": "0000000000001000000000000", "shift_x": 14, "shift_y": -42 },
 		{ "id": 23, "defname": "OBGRK02.DEF", "blockmap": "XX", "terrains": "0000000000001000000000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 20, "defname": "OBGRS02.DEF", "blockmap": "NXX", "terrains": "0000000000001000000000000", "shift_x": 14, "shift_y": 0 },
-		{ "id": 22, "defname": "OBGRS01.DEF", "blockmap": "XXXXLNXXXX", "terrains": "000011010001000000000000", "shift_x": -8, "shift_y": 0 },
+		{ "id": 22, "defname": "OBGRS01.DEF", "blockmap": "XXXXLNXXXX", "terrains": "0000011010001000000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 35, "defname": "OBGRS03.DEF", "blockmap": "XXXXXXX", "terrains": "1111111010000000000000100", "shift_x": 0, "shift_y": 0 },
 		{ "id": 21, "defname": "OBGST01.DEF", "blockmap": "X", "terrains": "1111111010000000000000100", "shift_x": 14, "shift_y": 0 },
 		{ "id": 61, "defname": "OBHGS00.DEF", "blockmap": "X", "terrains": "0000000000000000010000000", "shift_x": 14, "shift_y": 0 },
@@ -67,23 +67,23 @@
 		{ "id": 75, "defname": "OBLPS00.DEF", "blockmap": "X", "terrains": "0000000000000000100000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 76, "defname": "OBLPS01.DEF", "blockmap": "XX", "terrains": "0000000000000000100000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 77, "defname": "OBLPS02.DEF", "blockmap": "NXXLNX", "terrains": "0000000000000000100000000", "shift_x": 36, "shift_y": 0 },
-		{ "id": 78, "defname": "OBLPS03.DEF", "blockmap": "XXXXLNXXXX", "terrains": "000000000000000100000000", "shift_x": -8, "shift_y": 0 },
+		{ "id": 78, "defname": "OBLPS03.DEF", "blockmap": "XXXXLNXXXX", "terrains": "0000000000000000100000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 48, "defname": "OBLVS01.DEF", "blockmap": "XXLNNX", "terrains": "0000000100000000000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 49, "defname": "OBLVS02.DEF", "blockmap": "XXXLXXX", "terrains": "0000000100000000000000000", "shift_x": -8, "shift_y": 0 },
-		{ "id": 50, "defname": "OBLVS03.DEF", "blockmap": "XXXXLNXXX", "terrains": "000000100000000000000000", "shift_x": -30, "shift_y": 0 },
+		{ "id": 50, "defname": "OBLVS03.DEF", "blockmap": "XXXXLNXXX", "terrains": "0000000100000000000000000", "shift_x": -30, "shift_y": 0 },
 		{ "id": 51, "defname": "OBLVS04.DEF", "blockmap": "XXX", "terrains": "0000000100000000000000000", "shift_x": 14, "shift_y": -42 },
-		{ "id": 52, "defname": "OBLVS09.DEF", "blockmap": "XXLNXXLNNXX", "terrains": "000000100000000000000000", "shift_x": -8, "shift_y": 0 },
-		{ "id": 53, "defname": "OBLVS17.DEF", "blockmap": "NNXLXXXX", "terrains": "000000100000000000000000", "shift_x": -30, "shift_y": 0 },
-		{ "id": 54, "defname": "OBLVS22.DEF", "blockmap": "XXXLXXXX", "terrains": "000000100000000000000000", "shift_x": -30, "shift_y": 0 },
+		{ "id": 52, "defname": "OBLVS09.DEF", "blockmap": "XXLNXXLNNXX", "terrains": "0000000100000000000000000", "shift_x": -8, "shift_y": 0 },
+		{ "id": 53, "defname": "OBLVS17.DEF", "blockmap": "NNXLXXXX", "terrains": "0000000100000000000000000", "shift_x": -30, "shift_y": 0 },
+		{ "id": 54, "defname": "OBLVS22.DEF", "blockmap": "XXXLXXXX", "terrains": "0000000100000000000000000", "shift_x": -30, "shift_y": 0 },
 		{ "id": 88, "defname": "OBMCS00.DEF", "blockmap": "X", "terrains": "0000000000000001000000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 89, "defname": "OBMCS01.DEF", "blockmap": "XLNX", "terrains": "0000000000000001000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 90, "defname": "OBMCS02.DEF", "blockmap": "NXXLXX", "terrains": "0000000000000001000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 41, "defname": "OBRGS01.DEF", "blockmap": "XLXX", "terrains": "1111100000000000000001100", "shift_x": -8, "shift_y": 0 },
-		{ "id": 40, "defname": "OBRGS02.DEF", "blockmap": "NXXLNXXX", "terrains": "111100000000000000001100", "shift_x": 14, "shift_y": 0 },
+		{ "id": 40, "defname": "OBRGS02.DEF", "blockmap": "NXXLNXXX", "terrains": "1111100000000000000001100", "shift_x": 14, "shift_y": 0 },
 		{ "id": 42, "defname": "OBRGS03.DEF", "blockmap": "XXLNX", "terrains": "1111100000000000000001100", "shift_x": -8, "shift_y": 0 },
 		{ "id": 43, "defname": "OBRGS04.DEF", "blockmap": "XXLX", "terrains": "1111100000000000000001100", "shift_x": -30, "shift_y": 0 },
 		{ "id": 44, "defname": "OBRGS05.DEF", "blockmap": "NXLXX", "terrains": "1111100000000000000001100", "shift_x": -30, "shift_y": 0 },
-		{ "id": 16, "defname": "OBRGS06.DEF", "blockmap": "NXXXXXXLNNNNNNNXLNNNNNNNNX", "terrains": "11100000000000000001100", "shift_x": -30, "shift_y": -30 },
+		{ "id": 16, "defname": "OBRGS06.DEF", "blockmap": "NXXXXXXLNNNNNNNXLNNNNNNNNX", "terrains": "1111100000000000000001100", "shift_x": -30, "shift_y": -30 },
 		{ "id": 84, "defname": "OBRLS00.DEF", "blockmap": "X", "terrains": "0000000000000010000000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 85, "defname": "OBRLS01.DEF", "blockmap": "XX", "terrains": "0000000000000010000000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 86, "defname": "OBRLS02.DEF", "blockmap": "XXX", "terrains": "0000000000000010000000000", "shift_x": 14, "shift_y": 0 },
@@ -98,16 +98,16 @@
 		{ "id": 29, "defname": "OBSNS06.DEF", "blockmap": "LNXX", "terrains": "0000000001100000000000000", "shift_x": -8, "shift_y": 0 },
 		{ "id": 30, "defname": "OBSNS07.DEF", "blockmap": "XX", "terrains": "0000000001100000000000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 31, "defname": "OBSNS08.DEF", "blockmap": "LNXXX", "terrains": "0000000001100000000000000", "shift_x": 36, "shift_y": 0 },
-		{ "id": 32, "defname": "OBSNS09.DEF", "blockmap": "XXXXLNNXXXX", "terrains": "000000001100000000000000", "shift_x": -8, "shift_y": 0 },
-		{ "id": 33, "defname": "OBSNS10.DEF", "blockmap": "XXLNXLNXXLNNXXX", "terrains": "000000001100000000000000", "shift_x": -30, "shift_y": -30 },
+		{ "id": 32, "defname": "OBSNS09.DEF", "blockmap": "XXXXLNNXXXX", "terrains": "0000000001100000000000000", "shift_x": -8, "shift_y": 0 },
+		{ "id": 33, "defname": "OBSNS10.DEF", "blockmap": "XXLNXLNXXLNNXXX", "terrains": "0000000001100000000000000", "shift_x": -30, "shift_y": -30 },
 		{ "id": 45, "defname": "OBSUS01.DEF", "blockmap": "XXLXXX", "terrains": "0000000000010000000000000", "shift_x": -8, "shift_y": -42 },
 		{ "id": 46, "defname": "OBSUS02.DEF", "blockmap": "XXX", "terrains": "0000000000010000000000000", "shift_x": 14, "shift_y": -42 },
-		{ "id": 47, "defname": "OBSUS11B.DEF", "blockmap": "XXXLXXXX", "terrains": "000000000010000000000000", "shift_x": -9, "shift_y": -43 },
+		{ "id": 47, "defname": "OBSUS11B.DEF", "blockmap": "XXXLXXXX", "terrains": "0000000000010000000000000", "shift_x": -9, "shift_y": -43 },
 		{ "id": 34, "defname": "OBSWS01.DEF", "blockmap": "LNX", "terrains": "0000000000001000000000000", "shift_x": 36, "shift_y": 0 },
 		{ "id": 95, "defname": "OBSWS02.DEF", "blockmap": "XXXXXXX", "terrains": "0000000000001000000000000", "shift_x": -8, "shift_y": -42 },
 		{ "id": 36, "defname": "OBSWS03.DEF", "blockmap": "XX", "terrains": "0000000000001000000000000", "shift_x": 14, "shift_y": 0 },
 		{ "id": 37, "defname": "OBSWS04.DEF", "blockmap": "XXX", "terrains": "0000000000001000000000000", "shift_x": 14, "shift_y": 0 },
-		{ "id": 38, "defname": "OBSWS11B.DEF", "blockmap": "XXXXLXXXX", "terrains": "000000000001000000000000", "shift_x": -30, "shift_y": -40 },
+		{ "id": 38, "defname": "OBSWS11B.DEF", "blockmap": "XXXXLXXXX", "terrains": "0000000000001000000000000", "shift_x": -30, "shift_y": -40 },
 		{ "id": 39, "defname": "OBSWS13A.DEF", "blockmap": "XXXXLXX", "terrains": "0000000000001000000000000", "shift_x": 14, "shift_y": 0 }
 	]
 }

+ 19 - 11
lib/BattleState.cpp

@@ -592,9 +592,15 @@ TDmgRange BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* d
 	{
 		multBonus *= float(defender->valOfBonuses(Bonus::GENERAL_DAMAGE_REDUCTION, 1)) / 100.0f;
 	}
-	if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
+
+	TBonusListPtr curseEffects = attacker->getBonuses(Selector::type(Bonus::ALWAYS_MINIMUM_DAMAGE)); //attacker->getEffect(42);
+	TBonusListPtr blessEffects = attacker->getBonuses(Selector::type(Bonus::ALWAYS_MAXIMUM_DAMAGE)); //attacker->getEffect(43);
+	int curseBlessAdditiveModifier = blessEffects->totalValue() - curseEffects->totalValue();
+	double curseMultiplicativePenalty = curseEffects->size() ? (*std::max_element(curseEffects->begin(), curseEffects->end(), &Bonus::compareByAdditionalInfo))->additionalInfo : 0;
+
+	if(curseMultiplicativePenalty) //curse handling (partial, the rest is below)
 	{
-		multBonus *= 0.8f * float(VLC->spellh->spells[42]->powers[attacker->getEffect(42)->val]); //the second factor is 1 or 0
+		multBonus *= 1.0 - curseMultiplicativePenalty/100;
 	}
 
 	class HLP
@@ -633,14 +639,14 @@ TDmgRange BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* d
 
 	TDmgRange returnedVal;
 
-	if(attacker->getEffect(42)) //curse handling (rest)
+	if(curseEffects->size()) //curse handling (rest)
 	{
-		minDmg -= VLC->spellh->spells[42]->powers[attacker->getEffect(42)->val];
+		minDmg += curseBlessAdditiveModifier;
 		returnedVal = std::make_pair(int(minDmg), int(minDmg));
 	}
-	else if(attacker->getEffect(41)) //bless handling
+	else if(blessEffects->size()) //bless handling
 	{
-		maxDmg += VLC->spellh->spells[41]->powers[attacker->getEffect(41)->val];
+		maxDmg += curseBlessAdditiveModifier;
 		returnedVal =  std::make_pair(int(maxDmg), int(maxDmg));
 	}
 	else
@@ -1911,7 +1917,7 @@ SpellCasting::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInstance
 				break;
 			case 78:	//dispel helpful spells
 			{
-				boost::shared_ptr<BonusList> spellBon = subject->getSpellBonuses();
+				TBonusListPtr spellBon = subject->getSpellBonuses();
 				bool hasPositiveSpell = false;
 				BOOST_FOREACH(const Bonus * b, *spellBon)
 				{
@@ -1955,7 +1961,7 @@ SpellCasting::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInstance
 				return SpellCasting::STACK_IMMUNE_TO_SPELL;
 		}
 
-		boost::shared_ptr<BonusList> immunities = subject->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
+		TBonusListPtr 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);
@@ -2199,11 +2205,13 @@ void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
 		sf.back().valType = Bonus::INDEPENDENT_MAX;
 	 	sf.back().sid = sse.sid;
 	case 41: //bless
-	 	sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
+		sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
+		sf.back().valType = Bonus::INDEPENDENT_MAX;
 	 	sf.back().sid = sse.sid;
 	 	break;
 	case 42: //curse
-	 	sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.val >= 2 ? 20 : 0));
+	 	sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, power, sse.turnsRemain, sse.val >= 2 ? 20 : 0));
+		sf.back().valType = Bonus::INDEPENDENT_MAX;
 	 	sf.back().sid = sse.sid;
 	 	break;
 	case 43: //bloodlust
@@ -2434,7 +2442,7 @@ std::vector<si32> CStack::activeSpells() const
 {
 	std::vector<si32> ret;
 
-	boost::shared_ptr<BonusList> spellEffects = getSpellBonuses();
+	TBonusListPtr spellEffects = getSpellBonuses();
 	BOOST_FOREACH(const Bonus *it, *spellEffects)
 	{
 		if (!vstd::contains(ret, it->sid)) //do not duplicate spells with multiple effects

+ 1 - 1
lib/CGameState.cpp

@@ -1678,7 +1678,7 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)
 		t = static_cast<const CGTownInstance *>(stack.armyObj);
 	else if(h)
 	{	//hero speciality
-		boost::shared_ptr<BonusList> lista = h->speciality.getBonuses(Selector::typeSubtype(Bonus::SPECIAL_UPGRADE, base->idNumber));
+		TBonusListPtr lista = h->speciality.getBonuses(Selector::typeSubtype(Bonus::SPECIAL_UPGRADE, base->idNumber));
 		BOOST_FOREACH(const Bonus *it, *lista)
 		{
 			ui16 nid = it->additionalInfo;

+ 1 - 0
lib/CHeroHandler.cpp

@@ -153,6 +153,7 @@ void CHeroHandler::loadObstacles()
 		obi.defName = obs["defname"].String();
 		obi.blockmap = obs["blockmap"].String();
 		obi.allowedTerrains = obs["terrains"].String();
+		assert(obi.allowedTerrains.size() >= 25);
 		obi.posShift.first = obs["shift_x"].Float();
 		obi.posShift.second = obs["shift_y"].Float();
 

+ 3 - 3
lib/CObjectHandler.cpp

@@ -1877,12 +1877,12 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
 		ret.entries.push_back(GrowthInfo::Entry(VLC->generaltexth->allTexts[591], dwellingBonus));// \nExternal dwellings %+d
 		
 	//other *-of-legion-like bonuses (%d to growth cumulative with grail)
-	boost::shared_ptr<BonusList> bonuses = getBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level));
+	TBonusListPtr bonuses = getBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level));
 	BOOST_FOREACH(const Bonus *b, *bonuses)
 		ret.entries.push_back(GrowthInfo::Entry(b->Description() + " %+d", b->val));
 
 	//statue-of-legion-like bonus: % to base+castle
-	boost::shared_ptr<BonusList> bonuses2 = getBonuses(Selector::type(Bonus::CREATURE_GROWTH_PERCENT));
+	TBonusListPtr bonuses2 = getBonuses(Selector::type(Bonus::CREATURE_GROWTH_PERCENT));
 	BOOST_FOREACH(const Bonus *b, *bonuses2)
 		ret.entries.push_back(GrowthInfo::Entry(b->Description() + " %+d", b->val * (base + castleBonus) / 100));
 
@@ -2239,7 +2239,7 @@ void CGTownInstance::deserializationFix()
 
 void CGTownInstance::recreateBuildingsBonuses()
 {
-	boost::shared_ptr<BonusList> bl(new BonusList);
+	TBonusListPtr bl(new BonusList);
 	getExportedBonusList().getBonuses(bl, Selector::sourceType(Bonus::TOWN_STRUCTURE));
 	BOOST_FOREACH(Bonus *b, *bl)
 		removeBonus(b);

+ 12 - 12
lib/HeroBonus.cpp

@@ -147,7 +147,7 @@ void BonusList::getModifiersWDescr(TModDescr &out) const
 	}
 }
 
-void BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector) const
+void BonusList::getBonuses(TBonusListPtr out, const CSelector &selector) const
 {
 // 	BOOST_FOREACH(Bonus *i, *this)
 // 		if(selector(i) && i->effectRange == Bonus::NO_LIMIT)
@@ -156,7 +156,7 @@ void BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &se
 	getBonuses(out, selector, 0);
 }
 
-void BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const bool caching /*= false*/) const
+void BonusList::getBonuses(TBonusListPtr out, const CSelector &selector, const CSelector &limit, const bool caching /*= false*/) const
 {
 	for (unsigned int i = 0; i < bonuses.size(); i++)
 	{
@@ -170,7 +170,7 @@ void BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &se
 
 int BonusList::valOfBonuses(const CSelector &select) const
 {
-	boost::shared_ptr<BonusList> ret(new BonusList());
+	TBonusListPtr ret(new BonusList());
 	CSelector limit = 0;
 	getBonuses(ret, select, limit, false);
 	ret->eliminateDuplicates();
@@ -260,7 +260,7 @@ int IBonusBearer::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) cons
 int IBonusBearer::valOfBonuses(const CSelector &selector, const std::string &cachingStr) const
 {
 	CSelector limit = 0;
-	boost::shared_ptr<BonusList> hlp = getAllBonuses(selector, limit, NULL, cachingStr);
+	TBonusListPtr hlp = getAllBonuses(selector, limit, NULL, cachingStr);
 	return hlp->totalValue();
 }
 bool IBonusBearer::hasBonus(const CSelector &selector, const std::string &cachingStr /*= ""*/) const
@@ -303,12 +303,12 @@ int IBonusBearer::getBonusesCount(const CSelector &selector, const std::string &
 	return getBonuses(selector, cachingStr)->size();
 }
 
-const boost::shared_ptr<BonusList> IBonusBearer::getBonuses(const CSelector &selector, const std::string &cachingStr /*= ""*/) const
+const TBonusListPtr IBonusBearer::getBonuses(const CSelector &selector, const std::string &cachingStr /*= ""*/) const
 {
 	return getAllBonuses(selector, 0, NULL, cachingStr);
 }
 
-const boost::shared_ptr<BonusList> IBonusBearer::getBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr /*= ""*/) const
+const TBonusListPtr IBonusBearer::getBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr /*= ""*/) const
 {
 	return getAllBonuses(selector, limit, NULL, cachingStr);
 }
@@ -422,7 +422,7 @@ bool IBonusBearer::isLiving() const //TODO: theoreticaly there exists "LIVING" b
 	return(!hasBonus(Selector::type(Bonus::UNDEAD) || Selector::type(Bonus::NON_LIVING), cachingStr.str()));
 }
 
-const boost::shared_ptr<BonusList> IBonusBearer::getSpellBonuses() const
+const TBonusListPtr IBonusBearer::getSpellBonuses() const
 {
 	std::stringstream cachingStr;
 	cachingStr << "source_" << Bonus::SPELL_EFFECT;
@@ -468,7 +468,7 @@ void CBonusSystemNode::getParents(TNodes &out)
 	}	
 }
 
-void CBonusSystemNode::getAllBonusesRec(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const bool caching /*= false*/) const
+void CBonusSystemNode::getAllBonusesRec(TBonusListPtr out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const bool caching /*= false*/) const
 {
 	TCNodes lparents; 
 	getParents(lparents); 
@@ -478,9 +478,9 @@ void CBonusSystemNode::getAllBonusesRec(boost::shared_ptr<BonusList> out, const
 	bonuses.getBonuses(out, selector, limit, caching);
 }
 
-const boost::shared_ptr<BonusList> CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const std::string &cachingStr /*= ""*/) const
+const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const std::string &cachingStr /*= ""*/) const
 {
-	boost::shared_ptr<BonusList> ret(new BonusList());
+	TBonusListPtr ret(new BonusList());
 	if (CBonusSystemNode::cachingEnabled)
 	{
 		// Exclusive access for one thread
@@ -503,7 +503,7 @@ const boost::shared_ptr<BonusList> CBonusSystemNode::getAllBonuses(const CSelect
 		// pre-calculated bonus results. Limiters can't be cached so they have to be calculated.
 		if (cachingStr != "")
 		{
-			std::map<std::string, boost::shared_ptr<BonusList> >::iterator it(cachedRequests.find(cachingStr));
+			std::map<std::string, TBonusListPtr >::iterator it(cachedRequests.find(cachingStr));
 			if (cachedRequests.size() > 0 && it != cachedRequests.end())
 			{
 				ret = it->second;
@@ -589,7 +589,7 @@ void CBonusSystemNode::detachFrom(CBonusSystemNode *parent)
 
 void CBonusSystemNode::popBonuses(const CSelector &s)
 {
-	boost::shared_ptr<BonusList> bl(new BonusList);
+	TBonusListPtr bl(new BonusList);
 	exportedBonuses.getBonuses(bl, s);
 	BOOST_FOREACH(Bonus *b, *bl)
 		removeBonus(b);

+ 17 - 10
lib/HeroBonus.h

@@ -23,7 +23,9 @@ struct Bonus;
 class CBonusSystemNode;
 class ILimiter;
 class IPropagator;
+class BonusList;
 
+typedef boost::shared_ptr<BonusList> TBonusListPtr;
 typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions
 typedef std::set<CBonusSystemNode*> TNodes;
 typedef std::set<const CBonusSystemNode*> TCNodes;
@@ -139,7 +141,7 @@ namespace PrimarySkill
 	BONUS_NAME(HYPNOTIZED)								\
 	BONUS_NAME(ADDITIONAL_RETALIATION) /*value - number of additional retaliations*/ \
 	BONUS_NAME(MAGIC_MIRROR) /* value - chance of redirecting in %*/ \
-	BONUS_NAME(ALWAYS_MINIMUM_DAMAGE) /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal dmg]*/ \
+	BONUS_NAME(ALWAYS_MINIMUM_DAMAGE) /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage penalty (it'll subtracted from dmg), additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal minimal dmg]*/ \
 	BONUS_NAME(ALWAYS_MAXIMUM_DAMAGE) /*eg. bless effect, subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative bonus for dmg in %*/ \
 	BONUS_NAME(ATTACKS_NEAREST_CREATURE) /*while in berserk*/ \
 	BONUS_NAME(IN_FRENZY) /*value - level*/				\
@@ -272,6 +274,10 @@ struct DLL_EXPORT Bonus
 		h & duration & type & subtype & source & val & sid & description & additionalInfo & turnsRemain & valType & effectRange & limiter & propagator;
 	}
 
+	static bool compareByAdditionalInfo(const Bonus *a, const Bonus *b)
+	{
+		return a->additionalInfo < b->additionalInfo;
+	}
 	static bool OneDay(const Bonus *hb)
 	{
 		return hb->duration & Bonus::ONE_DAY;
@@ -357,10 +363,10 @@ public:
 
 	// 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 getBonuses(TBonusListPtr 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;
+	void getBonuses(TBonusListPtr out, const CSelector &selector) const;
 
 	//special find functions
 	Bonus *getFirst(const CSelector &select);
@@ -398,6 +404,7 @@ public:
 	friend inline std::vector<Bonus*>::iterator range_end(BonusList & x);
 };
 
+
 // Extensions for BOOST_FOREACH to enable iterating of BonusList objects
 // Don't touch/call this functions
 inline std::vector<Bonus*>::iterator range_begin(BonusList & x)
@@ -466,13 +473,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 std::string &cachingStr = "") const = 0; 
+	virtual const TBonusListPtr 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 std::string &cachingStr = "") const;  //out: pairs<modifier value, modifier description>
 	int getBonusesCount(const CSelector &selector, const std::string &cachingStr = "") const;
 	int valOfBonuses(const CSelector &selector, const std::string &cachingStr = "") 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;
+	const TBonusListPtr getBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr = "") const;
+	const TBonusListPtr getBonuses(const CSelector &selector, const std::string &cachingStr = "") const;
 
 	//legacy interface 
 	int valOfBonuses(Bonus::BonusType type, const CSelector &selector) const;
@@ -495,7 +502,7 @@ public:
 
 	si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
 	int getPrimSkillLevel(int id) const; //0-attack, 1-defence, 2-spell power, 3-knowledge
-	const boost::shared_ptr<BonusList> getSpellBonuses() const;
+	const TBonusListPtr getSpellBonuses() const;
 };
 
 class DLL_EXPORT CBonusSystemNode : public IBonusBearer
@@ -518,16 +525,16 @@ private:
 	// 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::map<std::string, boost::shared_ptr<BonusList> > cachedRequests;
+	mutable std::map<std::string, TBonusListPtr > cachedRequests;
 
-	void getAllBonusesRec(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const bool caching = false) const;
+	void getAllBonusesRec(TBonusListPtr out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const bool caching = false) const;
 
 public:
 
 	explicit CBonusSystemNode();
 	virtual ~CBonusSystemNode();
 	
-	const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const std::string &cachingStr = "") const;
+	const TBonusListPtr 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;
 

+ 4 - 4
server/CGameHandler.cpp

@@ -4370,7 +4370,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
 	if(attacker->hasBonusOfType(attackMode))
 	{
 		std::set<ui32> spellsToCast;
-		boost::shared_ptr<BonusList> spells = attacker->getBonuses(Selector::type(attackMode));
+		TBonusListPtr spells = attacker->getBonuses(Selector::type(attackMode));
 		BOOST_FOREACH(const Bonus *sf, *spells)
 		{
 			spellsToCast.insert (sf->subtype);
@@ -4391,7 +4391,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
 			if(oneOfAttacked == NULL) //all attacked creatures have been killed
 				return;
 			int spellLevel = 0;
-			boost::shared_ptr<BonusList> spellsByType = attacker->getBonuses(Selector::typeSubtype(attackMode, spellID));
+			TBonusListPtr spellsByType = attacker->getBonuses(Selector::typeSubtype(attackMode, spellID));
 			BOOST_FOREACH(const Bonus *sf, *spellsByType)
 			{
 				amax(spellLevel, sf->additionalInfo % 1000); //pick highest level
@@ -4452,7 +4452,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 		}
 	}
 	int acidDamage = 0;
-	boost::shared_ptr<BonusList> acidBreath = attacker->getBonuses(Selector::type(Bonus::ACID_BREATH));
+	TBonusListPtr acidBreath = attacker->getBonuses(Selector::type(Bonus::ACID_BREATH));
 	BOOST_FOREACH(const Bonus *b, *acidBreath)
 	{
 		if (b->additionalInfo > rand()%100)
@@ -4935,7 +4935,7 @@ void CGameHandler::runBattle()
 	{
 		if(gs->curB->heroes[i] && gs->curB->heroes[i]->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL))
 		{
-			boost::shared_ptr<BonusList> bl = gs->curB->heroes[i]->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL));
+			TBonusListPtr bl = gs->curB->heroes[i]->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL));
 			BOOST_FOREACH (Bonus *b, *bl)
 			{
 				handleSpellCasting(b->subtype, 3, -1, 0, gs->curB->heroes[i]->tempOwner, NULL, gs->curB->heroes[1-i], b->val, SpellCasting::HERO_CASTING, NULL);