Explorar el Código

Merge branch 'battle-dialog' into battle-dialog2

# Conflicts:
#	AI/BattleAI/BattleAI.h
#	AI/StupidAI/StupidAI.h
#	client/CPlayerInterface.cpp
#	client/CPlayerInterface.h
#	client/Client.cpp
#	client/NetPacksClient.cpp
#	client/battle/CBattleInterface.cpp
#	client/battle/CBattleInterface.h
#	client/battle/CBattleInterfaceClasses.cpp
#	client/battle/CBattleInterfaceClasses.h
#	config/schemas/settings.json
#	lib/CGameInterface.h
#	lib/IGameEventsReceiver.h
#	lib/NetPacks.h
#	lib/NetPacksLib.cpp
#	lib/battle/BattleInfo.cpp
#	server/CGameHandler.cpp
#	server/CQuery.h
nordsoft hace 2 años
padre
commit
ece8a2a41f
Se han modificado 4 ficheros con 90 adiciones y 47 borrados
  1. 5 1
      config/schemas/settings.json
  2. 1 0
      lib/battle/BattleInfo.cpp
  3. 62 46
      server/CGameHandler.cpp
  4. 22 0
      server/CQuery.cpp

+ 5 - 1
config/schemas/settings.json

@@ -182,7 +182,7 @@
 			"type" : "object",
 			"additionalProperties" : false,
 			"default": {},
-			"required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat", "objectAnimation", "terrainAnimation" ],
+			"required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat", "objectAnimation", "terrainAnimation", "alwaysSkipCombat" ],
 			"properties" : {
 				"heroMoveTime" : {
 					"type" : "number",
@@ -211,6 +211,10 @@
 				"terrainAnimation" : {
 					"type" : "boolean",
 					"default" : true
+				},
+				"alwaysSkipCombat" : {
+					"type" : "boolean",
+					"default" : false
 				}
 			}
 		},

+ 1 - 0
lib/battle/BattleInfo.cpp

@@ -205,6 +205,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
 	curB->battlefieldType = battlefieldType;
 	curB->round = -2;
 	curB->activeStack = -1;
+	curB->creatureBank = creatureBank;
 
 	if(town)
 	{

+ 62 - 46
server/CGameHandler.cpp

@@ -614,44 +614,56 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
 	if(heroDefender)
 		battleResult.data->exp[1] = heroDefender->calculateXp(battleResult.data->exp[1]);
 
-	const CArmedInstance *bEndArmy1 = gs->curB->sides.at(0).armyObject;
-	const CArmedInstance *bEndArmy2 = gs->curB->sides.at(1).armyObject;
-	const BattleResult::EResult result = battleResult.get()->result;
-
-	auto findBattleQuery = [this]() -> std::shared_ptr<CBattleQuery>
-	{
-		for (auto &q : queries.allQueries())
-		{
-			if (auto bq = std::dynamic_pointer_cast<CBattleQuery>(q))
-				if (bq->bi == gs->curB)
-					return bq;
-		}
-		return std::shared_ptr<CBattleQuery>();
-	};
-
-	auto battleQuery = findBattleQuery();
+	auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(gs->curB->sides[0].color));
 	if (!battleQuery)
 	{
 		logGlobal->error("Cannot find battle query!");
+		complain("Player " + boost::lexical_cast<std::string>(gs->curB->sides[0].color) + " has no battle query at the top!");
+		return;
 	}
-	if (battleQuery != queries.topQuery(gs->curB->sides[0].color))
-		complain("Player " + boost::lexical_cast<std::string>(gs->curB->sides[0].color) + " although in battle has no battle query at the top!");
 
 	battleQuery->result = boost::make_optional(*battleResult.data);
