Bläddra i källkod

Quick Combat system setting works… if user doesn't click in the meantime.

Michał W. Urbańczyk 12 år sedan
förälder
incheckning
04d11519ef

+ 66 - 66
client/CPlayerInterface.cpp

@@ -66,6 +66,15 @@
 // They do not own any mutexes intiially.
 // They do not own any mutexes intiially.
 #define THREAD_CREATED_BY_CLIENT
 #define THREAD_CREATED_BY_CLIENT
 
 
+#define RETURN_IF_QUICK_COMBAT		\
+	if(isAutoFightOn)				\
+		return;
+
+#define BATTLE_EVENT_POSSIBLE_RETURN\
+	if(LOCPLINT != this)			\
+		return;						\
+	RETURN_IF_QUICK_COMBAT
+
 using namespace boost::assign;
 using namespace boost::assign;
 using namespace CSDL_Ext;
 using namespace CSDL_Ext;
 
 
@@ -600,12 +609,19 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, BuildingID build
 void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
 void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
+	if(settings["adventure"]["quickCombat"].Bool())
+	{
+		autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String());
+		autofightingAI->init(cb);
+		autofightingAI->battleStart(army1, army2, int3(0,0,0), hero1, hero2, side);
+		isAutoFightOn = true;
+		cb->registerBattleInterface(autofightingAI);
 	}
 	}
-
+	
 	waitForAllDialogs();
 	waitForAllDialogs();
+
+	BATTLE_EVENT_POSSIBLE_RETURN;
+
 	GH.pushInt(battleInt);
 	GH.pushInt(battleInt);
 }
 }
 
 
@@ -613,10 +629,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
 void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom)
 void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	for(int b=0; b<healedStacks.size(); ++b)
 	for(int b=0; b<healedStacks.size(); ++b)
 	{
 	{
@@ -663,10 +676,7 @@ void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, u
 void CPlayerInterface::battleNewStackAppeared(const CStack * stack)
 void CPlayerInterface::battleNewStackAppeared(const CStack * stack)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->newStack(stack);
 	battleInt->newStack(stack);
 }
 }
@@ -674,10 +684,7 @@ void CPlayerInterface::battleNewStackAppeared(const CStack * stack)
 void CPlayerInterface::battleObstaclesRemoved(const std::set<si32> & removedObstacles)
 void CPlayerInterface::battleObstaclesRemoved(const std::set<si32> & removedObstacles)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 // 	for(std::set<si32>::const_iterator it = removedObstacles.begin(); it != removedObstacles.end(); ++it)
 // 	for(std::set<si32>::const_iterator it = removedObstacles.begin(); it != removedObstacles.end(); ++it)
 // 	{
 // 	{
@@ -697,10 +704,7 @@ void CPlayerInterface::battleObstaclesRemoved(const std::set<si32> & removedObst
 void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca)
 void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->stackIsCatapulting(ca);
 	battleInt->stackIsCatapulting(ca);
 }
 }
@@ -708,10 +712,7 @@ void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca)
 void CPlayerInterface::battleStacksRemoved(const BattleStacksRemoved & bsr)
 void CPlayerInterface::battleStacksRemoved(const BattleStacksRemoved & bsr)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	for(std::set<ui32>::const_iterator it = bsr.stackIDs.begin(); it != bsr.stackIDs.end(); ++it) //for each removed stack
 	for(std::set<ui32>::const_iterator it = bsr.stackIDs.begin(); it != bsr.stackIDs.end(); ++it) //for each removed stack
 	{
 	{
@@ -723,10 +724,7 @@ void CPlayerInterface::battleStacksRemoved(const BattleStacksRemoved & bsr)
 void CPlayerInterface::battleNewRound(int round) //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 void CPlayerInterface::battleNewRound(int round) //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->newRound(round);
 	battleInt->newRound(round);
 }
 }
@@ -734,10 +732,7 @@ void CPlayerInterface::battleNewRound(int round) //called at the beginning of ea
 void CPlayerInterface::actionStarted(const BattleAction &action)
 void CPlayerInterface::actionStarted(const BattleAction &action)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	curAction = new BattleAction(action);
 	curAction = new BattleAction(action);
 	battleInt->startAction(curAction);
 	battleInt->startAction(curAction);
