From 556763fb7b37febf275d918ba954ce274965dd53 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 18 Jul 2023 21:43:53 +0300 Subject: [PATCH] Fixed handling of tactics --- AI/BattleAI/BattleAI.cpp | 5 +++++ AI/BattleAI/BattleAI.h | 1 + AI/BattleAI/PotentialTargets.cpp | 2 +- AI/EmptyAI/CEmptyAI.cpp | 11 +++++++++++ AI/EmptyAI/CEmptyAI.h | 2 ++ AI/StupidAI/StupidAI.cpp | 5 +++++ AI/StupidAI/StupidAI.h | 1 + client/CPlayerInterface.cpp | 10 +--------- client/CPlayerInterface.h | 1 - client/Client.cpp | 7 +++++++ client/battle/BattleInterface.cpp | 7 ++++++- lib/CGameInterface.cpp | 8 -------- lib/CGameInterface.h | 4 +--- 13 files changed, 41 insertions(+), 23 deletions(-) diff --git a/AI/BattleAI/BattleAI.cpp b/AI/BattleAI/BattleAI.cpp index 7824c9683..25035917e 100644 --- a/AI/BattleAI/BattleAI.cpp +++ b/AI/BattleAI/BattleAI.cpp @@ -249,6 +249,11 @@ BattleAction CBattleAI::selectStackAction(const CStack * stack) return BattleAction::makeDefend(stack); } +void CBattleAI::yourTacticPhase(int distance) +{ + cb->battleMakeUnitAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); +} + void CBattleAI::activeStack( const CStack * stack ) { LOG_TRACE_PARAMS(logAi, "stack: %s", stack->nodeName()); diff --git a/AI/BattleAI/BattleAI.h b/AI/BattleAI/BattleAI.h index f89f8fccf..de0d02c48 100644 --- a/AI/BattleAI/BattleAI.h +++ b/AI/BattleAI/BattleAI.h @@ -72,6 +72,7 @@ public: void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only void activeStack(const CStack * stack) override; //called when it's turn of that stack + void yourTacticPhase(int distance) override; std::optional considerFleeingOrSurrendering(); diff --git a/AI/BattleAI/PotentialTargets.cpp b/AI/BattleAI/PotentialTargets.cpp index 63bf2b0c5..d55e1dfa8 100644 --- a/AI/BattleAI/PotentialTargets.cpp +++ b/AI/BattleAI/PotentialTargets.cpp @@ -89,7 +89,7 @@ PotentialTargets::PotentialTargets(const battle::Unit * attacker, const Hypothet { auto & bestAp = possibleAttacks[0]; - logGlobal->info("Battle AI best: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld", + logGlobal->debug("Battle AI best: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld", bestAp.attack.attacker->unitType()->getJsonKey(), state.battleGetUnitByPos(bestAp.dest)->unitType()->getJsonKey(), (int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(), diff --git a/AI/EmptyAI/CEmptyAI.cpp b/AI/EmptyAI/CEmptyAI.cpp index e20b6e6f2..da206ba4b 100644 --- a/AI/EmptyAI/CEmptyAI.cpp +++ b/AI/EmptyAI/CEmptyAI.cpp @@ -11,6 +11,7 @@ #include "CEmptyAI.h" #include "../../lib/CRandomGenerator.h" +#include "../../lib/CStack.h" void CEmptyAI::saveGame(BinarySerializer & h, const int version) { @@ -33,6 +34,16 @@ void CEmptyAI::yourTurn() cb->endTurn(); } +void CEmptyAI::activeStack(const CStack * stack) +{ + cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); +} + +void CEmptyAI::yourTacticPhase(int distance) +{ + cb->battleMakeUnitAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); +} + void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector &skills, QueryID queryID) { cb->selectionMade(CRandomGenerator::getDefault().nextInt((int)skills.size() - 1), queryID); diff --git a/AI/EmptyAI/CEmptyAI.h b/AI/EmptyAI/CEmptyAI.h index b71d7aa44..2598f5dbe 100644 --- a/AI/EmptyAI/CEmptyAI.h +++ b/AI/EmptyAI/CEmptyAI.h @@ -24,6 +24,8 @@ public: void initGameInterface(std::shared_ptr ENV, std::shared_ptr CB) override; void yourTurn() override; + void yourTacticPhase(int distance) override; + void activeStack(const CStack * stack) override; void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector &skills, QueryID queryID) override; void commanderGotLevel (const CCommanderInstance * commander, std::vector skills, QueryID queryID) override; void showBlockingDialog(const std::string &text, const std::vector &components, QueryID askID, const int soundID, bool selection, bool cancel) override; diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index bdd8ac809..fd69a38b2 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -88,6 +88,11 @@ static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const Battl return shooters[0] < shooters[1]; } +void CStupidAI::yourTacticPhase(int distance) +{ + cb->battleMakeUnitAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); +} + void CStupidAI::activeStack( const CStack * stack ) { //boost::this_thread::sleep(boost::posix_time::seconds(2)); diff --git a/AI/StupidAI/StupidAI.h b/AI/StupidAI/StupidAI.h index 187ce4566..593f1fa11 100644 --- a/AI/StupidAI/StupidAI.h +++ b/AI/StupidAI/StupidAI.h @@ -29,6 +29,7 @@ public: 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 activeStack(const CStack * stack) override; //called when it's turn of that stack + void yourTacticPhase(int distance) override; void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack void battleStacksAttacked(const std::vector & bsa, bool ranged) override; //called when stack receives damage (after battleAttack()) diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index f8e49b1bb..7e68dc73e 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -957,15 +957,7 @@ void CPlayerInterface::battleGateStateChanged(const EGateState state) void CPlayerInterface::yourTacticPhase(int distance) { - THREAD_CREATED_BY_CLIENT; - while(battleInt && battleInt->tacticsMode) - boost::this_thread::sleep(boost::posix_time::millisec(1)); -} - -void CPlayerInterface::forceEndTacticPhase() -{ - if (battleInt) - battleInt->tacticsMode = false; + EVENT_HANDLER_CALLED_BY_CLIENT; } void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &text, const std::vector & components, int soundID) diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index 91a8e2c0d..70a41df4c 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -176,7 +176,6 @@ protected: // Call-ins from server, should not be called directly, but only via void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack void battleGateStateChanged(const EGateState state) override; void yourTacticPhase(int distance) override; - void forceEndTacticPhase() override; public: // public interface for use by client via LOCPLINT access diff --git a/client/Client.cpp b/client/Client.cpp index c7cac033e..bed6fe7aa 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -597,6 +597,13 @@ void CClient::battleStarted(const BattleInfo * info) //Remove player interfaces for auto battle (quickCombat option) if(att && att->isAutoFightOn) { + if (att->cb->battleGetTacticDist()) + { + auto side = att->cb->playerToSide(att->playerID); + auto action = BattleAction::makeEndOFTacticPhase(*side); + att->cb->battleMakeTacticAction(action); + } + att.reset(); def.reset(); } diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index fe2bf07a4..589b1a2ec 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -629,6 +629,11 @@ void BattleInterface::tacticPhaseEnd() { stacksController->setActiveStack(nullptr); tacticsMode = false; + + auto side = tacticianInterface->cb->playerToSide(tacticianInterface->playerID); + auto action = BattleAction::makeEndOFTacticPhase(*side); + + tacticianInterface->cb->battleMakeTacticAction(action); } static bool immobile(const CStack *s) @@ -709,8 +714,8 @@ void BattleInterface::requestAutofightingAIToTakeAction() // the AI can take any action except end tactics phase (AI actions won't be triggered) //TODO implement the possibility that the AI will be triggered for further actions //TODO any solution to merge tactics phase & normal phase in the way it is handled by the player and battle interface? + tacticPhaseEnd(); stacksController->setActiveStack(nullptr); - tacticsMode = false; } else { diff --git a/lib/CGameInterface.cpp b/lib/CGameInterface.cpp index 5b636f30f..c499207e0 100644 --- a/lib/CGameInterface.cpp +++ b/lib/CGameInterface.cpp @@ -152,14 +152,6 @@ std::shared_ptr CDynLibHandler::getNewScriptingModule(const b } #endif -void CGlobalAI::activeStack(const CStack * stack) -{ - BattleAction ba; - ba.actionType = EActionType::DEFEND; - ba.stackNumber = stack->unitId(); - assert(0); -} - CGlobalAI::CGlobalAI() { human = false; diff --git a/lib/CGameInterface.h b/lib/CGameInterface.h index 5f0d71872..3b59b69b0 100644 --- a/lib/CGameInterface.h +++ b/lib/CGameInterface.h @@ -79,8 +79,7 @@ public: //battle call-ins virtual void activeStack(const CStack * stack)=0; //called when it's turn of that stack - virtual void yourTacticPhase(int distance){}; //called when interface has opportunity to use Tactics skill -> use cb->battleMakeTacticAction from this function - virtual void forceEndTacticPhase(){}; //force the tatic phase to end to clean up the tactic phase thread + virtual void yourTacticPhase(int distance)=0; //called when interface has opportunity to use Tactics skill -> use cb->battleMakeTacticAction from this function }; /// Central class for managing human player / AI interface logic @@ -132,7 +131,6 @@ class DLL_LINKAGE CGlobalAI : public CGameInterface // AI class (to derivate) public: std::shared_ptr env; CGlobalAI(); - virtual void activeStack(const CStack * stack) override; }; //class to be inherited by adventure-only AIs, it cedes battle actions to given battle-AI