浏览代码

* luck support
* support for distance/wall penalties & no * penalty abilities
* reworked damage calculation to fit OH3 formula better

mateuszb 15 年之前
父节点
当前提交
5d3d9689e8
共有 9 个文件被更改,包括 162 次插入53 次删除
  1. 11 1
      CCallback.cpp
  2. 6 2
      CCallback.h
  3. 1 1
      client/CAdvmapInterface.cpp
  4. 9 1
      client/CBattleInterface.cpp
  5. 1 1
      client/CPlayerInterface.cpp
  6. 1 1
      client/Client.cpp
  7. 123 41
      lib/CGameState.cpp
  8. 6 3
      lib/CGameState.h
  9. 4 2
      server/CGameHandler.cpp

+ 11 - 1
CCallback.cpp

@@ -669,7 +669,7 @@ std::pair<ui32, ui32> CCallback::battleEstimateDamage(int attackerID, int defend
 	const CStack * attacker = gs->curB->getStack(attackerID, false),
 	const CStack * attacker = gs->curB->getStack(attackerID, false),
 		* defender = gs->curB->getStack(defenderID);
 		* defender = gs->curB->getStack(defenderID);
 
 
-	return BattleInfo::calculateDmgRange(attacker, defender, attackerHero, defenderHero, battleCanShoot(attacker->ID, defender->position), 0);
+	return gs->curB->calculateDmgRange(attacker, defender, attackerHero, defenderHero, battleCanShoot(attacker->ID, defender->position), 0, false);
 }
 }
 
 
 ui8 CCallback::battleGetSiegeLevel()
 ui8 CCallback::battleGetSiegeLevel()
@@ -961,6 +961,16 @@ bool CCallback::hasAccess(int playerId) const
 	return playerId == player  ||  player < 0;
 	return playerId == player  ||  player < 0;
 }
 }
 
 
+si8 CCallback::battleHasDistancePenalty( int stackID, int destHex )
+{
+	return gs->curB->hasDistancePenalty(stackID, destHex);
+}
+
+si8 CCallback::battleHasWallPenalty( int stackID, int destHex )
+{
+	return gs->curB->hasWallPenalty(stackID, destHex);
+}
+
 InfoAboutTown::InfoAboutTown()
 InfoAboutTown::InfoAboutTown()
 {
 {
 	tType = NULL;
 	tType = NULL;

+ 6 - 2
CCallback.h

@@ -167,7 +167,7 @@ public:
 	virtual void getStackQueue( std::vector<const CStack *> &out, int howMany )=0; //returns vector of stack in order of their move sequence
 	virtual void getStackQueue( std::vector<const CStack *> &out, int howMany )=0; //returns vector of stack in order of their move sequence
 	virtual CCreature battleGetCreature(int number)=0; //returns type of creature by given number of stack
 	virtual CCreature battleGetCreature(int number)=0; //returns type of creature by given number of stack
 	//virtual bool battleMoveCreature(int ID, int dest)=0; //moves creature with id ID to dest if possible
 	//virtual bool battleMoveCreature(int ID, int dest)=0; //moves creature with id ID to dest if possible
-	virtual std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable)=0; //reutrns numbers of hexes reachable by creature with id ID
+	virtual std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable)=0; //returns numbers of hexes reachable by creature with id ID
 	virtual bool battleIsStackMine(int ID)=0; //returns true if stack with id ID belongs to caller
 	virtual bool battleIsStackMine(int ID)=0; //returns true if stack with id ID belongs to caller
 	virtual bool battleCanShoot(int ID, int dest)=0; //returns true if unit with id ID can shoot to dest
 	virtual bool battleCanShoot(int ID, int dest)=0; //returns true if unit with id ID can shoot to dest
 	virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
 	virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