@@ -746,10 +741,7 @@ void CPlayerInterface::actionStarted(const BattleAction &action)
 void CPlayerInterface::actionFinished(const BattleAction &action)
 void CPlayerInterface::actionFinished(const BattleAction &action)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->endAction(curAction);
 	battleInt->endAction(curAction);
 	delete curAction;
 	delete curAction;
@@ -760,6 +752,23 @@ BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when i
 {
 {
 	THREAD_CREATED_BY_CLIENT;
 	THREAD_CREATED_BY_CLIENT;
     logGlobal->traceStream() << "Awaiting command for " << stack->nodeName();
     logGlobal->traceStream() << "Awaiting command for " << stack->nodeName();
+
+	if(autofightingAI)
+	{
+		if(isAutoFightOn)
+		{
+			assert(autofightingAI);
+			auto ret = autofightingAI->activeStack(stack);
+			if(isAutoFightOn)
+			{
+				return ret;
+			}
+		}
+
+		cb->unregisterBattleInterface(autofightingAI);
+		autofightingAI = nullptr;
+	}
+
 	CBattleInterface *b = battleInt;
 	CBattleInterface *b = battleInt;
 
 
 	assert(!b->givenCommand->get()); //command buffer must be clean (we don't want to use old command)
 	assert(!b->givenCommand->get()); //command buffer must be clean (we don't want to use old command)
@@ -790,56 +799,56 @@ BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when i
 void CPlayerInterface::battleEnd(const BattleResult *br)
 void CPlayerInterface::battleEnd(const BattleResult *br)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
+	if(isAutoFightOn)
+	{
+		isAutoFightOn = false;
+		cb->unregisterBattleInterface(autofightingAI);
+		autofightingAI = nullptr;
+
+		SDL_Rect temp_rect = genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
+		auto resWindow = new CBattleResultWindow(*br, temp_rect, *this);
+		GH.pushInt(resWindow);
 		return;
 		return;
 	}
 	}
 
 
+	BATTLE_EVENT_POSSIBLE_RETURN;
+
 	battleInt->battleFinished(*br);
 	battleInt->battleFinished(*br);
 }
 }
 
 
 void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance)
 void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->stackMoved(stack, dest, distance);
 	battleInt->stackMoved(stack, dest, distance);
 }
 }
 void CPlayerInterface::battleSpellCast( const BattleSpellCast *sc )
 void CPlayerInterface::battleSpellCast( const BattleSpellCast *sc )
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->spellCast(sc);
 	battleInt->spellCast(sc);
 }
 }
 void CPlayerInterface::battleStacksEffectsSet( const SetStackEffect & sse )
 void CPlayerInterface::battleStacksEffectsSet( const SetStackEffect & sse )
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->battleStacksEffectsSet(sse);
 	battleInt->battleStacksEffectsSet(sse);
 }
 }
 void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte)
 void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
+	//TODO why is this different (no return on LOPLINT != this) ?
+
+	RETURN_IF_QUICK_COMBAT;
 	battleInt->battleTriggerEffect(bte);
 	battleInt->battleTriggerEffect(bte);
 }
 }
 void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
 void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 	
 	
 	std::vector<StackAttackedInfo> arg;
 	std::vector<StackAttackedInfo> arg;
 	for(std::vector<BattleStackAttacked>::const_iterator i = bsa.begin(); i != bsa.end(); i++)
 	for(std::vector<BattleStackAttacked>::const_iterator i = bsa.begin(); i != bsa.end(); i++)
@@ -866,10 +875,7 @@ void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacke
 void CPlayerInterface::battleAttack(const BattleAttack *ba)
 void CPlayerInterface::battleAttack(const BattleAttack *ba)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	assert(curAction);
 	assert(curAction);
 	if(ba->lucky()) //lucky hit
 	if(ba->lucky()) //lucky hit
@@ -938,10 +944,7 @@ void CPlayerInterface::battleAttack(const BattleAttack *ba)
 void CPlayerInterface::battleObstaclePlaced(const CObstacleInstance &obstacle)
 void CPlayerInterface::battleObstaclePlaced(const CObstacleInstance &obstacle)
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->obstaclePlaced(obstacle);
 	battleInt->obstaclePlaced(obstacle);
 }
 }
@@ -2236,10 +2239,7 @@ void CPlayerInterface::updateInfo(const CGObjectInstance * specific)
 void CPlayerInterface::battleNewRoundFirst( int round )
 void CPlayerInterface::battleNewRoundFirst( int round )
 {
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(LOCPLINT != this)
-	{ //another local interface should do this
-		return;
-	}
+	BATTLE_EVENT_POSSIBLE_RETURN;
 
 
 	battleInt->newRoundFirst(round);
 	battleInt->newRoundFirst(round);
 }
 }

