mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge pull request #2425 from IvanSavenko/fix_combat_replay
Attempt to fix combat replay queries
This commit is contained in:
commit
6c52293dd9
@ -826,7 +826,7 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
|
||||
ps.value = totalGain;
|
||||
}
|
||||
|
||||
void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
|
||||
void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed)
|
||||
{
|
||||
LOG_TRACE(logAi);
|
||||
side = Side;
|
||||
|
@ -83,7 +83,7 @@ public:
|
||||
BattleAction selectStackAction(const CStack * stack);
|
||||
std::optional<PossibleSpellcast> findBestCreatureSpell(const CStack *stack);
|
||||
|
||||
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side) override;
|
||||
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side, bool replayAllowed) override;
|
||||
//void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
|
||||
//void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
|
||||
//void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack
|
||||
|
@ -809,7 +809,7 @@ void AIGateway::makeTurn()
|
||||
for (auto h : cb->getHeroesInfo())
|
||||
{
|
||||
if (h->movementPointsRemaining())
|
||||
logAi->warn("Hero %s has %d MP left", h->getNameTranslated(), h->movementPointsRemaining());
|
||||
logAi->info("Hero %s has %d MP left", h->getNameTranslated(), h->movementPointsRemaining());
|
||||
}
|
||||
#if NKAI_TRACE_LEVEL == 0
|
||||
}
|
||||
@ -1065,14 +1065,14 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re
|
||||
}
|
||||
}
|
||||
|
||||
void AIGateway::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side)
|
||||
void AIGateway::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed)
|
||||
{
|
||||
NET_EVENT_HANDLER;
|
||||
assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
|
||||
status.setBattle(ONGOING_BATTLE);
|
||||
const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
|
||||
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
|
||||
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side);
|
||||
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side, replayAllowed);
|
||||
}
|
||||
|
||||
void AIGateway::battleEnd(const BattleResult * br, QueryID queryID)
|
||||
@ -1083,12 +1083,16 @@ void AIGateway::battleEnd(const BattleResult * br, QueryID queryID)
|
||||
bool won = br->winner == myCb->battleGetMySide();
|
||||
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename);
|
||||
battlename.clear();
|
||||
status.addQuery(queryID, "Combat result dialog");
|
||||
const int confirmAction = 0;
|
||||
requestActionASAP([=]()
|
||||
|
||||
if (queryID != -1)
|
||||
{
|
||||
answerQuery(queryID, confirmAction);
|
||||
});
|
||||
status.addQuery(queryID, "Combat result dialog");
|
||||
const int confirmAction = 0;
|
||||
requestActionASAP([=]()
|
||||
{
|
||||
answerQuery(queryID, confirmAction);
|
||||
});
|
||||
}
|
||||
CAdventureAI::battleEnd(br, queryID);
|
||||
}
|
||||
|
||||
@ -1175,7 +1179,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
if(startHpos == dst)
|
||||
{
|
||||
//FIXME: this assertion fails also if AI moves onto defeated guarded object
|
||||
assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
|
||||
//assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
|
||||
cb->moveHero(*h, h->convertFromVisitablePos(dst));
|
||||
afterMovementCheck(); // TODO: is it feasible to hero get killed there if game work properly?
|
||||
// If revisiting, teleport probing is never done, and so the entries into the list would remain unused and uncleared
|
||||
|
@ -169,7 +169,7 @@ public:
|
||||
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
|
||||
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
|
||||
|
||||
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side) override;
|
||||
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override;
|
||||
void battleEnd(const BattleResult * br, QueryID queryID) override;
|
||||
|
||||
void makeTurn();
|
||||
|
@ -242,7 +242,7 @@ void CStupidAI::battleStacksEffectsSet(const SetStackEffect & sse)
|
||||
print("battleStacksEffectsSet called");
|
||||
}
|
||||
|
||||
void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
|
||||
void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed)
|
||||
{
|
||||
print("battleStart called");
|
||||
side = Side;
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
void battleSpellCast(const BattleSpellCast *sc) override;
|
||||
void battleStacksEffectsSet(const SetStackEffect & sse) override;//called when a specific effect is set to stacks
|
||||
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
||||
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
|
||||
private:
|
||||
|
@ -819,7 +819,7 @@ void VCAI::makeTurn()
|
||||
for (auto h : cb->getHeroesInfo())
|
||||
{
|
||||
if (h->movementPointsRemaining())
|
||||
logAi->warn("Hero %s has %d MP left", h->getNameTranslated(), h->movementPointsRemaining());
|
||||
logAi->info("Hero %s has %d MP left", h->getNameTranslated(), h->movementPointsRemaining());
|
||||
}
|
||||
}
|
||||
catch (boost::thread_interrupted & e)
|
||||
@ -1575,14 +1575,14 @@ void VCAI::completeGoal(Goals::TSubgoal goal)
|
||||
|
||||
}
|
||||
|
||||
void VCAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side)
|
||||
void VCAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed)
|
||||
{
|
||||
NET_EVENT_HANDLER;
|
||||
assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
|
||||
status.setBattle(ONGOING_BATTLE);
|
||||
const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
|
||||
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
|
||||
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side);
|
||||
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side, replayAllowed);
|
||||
}
|
||||
|
||||
void VCAI::battleEnd(const BattleResult * br, QueryID queryID)
|
||||
@ -1593,12 +1593,16 @@ void VCAI::battleEnd(const BattleResult * br, QueryID queryID)
|
||||
bool won = br->winner == myCb->battleGetMySide();
|
||||
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename);
|
||||
battlename.clear();
|
||||
status.addQuery(queryID, "Combat result dialog");
|
||||
const int confirmAction = 0;
|
||||
requestActionASAP([=]()
|
||||
|
||||
if (queryID != -1)
|
||||
{
|
||||
answerQuery(queryID, confirmAction);
|
||||
});
|
||||
status.addQuery(queryID, "Combat result dialog");
|
||||
const int confirmAction = 0;
|
||||
requestActionASAP([=]()
|
||||
{
|
||||
answerQuery(queryID, confirmAction);
|
||||
});
|
||||
}
|
||||
CAdventureAI::battleEnd(br, queryID);
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ public:
|
||||
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
|
||||
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
|
||||
|
||||
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side) override;
|
||||
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override;
|
||||
void battleEnd(const BattleResult * br, QueryID queryID) override;
|
||||
|
||||
void makeTurn();
|
||||
|
@ -652,26 +652,20 @@ void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreat
|
||||
waitForAllDialogs();
|
||||
}
|
||||
|
||||
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, bool replayAllowed)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
bool autoBattleResultRefused = (lastBattleArmies.first == army1 && lastBattleArmies.second == army2);
|
||||
lastBattleArmies.first = army1;
|
||||
lastBattleArmies.second = army2;
|
||||
//quick combat with neutral creatures only
|
||||
auto * army2_object = dynamic_cast<const CGObjectInstance *>(army2);
|
||||
if((!autoBattleResultRefused && !allowBattleReplay && army2_object
|
||||
&& (army2_object->getOwner() == PlayerColor::UNFLAGGABLE || army2_object->getOwner() == PlayerColor::NEUTRAL)
|
||||
&& settings["adventure"]["quickCombat"].Bool())
|
||||
|| settings["adventure"]["alwaysSkipCombat"].Bool())
|
||||
|
||||
bool useQuickCombat = settings["adventure"]["quickCombat"].Bool();
|
||||
bool forceQuickCombat = settings["adventure"]["forceQuickCombat"].Bool();
|
||||
|
||||
if ((replayAllowed && useQuickCombat) || forceQuickCombat)
|
||||
{
|
||||
autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
|
||||
autofightingAI->initBattleInterface(env, cb);
|
||||
autofightingAI->battleStart(army1, army2, int3(0,0,0), hero1, hero2, side);
|
||||
autofightingAI->battleStart(army1, army2, tile, hero1, hero2, side, false);
|
||||
isAutoFightOn = true;
|
||||
cb->registerBattleInterface(autofightingAI);
|
||||
// Player shouldn't be able to move on adventure map if quick combat is going
|
||||
allowBattleReplay = true;
|
||||
}
|
||||
|
||||
//Don't wait for dialogs when we are non-active hot-seat player
|
||||
@ -843,13 +837,17 @@ void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID)
|
||||
|
||||
if(!battleInt)
|
||||
{
|
||||
bool allowManualReplay = allowBattleReplay && !settings["adventure"]["alwaysSkipCombat"].Bool();
|
||||
allowBattleReplay = false;
|
||||
bool allowManualReplay = queryID != -1;
|
||||
|
||||
auto wnd = std::make_shared<BattleResultWindow>(*br, *this, allowManualReplay);
|
||||
wnd->resultCallback = [=](ui32 selection)
|
||||
|
||||
if (allowManualReplay)
|
||||
{
|
||||
cb->selectionMade(selection, queryID);
|
||||
};
|
||||
wnd->resultCallback = [=](ui32 selection)
|
||||
{
|
||||
cb->selectionMade(selection, queryID);
|
||||
};
|
||||
}
|
||||
GH.windows().pushWindow(wnd);
|
||||
// #1490 - during AI turn when quick combat is on, we need to display the message and wait for user to close it.
|
||||
// Otherwise NewTurn causes freeze.
|
||||
|
@ -65,8 +65,6 @@ class CPlayerInterface : public CGameInterface, public IUpdateable
|
||||
int firstCall;
|
||||
int autosaveCount;
|
||||
|
||||
std::pair<const CCreatureSet *, const CCreatureSet *> lastBattleArmies;
|
||||
bool allowBattleReplay = false;
|
||||
std::list<std::shared_ptr<CInfoWindow>> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
|
||||
const BattleAction *curAction; //during the battle - action currently performed by active stack (or nullptr)
|
||||
|
||||
@ -169,7 +167,7 @@ protected: // Call-ins from server, should not be called directly, but only via
|
||||
void battleTriggerEffect(const BattleTriggerEffect & bte) override; //various one-shot effect
|
||||
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) override;
|
||||
void battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) override; //called by engine just before battle starts; side=0 - left, side=1 - right
|
||||
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleUnitsChanged(const std::vector<UnitChanges> & units) override;
|
||||
void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) override;
|
||||
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
|
@ -580,7 +580,7 @@ void CClient::battleStarted(const BattleInfo * info)
|
||||
auto callBattleStart = [&](PlayerColor color, ui8 side)
|
||||
{
|
||||
if(vstd::contains(battleints, color))
|
||||
battleints[color]->battleStart(leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side);
|
||||
battleints[color]->battleStart(leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed);
|
||||
};
|
||||
|
||||
callBattleStart(leftSide.color, 0);
|
||||
|
@ -501,7 +501,7 @@ void BattleWindow::bAutofightf()
|
||||
|
||||
auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
|
||||
ai->initBattleInterface(owner.curInt->env, owner.curInt->cb);
|
||||
ai->battleStart(owner.army1, owner.army2, int3(0,0,0), owner.attackingHeroInstance, owner.defendingHeroInstance, owner.curInt->cb->battleGetMySide());
|
||||
ai->battleStart(owner.army1, owner.army2, int3(0,0,0), owner.attackingHeroInstance, owner.defendingHeroInstance, owner.curInt->cb->battleGetMySide(), false);
|
||||
owner.curInt->autofightingAI = ai;
|
||||
owner.curInt->cb->registerBattleInterface(ai);
|
||||
|
||||
|
@ -223,7 +223,7 @@
|
||||
"type" : "object",
|
||||
"additionalProperties" : false,
|
||||
"default" : {},
|
||||
"required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat", "objectAnimation", "terrainAnimation", "alwaysSkipCombat", "borderScroll", "leftButtonDrag" ],
|
||||
"required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat", "objectAnimation", "terrainAnimation", "forceQuickCombat", "borderScroll", "leftButtonDrag" ],
|
||||
"properties" : {
|
||||
"heroMoveTime" : {
|
||||
"type" : "number",
|
||||
@ -253,7 +253,7 @@
|
||||
"type" : "boolean",
|
||||
"default" : true
|
||||
},
|
||||
"alwaysSkipCombat" : {
|
||||
"forceQuickCombat" : {
|
||||
"type" : "boolean",
|
||||
"default" : false
|
||||
},
|
||||
|
@ -168,13 +168,13 @@ void CAdventureAI::battleCatapultAttacked(const CatapultAttack & ca)
|
||||
}
|
||||
|
||||
void CAdventureAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile,
|
||||
const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side)
|
||||
const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed)
|
||||
{
|
||||
assert(!battleAI);
|
||||
assert(cbc);
|
||||
battleAI = CDynLibHandler::getNewBattleAI(getBattleAIName());
|
||||
battleAI->initBattleInterface(env, cbc);
|
||||
battleAI->battleStart(army1, army2, tile, hero1, hero2, side);
|
||||
battleAI->battleStart(army1, army2, tile, hero1, hero2, side, replayAllowed);
|
||||
}
|
||||
|
||||
void CAdventureAI::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged)
|
||||
|
@ -149,7 +149,7 @@ public:
|
||||
virtual void yourTacticPhase(int distance) override;
|
||||
virtual void battleNewRound(int round) override;
|
||||
virtual void battleCatapultAttacked(const CatapultAttack & ca) override;
|
||||
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override;
|
||||
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override;
|
||||
virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) override;
|
||||
virtual void actionStarted(const BattleAction &action) override;
|
||||
virtual void battleNewRoundFirst(int round) override;
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
virtual void battleStacksEffectsSet(const SetStackEffect & sse){};//called when a specific effect is set to stacks
|
||||
virtual void battleTriggerEffect(const BattleTriggerEffect & bte){}; //called for various one-shot effects
|
||||
virtual void battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) {}; //called just before battle start
|
||||
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed){}; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
virtual void battleUnitsChanged(const std::vector<UnitChanges> & units){};
|
||||
virtual void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles){};
|
||||
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
|
||||
|
@ -207,6 +207,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
curB->round = -2;
|
||||
curB->activeStack = -1;
|
||||
curB->creatureBank = creatureBank;
|
||||
curB->replayAllowed = false;
|
||||
|
||||
if(town)
|
||||
{
|
||||
|
@ -36,6 +36,7 @@ public:
|
||||
const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
|
||||
int3 tile; //for background and bonuses
|
||||
bool creatureBank; //auxilary field, do not serialize
|
||||
bool replayAllowed;
|
||||
std::vector<CStack*> stacks;
|
||||
std::vector<std::shared_ptr<CObstacleInstance> > obstacles;
|
||||
SiegeInfo si;
|
||||
@ -61,6 +62,10 @@ public:
|
||||
h & tacticsSide;
|
||||
h & tacticDistance;
|
||||
h & static_cast<CBonusSystemNode&>(*this);
|
||||
if (version > 824)
|
||||
h & replayAllowed;
|
||||
else
|
||||
replayAllowed = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
const ui32 SERIALIZATION_VERSION = 824;
|
||||
const ui32 SERIALIZATION_VERSION = 825;
|
||||
const ui32 MINIMAL_SERIALIZATION_VERSION = 824;
|
||||
const std::string SAVEGAME_MAGIC = "VCMISVG";
|
||||
|
||||
|
@ -607,9 +607,15 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
|
||||
const int queriedPlayers = battleQuery ? (int)boost::count(queries.allQueries(), battleQuery) : 0;
|
||||
finishingBattle = std::make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
|
||||
|
||||
auto battleDialogQuery = std::make_shared<CBattleDialogQuery>(this, gs->curB);
|
||||
battleResult.data->queryID = battleDialogQuery->queryID;
|
||||
queries.addQuery(battleDialogQuery);
|
||||
// in battles against neutrals, 1st player can ask to replay battle manually
|
||||
if (!gs->curB->sides[1].color.isValidPlayer())
|
||||
{
|
||||
auto battleDialogQuery = std::make_shared<CBattleDialogQuery>(this, gs->curB);
|
||||
battleResult.data->queryID = battleDialogQuery->queryID;
|
||||
queries.addQuery(battleDialogQuery);
|
||||
}
|
||||
else
|
||||
battleResult.data->queryID = -1;
|
||||
|
||||
//set same battle result for all queries
|
||||
for(auto q : queries.allQueries())
|
||||
@ -620,6 +626,9 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
|
||||
}
|
||||
|
||||
sendAndApply(battleResult.data); //after this point casualties objects are destroyed
|
||||
|
||||
if (battleResult.data->queryID == -1)
|
||||
endBattleConfirm(gs->curB);
|
||||
}
|
||||
|
||||
void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
|
||||
@ -2118,6 +2127,10 @@ void CGameHandler::setupBattle(int3 tile, const CArmedInstance *armies[2], const
|
||||
//send info about battles
|
||||
BattleStart bs;
|
||||
bs.info = BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
|
||||
|
||||
auto lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(bs.info->sides[0].color));
|
||||
bs.info->replayAllowed = lastBattleQuery == nullptr && !bs.info->sides[1].color.isValidPlayer();
|
||||
|
||||
sendAndApply(&bs);
|
||||
}
|
||||
|
||||
@ -2587,39 +2600,39 @@ void CGameHandler::startBattlePrimary(const CArmedInstance *army1, const CArmedI
|
||||
heroes[0] = hero1;
|
||||
heroes[1] = hero2;
|
||||
|
||||
|
||||
setupBattle(tile, armies, heroes, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
|
||||
|
||||
auto lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(gs->curB->sides[0].color));
|
||||
|
||||
//existing battle query for retying auto-combat
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(gs->curB->sides[0].color));
|
||||
if(battleQuery)
|
||||
if(lastBattleQuery)
|
||||
{
|
||||
for(int i : {0, 1})
|
||||
{
|
||||
if(heroes[i])
|
||||
{
|
||||
SetMana restoreInitialMana;
|
||||
restoreInitialMana.val = battleQuery->initialHeroMana[i];
|
||||
restoreInitialMana.val = lastBattleQuery->initialHeroMana[i];
|
||||
restoreInitialMana.hid = heroes[i]->id;
|
||||
sendAndApply(&restoreInitialMana);
|
||||
}
|
||||
}
|
||||
|
||||
battleQuery->bi = gs->curB;
|
||||
battleQuery->result = std::nullopt;
|
||||
battleQuery->belligerents[0] = gs->curB->sides[0].armyObject;
|
||||
battleQuery->belligerents[1] = gs->curB->sides[1].armyObject;
|
||||
lastBattleQuery->bi = gs->curB;
|
||||
lastBattleQuery->result = std::nullopt;
|
||||
lastBattleQuery->belligerents[0] = gs->curB->sides[0].armyObject;
|
||||
lastBattleQuery->belligerents[1] = gs->curB->sides[1].armyObject;
|
||||
}
|
||||
|
||||
battleQuery = std::make_shared<CBattleQuery>(this, gs->curB);
|
||||
auto nextBattleQuery = std::make_shared<CBattleQuery>(this, gs->curB);
|
||||
for(int i : {0, 1})
|
||||
{
|
||||
if(heroes[i])
|
||||
{
|
||||
battleQuery->initialHeroMana[i] = heroes[i]->mana;
|
||||
nextBattleQuery->initialHeroMana[i] = heroes[i]->mana;
|
||||
}
|
||||
}
|
||||
queries.addQuery(battleQuery);
|
||||
queries.addQuery(nextBattleQuery);
|
||||
|
||||
this->battleThread = std::make_unique<boost::thread>(boost::thread(&CGameHandler::runBattle, this));
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ void CObjectVisitQuery::onExposure(QueryPtr topQuery)
|
||||
if(gh->isValidObject(visitedObject))
|
||||
topQuery->notifyObjectAboutRemoval(*this);
|
||||
|
||||
owner->popQuery(*this);
|
||||
owner->popIfTop(*this);
|
||||
}
|
||||
|
||||
void Queries::popQuery(PlayerColor player, QueryPtr query)
|
||||
|
Loading…
Reference in New Issue
Block a user