Browse Source

Surrendering and related artifacts (Statesman's Medal,
Diplomat's Ring, Ambassador's Sash).

Michał W. Urbańczyk 14 years ago
parent
commit
7dbf105f6e
10 changed files with 131 additions and 228 deletions
  1. 11 0
      CCallback.cpp
  2. 2 0
      CCallback.h
  3. 8 0
      ChangeLog
  4. 28 4
      client/CBattleInterface.cpp
  5. 1 0
      client/CBattleInterface.h
  6. 36 0
      lib/BattleState.cpp
  7. 4 0
      lib/BattleState.h
  8. 8 0
      lib/CObjectHandler.cpp
  9. 32 224
      server/CGameHandler.cpp
  10. 1 0
      server/CGameHandler.h

+ 11 - 0
CCallback.cpp

@@ -1135,3 +1135,14 @@ bool CBattleCallback::battleMakeTacticAction( BattleAction * action )
 	sendRequest(&ma);
 	return true;
 }
+
+int CBattleCallback::battleGetSurrenderCost()
+{
+	if (!gs->curB)
+	{
+		tlog1 << "battleGetSurrenderCost called when no battle!\n";
+		return -1;
+	}
+
+	return gs->curB->getSurrenderingCost(player);
+}

+ 2 - 0
CCallback.h

@@ -99,6 +99,7 @@ public:
 	virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
 	virtual SpellCasting::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell)=0; //determines if given spell can be casted (and returns problem description)
 	virtual bool battleCanFlee()=0; //returns true if caller can flee from the battle
+	virtual int battleGetSurrenderCost()=0; //returns cost of surrendering battle, -1 if surrendering is not possible
 	virtual const CGTownInstance * battleGetDefendedTown()=0; //returns defended town if current battle is a siege, NULL instead
 	virtual ui8 battleGetWallState(int partOfWall)=0; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
 	virtual int battleGetWallUnderHex(THex hex)=0; //returns part of destructible wall / gate / keep under given hex or -1 if not found
@@ -237,6 +238,7 @@ public:
 	bool battleCanCastSpell() OVERRIDE; //returns true, if caller can cast a spell
 	SpellCasting::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell) OVERRIDE; //determines if given spell can be casted (and returns problem description)
 	bool battleCanFlee() OVERRIDE; //returns true if caller can flee from the battle
+	int battleGetSurrenderCost() OVERRIDE; //returns cost of surrendering battle, -1 if surrendering is not possible
 	const CGTownInstance * battleGetDefendedTown() OVERRIDE; //returns defended town if current battle is a siege, NULL instead
 	ui8 battleGetWallState(int partOfWall) OVERRIDE; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
 	int battleGetWallUnderHex(THex hex) OVERRIDE; //returns part of destructible wall / gate / keep under given hex or -1 if not found

+ 8 - 0
ChangeLog

@@ -1,3 +1,11 @@
+0.84 -> 0.85
+GENERAL:
+* New artifacts supported:
+- Statesman's Medal
+- Diplomat's Ring
+- Ambassador's Sash
+
+
 0.83 -> 0.84 (Mar 01 2011)
 GENERAL:
 * Bonus system has been rewritten

+ 28 - 4
client/CBattleInterface.cpp

@@ -37,6 +37,7 @@ const double M_PI = 3.14159265358979323846;
 #define _USE_MATH_DEFINES
 #include <cmath>
 #endif