+ 5 - 0
client/CPlayerInterface.h

@@ -111,6 +111,11 @@ public:
 	std::map<const CGHeroInstance *, CGPath> paths; //maps hero => selected path in adventure map
 	std::map<const CGHeroInstance *, CGPath> paths; //maps hero => selected path in adventure map
 	std::vector<const CGHeroInstance *> sleepingHeroes; //if hero is in here, he's sleeping
 	std::vector<const CGHeroInstance *> sleepingHeroes; //if hero is in here, he's sleeping
 
 
+	//During battle is quick combat mode is used
+	shared_ptr<CBattleGameInterface> autofightingAI; //AI that makes decisions
+	bool isAutoFightOn; //Flag, switch it to stop quick combat. Don't touch if there is no battle interface.
+
+
 	struct SpellbookLastSetting
 	struct SpellbookLastSetting
 	{
 	{
 		int spellbookLastPageBattle, spellbokLastPageAdvmap; //on which page we left spellbook
 		int spellbookLastPageBattle, spellbokLastPageAdvmap; //on which page we left spellbook

+ 10 - 9
client/Client.cpp

@@ -579,16 +579,17 @@ void CClient::battleStarted(const BattleInfo * info)
 // 		if(battleCallbacks.count(side))
 // 		if(battleCallbacks.count(side))
 // 			battleCallbacks[side]->setBattle(info);
 // 			battleCallbacks[side]->setBattle(info);
 
 
-	shared_ptr<CPlayerInterface> att, def;
-	if(vstd::contains(playerint, info->sides[0]) && playerint[info->sides[0]]->human)
-		att = std::dynamic_pointer_cast<CPlayerInterface>( playerint[info->sides[0]] );
-	else
-		att = NULL;
+	shared_ptr<CPlayerInterface> att = nullptr, def = nullptr;
 
 
-	if(vstd::contains(playerint, info->sides[1]) && playerint[info->sides[1]]->human)
-		def = std::dynamic_pointer_cast<CPlayerInterface>( playerint[info->sides[1]] );
-	else
-		def = NULL;
+	//If quick combat is not, do not prepare interfaces for battleint
+	if(!settings["adventure"]["quickCombat"].Bool())
+	{
+		if(vstd::contains(playerint, info->sides[0]) && playerint[info->sides[0]]->human)
+			att = std::dynamic_pointer_cast<CPlayerInterface>( playerint[info->sides[0]] );
+
+		if(vstd::contains(playerint, info->sides[1]) && playerint[info->sides[1]]->human)
+			def = std::dynamic_pointer_cast<CPlayerInterface>( playerint[info->sides[1]] );
+	}
 
 
 	if(!gNoGUI && (!!att || !!def || gs->scenarioOps->mode == StartInfo::DUEL))
 	if(!gNoGUI && (!!att || !!def || gs->scenarioOps->mode == StartInfo::DUEL))
 	{
 	{

+ 25 - 25
client/battle/CBattleInterface.cpp

@@ -97,7 +97,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	  currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL),  stackCanCastSpell(false), creatureCasting(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL), sp(NULL),
 	  currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL),  stackCanCastSpell(false), creatureCasting(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL), sp(NULL),
 	  siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0),
 	  siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0),
 	  givenCommand(NULL), myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL),
 	  givenCommand(NULL), myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL),