@@ -177,9 +177,11 @@ public:
 	virtual int battleGetWallUnderHex(int hex)=0; //returns part of destructible wall / gate / keep under given hex or -1 if not found
 	virtual int battleGetWallUnderHex(int hex)=0; //returns part of destructible wall / gate / keep under given hex or -1 if not found
 	virtual std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID)=0; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
 	virtual std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID)=0; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
 	virtual ui8 battleGetSiegeLevel()=0; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
 	virtual ui8 battleGetSiegeLevel()=0; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
-	virtual const CGHeroInstance * battleGetFightingHero(ui8 side) const =0; //returns hero corresponding ot given side (0 - attacker, 1 - defender)
+	virtual const CGHeroInstance * battleGetFightingHero(ui8 side) const =0; //returns hero corresponding to given side (0 - attacker, 1 - defender)
 	virtual si8 battleGetStackMorale(int stackID) =0; //returns morale of given stack
 	virtual si8 battleGetStackMorale(int stackID) =0; //returns morale of given stack
 	virtual si8 battleGetStackLuck(int stackID) =0; //returns luck of given stack
 	virtual si8 battleGetStackLuck(int stackID) =0; //returns luck of given stack
+	virtual si8 battleHasDistancePenalty(int stackID, int destHex) =0; //checks if given stack has distance penalty
+	virtual si8 battleHasWallPenalty(int stackID, int destHex) =0; //checks if given stack has wall penalty
 };
 };
 
 
 struct HeroMoveDetails
 struct HeroMoveDetails
@@ -302,6 +304,8 @@ public:
 	const CGHeroInstance * battleGetFightingHero(ui8 side) const; //returns hero corresponding ot given side (0 - attacker, 1 - defender)
 	const CGHeroInstance * battleGetFightingHero(ui8 side) const; //returns hero corresponding ot given side (0 - attacker, 1 - defender)
 	si8 battleGetStackMorale(int stackID); //returns morale of given stack
 	si8 battleGetStackMorale(int stackID); //returns morale of given stack
 	si8 battleGetStackLuck(int stackID); //returns luck of given stack
 	si8 battleGetStackLuck(int stackID); //returns luck of given stack
+	si8 battleHasDistancePenalty(int stackID, int destHex); //checks if given stack has distance penalty
+	si8 battleHasWallPenalty(int stackID, int destHex); //checks if given stack has wall penalty
 
 
 //XXX hmmm _tmain on _GNUC_ wtf?
 //XXX hmmm _tmain on _GNUC_ wtf?
 //friends
 //friends

+ 1 - 1
client/CAdvmapInterface.cpp

@@ -18,7 +18,7 @@
 #include "../hch/CObjectHandler.h"
 #include "../hch/CObjectHandler.h"
 #include "../hch/CTownHandler.h"
 #include "../hch/CTownHandler.h"
 #include "../lib/map.h"
 #include "../lib/map.h"
-#include "../mapHandler.h"
+#include "mapHandler.h"
 #include "../stdafx.h"
 #include "../stdafx.h"
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/algorithm/string/replace.hpp>

+ 9 - 1
client/CBattleInterface.cpp

