فهرست منبع

Support draw scenario (doesnt work properly)

nordsoft 2 سال پیش
والد
کامیت
b253b19dc3

+ 7 - 3
client/CPlayerInterface.cpp

@@ -707,12 +707,15 @@ void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreat
 void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	bool replay = (lastBattleArmies.first == army1 && lastBattleArmies.second == army2);
+	bool replay = (lastBattleArmies.first == army1 && lastBattleArmies.second == army2); //will be true if player already refused auto-battle result
 	lastBattleArmies.first = army1;
 	lastBattleArmies.second = army2;
 	//quick combat with neutral creatures only
 	auto * army2_object = dynamic_cast<const CGObjectInstance *>(army2);
-	if(!replay && army2_object && army2_object->getOwner() == PlayerColor::UNFLAGGABLE && settings["adventure"]["quickCombat"].Bool())
+	if((!replay && army2_object
+		&& army2_object->getOwner() == PlayerColor::UNFLAGGABLE
+		&& settings["adventure"]["quickCombat"].Bool())
+	   || settings["adventure"]["alwaysSkipBattle"].Bool())
 	{
 		autofightingAI = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
 		autofightingAI->init(env, cb);
@@ -938,7 +941,8 @@ void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID)
 
 		if(!battleInt)
 		{
-			auto wnd = std::make_shared<CBattleResultWindow>(*br, *this, true);
+			bool replay = !settings["adventure"]["alwaysSkipCombat"].Bool(); //do not allow manual replay
+			auto wnd = std::make_shared<CBattleResultWindow>(*br, *this, replay);
 			wnd->resultCallback = [=](ui32 selection)
 			{
 				cb->selectionMade(selection, queryID);

+ 1 - 1
client/Client.cpp

@@ -600,7 +600,7 @@ void CClient::battleStarted(const BattleInfo * info)
 	if(vstd::contains(playerint, rightSide.color) && playerint[rightSide.color]->human)
 		def = std::dynamic_pointer_cast<CPlayerInterface>(playerint[rightSide.color]);
 
-	//If quick combat is not, do not prepare interfaces for battleint
+	//Remove player interfaces for auto battle (quickCombat option)
 	if(att && att->isAutoFightOn)
 	{
 		att.reset();

+ 8 - 14
client/battle/CBattleInterfaceClasses.cpp

@@ -570,9 +570,9 @@ void CBattleResultWindow::show(SDL_Surface * to)
 	CCS->videoh->update(pos.x + 107, pos.y + 70, screen, true, false);
 }
 
-void CBattleResultWindow::bExitf()
+void CBattleResultWindow::buttonPressed(int button)
 {
-	resultCallback(0);
+	resultCallback(button);
 	CPlayerInterface &intTmp = owner; //copy reference because "this" will be destructed soon
 
 	close();
@@ -586,20 +586,14 @@ void CBattleResultWindow::bExitf()
 	CCS->videoh->close();
 }
 
+void CBattleResultWindow::bExitf()
+{
+	buttonPressed(0);
+}
+
 void CBattleResultWindow::bRepeatf()
 {
-	resultCallback(1);
-	CPlayerInterface &intTmp = owner; //copy reference because "this" will be destructed soon
-	
-	close();
-	
-	if(dynamic_cast<CBattleInterface*>(GH.topInt().get()))
-		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();
+	buttonPressed(1);
 }
 
 Point CClickableHex::getXYUnitAnim(BattleHex hexNum, const CStack * stack, CBattleInterface * cbi)

+ 2 - 0
client/battle/CBattleInterfaceClasses.h

@@ -122,6 +122,8 @@ private:
 	std::vector<std::shared_ptr<CAnimImage>> icons;
 	std::shared_ptr<CTextBox> description;
 	CPlayerInterface & owner;
+	
+	void buttonPressed(int button); //internal function for button callbacks
 public:
 	CBattleResultWindow(const BattleResult & br, CPlayerInterface & _owner, bool allowReplay = false);
 	~CBattleResultWindow();

+ 8 - 2
config/schemas/settings.json

@@ -124,7 +124,7 @@
 			"type" : "object",
 			"additionalProperties" : false,
 			"default": {},
-			"required" : [ "heroSpeed", "enemySpeed", "scrollSpeed", "heroReminder", "quickCombat" ],
+			"required" : [ "heroSpeed", "enemySpeed", "scrollSpeed", "heroReminder", "quickCombat", "alwaysSkipCombat" ],
 			"properties" : {
 				"heroSpeed" : {
 					"type" : "number",
@@ -144,7 +144,13 @@
 				},
 				"quickCombat" : {
 					"type" : "boolean",
-					"default" : true
+					"default" : true,
+					"description" : "enable to allow AI to play combats versus neutrals. Player can refuse battle result and replay it manually. This option can be switched from in-game menu"
+				},
+				"alwaysSkipCombat" : {
+					"type" : "boolean",
+					"default" : false,
+					"description" : "if enabled, all battles will be controlled by AI"
 				}
 			}
 		},

+ 11 - 5
server/CGameHandler.cpp

@@ -741,9 +741,9 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
 	CasualtiesAfterBattle cab1(bEndArmy1, battleInfo), cab2(bEndArmy2, battleInfo); //calculate casualties before deleting battle
 	ChangeSpells cs; //for Eagle Eye
 
-	if (finishingBattle->winnerHero)
+	if(!finishingBattle->isDraw() && finishingBattle->winnerHero)
 	{
-		if (int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(Bonus::SECONDARY_SKILL_VAL2, SecondarySkill::EAGLE_EYE))
+		if(int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(Bonus::SECONDARY_SKILL_VAL2, SecondarySkill::EAGLE_EYE))
 		{
 			double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::EAGLE_EYE);
 			for(auto & spellId : battleInfo->sides.at(!battleResult.data->winner).usedSpellsHistory)
@@ -756,7 +756,7 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
 	}
 	std::vector<const CArtifactInstance *> arts; //display them in window
 
-	if (result == BattleResult::NORMAL && finishingBattle->winnerHero)
+	if(result == BattleResult::NORMAL && !finishingBattle->isDraw() && finishingBattle->winnerHero)
 	{
 		auto sendMoveArtifact = [&](const CArtifactInstance *art, MoveArtifact *ma)
 		{
@@ -890,6 +890,11 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
 		RemoveObject ro(finishingBattle->loserHero->id);
 		sendAndApply(&ro);
 	}
+	if(finishingBattle->isDraw() && finishingBattle->winnerHero) //for draw case both heroes should be removed
+	{
+		RemoveObject ro(finishingBattle->winnerHero->id);
+		sendAndApply(&ro);
+	}
 	
 	if(battleResult.data->winner == BattleSide::DEFENDER
 	   && finishingBattle->winnerHero
@@ -900,10 +905,10 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
 		swapGarrisonOnSiege(finishingBattle->winnerHero->visitedTown->id); //return defending visitor from garrison to its rightful place
 	}
 	//give exp
-	if(battleResult.data->exp[finishingBattle->winnerSide] && finishingBattle->winnerHero)
+	if(!finishingBattle->isDraw() && battleResult.data->exp[finishingBattle->winnerSide] && finishingBattle->winnerHero)
 		changePrimSkill(finishingBattle->winnerHero, PrimarySkill::EXPERIENCE, battleResult.data->exp[finishingBattle->winnerSide]);
 	
-	queries.popIfTop(battleQuery);
+	//queries.popIfTop(battleQuery);
 	
 	BattleResultAccepted raccepted;
 	raccepted.army1 = const_cast<CArmedInstance*>(bEndArmy1);
@@ -914,6 +919,7 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
 	raccepted.exp[1] = battleResult.data->exp[1];
 	sendAndApply(&raccepted);
 
+	queries.popIfTop(battleQuery);
 	//--> continuation (battleAfterLevelUp) occurs after level-up queries are handled or on removing query (above)
 }
 

+ 2 - 0
server/CGameHandler.h

@@ -308,6 +308,8 @@ public:
 	{
 		FinishingBattleHelper();
 		FinishingBattleHelper(std::shared_ptr<const CBattleQuery> Query, int RemainingBattleQueriesCount);
+		
+		inline bool isDraw() const {return winnerSide == 2;}
 
 		const CGHeroInstance *winnerHero, *loserHero;
 		PlayerColor victor, loser;