-	  autofightingAI(nullptr), isAutoFightOn(false), aiThread(nullptr), background(nullptr)
+	  background(nullptr)
 {
 {
 	OBJ_CONSTRUCTION;
 	OBJ_CONSTRUCTION;
 
 
@@ -498,7 +498,7 @@ void CBattleInterface::setPrintMouseShadow(bool set)
 
 
 void CBattleInterface::activate()
 void CBattleInterface::activate()
 {
 {
-	if(isAutoFightOn)
+	if(curInt->isAutoFightOn)
 	{
 	{
 		bAutofight->activate();
 		bAutofight->activate();
 		return;
 		return;
@@ -1277,23 +1277,23 @@ void CBattleInterface::bAutofightf()
 		return;
 		return;
 	
 	
 	//Stop auto-fight mode
 	//Stop auto-fight mode
-	if(isAutoFightOn)
+	if(curInt->isAutoFightOn)
 	{
 	{
-		assert(autofightingAI);
-		isAutoFightOn = false;
+		assert(curInt->autofightingAI);
+		curInt->isAutoFightOn = false;
 		logGlobal->traceStream() << "Stopping the autofight...";
 		logGlobal->traceStream() << "Stopping the autofight...";
-		aiThread->interrupt();
-		aiThread->join();
-
-		autofightingAI = nullptr;
-		aiThread = nullptr;
 	}
 	}
 	else
 	else
 	{
 	{
-		isAutoFightOn = true;
-		autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String());
-		autofightingAI->init(curInt->cb);
-		autofightingAI->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide());
+		curInt->isAutoFightOn = true;	
+		deactivate();
+		bAutofight->activate();
+
+		auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String());
+		ai->init(curInt->cb);
+		ai->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide());
+		curInt->autofightingAI = ai;
+		curInt->cb->registerBattleInterface(ai);
 
 
 		requestAutofightingAIToTakeAction();
 		requestAutofightingAIToTakeAction();
 	}
 	}
@@ -1627,7 +1627,7 @@ void CBattleInterface::displayBattleFinished()
 	CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
 	CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
 
 
 	SDL_Rect temp_rect = genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
 	SDL_Rect temp_rect = genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
-	resWindow = new CBattleResultWindow(*bresult, temp_rect, this);
+	resWindow = new CBattleResultWindow(*bresult, temp_rect, *this->curInt);
 	GH.pushInt(resWindow);
 	GH.pushInt(resWindow);
 }
 }
 
 
@@ -2096,9 +2096,6 @@ void CBattleInterface::activateStack()
 	if(!pendingAnims.size() && !active)
 	if(!pendingAnims.size() && !active)
 		activate();
 		activate();
 
 
-	if(isAutoFightOn)
-		requestAutofightingAIToTakeAction();
-
 	GH.fakeMouseMove();
 	GH.fakeMouseMove();
 }
 }
 
 
@@ -3590,20 +3587,23 @@ InfoAboutHero CBattleInterface::enemyHero() const
 
 
 void CBattleInterface::requestAutofightingAIToTakeAction()
 void CBattleInterface::requestAutofightingAIToTakeAction()
 {
 {
-	assert(isAutoFightOn);
+	assert(curInt->isAutoFightOn);
 
 
-	deactivate();
-	bAutofight->activate();
-
-	aiThread = make_unique<boost::thread>([&] 
+	auto tmp = make_unique<boost::thread>([&] 
 	{
 	{
-		auto ba = new BattleAction(autofightingAI->activeStack(activeStack));
+		auto ba = new BattleAction(curInt->autofightingAI->activeStack(activeStack));
 
 
-		if(isAutoFightOn)
+		if(curInt->isAutoFightOn)
 		{
 		{
 			givenCommand->setn(ba);
 			givenCommand->setn(ba);
 		}
 		}
+		else
+		{
+			boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
+			activateStack();
+		}
 	});
 	});
+	tmp->detach();
 }
 }
 
 
 CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)
 CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)

+ 0 - 4
client/battle/CBattleInterface.h

@@ -156,10 +156,6 @@ private:
 	PossibleActions selectedAction; //last action chosen (and saved) by player
 	PossibleActions selectedAction; //last action chosen (and saved) by player
 	PossibleActions illegalAction; //most likely action that can't be performed here
 	PossibleActions illegalAction; //most likely action that can't be performed here
 
 
-	shared_ptr<CBattleGameInterface> autofightingAI;
-	bool isAutoFightOn;
-	unique_ptr<boost::thread> aiThread;
-
 	void requestAutofightingAIToTakeAction();
 	void requestAutofightingAIToTakeAction();
 
 
 	void getPossibleActionsForStack (const CStack * stack); //called when stack gets its turn
 	void getPossibleActionsForStack (const CStack * stack); //called when stack gets its turn

+ 35 - 49
client/battle/CBattleInterfaceClasses.cpp

@@ -304,13 +304,13 @@ void CBattleOptionsWindow::bExitf()
 	GH.popIntTotally(this);
 	GH.popIntTotally(this);
 }
 }
 
 
-CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect & pos, CBattleInterface * _owner)
+CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect & pos, CPlayerInterface &_owner)
 : owner(_owner)
 : owner(_owner)
 {
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	this->pos = pos;
 	this->pos = pos;
 	CPicture * bg = new CPicture("CPRESULT");
 	CPicture * bg = new CPicture("CPRESULT");
-	bg->colorize(owner->curInt->playerID);
+	bg->colorize(owner.playerID);
 
 
 	exit = new CAdventureMapButton ("", "", boost::bind(&CBattleResultWindow::bExitf,this), 384, 505, "iok6432.def", SDLK_RETURN);
 	exit = new CAdventureMapButton ("", "", boost::bind(&CBattleResultWindow::bExitf,this), 384, 505, "iok6432.def", SDLK_RETURN);
 	exit->borderColor = Colors::METALLIC_GOLD;
 	exit->borderColor = Colors::METALLIC_GOLD;
@@ -331,59 +331,40 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 	new CLabel(232, 332, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[408]);
 	new CLabel(232, 332, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[408]);
 	new CLabel(232, 428, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[409]);
 	new CLabel(232, 428, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[409]);
 
 
-	std::string attackerName, defenderName;
+	std::string sideNames[2] = {"N/A", "N/A"};
 
 
-	if(owner->attackingHeroInstance) //a hero attacked
+	for(int i = 0; i < 2; i++)
 	{
 	{
-		new CAnimImage("PortraitsLarge", owner->attackingHeroInstance->portrait, 0, 21, 38);
-		//setting attackerName
-		attackerName = owner->attackingHeroInstance->name;
-	}
-	else //a monster attacked
-	{
-		int bestMonsterID = -1;
-		ui32 bestPower = 0;
-		for(TSlots::const_iterator it = owner->army1->Slots().begin(); it!=owner->army1->Slots().end(); ++it)
+		auto heroInfo = owner.cb->battleGetHeroInfo(i);
+		const int xs[] = {21, 392};
+
+		if(heroInfo.portrait >= 0) //attacking hero 
 		{
 		{
-			if(it->second->type->AIValue > bestPower)
-			{
-				bestPower = it->second->type->AIValue;
-				bestMonsterID = it->second->type->idNumber;
-			}
+			new CAnimImage("PortraitsLarge", heroInfo.portrait, 0, xs[i], 38);
+			sideNames[i] = heroInfo.name;
 		}
 		}
-		new CAnimImage("TWCRPORT", bestMonsterID+2, 0, 21, 38);
-		//setting attackerName
-		attackerName =  CGI->creh->creatures[bestMonsterID]->namePl;
-	}
-	if(owner->defendingHeroInstance) //a hero defended
-	{
-		new CAnimImage("PortraitsLarge", owner->defendingHeroInstance->portrait, 0, 392, 38);
-		//setting defenderName
-		defenderName = owner->defendingHeroInstance->name;
-	}
-	else //a monster defended
-	{
-		int bestMonsterID = -1;
-		ui32 bestPower = 0;
-		for(TSlots::const_iterator it = owner->army2->Slots().begin(); it!=owner->army2->Slots().end(); ++it)
+		else
 		{
 		{
-			if( it->second->type->AIValue > bestPower)
+			int bestMonsterID = -1;
+			ui32 bestPower = 0;
+			auto stacks = owner.cb->battleGetAllStacks();
+			vstd::erase_if(stacks, [i](const CStack *stack) //erase stack of other side and not coming from garrison
+				{ return stack->attackerOwned == i  ||  !stack->base; });
+
+			auto best = vstd::maxElementByFun(stacks, [](const CStack *stack){ return stack->type->AIValue; });
+			if(best != stacks.end()) //should be always but to be safe...
 			{
 			{
-				bestPower = it->second->type->AIValue;
-				bestMonsterID = it->second->type->idNumber;
+				new CAnimImage("TWCRPORT", (*best)->type->idNumber+2, 0, xs[i], 38);
+				sideNames[i] = CGI->creh->creatures[(*best)->type->idNumber]->namePl;
 			}
 			}
 		}
 		}
-		new CAnimImage("TWCRPORT", CGI->creh->creatures[bestMonsterID]->iconIndex, 0, 392, 38);
-		//setting defenderName
-		defenderName =  CGI->creh->creatures[bestMonsterID]->namePl;
 	}
 	}
 
 
 	//printing attacker and defender's names
 	//printing attacker and defender's names
-	new CLabel( 89, 37, FONT_SMALL, TOPLEFT, Colors::WHITE, attackerName);
+	new CLabel( 89, 37, FONT_SMALL, TOPLEFT, Colors::WHITE, sideNames[0]);
+	new CLabel( 381, 53, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, sideNames[1]);
 
 
-	new CLabel( 381, 53, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, defenderName);
-
-	//printing casualities
+	//printing casualties
 	for(int step = 0; step < 2; ++step)
 	for(int step = 0; step < 2; ++step)
 	{
 	{
 		if(br.casualties[step].size()==0)
 		if(br.casualties[step].size()==0)
@@ -405,7 +386,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 		}
 		}
 	}
 	}
 	//printing result description
 	//printing result description