@@ -1757,7 +1757,15 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 					}
 					}
 					else if(curInt->cb->battleCanShoot(activeStack,myNumber)) //we can shoot enemy
 					else if(curInt->cb->battleCanShoot(activeStack,myNumber)) //we can shoot enemy
 					{
 					{
-						CGI->curh->changeGraphic(1,3);
+						if(curInt->cb->battleHasDistancePenalty(activeStack, myNumber) ||
+							curInt->cb->battleHasWallPenalty(activeStack, myNumber))
+						{
+							CGI->curh->changeGraphic(1,15);
+						}
+						else
+						{
+							CGI->curh->changeGraphic(1,3);
+						}
 						//setting console text
 						//setting console text
 						char buf[500];
 						char buf[500];
 						//calculating estimated dmg
 						//calculating estimated dmg

+ 1 - 1
client/CPlayerInterface.cpp

@@ -29,7 +29,7 @@
 #include "../lib/NetPacks.h"
 #include "../lib/NetPacks.h"
 #include "../lib/map.h"
 #include "../lib/map.h"
 #include "../lib/VCMIDirs.h"
 #include "../lib/VCMIDirs.h"
-#include "../mapHandler.h"
+#include "mapHandler.h"
 #include "../timeHandler.h"
 #include "../timeHandler.h"
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/format.hpp>
 #include <boost/format.hpp>

+ 1 - 1
client/Client.cpp

@@ -17,7 +17,7 @@
 #include "../lib/NetPacks.h"
 #include "../lib/NetPacks.h"
 #include "../lib/VCMI_Lib.h"
 #include "../lib/VCMI_Lib.h"
 #include "../lib/map.h"
 #include "../lib/map.h"
-#include "../mapHandler.h"
+#include "mapHandler.h"
 #include "CConfigHandler.h"
 #include "CConfigHandler.h"
 #include "Client.h"
 #include "Client.h"
 #include "GUIBase.h"
 #include "GUIBase.h"

+ 123 - 41
lib/CGameState.cpp

@@ -24,6 +24,8 @@
 #include <boost/thread/shared_mutex.hpp>
 #include <boost/thread/shared_mutex.hpp>
 #include <boost/assign/list_of.hpp>
 #include <boost/assign/list_of.hpp>
 #include "RegisterTypes.cpp"
 #include "RegisterTypes.cpp"
+#include <algorithm>
+#include <numeric>
 
 
 boost::rand48 ran;
 boost::rand48 ran;
 
 
@@ -2373,9 +2375,9 @@ bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom,
 	}
 	}
 	return true;
 	return true;
 }
 }
-std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge)
+std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky )
 {
 {
-	float attackDefenseBonus,
+	float additiveBonus=1.0f, multBonus=1.0f,
 		minDmg = attacker->creature->damageMin * attacker->amount, 
 		minDmg = attacker->creature->damageMin * attacker->amount, 
 		maxDmg = attacker->creature->damageMax * attacker->amount;
 		maxDmg = attacker->creature->damageMax * attacker->amount;
 
 
@@ -2400,36 +2402,37 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, cons
 		maxDmg *= attackerHero->getPrimSkillLevel(0) + 1; 
 		maxDmg *= attackerHero->getPrimSkillLevel(0) + 1; 
 	}
 	}
 
 
+	int attackDefenceDifference = 0;
 	if(attacker->hasFeatureOfType(StackFeature::GENERAL_ATTACK_REDUCTION))
 	if(attacker->hasFeatureOfType(StackFeature::GENERAL_ATTACK_REDUCTION))
 	{
 	{
 		float multAttackReduction = attacker->valOfFeatures(StackFeature::GENERAL_ATTACK_REDUCTION, -1024) / 100.0f;
 		float multAttackReduction = attacker->valOfFeatures(StackFeature::GENERAL_ATTACK_REDUCTION, -1024) / 100.0f;
-		attackDefenseBonus = attacker->Attack() * multAttackReduction;
+		attackDefenceDifference = attacker->Attack() * multAttackReduction;
 	}
 	}
 	else
 	else
 	{
 	{
-		attackDefenseBonus = attacker->Attack();
+		attackDefenceDifference = attacker->Attack();
 	}
 	}
 
 
 	if(attacker->hasFeatureOfType(StackFeature::ENEMY_DEFENCE_REDUCTION))
 	if(attacker->hasFeatureOfType(StackFeature::ENEMY_DEFENCE_REDUCTION))
 	{
 	{
 		float multDefenceReduction = (100.0f - attacker->valOfFeatures(StackFeature::ENEMY_DEFENCE_REDUCTION, -1024)) / 100.0f;
 		float multDefenceReduction = (100.0f - attacker->valOfFeatures(StackFeature::ENEMY_DEFENCE_REDUCTION, -1024)) / 100.0f;
-		attackDefenseBonus -= defender->Defense() * multDefenceReduction;
+		attackDefenceDifference -= defender->Defense() * multDefenceReduction;
 	}
 	}
 	else
 	else
 	{
 	{
-		attackDefenseBonus -= defender->Defense();
+		attackDefenceDifference -= defender->Defense();
 	}
 	}
 
 
 	//calculating total attack/defense skills modifier
 	//calculating total attack/defense skills modifier
 
 
 	if(!shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 0)) //bloodlust handling (etc.)
 	if(!shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 0)) //bloodlust handling (etc.)
 	{
 	{
-		attackDefenseBonus += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 0);
+		attackDefenceDifference += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 0);
 	}
 	}
 
 
 	if(shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 1)) //precision handling (etc.)
 	if(shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 1)) //precision handling (etc.)
 	{
 	{
-		attackDefenseBonus += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 1);
+		attackDefenceDifference += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 1);
 	}
 	}
 
 
 	if(attacker->getEffect(55)) //slayer handling
 	if(attacker->getEffect(55)) //slayer handling