+	
+	//set same battle result for all queries
+	for(auto q : queries.allQueries())
+	{
+		auto otherBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(q);
+		if(otherBattleQuery && otherBattleQuery->bi == battleQuery->bi)
+			otherBattleQuery->result = battleQuery->result;
+	}
 
 	//Check how many battle queries were created (number of players blocked by battle)
 	const int queriedPlayers = battleQuery ? (int)boost::count(queries.allQueries(), battleQuery) : 0;
-	finishingBattle = std::make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
+	finishingBattle = make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
+	
+	auto battleDialogQuery = std::make_shared<CBattleDialogQuery>(this, gs->curB);
+	battleResult.data->queryID = battleDialogQuery->queryID;
+	queries.addQuery(battleDialogQuery);
+	sendAndApply(battleResult.data); //after this point casualties objects are destroyed
+}
 
-	CasualtiesAfterBattle cab1(bEndArmy1, gs->curB), cab2(bEndArmy2, gs->curB); //calculate casualties before deleting battle
+void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
+{
+	auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(queries.topQuery(battleInfo->sides.at(0).color));
+	if(!battleQuery)
+	{
+		logGlobal->trace("No battle query, battle end was confirmed by another player");
+		return;
+	}
+	
+	const CArmedInstance *bEndArmy1 = battleInfo->sides.at(0).armyObject;
+	const CArmedInstance *bEndArmy2 = battleInfo->sides.at(1).armyObject;
+	const BattleResult::EResult result = battleResult.get()->result;
+	
+	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::LEARN_BATTLE_SPELL_LEVEL_LIMIT, -1))
 		{
 			double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(Bonus::LEARN_BATTLE_SPELL_CHANCE, 0);
-			for(auto & spellId : gs->curB->sides.at(!battleResult.data->winner).usedSpellsHistory)
+			for(auto & spellId : battleInfo->sides.at(!battleResult.data->winner).usedSpellsHistory)
 			{
 				auto spell = spellId.toSpell(VLC->spells());
 				if(spell && spell->getLevel() <= eagleEyeLevel && !finishingBattle->winnerHero->spellbookContainsSpell(spell->getId()) && getRandomGenerator().nextInt(99) < eagleEyeChance)
@@ -661,7 +673,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
 	}
 	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)
 		{
@@ -697,7 +709,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
 				//we assume that no big artifacts can be found
 				MoveArtifact ma;
 				ma.src = ArtifactLocation(finishingBattle->loserHero,
-					ArtifactPosition(GameConstants::BACKPACK_START)); //backpack automatically shifts arts to beginning
+										  ArtifactPosition(GameConstants::BACKPACK_START)); //backpack automatically shifts arts to beginning
 				const CArtifactInstance * art =  ma.src.getArt();
 				if (art->artType->getId() != ArtifactID::GRAIL) //grail may not be won
 				{
@@ -719,7 +731,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
 				}
 			}
 		}
-		for (auto armySlot : gs->curB->battleGetArmyObject(!battleResult.data->winner)->stacks)
+		for (auto armySlot : battleInfo->sides.at(!battleResult.data->winner).armyObject->stacks)
 		{
 			auto artifactsWorn = armySlot.second->artifactsWorn;
 			for (auto artSlot : artifactsWorn)
@@ -734,8 +746,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
 			}
 		}
 	}
-	sendAndApply(battleResult.data); //after this point casualties objects are destroyed
-
+	
 	if (arts.size()) //display loot
 	{
 		InfoWindow iw;
@@ -796,36 +807,41 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
 	}
 	cab1.updateArmy(this);
 	cab2.updateArmy(this); //take casualties after battle is deleted
-
-	if(battleResult.data->winner != BattleSide::ATTACKER && heroAttacker) //remove beaten Attacker
+	
+	if(finishingBattle->loserHero) //remove beaten hero
 	{
-		RemoveObject ro(heroAttacker->id);
+		RemoveObject ro(finishingBattle->loserHero->id);
 		sendAndApply(&ro);
 	}
