Index: lib/IGameCallback.cpp
===================================================================
--- lib/IGameCallback.cpp	(revision 2753)
+++ lib/IGameCallback.cpp	(working copy)
@@ -199,7 +199,7 @@
 	return gs->curB->battlefieldType;
 }
 
-// int CBattleInfoCallback::battleGetObstaclesAtTile(BattleHex tile) //returns bitfield 
+// int CBattleInfoCallback::battleGetObstaclesAtTile(BattleHex tile) //returns bitfield
 // {
 // 	//TODO - write
 // 	return -1;
@@ -294,7 +294,7 @@
     }
 }
 
-std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable)
+std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable, bool ignoreTactics)
 {
 	//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	if(!gs->curB)
@@ -302,7 +302,7 @@
 		tlog2<<"battleGetAvailableHexes called when there is no battle!"<<std::endl;
 		return std::vector<BattleHex>();
 	}
-	return gs->curB->getAccessibility(stack, addOccupiable, attackable);
+	return gs->curB->getAccessibility(stack, addOccupiable, attackable, false, ignoreTactics);
 	//return gs->battleGetRange(ID);
 }
 
@@ -435,7 +435,7 @@
 		return 0;
 
 	//TODO move to config file
-	static const int dmgs[] = {70, 70, -1, 
+	static const int dmgs[] = {70, 70, -1,
 								90, 70, 90,
 								70, 90, 70};
 	if(gs->curB->town->subID < ARRAY_COUNT(dmgs))
@@ -444,7 +444,7 @@
 }
 
 CGameState * CPrivilagedInfoCallback::gameState ()
