浏览代码

Merge branch 'develop' of https://github.com/vcmi/vcmi into develop

DjWarmonger 9 年之前
父节点
当前提交
51183228f2
共有 5 个文件被更改,包括 165 次插入156 次删除
  1. 31 31
      client/windows/CSpellWindow.cpp
  2. 34 29
      lib/CBattleCallback.cpp
  3. 1 4
      lib/GameConstants.h
  4. 64 63
      lib/mapping/CDrawRoadsOperation.cpp
  5. 35 29
      lib/spells/CDefaultSpellMechanics.cpp

+ 31 - 31
client/windows/CSpellWindow.cpp

@@ -6,6 +6,7 @@
 #include "CAdvmapInterface.h"
 #include "CAdvmapInterface.h"
 #include "GUIClasses.h"
 #include "GUIClasses.h"
 #include "InfoWindows.h"
 #include "InfoWindows.h"
+#include "CCastleInterface.h"
 
 
 #include "../CBitmapHandler.h"
 #include "../CBitmapHandler.h"
 #include "../CDefHandler.h"
 #include "../CDefHandler.h"
@@ -109,7 +110,7 @@ CSpellWindow::CSpellWindow(const SDL_Rect &, const CGHeroInstance * _myHero, CPl
 		Uint8 *sitesPerOurTab = s.combatSpell ? sitesPerTabBattle : sitesPerTabAdv;
 		Uint8 *sitesPerOurTab = s.combatSpell ? sitesPerTabBattle : sitesPerTabAdv;
 
 
 		++sitesPerOurTab[4];
 		++sitesPerOurTab[4];
-		
+
 		s.forEachSchool([&sitesPerOurTab](const SpellSchoolInfo & school, bool & stop)
 		s.forEachSchool([&sitesPerOurTab](const SpellSchoolInfo & school, bool & stop)
 		{
 		{
 			++sitesPerOurTab[(ui8)school.id];
 			++sitesPerOurTab[(ui8)school.id];
@@ -156,9 +157,9 @@ CSpellWindow::CSpellWindow(const SDL_Rect &, const CGHeroInstance * _myHero, CPl
 
 
 	leftCorner = BitmapHandler::loadBitmap("SpelTrnL.bmp", true);
 	leftCorner = BitmapHandler::loadBitmap("SpelTrnL.bmp", true);
 	rightCorner = BitmapHandler::loadBitmap("SpelTrnR.bmp", true);
 	rightCorner = BitmapHandler::loadBitmap("SpelTrnR.bmp", true);
-	
+
 	spells = new CAnimation("Spells.def");
 	spells = new CAnimation("Spells.def");
-		
+
 	spellTab = CDefHandler::giveDef("SpelTab.def");
 	spellTab = CDefHandler::giveDef("SpelTab.def");
 	schools = CDefHandler::giveDef("Schools.def");
 	schools = CDefHandler::giveDef("Schools.def");
 	schoolBorders[0] = CDefHandler::giveDef("SplevA.def");
 	schoolBorders[0] = CDefHandler::giveDef("SplevA.def");
@@ -380,9 +381,9 @@ public:
 		if(A.level<B.level)
 		if(A.level<B.level)
 			return true;
 			return true;
 		if(A.level>B.level)
 		if(A.level>B.level)
-			return false;		
-		
-		
+			return false;
+
+
 		for(ui8 schoolId = 0; schoolId < 4; schoolId++)
 		for(ui8 schoolId = 0; schoolId < 4; schoolId++)
 		{
 		{
 			if(A.school.at((ESpellSchool)schoolId) && !B.school.at((ESpellSchool)schoolId))
 			if(A.school.at((ESpellSchool)schoolId) && !B.school.at((ESpellSchool)schoolId))
@@ -390,7 +391,7 @@ public:
 			if(!A.school.at((ESpellSchool)schoolId) && B.school.at((ESpellSchool)schoolId))
 			if(!A.school.at((ESpellSchool)schoolId) && B.school.at((ESpellSchool)schoolId))
 				return false;
 				return false;
 		}
 		}
-		
+
 		return A.name < B.name;
 		return A.name < B.name;
 	}
 	}
 } spellsorter;
 } spellsorter;
@@ -400,8 +401,8 @@ void CSpellWindow::computeSpellsPerArea()
 	std::vector<SpellID> spellsCurSite;
 	std::vector<SpellID> spellsCurSite;
 	for(const SpellID & spellID : mySpells)
 	for(const SpellID & spellID : mySpells)
 	{
 	{
-		CSpell * s = spellID.toSpell(); 
-		
+		CSpell * s = spellID.toSpell();
+
 		if(s->combatSpell ^ !battleSpellsOnly
 		if(s->combatSpell ^ !battleSpellsOnly
 			&& ((selectedTab == 4) || (s->school[(ESpellSchool)selectedTab]))
 			&& ((selectedTab == 4) || (s->school[(ESpellSchool)selectedTab]))
 			)
 			)
@@ -533,7 +534,7 @@ void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key)
 	{
 	{
 		fexitb();
 		fexitb();
 		return;
 		return;
-	}		
+	}
 
 
 	if(key.state == SDL_PRESSED)
 	if(key.state == SDL_PRESSED)
 	{
 	{
@@ -622,10 +623,9 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 			owner->myInt->showInfoDialog(std::string(msgBuf));
 			owner->myInt->showInfoDialog(std::string(msgBuf));
 			return;
 			return;
 		}
 		}
-
 		//battle spell on adv map or adventure map spell during combat => display infowindow, not cast
 		//battle spell on adv map or adventure map spell during combat => display infowindow, not cast
 		if((sp->isCombatSpell() && !owner->myInt->battleInt)
 		if((sp->isCombatSpell() && !owner->myInt->battleInt)
-			|| (sp->isAdventureSpell() && owner->myInt->battleInt))
+		   || (sp->isAdventureSpell() && (owner->myInt->battleInt || owner->myInt->castleInt)))
 		{
 		{
 			std::vector<CComponent*> hlp(1, new CComponent(CComponent::spell, mySpell, 0));
 			std::vector<CComponent*> hlp(1, new CComponent(CComponent::spell, mySpell, 0));
 			LOCPLINT->showInfoDialog(sp->getLevelInfo(schoolLevel).description, hlp);
 			LOCPLINT->showInfoDialog(sp->getLevelInfo(schoolLevel).description, hlp);
@@ -705,26 +705,26 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 		{
 		{
 			const CGHeroInstance *h = owner->myHero;
 			const CGHeroInstance *h = owner->myHero;
 			GH.popInt(owner);
 			GH.popInt(owner);
-			
-			auto guard = vstd::makeScopeGuard([this]								
+
+			auto guard = vstd::makeScopeGuard([this]
 			{
 			{
 				(LOCPLINT->battleInt ? owner->myInt->spellbookSettings.spellbookLastTabBattle : owner->myInt->spellbookSettings.spellbookLastTabAdvmap) = owner->selectedTab;
 				(LOCPLINT->battleInt ? owner->myInt->spellbookSettings.spellbookLastTabBattle : owner->myInt->spellbookSettings.spellbookLastTabAdvmap) = owner->selectedTab;
-				(LOCPLINT->battleInt ? owner->myInt->spellbookSettings.spellbookLastPageBattle : owner->myInt->spellbookSettings.spellbokLastPageAdvmap) = owner->currentPage;				
+				(LOCPLINT->battleInt ? owner->myInt->spellbookSettings.spellbookLastPageBattle : owner->myInt->spellbookSettings.spellbokLastPageAdvmap) = owner->currentPage;
 				delete owner;
 				delete owner;
-			}); 
+			});
 
 
 			if(mySpell == SpellID::TOWN_PORTAL)
 			if(mySpell == SpellID::TOWN_PORTAL)
 			{
 			{
 				//special case
 				//special case
 				//todo: move to mechanics
 				//todo: move to mechanics
-				
+
 				std::vector <int> availableTowns;
 				std::vector <int> availableTowns;
 				std::vector <const CGTownInstance*> Towns = LOCPLINT->cb->getTownsInfo(false);
 				std::vector <const CGTownInstance*> Towns = LOCPLINT->cb->getTownsInfo(false);
 
 
 				vstd::erase_if(Towns, [this](const CGTownInstance * t)
 				vstd::erase_if(Towns, [this](const CGTownInstance * t)
 				{
 				{
-					const auto relations = owner->myInt->cb->getPlayerRelations(t->tempOwner, owner->myInt->playerID);	
-					return relations == PlayerRelations::ENEMIES; 				
+					const auto relations = owner->myInt->cb->getPlayerRelations(t->tempOwner, owner->myInt->playerID);
+					return relations == PlayerRelations::ENEMIES;
 				});
 				});
 
 
 				if (Towns.empty())
 				if (Towns.empty())
@@ -776,13 +776,13 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 							availableTowns.push_back(t->id.getNum());//add to the list
 							availableTowns.push_back(t->id.getNum());//add to the list
 						}
 						}
 					}
 					}
-					
+
 					auto castTownPortal = [h](int townId)
 					auto castTownPortal = [h](int townId)
 					{
 					{
 						const CGTownInstance * dest = LOCPLINT->cb->getTown(ObjectInstanceID(townId));
 						const CGTownInstance * dest = LOCPLINT->cb->getTown(ObjectInstanceID(townId));
-						LOCPLINT->cb->castSpell(h, SpellID::TOWN_PORTAL, dest->visitablePos());					
+						LOCPLINT->cb->castSpell(h, SpellID::TOWN_PORTAL, dest->visitablePos());
 					};
 					};
-					
+
 					if (availableTowns.empty())
 					if (availableTowns.empty())
 						LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[124]);
 						LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[124]);
 					else
 					else
@@ -791,13 +791,13 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 							CGI->generaltexth->jktexts[40], CGI->generaltexth->jktexts[41],
 							CGI->generaltexth->jktexts[40], CGI->generaltexth->jktexts[41],
 							castTownPortal));
 							castTownPortal));
 				}
 				}
