Browse Source

Fixed handling of tactics

Ivan Savenko 2 years ago
parent
commit
556763fb7b

+ 5 - 0
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());

+ 1 - 0
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<BattleAction> considerFleeingOrSurrendering();
 

+ 1 - 1
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(),

+ 11 - 0
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<SecondarySkill> &skills, QueryID queryID)
 {
 	cb->selectionMade(CRandomGenerator::getDefault().nextInt((int)skills.size() - 1), queryID);

+ 2 - 0
AI/EmptyAI/CEmptyAI.h

@@ -24,6 +24,8 @@ public:
 
 	void initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> 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<SecondarySkill> &skills, QueryID queryID) override;
 	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) override;
 	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override;

+ 5 - 0
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));

+ 1 - 0
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<BattleStackAttacked> & bsa, bool ranged) override; //called when stack receives damage (after battleAttack())

+ 1 - 9
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<Component> & components, int soundID)

+ 0 - 1
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
 

+ 7 - 0
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();
 	}

+ 6 - 1
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
 		{

+ 0 - 8
lib/CGameInterface.cpp

@@ -152,14 +152,6 @@ std::shared_ptr<scripting::Module> 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;

+ 1 - 3
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<Environment> 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