-{ 
+{
 	return gs;
 }
 
@@ -499,7 +499,7 @@
 				double distance = pos.dist2d(int3(xd,yd,pos.z)) - 0.5;
 				if(distance <= radious)
 				{
-					if(player < 0 
+					if(player < 0
 						|| (mode == 1  && team->fogOfWarMap[xd][yd][pos.z]==0)
 						|| (mode == -1 && team->fogOfWarMap[xd][yd][pos.z]==1)
 					)
@@ -523,7 +523,7 @@
 	std::vector<int> floors;
 	if(level == -1)
 	{
-		
+
 		for (int xd = 0; xd <= gs->map->width - 1; xd++)
 		for(int b=0; b<gs->map->twoLevel + 1; ++b) //if gs->map->twoLevel is false then false (0) + 1 is 1, if it's true (1) then we have 2
 		{
@@ -798,7 +798,7 @@
 bool CGameInfoCallback::getHeroInfo( const CGObjectInstance *hero, InfoAboutHero &dest ) const
 {
 	const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(hero);
-	
+
 	ERROR_RET_VAL_IF(!h, "That's not a hero!", false);
 	ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false);
 
@@ -878,7 +878,7 @@
 // 	const CArmedInstance *armi = dynamic_cast<const CArmedInstance*>(obj);
 // 	if(!armi)
 // 		return NULL;
-// 	else 
+// 	else
 // 		return armi;
 // }
 
@@ -938,7 +938,7 @@
 	ret.resize(gs->players[player].availableHeroes.size());
 	std::copy(gs->players[player].availableHeroes.begin(),gs->players[player].availableHeroes.end(),ret.begin());
 	return ret;
-}	
+}
 
 const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
 {
@@ -996,7 +996,7 @@
 	else if(ID == 6) //shipyard
 	{
 		const TerrainTile *tile = getTile(t->bestLocation());
-		
+
 		if(!tile || tile->tertype != TerrainTile::water )
 			ret = EBuildingState::NO_WATER; //lack of water
 	}
@@ -1079,7 +1079,7 @@
 	int ret = 0;
 	const PlayerState *p = gs->getPlayer(player);
 	ERROR_RET_VAL_IF(!p, "No such player!", -1);
-	
+
 	if(includeGarrisoned)
 		return p->heroes.size();
 	else
@@ -1135,7 +1135,7 @@
 	{
 		for (size_t j = 0; j < (*i).second.towns.size(); ++j)
 		{
-			if ((*i).first==player  
+			if ((*i).first==player
 				|| (isVisible((*i).second.towns[j],player) && !onlyOur))
 			{
 				ret.push_back((*i).second.towns[j]);
Index: lib/BattleState.cpp
===================================================================
--- lib/BattleState.cpp	(revision 2753)
+++ lib/BattleState.cpp	(working copy)
@@ -107,7 +107,7 @@
 {
 	for(ui32 g=0; g<stacks.size(); ++g)
 	{
-		if(stacks[g]->position == tileID 
+		if(stacks[g]->position == tileID
 			|| (stacks[g]->doubleWide() && stacks[g]->attackerOwned && stacks[g]->position-1 == tileID)
 			|| (stacks[g]->doubleWide() && !stacks[g]->attackerOwned && stacks[g]->position+1 == tileID))
 		{
@@ -234,8 +234,8 @@
 	for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
 		predecessor[b] = -1;
 	for(int g=0; g<GameConstants::BFIELD_SIZE; ++g)
-		dists[g] = 100000000;	
-	
+		dists[g] = 100000000;
+
 	std::queue< std::pair<BattleHex, bool> > hexq; //bfs queue <hex, accessible> (second filed used only if fillPredecessors is true)
 	hexq.push(std::make_pair(start, true));
 	dists[hexq.front().first] = 0;
@@ -269,7 +269,7 @@
 	}
 };
 
-std::vector<BattleHex> BattleInfo::getAccessibility( const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable /*= NULL*/, bool forPassingBy /*= false*/ ) const
+std::vector<BattleHex> BattleInfo::getAccessibility( const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable /*= NULL*/, bool forPassingBy /*= false*/, bool ignoreTactics ) const
 {
 	std::vector<BattleHex> ret;
 	bool ac[GameConstants::BFIELD_SIZE];
@@ -313,11 +313,11 @@
 					ac[v] = false;
 		}
 	}
-	
+
 	for (int i = 0; i < GameConstants::BFIELD_SIZE; ++i)
 	{
 		bool rangeFits;
-		if (tacticDistance)
+		if (tacticDistance && !ignoreTactics)
 		{
 			rangeFits = pr[i] >= 0; //reachable in terms of obstacles
 			if(!forPassingBy) //only if we're passing through, we may step out of the tactic range -> otherwise check range
@@ -326,7 +326,7 @@
 		else
 			rangeFits = dist[i] <= stack->Speed(0, true); //we can reach the stack
 
-		if(	( !addOccupiable && rangeFits && ac[i] ) 
+		if(	( !addOccupiable && rangeFits && ac[i] )
 			|| ( addOccupiable && rangeFits && isAccessible(i, ac, stack->doubleWide(), stack->attackerOwned, stack->hasBonusOfType(Bonus::FLYING), true) )//we can reach it
 			|| (vstd::contains(occupyable, i) && (!tacticDistance && dist[ i + (stack->attackerOwned ? 1 : -1 ) ] <= stack->Speed(0, true) ) && ac[i + (stack->attackerOwned ? 1 : -1 )] ) //it's occupyable and we can reach adjacent hex
 			)
@@ -366,14 +366,14 @@
 
 				continue;
 			}
-			
 
+
 			BOOST_FOREACH(BattleHex he, occupiedBySecond)
 			{
 				if(HLP::meleeAttackable(he, ret))
 					attackable->push_back(he);
 			}
-				
+
 		}
 	}
 
@@ -454,7 +454,7 @@
 	int dist[GameConstants::BFIELD_SIZE]; //calculated distances
 
 	makeBFS(start, accessibility, predecessor, dist, twoHex, attackerOwned, flyingCreature, false);
-	
+
 	if(predecessor[dest] == -1) //cannot reach destination
 	{
 		return std::make_pair(std::vector<BattleHex>(), 0);
@@ -476,7 +476,7 @@
 	bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg ) const
 {
 	double additiveBonus = 1.0, multBonus = 1.0,
-		minDmg = attacker->getMinDamage() * attackerCount, 
+		minDmg = attacker->getMinDamage() * attackerCount,
 		maxDmg = attacker->getMaxDamage() * attackerCount;
 
 	if(attacker->getCreature()->idNumber == 149) //arrow turret
@@ -496,8 +496,8 @@
 
 	if(attacker->hasBonusOfType(Bonus::SIEGE_WEAPON) && attacker->getCreature()->idNumber != 149) //any siege weapon, but only ballista can attack (second condition - not arrow turret)
 	{ //minDmg and maxDmg are multiplied by hero attack + 1
-		minDmg *= attackerHero->getPrimSkillLevel(0) + 1; 
-		maxDmg *= attackerHero->getPrimSkillLevel(0) + 1; 
+		minDmg *= attackerHero->getPrimSkillLevel(0) + 1;
+		maxDmg *= attackerHero->getPrimSkillLevel(0) + 1;
 	}
 
 	int attackDefenceDifference = 0;
@@ -1067,7 +1067,7 @@
 }
 
 std::pair<const CStack *, BattleHex> BattleInfo::getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const
-{	
+{
 	bool ac[GameConstants::BFIELD_SIZE];
 	std::set<BattleHex> occupyable;
 
@@ -1201,7 +1201,7 @@
 	int healedHealth;
 	if (spell->id == Spells::SACRIFICE && sacrificedStack)
 		healedHealth = (caster->getPrimSkillLevel(2) + sacrificedStack->MaxHealth() + spell->powers[caster->getSpellSchoolLevel(spell)]) * sacrificedStack->count;
-	else 
+	else
 		healedHealth = caster->getPrimSkillLevel(2) * spell->power + spell->powers[caster->getSpellSchoolLevel(spell)];
 	healedHealth = calculateSpellBonus(healedHealth, spell, caster, stack);
 	return std::min<ui32>(healedHealth, stack->MaxHealth() - stack->firstHPleft + (resurrect ? stack->baseAmount * stack->MaxHealth() : 0));
@@ -1393,7 +1393,7 @@
 bool BattleInfo::battleCanShoot(const CStack * stack, BattleHex dest) const
 {
 	if(tacticDistance) //no shooting during tactics
-		return false; 
+		return false;
 
 	const CStack *dst = getStackT(dest);
 
@@ -1446,9 +1446,9 @@
 	CStack * stack = NULL;
 	for(ui32 g=0; g<stacks.size(); ++g)
 	{
-		if(stacks[g]->position == pos 
-			|| (stacks[g]->doubleWide() 
-			&&( (stacks[g]->attackerOwned && stacks[g]->position-1 == pos) 
+		if(stacks[g]->position == pos
+			|| (stacks[g]->doubleWide()
+			&&( (stacks[g]->attackerOwned && stacks[g]->position-1 == pos)
 			||	(!stacks[g]->attackerOwned && stacks[g]->position+1 == pos)	)
 			) )
 		{
@@ -1486,7 +1486,7 @@
 void BattleInfo::localInit()
 {
 	belligerents[0]->battle = belligerents[1]->battle = this;
-	
+
 	BOOST_FOREACH(CArmedInstance *b, belligerents)
 		b->attachTo(this);
 
@@ -1620,7 +1620,7 @@
 	curB->castSpells[0] = curB->castSpells[1] = 0;
 	curB->sides[0] = armies[0]->tempOwner;
 	curB->sides[1] = armies[1]->tempOwner;
-	if(curB->sides[1] == 254) 
+	if(curB->sides[1] == 254)
 		curB->sides[1] = 255;
 
 	std::vector<CStack*> & stacks = (curB->stacks);
@@ -1661,7 +1661,7 @@
 	CGH::readBattlePositions(positions[3]["levels"], defenderTight);
 	CGH::readBattlePositions(positions[4]["levels"], attackerCreBank);
 	CGH::readBattlePositions(positions[5]["levels"], defenderCreBank);
-	
+
 	BOOST_FOREACH (auto position, config["commanderPositions"]["field"].Vector())
 	{
 		commanderField.push_back (position.Float());
@@ -1672,7 +1672,7 @@
 	}
 
 	//battleStartpos read
-	int k = 0; //stack serial 
+	int k = 0; //stack serial
 	for(TSlots::const_iterator i = armies[0]->Slots().begin(); i!=armies[0]->Slots().end(); i++, k++)
 	{
 		int pos;
@@ -1703,7 +1703,7 @@
 	}
 
 	//shifting positions of two-hex creatures
-	for(unsigned g=0; g<stacks.size(); ++g) 
+	for(unsigned g=0; g<stacks.size(); ++g)
 	{
 		//we should do that for creature bank too
 		if(stacks[g]->doubleWide() && stacks[g]->attackerOwned)
@@ -1837,7 +1837,7 @@
 		if(r.rand(1,100) <= 40) //put cliff-like obstacle
 		{
 			RangeGenerator obidgen(0, ABSOLUTE_OBSTACLES_COUNT-1, ourRand);
-			
+
 			try
 			{
 				auto obstPtr = make_shared<CObstacleInstance>();
@@ -2069,17 +2069,17 @@
 		}
 		break;
 	}
-	
 
+
 	if(spell->id < 10) //it's adventure spell (not combat))
 		return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
 
-	if(NBonus::hasOfType(heroes[1-cside], Bonus::SPELL_IMMUNITY, spell->id)) //non - casting hero provides immunity for this spell 
+	if(NBonus::hasOfType(heroes[1-cside], Bonus::SPELL_IMMUNITY, spell->id)) //non - casting hero provides immunity for this spell
 		return ESpellCastProblem::SECOND_HEROS_SPELL_IMMUNITY;
 
 	if(battleMinSpellLevel() > spell->level) //non - casting hero stops caster from casting this spell
 		return ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED;
-	
+
 	int spellIDs[] = {66, 67, 68, 69}; //IDs of summon elemental spells (fire, earth, water, air)
 	int creIDs[] = {114, 113, 115, 112}; //(fire, earth, water, air)
 
@@ -2161,8 +2161,8 @@
 	if(spell->getTargetType() == CSpell::OBSTACLE)
 	{
 		//isObstacleOnTile(dest)
-		// 
-		// 
+		//
+		//
 		//TODO
 		//assert that it's remove obstacle
 		//rules whether we can remove spell-created obstacle
@@ -2179,7 +2179,7 @@
 	{
 		if(!deadStack && !aliveStack)
 			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
-		if(spell->id == Spells::ANIMATE_DEAD  &&  deadStack  &&  !deadStack->hasBonusOfType(Bonus::UNDEAD)) 
+		if(spell->id == Spells::ANIMATE_DEAD  &&  deadStack  &&  !deadStack->hasBonusOfType(Bonus::UNDEAD))
 			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
 		if(deadStack && deadStack->owner != player) //you can resurrect only your own stacks //FIXME: it includes alive stacks as well
 			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
@@ -2377,7 +2377,7 @@
 			case Spells::BLESS:
 			case Spells::CURSE: //undeads are immune to bless & curse
 				if (subject->hasBonusOfType(Bonus::UNDEAD))
-					return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; 
+					return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
 				break;
 			case Spells::HASTE:
 			case Spells::SLOW:
@@ -2418,7 +2418,7 @@
 			}
 				break;
 		}
-		
+
 		bool damageSpell = (vstd::contains(VLC->spellh->damageSpells, spell->id));
 
 		if (damageSpell && subject->hasBonusOfType(Bonus::DIRECT_DAMAGE_IMMUNITY))
@@ -2465,7 +2465,7 @@
 
 		if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) ||
 			( immunities->size() > 0 && immunities->totalValue() >= spell->level && spell->level))
-		{ 
+		{
 			return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
 		}
 	}
@@ -2517,8 +2517,8 @@
 		for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
 		{
 			if( (*it)->hasBonusOfType(Bonus::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
-				|| ( (*it)->count - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft 
-		> 
+				|| ( (*it)->count - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft
+		>
 		usedSpellPower * 25 + sp->powers[spellLevel]
 			)
 			{
@@ -2571,7 +2571,7 @@
 	if(stacks.size())
 	{
 		//stacks vector may be sorted not by ID and they may be not contiguous -> find stack with max ID
-		auto highestIDStack = *std::max_element(stacks.begin(), stacks.end(), 
+		auto highestIDStack = *std::max_element(stacks.begin(), stacks.end(),
 								[](const CStack *a, const CStack *b) { return a->ID < b->ID; });
 
 		return highestIDStack->ID + 1;
@@ -2592,7 +2592,7 @@
 const CStack * BattleInfo::getStackIf(boost::function<bool(const CStack*)> pred) const
 {
 	auto stackItr = range::find_if(stacks, pred);
-	return stackItr == stacks.end() 
+	return stackItr == stacks.end()
 		? NULL
 		: *stackItr;
 }
@@ -2642,7 +2642,7 @@
 }
 
 CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
-	: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),   
+	: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
 	counterAttacks(1)
 {
 	assert(base);
@@ -2708,7 +2708,7 @@
 	speed = ((100 + percentBonus) * speed)/100;
 
 	//bind effect check - doesn't influence stack initiative
-	if (useBind && getEffect(72)) 
+	if (useBind && getEffect(72))
 	{
 		return 0;
 	}
@@ -2752,11 +2752,11 @@
 }
 
 void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
-{	
+{
 	si32 power = VLC->spellh->spells[sse.sid]->powers[sse.val];
 	switch(sse.sid)
 	{
-	case 27: //shield 
+	case 27: //shield
 	 	sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
 	 	sf.back().sid = sse.sid;
 	 	break;
@@ -2970,7 +2970,7 @@
 			return position - 1;
 		else
 			return position + 1;
-	} 
+	}
 	else
 	{
 		return BattleHex::INVALID;
@@ -3147,12 +3147,12 @@
 		&& BattleHex::mutualPosition(attackerPos, defenderPos + (defender->attackerOwned ? -1 : 1)) >= 0)
 		|| (defender->doubleWide() && attacker->doubleWide()//back <=> back
 		&& BattleHex::mutualPosition(attackerPos + (attacker->attackerOwned ? -1 : 1), defenderPos + (defender->attackerOwned ? -1 : 1)) >= 0);
-		
+
 }
 
 bool CStack::ableToRetaliate() const
 {
-	return alive() 
+	return alive()
 		&& (counterAttacks > 0 || hasBonusOfType(Bonus::UNLIMITED_RETALIATIONS))
 		&& !hasBonusOfType(Bonus::SIEGE_WEAPON)
 		&& !hasBonusOfType(Bonus::HYPNOTIZED)
Index: lib/IGameCallback.h
===================================================================
--- lib/IGameCallback.h	(revision 2753)
+++ lib/IGameCallback.h	(working copy)
@@ -104,7 +104,7 @@
 	TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true); //returns stacks on battlefield
 	void getStackQueue( std::vector<const CStack *> &out, int howMany ); //returns vector of stack in order of their move sequence
     void battleGetStackCountOutsideHexes(bool *ac); // returns hexes which when in front of a stack cause us to move the amount box back
-	std::vector<BattleHex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL); //returns numbers of hexes reachable by creature with id ID
+	std::vector<BattleHex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL, bool ignoreTactics = false); //returns numbers of hexes reachable by creature with id ID
 	std::vector<int> battleGetDistances(const CStack * stack, BattleHex hex = BattleHex::INVALID, BattleHex * predecessors = NULL); //returns vector of distances to [dest hex number]
 	std::set<BattleHex> battleGetAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID);
 	bool battleCanShoot(const CStack * stack, BattleHex dest); //returns true if unit with id ID can shoot to dest
@@ -162,7 +162,7 @@
 	const PlayerState * getPlayer(int color, bool verbose = true) const;
 	int getResource(int Player, int which) const;
 	bool isVisible(int3 pos) const;
-	int getPlayerRelations(ui8 color1, ui8 color2) const;// 0 = enemy, 1 = ally, 2 = same player 
+	int getPlayerRelations(ui8 color1, ui8 color2) const;// 0 = enemy, 1 = ally, 2 = same player
 	void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object
 	int getPlayerStatus(int player) const; //-1 if no such player
 	int getCurrentPlayer() const; //player that currently makes move // TODO synchronous turns
@@ -205,7 +205,7 @@
 	int howManyTowns(int Player) const;
 	const CGTownInstance * getTownInfo(int val, bool mode)const; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial)
 	std::vector<const CGHeroInstance *> getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited
-	std::string getTavernGossip(const CGObjectInstance * townOrTavern) const; 
+	std::string getTavernGossip(const CGObjectInstance * townOrTavern) const;
 	int canBuildStructure(const CGTownInstance *t, int ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
 	std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);
 	virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;
@@ -238,7 +238,7 @@
 
 	int getResourceAmount(int type)const;
 	TResources getResourceAmount() const;
-	const std::vector< std::vector< std::vector<ui8> > > & getVisibilityMap()const; //returns visibility map 
+	const std::vector< std::vector< std::vector<ui8> > > & getVisibilityMap()const; //returns visibility map
 	const PlayerSettings * getPlayerSettings(int color) const;
 };
 
@@ -288,7 +288,7 @@
 	virtual void setOwner(int objid, ui8 owner)=0;
 	virtual void setHoverName(int objid, MetaString * name)=0;
 	virtual void changePrimSkill(int ID, int which, si64 val, bool abs=false)=0;
-	virtual void changeSecSkill(int ID, int which, int val, bool abs=false)=0; 
+	virtual void changeSecSkill(int ID, int which, int val, bool abs=false)=0;
 	virtual void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
 	virtual ui32 showBlockingDialog(BlockingDialog *iw) =0; //synchronous version of above //TODO:
 	virtual void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb) =0; //cb will be called when player closes garrison window
Index: lib/BattleState.h
===================================================================
--- lib/BattleState.h	(revision 2753)
+++ lib/BattleState.h	(working copy)
@@ -32,7 +32,7 @@
 struct DLL_LINKAGE SiegeInfo
 {
 	ui8 wallState[8]; //[0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; 1 - intact, 2 - damaged, 3 - destroyed
-	
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & wallState;
@@ -98,7 +98,7 @@
 	int getAvaliableHex(TCreature creID, bool attackerOwned, int initialPos = -1) const; //find place for summon / clone effects
 	void makeBFS(BattleHex start, bool*accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const; //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result
 	std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
-	std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
+	std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL, bool forPassingBy = false, bool ignoreTactics = false) const; //returns vector of accessible tiles (taking into account the creature range)
 
 	bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
 	shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
@@ -166,7 +166,7 @@
 };
 
 class DLL_LINKAGE CStack : public CBonusSystemNode, public CStackBasicDescriptor
-{ 
+{
 public:
 	const CStackInstance *base;
 
Index: client/BattleInterface/CBattleInterface.cpp
===================================================================
--- client/BattleInterface/CBattleInterface.cpp	(revision 2753)
+++ client/BattleInterface/CBattleInterface.cpp	(working copy)
@@ -67,6 +67,14 @@
 	}
 } cmpst2 ;
 
+std::string formatDmgRange(std::pair<ui32, ui32> dmgRange)
+{
+	if(dmgRange.first != dmgRange.second)
+		return (boost::format("%d - %d") % dmgRange.first % dmgRange.second).str();
+	else
+		return (boost::format("%d") % dmgRange.first).str();
+}
+
 static void transformPalette(SDL_Surface * surf, double rCor, double gCor, double bCor)
 {
 	SDL_Color * colorsToChange = surf->format->palette->colors;
@@ -92,8 +100,8 @@
 
 CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen)
 	: queue(NULL), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0),
-	  activeStack(NULL), stackToActivate(NULL), selectedStack(NULL), mouseHoveredStack(-1), lastMouseHoveredStackAnimationTime(-1), previouslyHoveredHex(-1),
-	  currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL),  stackCanCastSpell(false), creatureCasting(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL), sp(NULL),
+	  activeStack(NULL), stackToActivate(NULL), selectedStack(NULL), mouseHoveredStack(-1), lastMouseHoveredStackAnimationTime(-1),
+	  currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL), stackCanCastSpell(false), creatureCasting(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL), sp(NULL),
 	  siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0),
 	  givenCommand(NULL), myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL)
 
@@ -123,10 +131,10 @@
 			pos.y += queue->pos.h / 2; //center whole window
 
 		queue->moveTo(Point(pos.x, pos.y - queue->pos.h));
-// 		queue->pos.x = pos.x;
-// 		queue->pos.y = pos.y - queue->pos.h;
-//  		pos.h += queue->pos.h;
-//  		center();
+//		queue->pos.x = pos.x;
+//		queue->pos.y = pos.y - queue->pos.h;
+//		pos.h += queue->pos.h;
+//		center();
 	}
 	queue->update();
 
@@ -198,16 +206,20 @@
 	transformPalette(amountEffNeutral, 1.00, 1.00, 0.18);
 
 	////blitting menu background and terrain
-// 	blitAt(background, pos.x, pos.y);
-// 	blitAt(menu, pos.x, 556 + pos.y);
+//	blitAt(background, pos.x, pos.y);
+//	blitAt(menu, pos.x, 556 + pos.y);
 
+	labelAtkEstimate = new CLabel(400 + pos.x, 200 + pos.y, FONT_MEDIUM, TOPLEFT, Colors::Cornsilk, "");
+	labelAtkEstimate->disable();
+	labelAtkEstimate->autoRedraw = false;
+
 	//preparing buttons and console
 	bOptions = new CAdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, boost::bind(&CBattleInterface::bOptionsf,this), 3, 561, "icm003.def", SDLK_o);
 	bSurrender = new CAdventureMapButton (CGI->generaltexth->zelp[379].first, CGI->generaltexth->zelp[379].second, boost::bind(&CBattleInterface::bSurrenderf,this), 54, 561, "icm001.def", SDLK_s);
 	bFlee = new CAdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, boost::bind(&CBattleInterface::bFleef,this), 105, 561, "icm002.def", SDLK_r);
 	bFlee->block(!curInt->cb->battleCanFlee());
 	bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
-	bAutofight  = new CAdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, boost::bind(&CBattleInterface::bAutofightf,this), 157, 561, "icm004.def", SDLK_a);
+	bAutofight = new CAdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, boost::bind(&CBattleInterface::bAutofightf,this), 157, 561, "icm004.def", SDLK_a);
 	bSpell = new CAdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, boost::bind(&CBattleInterface::bSpellf,this), 645, 561, "icm005.def", SDLK_c);
 	bSpell->block(true);
 	bWait = new CAdventureMapButton (CGI->generaltexth->zelp[386].first, CGI->generaltexth->zelp[386].second, boost::bind(&CBattleInterface::bWaitf,this), 696, 561, "icm006.def", SDLK_w);
@@ -373,7 +385,7 @@
 
 	int channel = CCS->soundh->playSoundFromSet(CCS->soundh->battleIntroSounds);
 	CCS->soundh->setCallback(channel, boost::bind(&CMusicHandler::playMusicFromSet, CCS->musich, CCS->musich->battleMusics, -1));
-    memset(stackCountOutsideHexes, 1, GameConstants::BFIELD_SIZE * sizeof(bool)); //initialize array with trues
+	memset(stackCountOutsideHexes, 1, GameConstants::BFIELD_SIZE * sizeof(bool)); //initialize array with trues
 
 	currentAction = INVALID;
 	selectedAction = INVALID;
@@ -398,6 +410,7 @@
 	SDL_FreeSurface(amountEffNeutral);
 	SDL_FreeSurface(cellBorders);
 	SDL_FreeSurface(backgroundWithHexes);
+	delete labelAtkEstimate;
 	delete bOptions;
 	delete bSurrender;
 	delete bFlee;
@@ -585,13 +598,12 @@
 	{
 		if(bfield[b]->strictHovered && bfield[b]->hovered)
 		{
-			if(previouslyHoveredHex == -1) previouslyHoveredHex = b; //something to start with
-			if(currentlyHoveredHex == -1) currentlyHoveredHex = b; //something to start with
-			if(currentlyHoveredHex != b) //repair hover info
+			// clear death toll estimate of previously hovered enemy stack
+			if(currentlyHoveredHex >= 0 && currentlyHoveredHex != b)
 			{
-				previouslyHoveredHex = currentlyHoveredHex;
-				currentlyHoveredHex = b;
+				labelAtkEstimate->setTxt( "" );
 			}
+
 			//print shade
 			if(spellToCast) //when casting spell
 			{
@@ -626,7 +638,7 @@
 			{//TODO: do not check it every frame
 				if (activeStack) //highlight all attackable hexes
 				{
-					std::set<BattleHex> set = curInt->cb->battleGetAttackedHexes(activeStack, currentlyHoveredHex, attackingHex);
+					std::set<BattleHex> set = curInt->cb->battleGetAttackedHexes(activeStack, b, attackingHex);
 					BOOST_FOREACH(BattleHex hex, set)
 					{
 						int x = 14 + ((hex/GameConstants::BFIELD_WIDTH)%2==0 ? 22 : 0) + 44*(hex%GameConstants::BFIELD_WIDTH) + pos.x;
@@ -636,15 +648,25 @@
 					}
 				}
 
-				//patch by ench0: show enemy stack movement shadow
-				// activeStack == NULL means it is opponent's turn...
+				//patch by ench0
+				//	 on hover over enemy stack:
+				//		- show movement shadow of this enemy stack; and
+				//		- show estimated dmg to this enemy stack by our active stack
+				// Note: activeStack == NULL means it is opponent's turn
 				if(activeStack && settings["battle"]["stackRange"].Bool())
 				{
-					// display the movement shadow of the stack at b (i.e. stack under mouse)
+					// Do we have a stack at hex under mouse pointer and is it alive?
 					const CStack * const shere = curInt->cb->battleGetStackByPos(b, false);
 					if (shere && shere != activeStack && shere->alive())
 					{
-						std::vector<BattleHex> v = curInt->cb->battleGetAvailableHexes(shere, true );
+						// display the movement shadow of the stack at b.
+						//
+						// Note by ench0: Last bool=true indicates that we want want to display the real range
+						// of the creature even during tactics mode. Default behaviour is 'false' and that
+						// results in weird behaviour during tactics (shadow of the enemy being displayed on the
+						// attackers part of the battlefield) , which IMHO is an indication of some logic
+						// problem with the BattleInfo::getAccessibility method...
+						std::vector<BattleHex> v = curInt->cb->battleGetAvailableHexes(shere, true, NULL, true);
 						BOOST_FOREACH (BattleHex hex, v)
 						{
 							int x = 14 + ((hex / GameConstants::BFIELD_WIDTH ) % 2 == 0 ? 22 : 0) + 44 * (hex % GameConstants::BFIELD_WIDTH) + pos.x;
@@ -652,6 +674,53 @@
 							SDL_Rect temp_rect = genRect (cellShade->h, cellShade->w, x, y);
 							CSDL_Ext::blit8bppAlphaTo24bpp (cellShade, NULL, to, &temp_rect);
 						}
+
+						// if it is an enemy stack then calculate estimated damage
+						if( activeStack->owner != shere->owner )
+						{
+							// Calculate damage only once, when mouse moves over the
+							// stack for the first time (not every frame)
+							if(currentlyHoveredHex != b)
+							{
+								assert(activeStack);
+								assert(shere);
+								assert(curInt);
+								assert(curInt->cb);
+
+								TDmgRange rngEstDamage = curInt->cb->battleEstimateDamage(activeStack, shere); //calculating estimated dmg
+								ui32 iTotalStackHealth = shere->getCreature()->MaxHealth() * ( shere->count - 1 ) + shere->firstHPleft;
+								ui32 iEstDmgMin = rngEstDamage.first;
+								ui32 iEstDmgMax = rngEstDamage.second;
+								ui32 iNumCreaturesWillDieMin = 0;
+								ui32 iNumCreaturesWillDieMax = 0;
+
+								// if we can't kill even the first (possibly wounded) creature with
+								// max possible damage then we're not killing anything here
+								if( shere->firstHPleft <= iEstDmgMax )
+								{
+									iEstDmgMax -= shere->firstHPleft;
+									iNumCreaturesWillDieMax = iEstDmgMax / shere->getCreature()->MaxHealth() + 1;
+									if( iNumCreaturesWillDieMax > shere->count ) iNumCreaturesWillDieMax = shere->count;
+
+									if( shere->firstHPleft <= iEstDmgMin )
+									{
+										iEstDmgMin -= shere->firstHPleft;
+										iNumCreaturesWillDieMin = iEstDmgMin / shere->getCreature()->MaxHealth() + 1;
+										if( iNumCreaturesWillDieMin > shere->count ) iNumCreaturesWillDieMin = shere->count;
+									}
+								}
+
+								// display a label with the estimated damage to this enemy stack. The label
+								// will appear to the right of the creature.
+								{
+									std::string estDeadText = (boost::format("Kills %d to %d") % iNumCreaturesWillDieMin % iNumCreaturesWillDieMax).str();
+
+									labelAtkEstimate->setTxt( estDeadText );
+									labelAtkEstimate->pos.x = bfield[b]->pos.x + bfield[b]->pos.w;
+									labelAtkEstimate->pos.y = bfield[b]->pos.y;
+								}
+							}
+						}
 					}
 				}
 
@@ -661,6 +730,9 @@
 				SDL_Rect temp_rect = genRect(cellShade->h, cellShade->w, x, y);
 				CSDL_Ext::blit8bppAlphaTo24bpp(cellShade, NULL, to, &temp_rect);
 			}
+
+			currentlyHoveredHex = b;
+			break;
 		}
 	}
 
@@ -678,7 +750,7 @@
 	for(size_t b = 0; b < obstacles.size(); ++b)
 	{
 		const auto &oi = obstacles[b];
-		if(oi->obstacleType != CObstacleInstance::ABSOLUTE_OBSTACLE  && oi->obstacleType != CObstacleInstance::MOAT)
+		if(oi->obstacleType != CObstacleInstance::ABSOLUTE_OBSTACLE && oi->obstacleType != CObstacleInstance::MOAT)
 		{
 			//BattleHex position = CGI->heroh->obstacles.find(obstacles[b].ID)->second.getMaxBlocked(obstacles[b].pos);
 			hexToObstacle.insert(std::make_pair(oi->pos, b));
@@ -752,7 +824,7 @@
 
 		if(changedStack)
 		{
-			//we may have changed active interface (another side in hot-seat), 
+			//we may have changed active interface (another side in hot-seat),
 			// so we can't continue drawing with old setting. So we call ourselves again and end.
 			SDL_SetClipRect(to, &buf); //restoring previous clip_rect
 			show(to);
@@ -882,6 +954,7 @@
 	}
 	else
 	{
+		labelAtkEstimate->showAll(to);
 		console->showAll(to);
 		bConsoleUp->showAll(to);
 		bConsoleDown->showAll(to);
@@ -1330,7 +1403,7 @@
 	creAnims[stack->ID]->setType(CCreatureAnim::HOLDING);
 	creAnims[stack->ID]->pos = Rect(coords.x, coords.y, creAnims[stack->ID]->fullWidth, creAnims[stack->ID]->fullHeight);
 	creDir[stack->ID] = stack->attackerOwned;
-	
+
 }
 
 void CBattleInterface::stackRemoved(int stackID)
@@ -1989,7 +2062,7 @@
 	//set casting flag to true if creature can use it to not check it every time
 	const Bonus *spellcaster = s->getBonus(Selector::type(Bonus::SPELLCASTER)),
 		*randomSpellcaster = s->getBonus(Selector::type(Bonus::RANDOM_SPELLCASTER));
-	if (s->casts &&  (spellcaster || randomSpellcaster))
+	if (s->casts && (spellcaster || randomSpellcaster))
 	{
 		stackCanCastSpell = true;
 		if(randomSpellcaster)
@@ -2185,13 +2258,13 @@
 			&& !stack->hasBonusOfType(Bonus::SIEGE_WEAPON) //and not a war machine...
 	)
 	{
-        const BattleHex nextPos = stack->position + (stack->attackerOwned ? 1 : -1);
-        const bool edge = stack->position % GameConstants::BFIELD_WIDTH == (stack->attackerOwned ? GameConstants::BFIELD_WIDTH - 2 : 1);
-        const bool moveInside = !edge && !stackCountOutsideHexes[nextPos];
+		const BattleHex nextPos = stack->position + (stack->attackerOwned ? 1 : -1);
+		const bool edge = stack->position % GameConstants::BFIELD_WIDTH == (stack->attackerOwned ? GameConstants::BFIELD_WIDTH - 2 : 1);
+		const bool moveInside = !edge && !stackCountOutsideHexes[nextPos];
 		int xAdd = (stack->attackerOwned ? 220 : 202) +
-                   (stack->doubleWide() ? 44 : 0) * (stack->attackerOwned ? +1 : -1) +
-                   (moveInside ? amountNormal->w + 10 : 0) * (stack->attackerOwned ? -1 : +1);
-        int yAdd = 260 + ((stack->attackerOwned || moveInside) ? 0 : -15);
+				   (stack->doubleWide() ? 44 : 0) * (stack->attackerOwned ? +1 : -1) +
+				   (moveInside ? amountNormal->w + 10 : 0) * (stack->attackerOwned ? -1 : +1);
+		int yAdd = 260 + ((stack->attackerOwned || moveInside) ? 0 : -15);
 		//blitting amount background box
 		SDL_Surface *amountBG = NULL;
 		TBonusListPtr spellEffects = stack->getSpellBonuses();
@@ -2457,10 +2530,10 @@
 void CBattleInterface::endAction(const BattleAction* action)
 {
 	const CStack * stack = curInt->cb->battleGetStackByID(action->stackNumber);
-	//if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //activating interface when move is finished
-// 	{
-// 		activate();
-// 	}
+//	if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //activating interface when move is finished
+//	{
+//		activate();
+//	}
 	if(action->actionType == BattleAction::HERO_SPELL)
 	{
 		if(action->side)
@@ -2479,9 +2552,9 @@
 
 	//check if we should reverse stacks
 	//for some strange reason, it's not enough
-// 	std::set<const CStack *> stacks;
-// 	stacks.insert(LOCPLINT->cb->battleGetStackByID(action->stackNumber));
-// 	stacks.insert(LOCPLINT->cb->battleGetStackByPos(action->destinationTile));
+//	std::set<const CStack *> stacks;
+//	stacks.insert(LOCPLINT->cb->battleGetStackByID(action->stackNumber));
+//	stacks.insert(LOCPLINT->cb->battleGetStackByPos(action->destinationTile));
 	TStacks stacks = curInt->cb->battleGetStacks(CBattleCallback::MINE_AND_ENEMY);
 
 	BOOST_FOREACH(const CStack *s, stacks)
@@ -2495,7 +2568,7 @@
 	queue->update();
 
 	if(tacticsMode) //stack ended movement in tactics phase -> select the next one
-		bTacticNextStack(stack); 
+		bTacticNextStack(stack);
 
 	if( action->actionType == BattleAction::HERO_SPELL) //we have activated next stack after sending request that has been just realized -> blockmap due to movement has changed
 		redrawBackgroundWithHexes(activeStack);
@@ -2679,14 +2752,6 @@
 	return NO_LOCATION; //should never happen
 }
 
-std::string formatDmgRange(std::pair<ui32, ui32> dmgRange)
-{
-	if(dmgRange.first != dmgRange.second)
-		return (boost::format("%d - %d") % dmgRange.first % dmgRange.second).str();
-	else
-		return (boost::format("%d") % dmgRange.first).str();
-}
-
 bool CBattleInterface::canStackMoveHere (const CStack * activeStack, BattleHex myNumber)
 {
 	std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes (activeStack, false);
@@ -2705,17 +2770,17 @@
 	if(!myTurn) //we are not permit to do anything
 		return;
 
-	// This function handles mouse move over hexes and l-clicking on them. 
+	// This function handles mouse move over hexes and l-clicking on them.
 	// First we decide what happens if player clicks on this hex and set appropriately
 	// consoleMsg, cursorFrame/Type and prepare lambda realizeAction.
-	// 
+	//
 	// Then, depending whether it was hover/click we either call the action or set tooltip/cursor.
 
 	//used when hovering -> tooltip message and cursor to be set
 	std::string consoleMsg;
 	bool setCursor = true; //if we want to suppress setting cursor
 	int cursorType = ECursor::COMBAT, cursorFrame = ECursor::COMBAT_POINTER;
-	
+
 	//used when l-clicking -> action to be called upon the click
 	std::function<void()> realizeAction;
 
@@ -2731,7 +2796,7 @@
 		}
 		if(eventType == LCLICK && realizeAction)
 		{
-			//opening creature window shouldn't affect myTurn... 
+			//opening creature window shouldn't affect myTurn...
 			if(currentAction != CREATURE_INFO)
 			{
 				myTurn = false; //tends to crash with empty calls
@@ -2751,10 +2816,10 @@
 	bool ourStack = false;
 	if (shere)
 		ourStack = shere->owner == curInt->playerID;
-	
+
 	//TODO: handle
 	bool noStackIsHovered = true; //will cause removing a blue glow
-	
+
 	localActions.clear();
 	illegalActions.clear();
 
@@ -2762,9 +2827,9 @@
 	{
 		bool legalAction = false; //this action is legal and can't be performed
 		bool notLegal = false; //this action is not legal and should display message
-		
+
 		switch (action)
-		{ 
+		{
 			case CHOOSE_TACTICS_STACK:
 				if (shere && ourStack)
 					legalAction = true;
@@ -2836,7 +2901,7 @@
 				if (creatureCasting)
 					skill = sactive->valOfBonuses(Selector::typeSubtype(Bonus::SPELLCASTER, Spells::TELEPORT));
 				else
-					skill = getActiveHero()->getSpellSchoolLevel (CGI->spellh->spells[spellToCast->additionalInfo]); 
+					skill = getActiveHero()->getSpellSchoolLevel (CGI->spellh->spells[spellToCast->additionalInfo]);
 				//TODO: explicitely save power, skill
 				if (curInt->cb->battleCanTeleportTo(selectedStack, myNumber, skill))
 					legalAction = true;
@@ -2862,7 +2927,7 @@
 					auto tilesThatMustBeClear = sp->rangeInHexes(myNumber, hero->getSpellSchoolLevel(sp), side, &hexesOutsideBattlefield);
 					BOOST_FOREACH(BattleHex hex, tilesThatMustBeClear)
 					{
-						if(curInt->cb->battleGetStackByPos(hex)  ||  !!curInt->cb->battleGetObstacleOnPos(hex, false) 
+						if(curInt->cb->battleGetStackByPos(hex)  ||  !!curInt->cb->battleGetObstacleOnPos(hex, false)
 						 || !hex.isAvailable())
 						{
 							legalAction = false;
@@ -3052,14 +3117,14 @@
 				cursorFrame = ECursor::COMBAT_QUERY;
 				consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str();
 				realizeAction = [=]{ GH.pushInt(createCreWindow(shere, true)); };
-	
+
 				//setting console text
 				const time_t curTime = time(NULL);
 				CCreatureAnimation *hoveredStackAnim = creAnims[shere->ID];
 
 				if (shere->ID != mouseHoveredStack
 					&& curTime > lastMouseHoveredStackAnimationTime + HOVER_ANIM_DELTA
-					&& hoveredStackAnim->getType() == CCreatureAnim::HOLDING 
+					&& hoveredStackAnim->getType() == CCreatureAnim::HOLDING
 					&& hoveredStackAnim->framesInGroup(CCreatureAnim::MOUSEON) > 0)
 				{
 					hoveredStackAnim->playOnce(CCreatureAnim::MOUSEON);
@@ -3104,7 +3169,7 @@
 		cursorFrame = 0;
 		if(consoleMsg.empty() && sp)
 			consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % sp->name); //Cast %s
-		
+
 		realizeAction = [=]
 		{
 			if (secondaryTarget) //select that target now
@@ -3112,7 +3177,7 @@
 				possibleActions.clear();
 				switch (sp->id)
 				{
-					case Spells::TELEPORT: //don't cast spell yet, only select target		
+					case Spells::TELEPORT: //don't cast spell yet, only select target
 						possibleActions.push_back (TELEPORT);
 						spellToCast->selectedStack = selectedStack->ID;
 						break;
@@ -3162,7 +3227,7 @@
 bool CBattleInterface::isCastingPossibleHere (const CStack * sactive, const CStack * shere, BattleHex myNumber)
 {
 	creatureCasting = stackCanCastSpell && !spellDestSelectMode; //TODO: allow creatures to cast aimed spells
-							
+
 	bool isCastingPossible = true;
 
 	int spellID = -1;
@@ -3175,7 +3240,7 @@
 		spellID  = spellToCast->additionalInfo;
 
 	sp = NULL;
-	if (spellID >= 0) 
+	if (spellID >= 0)
 		sp = CGI->spellh->spells[spellID];
 
 	if (sp)
@@ -3444,7 +3509,7 @@
 	assert(!defname.empty());
 	//we assume here that effect graphics have the same size as the usual obstacle image
 	// -> if we know how to blit obstacle, let's blit the effect in the same place
-	Point whereTo = whereToBlitObstacleImage(imageOfObstacle(oi), oi); 
+	Point whereTo = whereToBlitObstacleImage(imageOfObstacle(oi), oi);
 	addNewAnim(new CSpellEffectAnimation(this, defname, whereTo.x, whereTo.y));
 
 	//TODO we need to wait after playing sound till it's finished, otherwise it overlaps and sounds really bad
Index: client/BattleInterface/CBattleInterface.h
===================================================================
--- client/BattleInterface/CBattleInterface.h	(revision 2753)
+++ client/BattleInterface/CBattleInterface.h	(working copy)
@@ -100,10 +100,12 @@
 		FREE_LOCATION, //used with Force Field and Fire Wall - all tiles affected by spell must be free
 		CATAPULT, HEAL, RISE_DEMONS
 	};
+
 private:
 	SDL_Surface * background, * menu, * amountNormal, * amountNegative, * amountPositive, * amountEffNeutral, * cellBorders, * backgroundWithHexes;
 	CAdventureMapButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell,
 		* bWait, * bDefence, * bConsoleUp, * bConsoleDown, *btactNext, *btactEnd;
+	CLabel * labelAtkEstimate; // a GUI element to display projected attack results when hovering mouse over enemy stack. TODO: Using CLabel is really a hack, some better-looking GUI element should be used...
 	CBattleConsole * console;
 	CBattleHero * attackingHero, * defendingHero; //fighting heroes
 	CStackQueue *queue;
@@ -184,7 +186,7 @@
 		const CBattleInterface * owner;
 	public:
 		const CGTownInstance * town; //besieged town
-		
+
 		SiegeHelper(const CGTownInstance * siegeTown, const CBattleInterface * _owner); //c-tor
 		~SiegeHelper(); //d-tor
 
@@ -287,7 +289,7 @@
 	friend class CPlayerInterface;
 	friend class CAdventureMapButton;
 	friend class CInGameConsole;
-	
+
 	friend class CBattleResultWindow;
 	friend class CBattleHero;
 	friend class CSpellEffectAnimation;