-				return;	
+				return;
 			}
 			}
-			
+
 			if(mySpell == SpellID::SUMMON_BOAT)
 			if(mySpell == SpellID::SUMMON_BOAT)
 			{
 			{
 				//special case
 				//special case
-				//todo: move to mechanics				
+				//todo: move to mechanics
 				int3 pos = h->bestLocation();
 				int3 pos = h->bestLocation();
 				if(pos.x < 0)
 				if(pos.x < 0)
 				{
 				{
@@ -805,10 +805,10 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 					return;
 					return;
 				}
 				}
 			}
 			}
-			
+
 			if(sp->getTargetType() == CSpell::LOCATION)
 			if(sp->getTargetType() == CSpell::LOCATION)
 			{
 			{
-				adventureInt->enterCastingMode(sp);		
+				adventureInt->enterCastingMode(sp);
 			}
 			}
 			else if(sp->getTargetType() == CSpell::NO_TARGET)
 			else if(sp->getTargetType() == CSpell::NO_TARGET)
 			{
 			{
@@ -817,7 +817,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
 			else
 			else
 			{
 			{
 				logGlobal->error("Invalid spell target type");
 				logGlobal->error("Invalid spell target type");
-			}			
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -865,11 +865,11 @@ void CSpellWindow::SpellArea::showAll(SDL_Surface * to)
 	if(mySpell < 0)
 	if(mySpell < 0)
 		return;
 		return;
 
 
-	const CSpell * spell = mySpell.toSpell();	
+	const CSpell * spell = mySpell.toSpell();
 	owner->spells->load(mySpell);
 	owner->spells->load(mySpell);
-	
+
 	IImage * icon = owner->spells->getImage(mySpell,0,false);
 	IImage * icon = owner->spells->getImage(mySpell,0,false);
-	
+
 	if(icon != nullptr)
 	if(icon != nullptr)
 		icon->draw(to, pos.x, pos.y);
 		icon->draw(to, pos.x, pos.y);
 	else
 	else

+ 34 - 29
lib/CBattleCallback.cpp

@@ -187,11 +187,11 @@ TStacks CBattleInfoEssentials::battleGetStacksIf(TStackFilter predicate, bool in
 {
 {
 	TStacks ret;
 	TStacks ret;
 	RETURN_IF_NOT_BATTLE(ret);
 	RETURN_IF_NOT_BATTLE(ret);
-	
+
 	vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), [=](const CStack * s){
 	vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), [=](const CStack * s){
 		return predicate(s) && (includeTurrets || !(s->type->idNumber == CreatureID::ARROW_TOWERS));
 		return predicate(s) && (includeTurrets || !(s->type->idNumber == CreatureID::ARROW_TOWERS));
 	});
 	});
-	
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -784,23 +784,23 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack
 bool CBattleInfoCallback::battleCanAttack(const CStack * stack, const CStack * target, BattleHex dest) const
 bool CBattleInfoCallback::battleCanAttack(const CStack * stack, const CStack * target, BattleHex dest) const
 {
 {
 	RETURN_IF_NOT_BATTLE(false);
 	RETURN_IF_NOT_BATTLE(false);
-	
+
 	if(battleTacticDist())
 	if(battleTacticDist())
 		return false;
 		return false;
-	
+
 	if (!stack || !target)
 	if (!stack || !target)
 		return false;
 		return false;
-	
+
 	if (stack->owner == target->owner)
 	if (stack->owner == target->owner)
 		return false;
 		return false;
-	
+
 	auto &id = stack->getCreature()->idNumber;
 	auto &id = stack->getCreature()->idNumber;
 	if (id == CreatureID::FIRST_AID_TENT || id == CreatureID::CATAPULT)
 	if (id == CreatureID::FIRST_AID_TENT || id == CreatureID::CATAPULT)
 		return false;
 		return false;
-	
+
 	if (!target->alive())
 	if (!target->alive())
 		return false;
 		return false;
-	
+
 	return true;
 	return true;
 }
 }
 
 
@@ -997,7 +997,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
 	const bool distPenalty = !info.attackerBonuses->hasBonusOfType(Bonus::NO_DISTANCE_PENALTY) && battleHasDistancePenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition);
 	const bool distPenalty = !info.attackerBonuses->hasBonusOfType(Bonus::NO_DISTANCE_PENALTY) && battleHasDistancePenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition);
 	const bool obstaclePenalty = battleHasWallPenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition);
 	const bool obstaclePenalty = battleHasWallPenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition);
 
 