+#include <boost/format.hpp>
 
 /*
  * CBattleInterface.cpp, part of VCMI engine
@@ -1198,8 +1199,8 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	bOptions = new AdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, boost::bind(&CBattleInterface::bOptionsf,this), 3 + pos.x, 561 + pos.y, "icm003.def", SDLK_o);
 	bSurrender = new AdventureMapButton (CGI->generaltexth->zelp[379].first, CGI->generaltexth->zelp[379].second, boost::bind(&CBattleInterface::bSurrenderf,this), 54 + pos.x, 561 + pos.y, "icm001.def", SDLK_s);
 	bFlee = new AdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, boost::bind(&CBattleInterface::bFleef,this), 105 + pos.x, 561 + pos.y, "icm002.def", SDLK_r);
-	bSurrender->block(!curInt->cb->battleCanFlee());
 	bFlee->block(!curInt->cb->battleCanFlee());	
+	bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
 	bAutofight  = new AdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, boost::bind(&CBattleInterface::bAutofightf,this), 157 + pos.x, 561 + pos.y, "icm004.def", SDLK_a);
 	bSpell = new AdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, boost::bind(&CBattleInterface::bSpellf,this), 645 + pos.x, 561 + pos.y, "icm005.def", SDLK_c);
 	bSpell->block(true);
@@ -2160,6 +2161,15 @@ void CBattleInterface::bSurrenderf()
 {
 	if(spellDestSelectMode) //we are casting a spell
 		return;
+
+	int cost = curInt->cb->battleGetSurrenderCost();
+	if(cost >= 0)
+	{
+		const CGHeroInstance *opponent = curInt->cb->battleGetFightingHero(1);
+		std::string enemyHeroName = opponent ? opponent->name : "#ENEMY#"; //TODO: should surrendering without enemy hero be enabled? 
+		std::string surrenderMessage = boost::str(boost::format(CGI->generaltexth->allTexts[32]) % enemyHeroName % cost); //%s states: "I will accept your surrender and grant you and your troops safe passage for the price of %d gold."
+		curInt->showYesNoDialog(surrenderMessage, std::vector<SComponent*>(), boost::bind(&CBattleInterface::reallySurrender,this), 0, false);
+	}
 }
 
 void CBattleInterface::bFleef()
@@ -2170,7 +2180,7 @@ void CBattleInterface::bFleef()
 	if( curInt->cb->battleCanFlee() )
 	{
 		CFunctionList<void()> ony = boost::bind(&CBattleInterface::reallyFlee,this);
-		curInt->showYesNoDialog(CGI->generaltexth->allTexts[28],std::vector<SComponent*>(), ony, 0, false);
+		curInt->showYesNoDialog(CGI->generaltexth->allTexts[28],std::vector<SComponent*>(), ony, 0, false); //Are you sure you want to retreat?
 	}
 	else
 	{
@@ -2185,7 +2195,7 @@ void CBattleInterface::bFleef()
 				heroName = defendingHeroInstance->name;
 		//calculating text
 		char buffer[1000];
-		sprintf(buffer, CGI->generaltexth->allTexts[340].c_str(), heroName.c_str());
+		sprintf(buffer, CGI->generaltexth->allTexts[340].c_str(), heroName.c_str()); //The Shackles of War are present.  %s can not retreat!
 
 		//printing message
 		curInt->showInfoDialog(std::string(buffer), comps);
@@ -2194,10 +2204,23 @@ void CBattleInterface::bFleef()
 
 void CBattleInterface::reallyFlee()
 {
-	giveCommand(4,0,0);
+	giveCommand(BattleAction::RETREAT,0,0);
 	CCS->curh->changeGraphic(0, 0);
 }
 
+void CBattleInterface::reallySurrender()
+{
+	if(curInt->cb->getResourceAmount(Res::GOLD) < curInt->cb->battleGetSurrenderCost())
+	{
+		curInt->showInfoDialog(CGI->generaltexth->allTexts[29]); //You don't have enough gold!
+	}
+	else
+	{
+		giveCommand(BattleAction::SURRENDER,0,0);
+		CCS->curh->changeGraphic(0, 0);
+	}
+}
+
 void CBattleInterface::bAutofightf()
 {
 	if(spellDestSelectMode) //we are casting a spell
@@ -3013,6 +3036,7 @@ void CBattleInterface::activateStack()
 	bSpell->block(!curInt->cb->battleCanCastSpell());
 	bSurrender->block((curInt == attackerInt ? defendingHeroInstance : attackingHeroInstance) == NULL);
 	bFlee->block(!curInt->cb->battleCanFlee());
+	bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
 
 	GH.fakeMouseMove();
 

+ 1 - 0
client/CBattleInterface.h

@@ -496,6 +496,7 @@ public:
 	void bSurrenderf();
 	void bFleef();
 	void reallyFlee(); //performs fleeing without asking player
+	void reallySurrender(); //performs surrendering without asking player
 	void bAutofightf();
 	void bSpellf();
 	void bWaitf();

+ 36 - 0
lib/BattleState.cpp

@@ -1883,6 +1883,42 @@ std::vector<ui32> BattleInfo::calculateResistedStacks( const CSpell * sp, const
 	return ret;
 }
 
+int BattleInfo::getSurrenderingCost(int player) const
+{
+	if(!battleCanFlee(player)) //to surrender, conditions of fleeing must be fulfilled
+		return -1;
+	if(!getHero(theOtherPlayer(player))) //additionally, there must be an enemy hero
+		return -2;
+
+	int ret = 0;
+	double discount = 0;
+	BOOST_FOREACH(const CStack *s, stacks)
+		if(s->owner == player  &&  s->base) //we pay for our stack that comes from our army (the last condition eliminates summoned cres and war machines)
+			ret += s->getCreature()->cost[Res::GOLD] * s->count;
+
+	if(const CGHeroInstance *h = getHero(player))
+		discount += h->valOfBonuses(Bonus::SURRENDER_DISCOUNT);
+
+	ret *= (100.0 - discount) / 100.0;
+	amax(ret, 0); //no negative costs for >100% discounts (impossible in original H3 mechanics, but some day...)
+	return ret;
+}
+
+int BattleInfo::theOtherPlayer(int player) const
+{
+	return sides[!whatSide(player)];
+}
+
+ui8 BattleInfo::whatSide(int player) const
+{
+	for(int i = 0; i < ARRAY_COUNT(sides); i++)
+		if(sides[i] == player)
+			return i;
+
+	tlog1 << "BattleInfo::whatSide: Player " << player << " is not in battle!\n";
+	return -1;
+}
+
 CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
 	: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),   
 	counterAttacks(1)

+ 4 - 0
lib/BattleState.h

@@ -131,6 +131,10 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
 	void localInit();
 	static BattleInfo * setupBattle( int3 tile, int terrain, int terType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town );
 	bool isInTacticRange( THex dest ) const;
+	int getSurrenderingCost(int player) const;
+
+	int theOtherPlayer(int player) const;
+	ui8 whatSide(int player) const;
 };
 
 class DLL_EXPORT CStack : public CBonusSystemNode, public CStackBasicDescriptor

+ 8 - 0
lib/CObjectHandler.cpp

@@ -1177,6 +1177,14 @@ void CGHeroInstance::updateSkill(int which, int val)
 		else
 			b->val = +val;
 	}
+	else if(which == DIPLOMACY) //surrender discount: 20% per level
+	{
+		
+		if(Bonus *b = getBonus(Selector::type(Bonus::SURRENDER_DISCOUNT) && Selector::sourceType(Bonus::SECONDARY_SKILL)))
+			b->val = +val;
+		else
+			addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::SURRENDER_DISCOUNT, Bonus::SECONDARY_SKILL, val * 20, which));
+	}
 
 	int skillVal = 0;
 	switch (which)

+ 32 - 224
server/CGameHandler.cpp

@@ -1254,11 +1254,7 @@ void CGameHandler::checkForBattleEnd( std::vector<CStack*> &stacks )
 	}
 	if(!hasStack[0] || !hasStack[1]) //somebody has won
 	{
-		BattleResult *br = new BattleResult; //will be deleted at the end of startBattle(...)
-		br->result = 0;
-		br->winner = hasStack[1]; //fleeing side loses
-		gs->curB->calculateCasualties(br->casualties);
-		battleResult.set(br);
+		setBattleResult(0, hasStack[1]);
 	}
 }
 
@@ -1665,40 +1661,6 @@ void CGameHandler::stopHeroVisitCastle(int obj, int heroID)
 	sendAndApply(&vc);
 }
 
-// bool CGameHandler::removeArtifact(const CArtifact* art, int hid)
-// {
-// 	const CGHeroInstance* h = getHero(hid);
-// 
-// 	SetHeroArtifacts sha;
-// 	sha.hid = hid;
-// 	sha.artifacts = h->artifacts;
-// 	sha.artifWorn = h->artifWorn;
-// 	
-// 	std::vector<const CArtifact*>::iterator it;
-// 	if 	((it = std::find(sha.artifacts.begin(), sha.artifacts.end(), art)) != sha.artifacts.end()) //it is in backpack
-// 		sha.artifacts.erase(it);
-// 	else //worn
-// 	{
-// 		std::map<ui16, const CArtifact*>::iterator itr;
-// 		for (itr = sha.artifWorn.begin(); itr != sha.artifWorn.end(); ++itr)
-// 		{
-// 			if (itr->second == art)
-// 			{
-// 				VLC->arth->unequipArtifact(sha.artifWorn, itr->first);
-// 				break;
-// 			}
-// 		}
-// 
-// 		if(itr == sha.artifWorn.end())
-// 		{
-// 			tlog2 << "Cannot find artifact to remove!\n";
-// 			return false;
-// 		}
-// 	}
-// 	sendAndApply(&sha);
-// 	return true;
-// }
-
 void CGameHandler::removeArtifact(const ArtifactLocation &al)
 {
 	assert(al.getArt());
@@ -1737,13 +1699,6 @@ void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstan
 	startBattleI(army1, army2, army2->visitablePos(), cb, creatureBank);
 }
 
-//void CGameHandler::startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb) //for hero<=>neutral army
-//{
-//	CGHeroInstance* h = const_cast<CGHeroInstance*>(getHero(heroID));
-//	startBattleI(&h->army,&army,tile,h,NULL,cb);
-//	//battle(&h->army,army,tile,h,NULL);
-//}
-
 void CGameHandler::changeSpells( int hid, bool give, const std::set<ui32> &spells )
 {
 	ChangeSpells cs;
@@ -2534,17 +2489,7 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 		COMPLAIN_RET("No artifact to move!");
 	if (destArtifact && srcHero->tempOwner != destHero->tempOwner)
 		COMPLAIN_RET("Can't touch artifact on hero of another player!");
-
-
-
-// 	// Combinational artifacts needs to be removed first so they don't get denied movement because of their own locks.
-// 	if (srcHeroID == destHeroID && srcSlot < 19 && destSlot < 19) 
-// 	{
-// 		sha.setArtAtPos(srcSlot, NULL);
-// 		if (!vstd::contains(sha.artifWorn, destSlot))
-// 			destArtifact = NULL;
-// 	}
-
+	
 	// Check if src/dest slots are appropriate for the artifacts exchanged.
 	// Moving to the backpack is always allowed.
 	if ((!srcArtifact || destSlot < Arts::BACKPACK_START)
@@ -2562,10 +2507,6 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 	if(dst.slot >= Arts::BACKPACK_START)
 		amin(dst.slot, Arts::BACKPACK_START + dst.hero->artifactsInBackpack.size());
 
-//  	// Correction for destination from removing source artifact in backpack.
-//  	if (src.slot >= 19 && dst.slot >= 19 && src.slot < dst.slot)
-//  		dst.slot--;
-
 	if (src.slot == dst.slot  &&  src.hero == dst.hero)
 		COMPLAIN_RET("Won't move artifact: Dest same as source!");
 
@@ -2583,37 +2524,6 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
 		moveArtifact(src, dst);
 	}
 
-// 
-// 	// If dest does not fit in src, put it in dest's backpack instead.
-// 	if (srcHeroID == destHeroID) // To avoid stumbling on own locks, remove artifact first.
-// 		sha.setArtAtPos(destSlot, NULL);
-// 	const bool destFits = !destArtifact || srcSlot >= 19 || destSlot >= 19 || destArtifact->fitsAt(sha.artifWorn, srcSlot);
-// 	if (srcHeroID == destHeroID && destArtifact)
-// 		sha.setArtAtPos(destSlot, destArtifact);
-// 
-// 	sha.setArtAtPos(srcSlot, NULL);
-// 	if (destSlot < 19 && (destArtifact || srcSlot < 19) && destFits)
-// 		sha.setArtAtPos(srcSlot, destArtifact ? destArtifact : NULL);
-// 
-// 	// Internal hero artifact arrangement.
-// 	if(srcHero == destHero) 
-// 	{
-// 
-// 		sha.setArtAtPos(destSlot, srcHero->getArtAtPos(srcSlot));
-// 	}
-// 	if (srcHeroID != destHeroID) 
-// 	{
-// 		// Exchange between two different heroes.
-// 		SetHeroArtifacts sha2;
-// 		sha2.hid = destHeroID;
-// 		sha2.artifacts = destHero->artifacts;
-// 		sha2.artifWorn = destHero->artifWorn;
-// 		sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact : NULL);
-// 		if (!destFits)
-// 			sha2.setArtAtPos(sha2.artifacts.size() + 19, destHero->getArtAtPos(destSlot));
-// 		sendAndApply(&sha2);
-// 	}
-// 	sendAndApply(&sha);
 	return true;
 }
 
@@ -2656,118 +2566,7 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 		da.al = ArtifactLocation(hero, artifactSlot);
 		sendAndApply(&da);
 	}
-	/*
-	SetHeroArtifacts sha;
-	sha.hid = heroID;
-	sha.artifacts = hero->artifacts;
-	sha.artifWorn = hero->artifWorn;
-
-	if (assemble)
-	{
-		if (VLC->arth->artifacts.size() < assembleTo)
-		{
-			complain("Illegal artifact to assemble to.");
-			return false;
-		}
-
-		if (!destArtifact->canBeAssembledTo(hero->artifWorn, assembleTo))
-		{
-			complain("Artifact cannot be assembled.");
-			return false;
-		}
-
-		const CArtifact &artifact = *VLC->arth->artifacts[assembleTo];
-
-		if (artifact.constituents == NULL)
-		{
-			complain("Not a combinational artifact.");
-			return false;
-		}
-
-		// Perform assembly.
-		bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
-		const bool destSpecific = vstd::contains(artifact.possibleSlots, artifactSlot); // Prefer the chosen slot as the location for the assembled artifact.
-
-		BOOST_FOREACH(ui32 constituentID, *artifact.constituents)
-		{
-			if (destSpecific && constituentID == destArtifact->id)
-			{
-				sha.artifWorn[artifactSlot] = VLC->arth->artifacts[assembleTo];
-				destConsumed = true;
-				continue;
-			}
-
-			bool found = false;
-			for (std::map<ui16, const CArtifact*>::iterator it = sha.artifWorn.begin(); it != sha.artifWorn.end(); ++it)
-			{
-				if (it->second->id == constituentID)
-				{ // Found possible constituent to substitute.
-					if (destSpecific && !destConsumed && it->second->id == destArtifact->id)
-					{
-						// Find the specified destination for assembled artifact.
-						if (it->first == artifactSlot)
-						{
-							it->second = VLC->arth->artifacts[assembleTo];
-							destConsumed = true;
-
-							found = true;
-							break;
-						}
-					}
-					else
-					{
-						// Either put the assembled artifact in a fitting spot, or put a lock.
-						if (!destSpecific && !destConsumed && vstd::contains(artifact.possibleSlots, it->first))
-						{
-							it->second = VLC->arth->artifacts[assembleTo];
-							destConsumed = true;
-						}
-						else
-						{
-							it->second = VLC->arth->artifacts[145];
-						}
-
-						found = true;
-						break;
-					}
-				}
-			}
-			if (!found) {
-				complain("Constituent missing.");
-				return false;
-			}
-		}
-	}
-	else
-	{
-		// Perform disassembly.
-		bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
-		BOOST_FOREACH(ui32 constituentID, *destArtifact->constituents)
-		{
-			const CArtifact &constituent = *VLC->arth->artifacts[constituentID];
-
-			if (!destConsumed && vstd::contains(constituent.possibleSlots, artifactSlot))
-			{
-				sha.artifWorn[artifactSlot] = VLC->arth->artifacts[constituentID];
-				destConsumed = true;
-			}
-			else
-			{
-				BOOST_REVERSE_FOREACH(ui16 slotID, constituent.possibleSlots)
-				{
-					if (vstd::contains(sha.artifWorn, slotID) && sha.artifWorn[slotID]->id == 145)
-					{
-						const_cast<CArtifact*>(sha.artifWorn[slotID])->id = constituentID;
-						break;
-					}
-				}
-			}
-		}
-	}
 
-	sendAndApply(&sha);
-
-	return true;*/
 	return false;
 }
 