@@ -2455,42 +2458,44 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, cons
 		{
 		{
 			if(defender->creature->idNumber == affectedIds[g])
 			if(defender->creature->idNumber == affectedIds[g])
 			{
 			{
-				attackDefenseBonus += VLC->spellh->spells[55].powers[attacker->getEffect(55)->level];
+				attackDefenceDifference += VLC->spellh->spells[55].powers[attacker->getEffect(55)->level];
 				break;
 				break;
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	float dmgBonusMultiplier = 1.0f;
-
-	//applying jousting bonus
-	if( attacker->hasFeatureOfType(StackFeature::JOUSTING) && !defender->hasFeatureOfType(StackFeature::CHARGE_IMMUNITY) )
-		dmgBonusMultiplier += charge * 0.05f;
-
 	//bonus from attack/defense skills
 	//bonus from attack/defense skills
-	if(attackDefenseBonus < 0) //decreasing dmg
+	if(attackDefenceDifference < 0) //decreasing dmg
 	{
 	{
-		if(0.02f * (-attackDefenseBonus) > 0.3f)
+		float dec = 0.025f * (-attackDefenceDifference);
+		if(dec > 0.7f)
 		{
 		{
-			dmgBonusMultiplier += -0.3f;
+			multBonus *= 1.0f - dec;
 		}
 		}
 		else
 		else
 		{
 		{
-			dmgBonusMultiplier += 0.02f * attackDefenseBonus;
+			multBonus *= dec;
 		}
 		}
 	}
 	}
 	else //increasing dmg
 	else //increasing dmg
 	{
 	{
-		if(0.05f * attackDefenseBonus > 4.0f)
+		float inc = 0.05f * attackDefenceDifference;
+		if(inc > 4.0f)
 		{
 		{
-			dmgBonusMultiplier += 4.0f;
+			additiveBonus += 4.0f;
 		}
 		}
 		else
 		else
 		{
 		{
-			dmgBonusMultiplier += 0.05f * attackDefenseBonus;
+			additiveBonus += inc;
 		}
 		}
 	}
 	}
+	
 
 
+	//applying jousting bonus
+	if( attacker->hasFeatureOfType(StackFeature::JOUSTING) && !defender->hasFeatureOfType(StackFeature::CHARGE_IMMUNITY) )
+		additiveBonus += charge * 0.05f;
+
+	
 	//handling secondary abilities and artifacts giving premies to them
 	//handling secondary abilities and artifacts giving premies to them
 	if(attackerHero)
 	if(attackerHero)
 	{
 	{
@@ -2499,20 +2504,20 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, cons
 			switch(attackerHero->getSecSkillLevel(1)) //archery
 			switch(attackerHero->getSecSkillLevel(1)) //archery
 			{
 			{
 			case 1: //basic
 			case 1: //basic
-				dmgBonusMultiplier += 0.1f;
+				additiveBonus += 0.1f;
 				break;
 				break;
 			case 2: //advanced
 			case 2: //advanced
-				dmgBonusMultiplier += 0.25f;
+				additiveBonus += 0.25f;
 				break;
 				break;
 			case 3: //expert
 			case 3: //expert
-				dmgBonusMultiplier += 0.5f;
+				additiveBonus += 0.5f;
 				break;
 				break;
 			}
 			}
 
 
 			if(attackerHero->getSecSkillLevel(1) > 0) //non-none level
 			if(attackerHero->getSecSkillLevel(1) > 0) //non-none level
 			{
 			{
 				//apply artifact premy to archery
 				//apply artifact premy to archery
-				dmgBonusMultiplier += attackerHero->valOfBonuses(HeroBonus::SECONDARY_SKILL_PREMY, 1) / 100.0f;
+				additiveBonus += attackerHero->valOfBonuses(HeroBonus::SECONDARY_SKILL_PREMY, 1) / 100.0f;
 			}
 			}
 		}
 		}
 		else
 		else
@@ -2520,54 +2525,85 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, cons
 			switch(attackerHero->getSecSkillLevel(22)) //offense
 			switch(attackerHero->getSecSkillLevel(22)) //offense
 			{
 			{
 			case 1: //basic
 			case 1: //basic
-				dmgBonusMultiplier += 0.1f;
+				additiveBonus += 0.1f;
 				break;
 				break;
 			case 2: //advanced
 			case 2: //advanced
-				dmgBonusMultiplier += 0.2f;
+				additiveBonus += 0.2f;
 				break;
 				break;
 			case 3: //expert
 			case 3: //expert
-				dmgBonusMultiplier += 0.3f;
+				additiveBonus += 0.3f;
 				break;
 				break;
 			}
 			}
 		}
 		}
 	}
 	}