-	if (info.shooting)
+	if(info.shooting)
 	{
 	{
 		if (distPenalty || info.defenderBonuses->hasBonus(isAdvancedAirShield))
 		if (distPenalty || info.defenderBonuses->hasBonus(isAdvancedAirShield))
 		{
 		{
@@ -1013,9 +1013,14 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
 		multBonus *= 0.5;
 		multBonus *= 0.5;
 	}
 	}
 
 
+	// psychic elementals versus mind immune units 50%
+	if(attackerType->idNumber == CreatureID::PSYCHIC_ELEMENTAL
+	   && info.defenderBonuses->hasBonusOfType(Bonus::MIND_IMMUNITY))
+	{
+		multBonus *= 0.5;
+	}
 
 
 	// TODO attack on petrified unit 50%
 	// TODO attack on petrified unit 50%
-	// psychic elementals versus mind immune units 50%
 	// blinded unit retaliates
 	// blinded unit retaliates
 
 
 	minDmg *= additiveBonus * multBonus;
 	minDmg *= additiveBonus * multBonus;
@@ -1265,8 +1270,8 @@ std::pair<const CStack *, BattleHex> CBattleInfoCallback::getNearestStack(const
 	// I hate std::pairs with their undescriptive member names first / second
 	// I hate std::pairs with their undescriptive member names first / second
 	struct DistStack
 	struct DistStack
 	{
 	{
-		int distanceToPred;	
-		BattleHex destination;	
+		int distanceToPred;
+		BattleHex destination;
 		const CStack *stack;
 		const CStack *stack;
 	};
 	};
 
 
@@ -1276,7 +1281,7 @@ std::pair<const CStack *, BattleHex> CBattleInfoCallback::getNearestStack(const
 	{
 	{
 		return s != closest && s->alive() && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned);
 		return s != closest && s->alive() && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned);
 	}, false);
 	}, false);
-	
+
 	for(const CStack * st : possibleStacks)
 	for(const CStack * st : possibleStacks)
 		for(BattleHex hex : avHexes)
 		for(BattleHex hex : avHexes)
 			if(CStack::isMeleeAttackPossible(closest, st, hex))
 			if(CStack::isMeleeAttackPossible(closest, st, hex))
@@ -1628,9 +1633,9 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
 		return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
 		return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
 
 
 	const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCast(this, player);
 	const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCast(this, player);
-	
+
 	if(specificProblem != ESpellCastProblem::OK)
 	if(specificProblem != ESpellCastProblem::OK)