-
-	if(battleResult.data->winner != BattleSide::DEFENDER && heroDefender) //remove beaten Defender
+	if(finishingBattle->isDraw() && finishingBattle->winnerHero) //for draw case both heroes should be removed
 	{
-		RemoveObject ro(heroDefender->id);
+		RemoveObject ro(finishingBattle->winnerHero->id);
 		sendAndApply(&ro);
 	}
-
-	if(battleResult.data->winner == BattleSide::DEFENDER 
-		&& heroDefender 
-		&& heroDefender->visitedTown
-		&& !heroDefender->inTownGarrison
-		&& heroDefender->visitedTown->garrisonHero == heroDefender)
+	
+	if(battleResult.data->winner == BattleSide::DEFENDER
+	   && finishingBattle->winnerHero
+	   && finishingBattle->winnerHero->visitedTown
+	   && !finishingBattle->winnerHero->inTownGarrison
+	   && finishingBattle->winnerHero->visitedTown->garrisonHero == finishingBattle->winnerHero)
 	{
-		swapGarrisonOnSiege(heroDefender->visitedTown->id); //return defending visitor from garrison to its rightful place
+		swapGarrisonOnSiege(finishingBattle->winnerHero->visitedTown->id); //return defending visitor from garrison to its rightful place
 	}
 	//give exp
-	if(battleResult.data->exp[0] && heroAttacker && battleResult.get()->winner == BattleSide::ATTACKER)
-		changePrimSkill(heroAttacker, PrimarySkill::EXPERIENCE, battleResult.data->exp[0]);
-	else if(battleResult.data->exp[1] && heroDefender && battleResult.get()->winner == BattleSide::DEFENDER)
-		changePrimSkill(heroDefender, PrimarySkill::EXPERIENCE, battleResult.data->exp[1]);
+	if(!finishingBattle->isDraw() && battleResult.data->exp[finishingBattle->winnerSide] && finishingBattle->winnerHero)
+		changePrimSkill(finishingBattle->winnerHero, PrimarySkill::EXPERIENCE, battleResult.data->exp[finishingBattle->winnerSide]);
+	
+	BattleResultAccepted raccepted;
+	raccepted.army1 = const_cast<CArmedInstance*>(bEndArmy1);
+	raccepted.army2 = const_cast<CArmedInstance*>(bEndArmy2);
+	raccepted.hero1 = const_cast<CGHeroInstance*>(battleInfo->sides.at(0).hero);
+	raccepted.hero2 = const_cast<CGHeroInstance*>(battleInfo->sides.at(1).hero);
+	raccepted.exp[0] = battleResult.data->exp[0];
+	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)
+	//--> continuation (battleAfterLevelUp) occurs after level-up queries are handled or on removing query
 }
 
 void CGameHandler::battleAfterLevelUp(const BattleResult &result)

+ 22 - 0
server/CQuery.cpp

@@ -386,6 +386,28 @@ bool CGarrisonDialogQuery::blocksPack(const CPack * pack) const
 
 	return CDialogQuery::blocksPack(pack);
 }
+	
+CBattleDialogQuery::CBattleDialogQuery(CGameHandler * owner, const BattleInfo * Bi):
+	CDialogQuery(owner)
+{
+	bi = Bi;
+	
+	for(auto & side : bi->sides)
+		addPlayer(side.color);
+}
+
+void CBattleDialogQuery::onRemoval(PlayerColor color)
+{
+	assert(answer);
+	if(*answer == 1)
+	{
+		gh->startBattlePrimary(bi->sides[0].armyObject, bi->sides[1].armyObject, bi->tile, bi->sides[0].hero, bi->sides[1].hero, bi->creatureBank, bi->town);
+	}
+	else
+	{
+		gh->endBattleConfirm(bi);
+	}
+}
 
 CBattleDialogQuery::CBattleDialogQuery(CGameHandler * owner, const BattleInfo * Bi):
 	CDialogQuery(owner)