+
 	if(defendingHero)
 	if(defendingHero)
 	{
 	{
 		switch(defendingHero->getSecSkillLevel(23)) //armorer
 		switch(defendingHero->getSecSkillLevel(23)) //armorer
 		{
 		{
 		case 1: //basic
 		case 1: //basic
-			dmgBonusMultiplier *= 0.95f;
+			multBonus *= 0.95f;
 			break;
 			break;
 		case 2: //advanced
 		case 2: //advanced
-			dmgBonusMultiplier *= 0.9f;
+			multBonus *= 0.9f;
 			break;
 			break;
 		case 3: //expert
 		case 3: //expert
-			dmgBonusMultiplier *= 0.85f;
+			multBonus *= 0.85f;
 			break;
 			break;
 		}
 		}
 	}
 	}
 
 
 	//handling hate effect
 	//handling hate effect
 	if( attacker->hasFeatureOfType(StackFeature::HATE, defender->creature->idNumber) )
 	if( attacker->hasFeatureOfType(StackFeature::HATE, defender->creature->idNumber) )
-		dmgBonusMultiplier += 0.5f;
+		additiveBonus += 0.5f;
+
+	//luck bonus
+	if (lucky)
+	{
+		additiveBonus += 1.0f;
+	}
 
 
 	//handling spell effects
 	//handling spell effects
 	if(!shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) //eg. shield
 	if(!shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) //eg. shield
 	{
 	{
-		dmgBonusMultiplier *= float(defender->valOfFeatures(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) / 100.0f;
+		multBonus *= float(defender->valOfFeatures(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) / 100.0f;
 	}
 	}
 	else if(shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 1)) //eg. air shield
 	else if(shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 1)) //eg. air shield
 	{
 	{
-		dmgBonusMultiplier *= float(defender->valOfFeatures(StackFeature::GENERAL_DAMAGE_REDUCTION, 1)) / 100.0f;
+		multBonus *= float(defender->valOfFeatures(StackFeature::GENERAL_DAMAGE_REDUCTION, 1)) / 100.0f;
 	}
 	}
 	if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
 	if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
 	{
 	{
-		dmgBonusMultiplier *= 0.8f * float(VLC->spellh->spells[42].powers[attacker->getEffect(42)->level]); //the second factor is 1 or 0
+		multBonus *= 0.8f * float(VLC->spellh->spells[42].powers[attacker->getEffect(42)->level]); //the second factor is 1 or 0
 	}
 	}
 
 