-		return specificProblem;	
+		return specificProblem;
 
 
 	if(spell->isNegative() || spell->hasEffects())
 	if(spell->isNegative() || spell->hasEffects())
 	{
 	{
@@ -1667,7 +1672,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
 			{
 			{
 				bool immune =  ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
 				bool immune =  ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
 				bool casterStack = stack->owner == caster->getOwner();
 				bool casterStack = stack->owner == caster->getOwner();
-				
+
                 if(!immune)
                 if(!immune)
                 {
                 {
 					switch (spell->positiveness)
 					switch (spell->positiveness)
@@ -1716,12 +1721,12 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetPossibleTargets(PlayerColor
 		{
 		{
 			const CGHeroInstance * caster = battleGetFightingHero(playerToSide(player)); //TODO
 			const CGHeroInstance * caster = battleGetFightingHero(playerToSide(player)); //TODO
 			const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell));
 			const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell));
-			
+
 			for(const CStack * stack : battleAliveStacks())
 			for(const CStack * stack : battleAliveStacks())
 			{
 			{
 				bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
 				bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
 				bool casterStack = stack->owner == caster->getOwner();
 				bool casterStack = stack->owner == caster->getOwner();
-				
+
 				if(!immune)
 				if(!immune)
 					switch (spell->positiveness)
 					switch (spell->positiveness)
 					{
 					{
@@ -1784,7 +1789,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
 	{
 	{
 		logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpellHere: no spellcaster.";
 		logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpellHere: no spellcaster.";
 		return ESpellCastProblem::INVALID;
 		return ESpellCastProblem::INVALID;
-	}	
+	}
 	const PlayerColor player = caster->getOwner();
 	const PlayerColor player = caster->getOwner();
 	ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(caster, spell, mode);
 	ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(caster, spell, mode);
 	if(moreGeneralProblem != ESpellCastProblem::OK)
 	if(moreGeneralProblem != ESpellCastProblem::OK)
@@ -1894,19 +1899,19 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
 	RETURN_IF_NOT_BATTLE(SpellID::NONE);
 	RETURN_IF_NOT_BATTLE(SpellID::NONE);
 	//This is complete list. No spells from mods.
 	//This is complete list. No spells from mods.
 	//todo: this should be Spellbook of caster Stack
 	//todo: this should be Spellbook of caster Stack
-	static const std::set<SpellID> allPossibleSpells = 
+	static const std::set<SpellID> allPossibleSpells =
 	{
 	{
 		SpellID::AIR_SHIELD,
 		SpellID::AIR_SHIELD,
 		SpellID::ANTI_MAGIC,
 		SpellID::ANTI_MAGIC,
-		SpellID::BLESS,		
+		SpellID::BLESS,
 		SpellID::BLOODLUST,
 		SpellID::BLOODLUST,
 		SpellID::COUNTERSTRIKE,
 		SpellID::COUNTERSTRIKE,
 		SpellID::CURE,
 		SpellID::CURE,
-		SpellID::FIRE_SHIELD,		
+		SpellID::FIRE_SHIELD,
 		SpellID::FORTUNE,
 		SpellID::FORTUNE,
 		SpellID::HASTE,
 		SpellID::HASTE,
 		SpellID::MAGIC_MIRROR,
 		SpellID::MAGIC_MIRROR,
-		SpellID::MIRTH,				
+		SpellID::MIRTH,
 		SpellID::PRAYER,
 		SpellID::PRAYER,
 		SpellID::PRECISION,
 		SpellID::PRECISION,
 		SpellID::PROTECTION_FROM_AIR,
 		SpellID::PROTECTION_FROM_AIR,
@@ -1918,7 +1923,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
 		SpellID::STONE_SKIN
 		SpellID::STONE_SKIN
 	};
 	};
 	std::vector<SpellID> beneficialSpells;
 	std::vector<SpellID> beneficialSpells;
-	
+
 	auto getAliveEnemy = [=](const std::function<bool(const CStack * )> & pred)
 	auto getAliveEnemy = [=](const std::function<bool(const CStack * )> & pred)
 	{
 	{
 		return getStackIf([=](const CStack * stack)
 		return getStackIf([=](const CStack * stack)
@@ -1938,7 +1943,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
 		{
 		{
 		case SpellID::SHIELD:
 		case SpellID::SHIELD:
 		case SpellID::FIRE_SHIELD: // not if all enemy units are shooters
 		case SpellID::FIRE_SHIELD: // not if all enemy units are shooters
-			{				
+			{
 				auto walker = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack
 				auto walker = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack
 				{
 				{
 					return !stack->shots;
 					return !stack->shots;
@@ -1963,7 +1968,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
 		case SpellID::PROTECTION_FROM_AIR:
 		case SpellID::PROTECTION_FROM_AIR:
 		case SpellID::PROTECTION_FROM_EARTH:
 		case SpellID::PROTECTION_FROM_EARTH:
 		case SpellID::PROTECTION_FROM_FIRE:
 		case SpellID::PROTECTION_FROM_FIRE:
-		case SpellID::PROTECTION_FROM_WATER:				
+		case SpellID::PROTECTION_FROM_WATER:
 			{
 			{
 				const ui8 enemySide = (ui8)subject->attackerOwned;
 				const ui8 enemySide = (ui8)subject->attackerOwned;
 				//todo: only if enemy has spellbook
 				//todo: only if enemy has spellbook
@@ -2006,7 +2011,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
 			}
 			}
 			break;
 			break;
 		}
 		}
-		beneficialSpells.push_back(spellID);		
+		beneficialSpells.push_back(spellID);
 	}
 	}
 
 
 	if(!beneficialSpells.empty())
 	if(!beneficialSpells.empty())
@@ -2190,13 +2195,13 @@ TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose /*= MINE_AN
 	{
 	{
 		ASSERT_IF_CALLED_WITH_PLAYER
 		ASSERT_IF_CALLED_WITH_PLAYER
 	}
 	}
-	
+
 	return battleGetStacksIf([=](const CStack * s){
 	return battleGetStacksIf([=](const CStack * s){
 		const bool ownerMatches = (whose == MINE_AND_ENEMY)
 		const bool ownerMatches = (whose == MINE_AND_ENEMY)
 			|| (whose == ONLY_MINE && s->owner == player)
 			|| (whose == ONLY_MINE && s->owner == player)
 			|| (whose == ONLY_ENEMY && s->owner != player);
 			|| (whose == ONLY_ENEMY && s->owner != player);
 		const bool alivenessMatches = s->alive()  ||  !onlyAlive;
 		const bool alivenessMatches = s->alive()  ||  !onlyAlive;
-		return ownerMatches && alivenessMatches;		
+		return ownerMatches && alivenessMatches;
 	});
 	});
 }
 }
 
 

+ 1 - 4
lib/GameConstants.h

@@ -968,6 +968,7 @@ public:
 		WATER_ELEMENTAL = 115,
 		WATER_ELEMENTAL = 115,
 		GOLD_GOLEM = 116,
 		GOLD_GOLEM = 116,
 		DIAMOND_GOLEM = 117,
 		DIAMOND_GOLEM = 117,
+		PSYCHIC_ELEMENTAL = 120,
 		CATAPULT = 145,
 		CATAPULT = 145,
 		BALLISTA = 146,
 		BALLISTA = 146,
 		FIRST_AID_TENT = 147,
 		FIRST_AID_TENT = 147,
@@ -1053,7 +1054,3 @@ typedef int TRmgTemplateZoneId;
 #undef ID_LIKE_OPERATORS_INTERNAL
 #undef ID_LIKE_OPERATORS_INTERNAL
 #undef INSTID_LIKE_CLASS_COMMON
 #undef INSTID_LIKE_CLASS_COMMON
 #undef OP_DECL_INT
 #undef OP_DECL_INT
-
-
-
-

+ 64 - 63
lib/mapping/CDrawRoadsOperation.cpp

@@ -12,7 +12,7 @@
 #include "CDrawRoadsOperation.h"
 #include "CDrawRoadsOperation.h"
 #include "CMap.h"
 #include "CMap.h"
 
 
-const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::patterns = 
+const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::patterns =
 {
 {
 	//single tile. fall-back pattern
 	//single tile. fall-back pattern
 	{
 	{
@@ -31,7 +31,7 @@ const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::pattern
 		{
 		{
           "?","-","+",
           "?","-","+",
           "-","+","+",
           "-","+","+",
-          "+","+","?" 
+          "+","+","?"
         },
         },
         {2,5},
         {2,5},
         {-1,-1},
         {-1,-1},
@@ -43,7 +43,7 @@ const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::pattern
 		{
 		{
           "?","-","?",
           "?","-","?",
           "-","+","+",
           "-","+","+",
-          "?","+","?" 
+          "?","+","?"
         },
         },
         {0,1},
         {0,1},
         {0,3},
         {0,3},
@@ -55,7 +55,7 @@ const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::pattern
 		{
 		{
           "?","-","?",
           "?","-","?",
           "-","+","+",
           "-","+","+",
-          "?","-","?"   
+          "?","-","?"
         },
         },
         {15,15},{11,12},
         {15,15},{11,12},
         true,
         true,
@@ -66,7 +66,7 @@ const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::pattern
 		{
 		{
           "?","-","?",
           "?","-","?",
           "-","+","-",
           "-","+","-",
-          "?","+","?" 
+          "?","+","?"
         },
         },
         {14,14},{9,10},
         {14,14},{9,10},
         false,
         false,
@@ -77,7 +77,7 @@ const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::pattern
 		{
 		{
           "?","+","?",
           "?","+","?",
           "-","+","+",
           "-","+","+",
-          "?","+","?"  
+          "?","+","?"
         },
         },
         {6,7},{7,8},
         {6,7},{7,8},
         true,
         true,
@@ -88,46 +88,46 @@ const std::vector<CDrawRoadsOperation::RoadPattern> CDrawRoadsOperation::pattern
 		{
 		{
           "?","-","?",
           "?","-","?",
           "+","+","+",
           "+","+","+",
-          "?","+","?" 
+          "?","+","?"
         },
         },
         {8,9},{5,6},
         {8,9},{5,6},
         false,
         false,
         true
         true
 	},
 	},
-	//Straight Horizontal 
+	//Straight Horizontal
 	{
 	{
 		{
 		{
           "?","-","?",
           "?","-","?",
           "+","+","+",
           "+","+","+",
-          "?","-","?"  
+          "?","-","?"
         },
         },
         {12,13},{11,12},
         {12,13},{11,12},
         false,
         false,
         false
         false
 	},
 	},
-	//Straight Vertical 
+	//Straight Vertical
 	{
 	{
 		{
 		{
           "?","+","?",
           "?","+","?",
           "-","+","-",
           "-","+","-",
-          "?","+","?" 
+          "?","+","?"
         },
         },
         {10,11},{9,10},
         {10,11},{9,10},
         false,
         false,
         false
         false
 	},
 	},
-	//X-cross 
+	//X-cross
 	{
 	{
 		{
 		{
           "?","+","?",
           "?","+","?",
           "+","+","+",
           "+","+","+",
-          "?","+","?"  
+          "?","+","?"
         },
         },
         {16,16},{4,4},
         {16,16},{4,4},
         false,
         false,
         false
         false
-	}			
-	
+	}
+
 };
 };
 
 
 static bool ruleIsNone(const std::string & rule)
 static bool ruleIsNone(const std::string & rule)
@@ -140,45 +140,47 @@ static bool ruleIsSomething(const std::string & rule)
 	return rule == "+";
 	return rule == "+";
 }
 }
 
 
+#ifndef NDEBUG
 static bool ruleIsAny(const std::string & rule)
 static bool ruleIsAny(const std::string & rule)
 {
 {
 	return rule == "?";
 	return rule == "?";
 }
 }
+#endif
 
 
 ///CDrawRoadsOperation
 ///CDrawRoadsOperation
 CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, ERoadType::ERoadType roadType, CRandomGenerator * gen):
 CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, ERoadType::ERoadType roadType, CRandomGenerator * gen):
 	CMapOperation(map),terrainSel(terrainSel), roadType(roadType), gen(gen)
 	CMapOperation(map),terrainSel(terrainSel), roadType(roadType), gen(gen)
 {
 {
-	
+
 }
 }
 
 
 void CDrawRoadsOperation::execute()
 void CDrawRoadsOperation::execute()
 {
 {
 	std::set<int3> invalidated;
 	std::set<int3> invalidated;
-	
+
 	for(const auto & pos : terrainSel.getSelectedItems())
 	for(const auto & pos : terrainSel.getSelectedItems())
 	{
 	{
 		auto & tile = map->getTile(pos);
 		auto & tile = map->getTile(pos);
 		tile.roadType = roadType;
 		tile.roadType = roadType;
-		
+
 		auto rect = extendTileAroundSafely(pos);
 		auto rect = extendTileAroundSafely(pos);
 		rect.forEach([&invalidated](const int3 & pos)
 		rect.forEach([&invalidated](const int3 & pos)
 		{
 		{
 			invalidated.insert(pos);
 			invalidated.insert(pos);
 		});
 		});
 	}
 	}
-	
-	updateTiles(invalidated);	
+
+	updateTiles(invalidated);
 }
 }
 
 
 void CDrawRoadsOperation::undo()
 void CDrawRoadsOperation::undo()
 {
 {
-  //TODO	
+  //TODO
 }
 }
 
 
 void CDrawRoadsOperation::redo()
 void CDrawRoadsOperation::redo()
 {
 {
-  //TODO	
+  //TODO
 }
 }
 
 
 std::string CDrawRoadsOperation::getLabel() const
 std::string CDrawRoadsOperation::getLabel() const
@@ -188,14 +190,14 @@ std::string CDrawRoadsOperation::getLabel() const
 
 
 bool CDrawRoadsOperation::canApplyPattern(const RoadPattern & pattern) const
 bool CDrawRoadsOperation::canApplyPattern(const RoadPattern & pattern) const
 {
 {
-	//TODO: this method should be virtual for river support	
+	//TODO: this method should be virtual for river support
 	return pattern.roadMapping.first >= 0;
 	return pattern.roadMapping.first >= 0;
 }
 }
 
 
 void CDrawRoadsOperation::flipPattern(RoadPattern& pattern, int flip) const
 void CDrawRoadsOperation::flipPattern(RoadPattern& pattern, int flip) const
 {
 {
 	//todo: use cashing here and also in terrain patterns
 	//todo: use cashing here and also in terrain patterns
-	
+
 	if(flip == 0)
 	if(flip == 0)
 	{
 	{
 		return;
 		return;
@@ -217,7 +219,7 @@ void CDrawRoadsOperation::flipPattern(RoadPattern& pattern, int flip) const
 		{
 		{
 			std::swap(pattern.data[i], pattern.data[6 + i]);
 			std::swap(pattern.data[i], pattern.data[6 + i]);
 		}
 		}
-	}	
+	}
 }
 }
 
 
 
 
@@ -226,98 +228,98 @@ bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const
 	return tile.roadType != ERoadType::NO_ROAD; //TODO: this method should be virtual for river support
 	return tile.roadType != ERoadType::NO_ROAD; //TODO: this method should be virtual for river support
 }
 }
 
 
-void CDrawRoadsOperation::updateTiles(std::set<int3> & invalidated) 
+void CDrawRoadsOperation::updateTiles(std::set<int3> & invalidated)
 {
 {
 	for(int3 coord : invalidated)
 	for(int3 coord : invalidated)
 	{
 	{
 		TerrainTile & tile = map->getTile(coord);
 		TerrainTile & tile = map->getTile(coord);
 		ValidationResult result(false);
 		ValidationResult result(false);
-		
+
 		if(!needUpdateTile(tile))
 		if(!needUpdateTile(tile))
 			continue;
 			continue;
-			
+
 		int bestPattern = -1;
 		int bestPattern = -1;
-		
+
 		for(int k = 0; k < patterns.size(); ++k)
 		for(int k = 0; k < patterns.size(); ++k)
 		{
 		{
 			result = validateTile(patterns[k], coord);
 			result = validateTile(patterns[k], coord);
-			
+
 			if(result.result)
 			if(result.result)
 			{
 			{
 				bestPattern = k;
 				bestPattern = k;
 				break;
 				break;
 			}
 			}
 		}
 		}
-		
+
 		if(bestPattern != -1)
 		if(bestPattern != -1)
 		{
 		{
 			updateTile(tile, patterns[bestPattern], result.flip);
 			updateTile(tile, patterns[bestPattern], result.flip);
 		}
 		}
-		
+
 	}
 	}
 };
 };
 
 
 bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const
 bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const
 {
 {
-//TODO: this method should be virtual for river support	
+//TODO: this method should be virtual for river support
 
 
-   return map->getTile(pos).roadType != ERoadType::NO_ROAD;	
+   return map->getTile(pos).roadType != ERoadType::NO_ROAD;
 }
 }
 
 
 
 
 void CDrawRoadsOperation::updateTile(TerrainTile & tile, const RoadPattern & pattern, const int flip)
 void CDrawRoadsOperation::updateTile(TerrainTile & tile, const RoadPattern & pattern, const int flip)
 {
 {
-  //TODO: this method should be virtual for river support	
-  
+  //TODO: this method should be virtual for river support
+
 	const std::pair<int, int> & mapping  = pattern.roadMapping;
 	const std::pair<int, int> & mapping  = pattern.roadMapping;
-  
+
 	tile.roadDir = gen->nextInt(mapping.first, mapping.second);
 	tile.roadDir = gen->nextInt(mapping.first, mapping.second);
-	tile.extTileFlags = (tile.extTileFlags & 0xCF) | (flip << 4); 
+	tile.extTileFlags = (tile.extTileFlags & 0xCF) | (flip << 4);
 }
 }
 
 
 CDrawRoadsOperation::ValidationResult CDrawRoadsOperation::validateTile(const RoadPattern & pattern, const int3 & pos)
 CDrawRoadsOperation::ValidationResult CDrawRoadsOperation::validateTile(const RoadPattern & pattern, const int3 & pos)
 {
 {
 	ValidationResult result(false);
 	ValidationResult result(false);
-	
+
 	if(!canApplyPattern(pattern))
 	if(!canApplyPattern(pattern))
 		return result;
 		return result;
-	
-	
+
+
 	for(int flip = 0; flip < 4; ++flip)
 	for(int flip = 0; flip < 4; ++flip)
 	{
 	{
-		if((flip == FLIP_PATTERN_BOTH) && !(pattern.hasHFlip && pattern.hasVFlip)) 
+		if((flip == FLIP_PATTERN_BOTH) && !(pattern.hasHFlip && pattern.hasVFlip))
 			continue;
 			continue;
-		if((flip == FLIP_PATTERN_HORIZONTAL) && !pattern.hasHFlip) 
+		if((flip == FLIP_PATTERN_HORIZONTAL) && !pattern.hasHFlip)
 			continue;
 			continue;
-		if((flip == FLIP_PATTERN_VERTICAL) && !(pattern.hasVFlip)) 
+		if((flip == FLIP_PATTERN_VERTICAL) && !(pattern.hasVFlip))
 			continue;
 			continue;
-		
-		RoadPattern flipped = pattern;		
-		
+
+		RoadPattern flipped = pattern;
+
 		flipPattern(flipped, flip);
 		flipPattern(flipped, flip);
-		
+
 		bool validated = true;
 		bool validated = true;
-		
+
 		for(int i = 0; i < 9; ++i)
 		for(int i = 0; i < 9; ++i)
 		{
 		{
 			if(4 == i)
 			if(4 == i)
 				continue;
 				continue;
 			int cx = pos.x + (i % 3) - 1;
 			int cx = pos.x + (i % 3) - 1;
 			int cy = pos.y + (i / 3) - 1;
 			int cy = pos.y + (i / 3) - 1;
-			
+
 			int3 currentPos(cx, cy, pos.z);
 			int3 currentPos(cx, cy, pos.z);
-			
+
 			bool hasSomething;
 			bool hasSomething;
-			
+
 			if(!map->isInTheMap(currentPos))
 			if(!map->isInTheMap(currentPos))
 			{
 			{
 				hasSomething = true; //road/river can go out of map
 				hasSomething = true; //road/river can go out of map
 			}
 			}
 			else
 			else
 			{
 			{
-				hasSomething = tileHasSomething(currentPos);				
+				hasSomething = tileHasSomething(currentPos);
 			}
 			}
-			
+
 			if(ruleIsSomething(flipped.data[i]))
 			if(ruleIsSomething(flipped.data[i]))
 			{
 			{
 				if(!hasSomething)
 				if(!hasSomething)
@@ -332,23 +334,22 @@ CDrawRoadsOperation::ValidationResult CDrawRoadsOperation::validateTile(const Ro
 				{
 				{
 					validated = false;
 					validated = false;
 					break;
 					break;
-				}		
+				}
 			}
 			}
 			else
 			else
 			{
 			{
-				assert(ruleIsAny(flipped.data[i]));			
-			}		
-			
+				assert(ruleIsAny(flipped.data[i]));
+			}
+
 		}
 		}
-		
+
 		if(validated)
 		if(validated)
 		{
 		{
 			result.result = true;
 			result.result = true;
 			result.flip = flip;
 			result.flip = flip;
-			return result;			
-		}		
+			return result;
+		}
 	}
 	}
-	
+
 	return result;
 	return result;
 }
 }
-

+ 35 - 29
lib/spells/CDefaultSpellMechanics.cpp

@@ -154,6 +154,13 @@ bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, Adve
 	}
 	}
 
 
 	const CGHeroInstance * caster = parameters.caster;
 	const CGHeroInstance * caster = parameters.caster;
+
+	if(caster->inTownGarrison)
+	{
+		env->complain("Attempt to cast an adventure spell in town garrison");
+		return false;
+	}
+
 	const int cost = caster->getSpellCost(owner);
 	const int cost = caster->getSpellCost(owner);
 
 
 	if(!caster->canCastThisSpell(owner))
 	if(!caster->canCastThisSpell(owner))
@@ -174,7 +181,7 @@ bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, Adve
 		asc.spellID = owner->id;
 		asc.spellID = owner->id;
 		env->sendAndApply(&asc);
 		env->sendAndApply(&asc);
 	}
 	}
-	
+
 	switch(applyAdventureEffects(env, parameters))
 	switch(applyAdventureEffects(env, parameters))
 	{
 	{
 	case ESpellCastResult::OK:
 	case ESpellCastResult::OK:
@@ -184,7 +191,7 @@ bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, Adve
 			sm.absolute = false;
 			sm.absolute = false;
 			sm.val = -cost;
 			sm.val = -cost;
 			env->sendAndApply(&sm);
 			env->sendAndApply(&sm);
-			return true;			
+			return true;
 		}
 		}
 		break;
 		break;
 	case ESpellCastResult::CANCEL:
 	case ESpellCastResult::CANCEL:
@@ -224,16 +231,16 @@ ESpellCastResult DefaultSpellMechanics::applyAdventureEffects(const SpellCastEnv
 void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
 void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
 {
 {
 	logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
 	logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
-	
+
 	if(nullptr == parameters.caster)
 	if(nullptr == parameters.caster)
 	{
 	{
 		env->complain("No spell-caster provided.");
 		env->complain("No spell-caster provided.");
-		return;		
+		return;
 	}
 	}
-	
+
 	BattleSpellCast sc;
 	BattleSpellCast sc;
 	prepareBattleCast(parameters, sc);
 	prepareBattleCast(parameters, sc);
-	
+
 	//check it there is opponent hero
 	//check it there is opponent hero
 	const ui8 otherSide = 1-parameters.casterSide;
 	const ui8 otherSide = 1-parameters.casterSide;
 	const CGHeroInstance * otherHero = nullptr;
 	const CGHeroInstance * otherHero = nullptr;
@@ -247,7 +254,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
 		spellCost = parameters.cb->battleGetSpellCost(owner, parameters.casterHero);
 		spellCost = parameters.cb->battleGetSpellCost(owner, parameters.casterHero);
 
 
 		if(nullptr != otherHero) //handle mana channel
 		if(nullptr != otherHero) //handle mana channel
-		{			
+		{
 			int manaChannel = 0;
 			int manaChannel = 0;
 			for(const CStack * stack : parameters.cb->battleGetAllStacks(true)) //TODO: shouldn't bonus system handle it somehow?
 			for(const CStack * stack : parameters.cb->battleGetAllStacks(true)) //TODO: shouldn't bonus system handle it somehow?
 			{
 			{
@@ -271,10 +278,10 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
 	logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
 	logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
 
 
 	std::vector <const CStack*> reflected;//for magic mirror
 	std::vector <const CStack*> reflected;//for magic mirror
-	//checking if creatures resist	
+	//checking if creatures resist
 	handleResistance(env, attackedCres, sc);
 	handleResistance(env, attackedCres, sc);
 	//it is actual spell and can be reflected to single target, no recurrence
 	//it is actual spell and can be reflected to single target, no recurrence
-	const bool tryMagicMirror = owner->isNegative() && owner->level && owner->getLevelInfo(0).range == "0";	
+	const bool tryMagicMirror = owner->isNegative() && owner->level && owner->getLevelInfo(0).range == "0";
 	if(tryMagicMirror)
 	if(tryMagicMirror)
 	{
 	{
 		for(auto s : attackedCres)
 		for(auto s : attackedCres)
@@ -295,7 +302,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
 			effect.effect = 3;
 			effect.effect = 3;
 			effect.stack = s->ID;
 			effect.stack = s->ID;
 			sc.customEffects.push_back(effect);
 			sc.customEffects.push_back(effect);
-		}		
+		}
 	}
 	}
 
 
 	for(auto cre : attackedCres)
 	for(auto cre : attackedCres)
@@ -376,13 +383,13 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
 	}
 	}
 }
 }
 
 
-void DefaultSpellMechanics::battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet, 
+void DefaultSpellMechanics::battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
 	const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const
 	const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const
 {
 {
 	const std::string attackedName = attackedStack->getName();
 	const std::string attackedName = attackedStack->getName();
 	const std::string attackedNameSing = attackedStack->getCreature()->nameSing;
 	const std::string attackedNameSing = attackedStack->getCreature()->nameSing;
 	const std::string attackedNamePl = attackedStack->getCreature()->namePl;
 	const std::string attackedNamePl = attackedStack->getCreature()->namePl;
-	
+
 	auto getPluralFormat = [attackedStack](const int baseTextID) -> boost::format
 	auto getPluralFormat = [attackedStack](const int baseTextID) -> boost::format
 	{
 	{
 		return boost::format(VLC->generaltexth->allTexts[(attackedStack->count > 1 ? baseTextID + 1 : baseTextID)]);
 		return boost::format(VLC->generaltexth->allTexts[(attackedStack->count > 1 ? baseTextID + 1 : baseTextID)]);
@@ -470,7 +477,7 @@ void DefaultSpellMechanics::battleLogSingleTarget(std::vector<std::string> & log
 			logLines.push_back(text.str());
 			logLines.push_back(text.str());
 		}
 		}
 		break;
 		break;
-	}	
+	}
 }
 }
 
 
 void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
 void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
@@ -479,7 +486,7 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
 	if(owner->isOffensiveSpell())
 	if(owner->isOffensiveSpell())
 	{
 	{
 		int spellDamage = parameters.effectValue;
 		int spellDamage = parameters.effectValue;
-		
+
 		int chainLightningModifier = 0;
 		int chainLightningModifier = 0;
 		for(auto & attackedCre : ctx.attackedCres)
 		for(auto & attackedCre : ctx.attackedCres)
 		{
 		{
@@ -522,13 +529,13 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
 				vstd::amax(maxDuration, b.turnsRemain);
 				vstd::amax(maxDuration, b.turnsRemain);
 				sse.effect.push_back(b);
 				sse.effect.push_back(b);
 			}
 			}
-			//if all spell effects have special duration, use it 
-			duration = maxDuration;			
+			//if all spell effects have special duration, use it
+			duration = maxDuration;
 		}
 		}
 		//fix to original config: shield should display damage reduction
 		//fix to original config: shield should display damage reduction
 		if(owner->id == SpellID::SHIELD || owner->id == SpellID::AIR_SHIELD)
 		if(owner->id == SpellID::SHIELD || owner->id == SpellID::AIR_SHIELD)
 		{
 		{
-			sse.effect.back().val = (100 - sse.effect.back().val); 
+			sse.effect.back().val = (100 - sse.effect.back().val);
 		}
 		}
 		//we need to know who cast Bind
 		//we need to know who cast Bind
 		if(owner->id == SpellID::BIND && parameters.casterStack)
 		if(owner->id == SpellID::BIND && parameters.casterStack)
@@ -593,7 +600,7 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
 		if(!sse.stacks.empty())
 		if(!sse.stacks.empty())
 			env->sendAndApply(&sse);
 			env->sendAndApply(&sse);
 
 
-	}	
+	}
 }
 }
 
 
 std::vector<BattleHex> DefaultSpellMechanics::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
 std::vector<BattleHex> DefaultSpellMechanics::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
@@ -738,7 +745,7 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargeting
 
 
 ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
 ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
 {
 {
-	//no problems by default, this method is for spell-specific problems	
+	//no problems by default, this method is for spell-specific problems
 	return ESpellCastProblem::OK;
 	return ESpellCastProblem::OK;
 }
 }
 
 
@@ -756,7 +763,7 @@ void DefaultSpellMechanics::doDispell(BattleInfo * battle, const BattleSpellCast
 		if(sourceSpell != nullptr)
 		if(sourceSpell != nullptr)
 		{
 		{
 			//Special case: DISRUPTING_RAY is "immune" to dispell
 			//Special case: DISRUPTING_RAY is "immune" to dispell
-			//Other even PERMANENT effects can be removed (f.e. BIND)						
+			//Other even PERMANENT effects can be removed (f.e. BIND)
 			if(sourceSpell->id == SpellID::DISRUPTING_RAY)
 			if(sourceSpell->id == SpellID::DISRUPTING_RAY)
 				return false;
 				return false;
 		}
 		}
@@ -766,7 +773,7 @@ void DefaultSpellMechanics::doDispell(BattleInfo * battle, const BattleSpellCast
 	{
 	{
 		CStack *s = battle->getStack(stackID);
 		CStack *s = battle->getStack(stackID);
 		s->popBonuses(CSelector(localSelector).And(selector));
 		s->popBonuses(CSelector(localSelector).And(selector));
-	}	
+	}
 }
 }
 
 
 void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, BattleSpellCastParameters& parameters) const
 void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, BattleSpellCastParameters& parameters) const
@@ -781,12 +788,12 @@ void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, Bat
 	if(!destination.isValid())
 	if(!destination.isValid())
 	{
 	{
 		env->complain("MagicMirror: invalid destination");
 		env->complain("MagicMirror: invalid destination");
-		return;		
+		return;
 	}
 	}
 
 
 	BattleSpellCast sc;
 	BattleSpellCast sc;
 	prepareBattleCast(parameters, sc);
 	prepareBattleCast(parameters, sc);
-	
+
 	//calculating affected creatures for all spells
 	//calculating affected creatures for all spells
 	//must be vector, as in Chain Lightning order matters
 	//must be vector, as in Chain Lightning order matters
 	std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector
 	std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector
@@ -802,14 +809,14 @@ void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, Bat
 	{
 	{
 		sc.affectedCres.insert(cre->ID);
 		sc.affectedCres.insert(cre->ID);
 	}
 	}
-	
+
 	StacksInjured si;
 	StacksInjured si;
 	SpellCastContext ctx(attackedCres, sc, si);
 	SpellCastContext ctx(attackedCres, sc, si);
 	applyBattleEffects(env, parameters, ctx);
 	applyBattleEffects(env, parameters, ctx);
 
 
 	env->sendAndApply(&sc);
 	env->sendAndApply(&sc);
 	if(!si.stacks.empty()) //after spellcast info shows
 	if(!si.stacks.empty()) //after spellcast info shows
-		env->sendAndApply(&si);	
+		env->sendAndApply(&si);
 	logGlobal->debugStream() << "Finished spell cast. Spell: "<<owner->name<<"; mode: MAGIC_MIRROR";
 	logGlobal->debugStream() << "Finished spell cast. Spell: "<<owner->name<<"; mode: MAGIC_MIRROR";
 }
 }
 
 
@@ -842,8 +849,8 @@ void DefaultSpellMechanics::handleResistance(const SpellCastEnvironment * env, s
 			effect.effect = 78;
 			effect.effect = 78;
 			effect.stack = s->ID;
 			effect.stack = s->ID;
 			sc.customEffects.push_back(effect);
 			sc.customEffects.push_back(effect);
-		}		
-	}	
+		}
+	}
 }
 }
 
 
 void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& parameters, BattleSpellCast& sc) const
 void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& parameters, BattleSpellCast& sc) const
@@ -855,6 +862,5 @@ void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& p
 	sc.dmgToDisplay = 0;
 	sc.dmgToDisplay = 0;
 	sc.castByHero = parameters.mode == ECastingMode::HERO_CASTING;
 	sc.castByHero = parameters.mode == ECastingMode::HERO_CASTING;
 	sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1);
 	sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1);
-	sc.manaGained = 0;	
+	sc.manaGained = 0;
 }
 }
-