@@ -3142,17 +2941,28 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 		}
 	case BattleAction::RETREAT: //retreat/flee
 		{
-			if( !gs->curB->battleCanFlee(ba.side ? gs->curB->sides[1] : gs->curB->sides[0]) )
-				break;
-			//TODO: remove retreating hero from map and place it in recruitment list
-			BattleResult *br = new BattleResult;
-			br->result = 1;
-			br->winner = !ba.side; //fleeing side loses
-			gs->curB->calculateCasualties(br->casualties);
-			giveExp(*br);
-			battleResult.set(br);
+			if(!gs->curB->battleCanFlee(gs->curB->sides[ba.side]))
+				complain("Cannot retreat!");
+			else
+				setBattleResult(1, !ba.side); //surrendering side loses
 			break;
 		}
+	case BattleAction::SURRENDER:
+		{
+			int player = gs->curB->sides[ba.side];
+			int cost = gs->curB->getSurrenderingCost(player);
+			if(cost < 0)
+				complain("Cannot surrender!");
+			else if(getResource(player, Res::GOLD) < cost)
+				complain("Not enough gold to surrender!");
+			else
+			{
+				giveResource(player, Res::GOLD, -cost);
+				setBattleResult(2, !ba.side); //surrendering side loses
+			}
+			break;
+		}
+		break;
 	case BattleAction::WALK_AND_ATTACK: //walk or attack
 		{
 			sendAndApply(&StartAction(ba)); //start movement and attack
@@ -3538,17 +3348,6 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 		if(!hero) return;
 		for (int g=7; g<=140; ++g)
 			giveHeroNewArtifact(hero, VLC->arth->artifacts[g], -1);
-
-// 		SetHeroArtifacts sha;
-// 		sha.hid = hero->id;
-// 		sha.artifacts = hero->artifacts;
-// 		sha.artifWorn = hero->artifWorn;
-// 		sha.artifacts.push_back(VLC->arth->artifacts[2]); //grail
-// 		for (int g=7; g<=140; ++g)
-// 		{
-// 			sha.artifacts.push_back(VLC->arth->artifacts[g]);
-// 		}
-// 		sendAndApply(&sha);
 	}
 	else
 		cheated = false;