+	class HLP
+	{
+	public:
+		static bool hasAdvancedAirShield(const CStack * stack)
+		{
+			for(int g=0; g<stack->effects.size(); ++g)
+			{
+				if (stack->effects[g].id == 28 && stack->effects[g].level >= 2)
+				{
+					return true;
+				}
+			}
+			return false;
+		}
+	};
+
+	//wall / distance penalty + advanced air shield
+	if (shooting && (
+		hasDistancePenalty(attacker->ID, defender->position) || hasWallPenalty(attacker->ID, defender->position) ||
+		HLP::hasAdvancedAirShield(defender) )
+		)
+	{
+		multBonus *= 0.5;
+	}
 
 
-	minDmg *= dmgBonusMultiplier;
-	maxDmg *= dmgBonusMultiplier;
+	minDmg *= additiveBonus * multBonus;
+	maxDmg *= additiveBonus * multBonus;
 
 
 	std::pair<ui32, ui32> returnedVal;
 	std::pair<ui32, ui32> returnedVal;
 
 
@@ -2593,12 +2629,21 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, cons
 	return returnedVal;
 	return returnedVal;
 }
 }
 
 
-ui32 BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge)
+ui32 BattleInfo::calculateDmg( const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky )
 {
 {
-	std::pair<ui32, ui32> range = calculateDmgRange(attacker, defender, attackerHero, defendingHero, shooting, charge);
+	std::pair<ui32, ui32> range = calculateDmgRange(attacker, defender, attackerHero, defendingHero, shooting, charge, lucky);
 
 
 	if(range.first != range.second)
 	if(range.first != range.second)
-		return range.first  +  rand() % (range.second - range.first + 1);
+	{
+		int valuesToAverage[10];
+		int howManyToAv = std::min<ui32>(10, attacker->amount);
+		for (int g=0; g<howManyToAv; ++g)
+		{
+			valuesToAverage[g] = range.first  +  rand() % (range.second - range.first + 1);
+		}
+
+		return std::accumulate(valuesToAverage, valuesToAverage + howManyToAv, 0) / howManyToAv;
+	}
 	else
 	else
 		return range.first;
 		return range.first;
 }
 }
@@ -2809,6 +2854,13 @@ int BattleInfo::hexToWallPart(int hex) const
 	return -1; //not found!
 	return -1; //not found!
 }
 }
 
 
+int BattleInfo::lineToWallHex( int line ) const
+{
+	static const int lineToHex[] = {12, 29, 45, 62, 78, 95, 112, 130, 147, 165, 182};
+
+	return lineToHex[line];
+}
+
 std::pair<const CStack *, int> BattleInfo::getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const
 std::pair<const CStack *, int> BattleInfo::getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const
 {	
 {	
 	bool ac[BFIELD_SIZE];
 	bool ac[BFIELD_SIZE];
@@ -3585,6 +3637,36 @@ si8 BattleInfo::Luck( const CStack * st ) const
 	return ret;
 	return ret;
 }
 }
 
 
