mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Minor rework & cleanup of combat replays
This commit is contained in:
parent
b8110218c0
commit
aed8c411fc
@ -826,7 +826,7 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
|
|||||||
ps.value = totalGain;
|
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);
|
LOG_TRACE(logAi);
|
||||||
side = Side;
|
side = Side;
|
||||||
|
@ -83,7 +83,7 @@ public:
|
|||||||
BattleAction selectStackAction(const CStack * stack);
|
BattleAction selectStackAction(const CStack * stack);
|
||||||
std::optional<PossibleSpellcast> findBestCreatureSpell(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 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 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
|
//void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack
|
||||||
|
@ -809,7 +809,7 @@ void AIGateway::makeTurn()
|
|||||||
for (auto h : cb->getHeroesInfo())
|
for (auto h : cb->getHeroesInfo())
|
||||||
{
|
{
|
||||||
if (h->movementPointsRemaining())
|
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
|
#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;
|
NET_EVENT_HANDLER;
|
||||||
assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
|
assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
|
||||||
status.setBattle(ONGOING_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
|
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());
|
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)
|
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();
|
bool won = br->winner == myCb->battleGetMySide();
|
||||||
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename);
|
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename);
|
||||||
battlename.clear();
|
battlename.clear();
|
||||||
status.addQuery(queryID, "Combat result dialog");
|
|
||||||
const int confirmAction = 0;
|
if (queryID != -1)
|
||||||
requestActionASAP([=]()
|
|
||||||
{
|
{
|
||||||
answerQuery(queryID, confirmAction);
|
status.addQuery(queryID, "Combat result dialog");
|
||||||
});
|
const int confirmAction = 0;
|
||||||
|
requestActionASAP([=]()
|
||||||
|
{
|
||||||
|
answerQuery(queryID, confirmAction);
|
||||||
|
});
|
||||||
|
}
|
||||||
CAdventureAI::battleEnd(br, queryID);
|
CAdventureAI::battleEnd(br, queryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1175,7 +1179,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
if(startHpos == dst)
|
if(startHpos == dst)
|
||||||
{
|
{
|
||||||
//FIXME: this assertion fails also if AI moves onto defeated guarded object
|
//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));
|
cb->moveHero(*h, h->convertFromVisitablePos(dst));
|
||||||
afterMovementCheck(); // TODO: is it feasible to hero get killed there if game work properly?
|
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
|
// 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;
|
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
|
||||||
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) 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 battleEnd(const BattleResult * br, QueryID queryID) override;
|
||||||
|
|
||||||
void makeTurn();
|
void makeTurn();
|
||||||
|
@ -242,7 +242,7 @@ void CStupidAI::battleStacksEffectsSet(const SetStackEffect & sse)
|
|||||||
print("battleStacksEffectsSet called");
|
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");
|
print("battleStart called");
|
||||||
side = Side;
|
side = Side;
|
||||||
|
@ -44,7 +44,7 @@ public:
|
|||||||
void battleSpellCast(const BattleSpellCast *sc) override;
|
void battleSpellCast(const BattleSpellCast *sc) override;
|
||||||
void battleStacksEffectsSet(const SetStackEffect & sse) override;//called when a specific effect is set to stacks
|
void battleStacksEffectsSet(const SetStackEffect & sse) override;//called when a specific effect is set to stacks
|
||||||
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
//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
|
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -819,7 +819,7 @@ void VCAI::makeTurn()
|
|||||||
for (auto h : cb->getHeroesInfo())
|
for (auto h : cb->getHeroesInfo())
|
||||||
{
|
{
|
||||||
if (h->movementPointsRemaining())
|
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)
|
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;
|
NET_EVENT_HANDLER;
|
||||||
assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
|
assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
|
||||||
status.setBattle(ONGOING_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
|
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());
|
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)
|
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();
|
bool won = br->winner == myCb->battleGetMySide();
|
||||||
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename);
|
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename);
|
||||||
battlename.clear();
|
battlename.clear();
|
||||||
status.addQuery(queryID, "Combat result dialog");
|
|
||||||
const int confirmAction = 0;
|
if (queryID != -1)
|
||||||
requestActionASAP([=]()
|
|
||||||
{
|
{
|
||||||
answerQuery(queryID, confirmAction);
|
status.addQuery(queryID, "Combat result dialog");
|
||||||
});
|
const int confirmAction = 0;
|
||||||
|
requestActionASAP([=]()
|
||||||
|
{
|
||||||
|
answerQuery(queryID, confirmAction);
|
||||||
|
});
|
||||||
|
}
|
||||||
CAdventureAI::battleEnd(br, queryID);
|
CAdventureAI::battleEnd(br, queryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ public:
|
|||||||
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
|
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
|
||||||
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) 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 battleEnd(const BattleResult * br, QueryID queryID) override;
|
||||||
|
|
||||||
void makeTurn();
|
void makeTurn();
|
||||||
|
@ -652,26 +652,20 @@ void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreat
|
|||||||
waitForAllDialogs();
|
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;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
bool autoBattleResultRefused = (lastBattleArmies.first == army1 && lastBattleArmies.second == army2);
|
|
||||||
lastBattleArmies.first = army1;
|
bool useQuickCombat = settings["adventure"]["quickCombat"].Bool();
|
||||||
lastBattleArmies.second = army2;
|
bool forceQuickCombat = settings["adventure"]["forceQuickCombat"].Bool();
|
||||||
//quick combat with neutral creatures only
|
|
||||||
auto * army2_object = dynamic_cast<const CGObjectInstance *>(army2);
|
if ((replayAllowed && useQuickCombat) || forceQuickCombat)
|
||||||
if((!autoBattleResultRefused && !allowBattleReplay && army2_object
|
|
||||||
&& (army2_object->getOwner() == PlayerColor::UNFLAGGABLE || army2_object->getOwner() == PlayerColor::NEUTRAL)
|
|
||||||
&& settings["adventure"]["quickCombat"].Bool())
|
|
||||||
|| settings["adventure"]["alwaysSkipCombat"].Bool())
|
|
||||||
{
|
{
|
||||||
autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
|
autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
|
||||||
autofightingAI->initBattleInterface(env, cb);
|
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;
|
isAutoFightOn = true;
|
||||||
cb->registerBattleInterface(autofightingAI);
|
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
|
//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)
|
if(!battleInt)
|
||||||
{
|
{
|
||||||
bool allowManualReplay = allowBattleReplay && !settings["adventure"]["alwaysSkipCombat"].Bool();
|
bool allowManualReplay = queryID != -1;
|
||||||
allowBattleReplay = false;
|
|
||||||
auto wnd = std::make_shared<BattleResultWindow>(*br, *this, allowManualReplay);
|
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);
|
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.
|
// #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.
|
// Otherwise NewTurn causes freeze.
|
||||||
|
@ -65,8 +65,6 @@ class CPlayerInterface : public CGameInterface, public IUpdateable
|
|||||||
int firstCall;
|
int firstCall;
|
||||||
int autosaveCount;
|
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!)
|
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)
|
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 battleTriggerEffect(const BattleTriggerEffect & bte) override; //various one-shot effect
|
||||||
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) override;
|
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 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 battleUnitsChanged(const std::vector<UnitChanges> & units) override;
|
||||||
void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) override;
|
void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) override;
|
||||||
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
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)
|
auto callBattleStart = [&](PlayerColor color, ui8 side)
|
||||||
{
|
{
|
||||||
if(vstd::contains(battleints, color))
|
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);
|
callBattleStart(leftSide.color, 0);
|
||||||
|
@ -501,7 +501,7 @@ void BattleWindow::bAutofightf()
|
|||||||
|
|
||||||
auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
|
auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
|
||||||
ai->initBattleInterface(owner.curInt->env, owner.curInt->cb);
|
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->autofightingAI = ai;
|
||||||
owner.curInt->cb->registerBattleInterface(ai);
|
owner.curInt->cb->registerBattleInterface(ai);
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@
|
|||||||
"type" : "object",
|
"type" : "object",
|
||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
"default" : {},
|
"default" : {},
|
||||||
"required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat", "objectAnimation", "terrainAnimation", "alwaysSkipCombat", "borderScroll", "leftButtonDrag" ],
|
"required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat", "objectAnimation", "terrainAnimation", "forceQuickCombat", "borderScroll", "leftButtonDrag" ],
|
||||||
"properties" : {
|
"properties" : {
|
||||||
"heroMoveTime" : {
|
"heroMoveTime" : {
|
||||||
"type" : "number",
|
"type" : "number",
|
||||||
@ -253,7 +253,7 @@
|
|||||||
"type" : "boolean",
|
"type" : "boolean",
|
||||||
"default" : true
|
"default" : true
|
||||||
},
|
},
|
||||||
"alwaysSkipCombat" : {
|
"forceQuickCombat" : {
|
||||||
"type" : "boolean",
|
"type" : "boolean",
|
||||||
"default" : false
|
"default" : false
|
||||||
},
|
},
|
||||||
|
@ -168,13 +168,13 @@ void CAdventureAI::battleCatapultAttacked(const CatapultAttack & ca)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CAdventureAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile,
|
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(!battleAI);
|
||||||
assert(cbc);
|
assert(cbc);
|
||||||
battleAI = CDynLibHandler::getNewBattleAI(getBattleAIName());
|
battleAI = CDynLibHandler::getNewBattleAI(getBattleAIName());
|
||||||
battleAI->initBattleInterface(env, cbc);
|
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)
|
void CAdventureAI::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged)
|
||||||
|
@ -149,7 +149,7 @@ public:
|
|||||||
virtual void yourTacticPhase(int distance) override;
|
virtual void yourTacticPhase(int distance) override;
|
||||||
virtual void battleNewRound(int round) override;
|
virtual void battleNewRound(int round) override;
|
||||||
virtual void battleCatapultAttacked(const CatapultAttack & ca) 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 battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) override;
|
||||||
virtual void actionStarted(const BattleAction &action) override;
|
virtual void actionStarted(const BattleAction &action) override;
|
||||||
virtual void battleNewRoundFirst(int round) 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 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 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 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 battleUnitsChanged(const std::vector<UnitChanges> & units){};
|
||||||
virtual void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles){};
|
virtual void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles){};
|
||||||
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
|
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->round = -2;
|
||||||
curB->activeStack = -1;
|
curB->activeStack = -1;
|
||||||
curB->creatureBank = creatureBank;
|
curB->creatureBank = creatureBank;
|
||||||
|
curB->replayAllowed = false;
|
||||||
|
|
||||||
if(town)
|
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)
|
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
|
int3 tile; //for background and bonuses
|
||||||
bool creatureBank; //auxilary field, do not serialize
|
bool creatureBank; //auxilary field, do not serialize
|
||||||
|
bool replayAllowed;
|
||||||
std::vector<CStack*> stacks;
|
std::vector<CStack*> stacks;
|
||||||
std::vector<std::shared_ptr<CObstacleInstance> > obstacles;
|
std::vector<std::shared_ptr<CObstacleInstance> > obstacles;
|
||||||
SiegeInfo si;
|
SiegeInfo si;
|
||||||
@ -61,6 +62,10 @@ public:
|
|||||||
h & tacticsSide;
|
h & tacticsSide;
|
||||||
h & tacticDistance;
|
h & tacticDistance;
|
||||||
h & static_cast<CBonusSystemNode&>(*this);
|
h & static_cast<CBonusSystemNode&>(*this);
|
||||||
|
if (version > 824)
|
||||||
|
h & replayAllowed;
|
||||||
|
else
|
||||||
|
replayAllowed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
const ui32 SERIALIZATION_VERSION = 824;
|
const ui32 SERIALIZATION_VERSION = 825;
|
||||||
const ui32 MINIMAL_SERIALIZATION_VERSION = 824;
|
const ui32 MINIMAL_SERIALIZATION_VERSION = 824;
|
||||||
const std::string SAVEGAME_MAGIC = "VCMISVG";
|
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;
|
const int queriedPlayers = battleQuery ? (int)boost::count(queries.allQueries(), battleQuery) : 0;
|
||||||
finishingBattle = std::make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
|
finishingBattle = std::make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
|
||||||
|
|
||||||
auto battleDialogQuery = std::make_shared<CBattleDialogQuery>(this, gs->curB);
|
// in battles against neutrals, 1st player can ask to replay battle manually
|
||||||
battleResult.data->queryID = battleDialogQuery->queryID;
|
if (!gs->curB->sides[1].color.isValidPlayer())
|
||||||
queries.addQuery(battleDialogQuery);
|
{
|
||||||
|
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
|
//set same battle result for all queries
|
||||||
for(auto q : queries.allQueries())
|
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
|
sendAndApply(battleResult.data); //after this point casualties objects are destroyed
|
||||||
|
|
||||||
|
if (battleResult.data->queryID == -1)
|
||||||
|
endBattleConfirm(gs->curB);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
|
void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
|
||||||
@ -2118,6 +2127,10 @@ void CGameHandler::setupBattle(int3 tile, const CArmedInstance *armies[2], const
|
|||||||
//send info about battles
|
//send info about battles
|
||||||
BattleStart bs;
|
BattleStart bs;
|
||||||
bs.info = BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
|
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);
|
sendAndApply(&bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2587,39 +2600,39 @@ void CGameHandler::startBattlePrimary(const CArmedInstance *army1, const CArmedI
|
|||||||
heroes[0] = hero1;
|
heroes[0] = hero1;
|
||||||
heroes[1] = hero2;
|
heroes[1] = hero2;
|
||||||
|
|
||||||
|
|
||||||
setupBattle(tile, armies, heroes, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
|
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
|
//existing battle query for retying auto-combat
|
||||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(gs->curB->sides[0].color));
|
if(lastBattleQuery)
|
||||||
if(battleQuery)
|
|
||||||
{
|
{
|
||||||
for(int i : {0, 1})
|
for(int i : {0, 1})
|
||||||
{
|
{
|
||||||
if(heroes[i])
|
if(heroes[i])
|
||||||
{
|
{
|
||||||
SetMana restoreInitialMana;
|
SetMana restoreInitialMana;
|
||||||
restoreInitialMana.val = battleQuery->initialHeroMana[i];
|
restoreInitialMana.val = lastBattleQuery->initialHeroMana[i];
|
||||||
restoreInitialMana.hid = heroes[i]->id;
|
restoreInitialMana.hid = heroes[i]->id;
|
||||||
sendAndApply(&restoreInitialMana);
|
sendAndApply(&restoreInitialMana);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
battleQuery->bi = gs->curB;
|
lastBattleQuery->bi = gs->curB;
|
||||||
battleQuery->result = std::nullopt;
|
lastBattleQuery->result = std::nullopt;
|
||||||
battleQuery->belligerents[0] = gs->curB->sides[0].armyObject;
|
lastBattleQuery->belligerents[0] = gs->curB->sides[0].armyObject;
|
||||||
battleQuery->belligerents[1] = gs->curB->sides[1].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})
|
for(int i : {0, 1})
|
||||||
{
|
{
|
||||||
if(heroes[i])
|
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));
|
this->battleThread = std::make_unique<boost::thread>(boost::thread(&CGameHandler::runBattle, this));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user