@@ -3730,7 +3529,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 {
 	switch(ba.actionType)
 	{
-	case 1: //hero casts spell
+	case BattleAction::HERO_SPELL: //hero casts spell
 		{
 			const CGHeroInstance *h = gs->curB->heroes[ba.side];
 			const CGHeroInstance *secondHero = gs->curB->heroes[!ba.side];
@@ -5062,6 +4861,15 @@ void CGameHandler::giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact
 	giveHeroArtifact(h, a, pos);
 }
 
+void CGameHandler::setBattleResult(int resultType, int victoriusSide)
+{
+	BattleResult *br = new BattleResult;
+	br->result = resultType;
+	br->winner = victoriusSide; //surrendering side loses
+	gs->curB->calculateCasualties(br->casualties);
+	battleResult.set(br);
+}
+
 CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleInfo *bat)
 {
 	int color = army->tempOwner;

+ 1 - 0
server/CGameHandler.h

@@ -120,6 +120,7 @@ public:
 	void prepareAttack(BattleAttack &bat, const CStack *att, const CStack *def, int distance); //distance - number of hexes travelled before attacking
 	void checkForBattleEnd( std::vector<CStack*> &stacks );
 	void setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town);
+	void setBattleResult(int resultType, int victoriusSide);
 
 	CGameHandler(void);
 	~CGameHandler(void);