+si8 BattleInfo::hasDistancePenalty( int stackID, int destHex )
+{
+	const CStack * stack = getStack(stackID);
+
+	int distance = std::abs(destHex % BFIELD_WIDTH - stack->position % BFIELD_WIDTH);
+
+	//I hope it's approximately correct
+	return distance > 8 && !stack->hasFeatureOfType(StackFeature::NO_DISTANCE_PENALTY);
+}
+
+si8 BattleInfo::hasWallPenalty( int stackID, int destHex )
+{
+	if (siege == 0)
+	{
+		return false;
+	}
+	const CStack * stack = getStack(stackID);
+	if (stack->hasFeatureOfType(StackFeature::NO_WALL_PENALTY));
+	{
+		return false;
+	}
+	int wallInStackLine = lineToWallHex(stack->position/BFIELD_WIDTH);
+	int wallInDestLine = lineToWallHex(destHex/BFIELD_WIDTH);
+
+	bool stackLeft = stack->position < wallInStackLine;
+	bool destLeft = destHex < wallInDestLine;
+
+	return stackLeft != destLeft;
+}
+
 int3 CPath::startPos() const
 int3 CPath::startPos() const
 {
 {
 	return nodes[nodes.size()-1].coord;
 	return nodes[nodes.size()-1].coord;

+ 6 - 3
lib/CGameState.h

@@ -188,19 +188,22 @@ struct DLL_EXPORT BattleInfo
 	si8 Morale(const CStack * st) const; //get morale of stack with all modificators
 	si8 Morale(const CStack * st) const; //get morale of stack with all modificators
 	si8 Luck(const CStack * st) const; //get luck of stack with all modificators
 	si8 Luck(const CStack * st) const; //get luck of stack with all modificators
 
 
-	bool isStackBlocked(int ID); //returns true if there is neighbouring enemy stack
+	bool isStackBlocked(int ID); //returns true if there is neighboring enemy stack
 	static signed char mutualPosition(int hex1, int hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
 	static signed char mutualPosition(int hex1, int hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
 	static std::vector<int> neighbouringTiles(int hex);
 	static std::vector<int> neighbouringTiles(int hex);
-	static ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge); //charge - number of hexes travelled before attack (for champion's jousting)
-	static std::pair<ui32, ui32> calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge); //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
+	ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky); //charge - number of hexes travelled before attack (for champion's jousting)
+	std::pair<ui32, ui32> calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky); //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
 	void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
 	void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
 	std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile); //calculates stack affected by given spell
 	std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile); //calculates stack affected by given spell
 	static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster);
 	static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster);
 	CStack * generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
 	CStack * generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
 	ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
 	ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
 	int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
 	int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
+	int lineToWallHex(int line) const; //returns hex with wall in given line
 	std::pair<const CStack *, int> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const; //if attackerOwned is indetermnate, returened stack is of any owner; hex is the number of hex we should be looking from; returns (nerarest creature, predecessorHex)
 	std::pair<const CStack *, int> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const; //if attackerOwned is indetermnate, returened stack is of any owner; hex is the number of hex we should be looking from; returns (nerarest creature, predecessorHex)
 	ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const; //calculates damage inflicted by spell
 	ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const; //calculates damage inflicted by spell
+	si8 hasDistancePenalty(int stackID, int destHex); //determines if given stack has distance penalty shooting given pos
+	si8 hasWallPenalty(int stackID, int destHex); //determines if given stack has wall penalty shooting given pos
 };
 };
 
 
 class DLL_EXPORT CStack
 class DLL_EXPORT CStack

+ 4 - 2
server/CGameHandler.cpp

@@ -637,13 +637,15 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
 	BattleStackAttacked *bsa = &bat.bsa.back();
 	BattleStackAttacked *bsa = &bat.bsa.back();
 	bsa->stackAttacked = def->ID;
 	bsa->stackAttacked = def->ID;
 	bsa->attackerID = att->ID;
 	bsa->attackerID = att->ID;
-	bsa->damageAmount = BattleInfo::calculateDmg(att, def, gs->battleGetOwner(att->ID), gs->battleGetOwner(def->ID), bat.shot(), distance);//counting dealt damage
-	
 	if(gs->curB->Luck(att) > 0  &&  rand()%24 < gs->curB->Luck(att))
 	if(gs->curB->Luck(att) > 0  &&  rand()%24 < gs->curB->Luck(att))
 	{
 	{
 		bsa->damageAmount *= 2;
 		bsa->damageAmount *= 2;
 		bat.flags |= 4;
 		bat.flags |= 4;
 	}
 	}
+
+	bsa->damageAmount = gs->curB->calculateDmg(att, def, gs->battleGetOwner(att->ID), gs->battleGetOwner(def->ID), bat.shot(), distance, bat.lucky());//counting dealt damage
+	
+	
 	int dmg = bsa->damageAmount;
 	int dmg = bsa->damageAmount;
 	prepareAttacked(*bsa, def);
 	prepareAttacked(*bsa, def);