-	bool weAreAttacker = (owner->curInt->playerID == owner->attackingHeroInstance->tempOwner);
+	bool weAreAttacker = !(owner.cb->battleGetMySide());
 	if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won
 	if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won
 	{
 	{
 		int text=-1;
 		int text=-1;
@@ -420,7 +401,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 		CCS->videoh->open("WIN3.BIK");
 		CCS->videoh->open("WIN3.BIK");
 		std::string str = CGI->generaltexth->allTexts[text];
 		std::string str = CGI->generaltexth->allTexts[text];
 
 
-		const CGHeroInstance * ourHero = weAreAttacker? owner->attackingHeroInstance : owner->defendingHeroInstance;
+		const CGHeroInstance * ourHero = owner.cb->battleGetMyHero();
 		if (ourHero)
 		if (ourHero)
 		{
 		{
 			str += CGI->generaltexth->allTexts[305];
 			str += CGI->generaltexth->allTexts[305];
@@ -465,7 +446,7 @@ CBattleResultWindow::~CBattleResultWindow()
 
 
 void CBattleResultWindow::activate()
 void CBattleResultWindow::activate()
 {
 {
-	owner->curInt->showingDialog->set(true);
+	owner.showingDialog->set(true);
 	CIntObject::activate();
 	CIntObject::activate();
 }
 }
 
 
@@ -483,9 +464,14 @@ void CBattleResultWindow::bExitf()
 		return;
 		return;
 	}
 	}
 
 
-	auto intTmp = owner->curInt;
-	GH.popInts(2); //first - we; second - battle interface
-	intTmp->showingDialog->setn(false);
+	CPlayerInterface &intTmp = owner; //copy reference because "this" will be destructed soon
+	GH.popIntTotally(this);
+	if(dynamic_cast<CBattleInterface*>(GH.topInt()))
+		GH.popInts(1); //pop battle interface if present
+
+	//Result window and battle interface are gone. We requested all dialogs to be closed before opening the battle, 
+	//so we can be sure that there is no dialogs left on GUI stack.
+	intTmp.showingDialog->setn(false);
 	CCS->videoh->close();
 	CCS->videoh->close();
 }
 }
 
 

+ 3 - 2
client/battle/CBattleInterfaceClasses.h

@@ -14,6 +14,7 @@ class CLabel;
 struct BattleResult;
 struct BattleResult;
 class CStack;
 class CStack;
 class CAnimImage;
 class CAnimImage;
+class CPlayerInterface;
 
 
 /*
 /*
  * CBattleInterfaceClasses.h, part of VCMI engine
  * CBattleInterfaceClasses.h, part of VCMI engine
@@ -87,9 +88,9 @@ class CBattleResultWindow : public CIntObject
 {
 {
 private:
 private:
 	CAdventureMapButton *exit;
 	CAdventureMapButton *exit;
-	CBattleInterface *owner;
+	CPlayerInterface &owner;
 public:
 public:
-	CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CBattleInterface * _owner); //c-tor
+	CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CPlayerInterface &_owner); //c-tor
 	~CBattleResultWindow(); //d-tor
 	~CBattleResultWindow(); //d-tor
 
 
 	void bExitf(); //exit button callback
 	void bExitf(); //exit button callback

+ 3 - 0
lib/CBattleCallback.cpp

@@ -288,7 +288,10 @@ InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo( ui8 side ) const
 {
 {
 	auto hero = getBattle()->heroes[side];
 	auto hero = getBattle()->heroes[side];
 	if(!hero)
 	if(!hero)
+	{
         logGlobal->warnStream() << __FUNCTION__ << ": side " << (int)side << " does not have hero!";
         logGlobal->warnStream() << __FUNCTION__ << ": side " << (int)side << " does not have hero!";
+		return InfoAboutHero();
+	}
 
 
 	return InfoAboutHero(hero, battleDoWeKnowAbout(side));
 	return InfoAboutHero(hero, battleDoWeKnowAbout(side));
 }
 }