1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

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

This commit is contained in:
Michał W. Urbańczyk
2013-06-23 11:25:48 +00:00
parent 2a471eeb1a
commit 04d11519ef
8 changed files with 149 additions and 157 deletions

View File

@@ -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) if(settings["adventure"]["quickCombat"].Bool())
{ //another local interface should do this {
return; 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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) if(isAutoFightOn)
{ //another local interface should do this {
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
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) BATTLE_EVENT_POSSIBLE_RETURN;
{ //another local interface should do this
return;
}
battleInt->newRoundFirst(round); battleInt->newRoundFirst(round);
} }

View File

@@ -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

View File

@@ -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; shared_ptr<CPlayerInterface> att = nullptr, def = nullptr;
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;
if(vstd::contains(playerint, info->sides[1]) && playerint[info->sides[1]]->human) //If quick combat is not, do not prepare interfaces for battleint
def = std::dynamic_pointer_cast<CPlayerInterface>( playerint[info->sides[1]] ); if(!settings["adventure"]["quickCombat"].Bool())
else {
def = NULL; 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))
{ {

View File

@@ -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); assert(curInt->autofightingAI);
isAutoFightOn = false; 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; curInt->isAutoFightOn = true;
autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String()); deactivate();
autofightingAI->init(curInt->cb); bAutofight->activate();
autofightingAI->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide());
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(); auto tmp = make_unique<boost::thread>([&]
bAutofight->activate();
aiThread = 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)

View File

@@ -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

View File

@@ -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); auto heroInfo = owner.cb->battleGetHeroInfo(i);
//setting attackerName const int xs[] = {21, 392};
attackerName = owner->attackingHeroInstance->name;
} if(heroInfo.portrait >= 0) //attacking hero
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)
{ {
if(it->second->type->AIValue > bestPower) new CAnimImage("PortraitsLarge", heroInfo.portrait, 0, xs[i], 38);
sideNames[i] = heroInfo.name;
}
else
{
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; new CAnimImage("TWCRPORT", (*best)->type->idNumber+2, 0, xs[i], 38);
bestMonsterID = it->second->type->idNumber; sideNames[i] = CGI->creh->creatures[(*best)->type->idNumber]->namePl;
} }
} }
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)
{
if( it->second->type->AIValue > bestPower)
{
bestPower = it->second->type->AIValue;
bestMonsterID = it->second->type->idNumber;
}
}
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 casualties
//printing casualities
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; CPlayerInterface &intTmp = owner; //copy reference because "this" will be destructed soon
GH.popInts(2); //first - we; second - battle interface GH.popIntTotally(this);
intTmp->showingDialog->setn(false); 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();
} }

View File

@@ -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

View File

@@ -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));
} }