Forráskód Böngészése

Merge pull request #4499 from vcmi/beta

Merge beta -> master
Ivan Savenko 1 éve
szülő
commit
f1be5b0e93

+ 5 - 0
.github/workflows/github.yml

@@ -177,6 +177,11 @@ jobs:
         distribution: 'temurin'
         java-version: '11'
 
+    # a hack to build ID for x64 build in order for Google Play to allow upload of both 32 and 64 bit builds
+    - name: Bump Android x64 build ID
+      if: ${{ matrix.platform == 'android-64' }}
+      run: perl -i -pe 's/versionCode (\d+)/$x=$1+1; "versionCode $x"/e' android/vcmi-app/build.gradle
+
     - name: Build Number
       run: |
         source '${{github.workspace}}/CI/get_package_name.sh'

+ 4 - 5
AI/BattleAI/BattleEvaluator.cpp

@@ -265,7 +265,7 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector
 	{
 		std::sort(targetHexes.begin(), targetHexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
 			{
-				return reachability.distances[h1] < reachability.distances[h2];
+				return reachability.distances.at(h1) < reachability.distances.at(h2);
 			});
 
 		for(auto hex : targetHexes)
@@ -283,7 +283,7 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector
 			}
 		}
 
-		if(reachability.distances[targetHexes.front()] <= GameConstants::BFIELD_SIZE)
+		if(reachability.distances.at(targetHexes.front()) <= GameConstants::BFIELD_SIZE)
 		{
 			break;
 		}
@@ -291,16 +291,15 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector
 		std::vector<BattleHex> copy = targetHexes;
 
 		for(auto hex : copy)
-		{
 			vstd::concatenate(targetHexes, hex.allNeighbouringTiles());
-		}
 
+		vstd::erase_if(targetHexes, [](const BattleHex & hex) {return !hex.isValid();});
 		vstd::removeDuplicates(targetHexes);
 	}
 
 	BattleHex bestNeighbor = targetHexes.front();
 
-	if(reachability.distances[bestNeighbor] > GameConstants::BFIELD_SIZE)
+	if(reachability.distances.at(bestNeighbor) > GameConstants::BFIELD_SIZE)
 	{
 		return BattleAction::makeDefend(stack);
 	}

+ 4 - 4
AI/BattleAI/BattleExchangeVariant.cpp

@@ -764,7 +764,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
 
 			ReachabilityInfo unitReachability = reachabilityIter != reachabilityCache.end() ? reachabilityIter->second : turnBattle.getReachability(unit);
 
-			bool reachable = unitReachability.distances[hex] <= radius;
+			bool reachable = unitReachability.distances.at(hex) <= radius;
 
 			if(!reachable && unitReachability.accessibility[hex] == EAccessibility::ALIVE_STACK)
 			{
@@ -774,7 +774,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
 				{
 					for(BattleHex neighbor : hex.neighbouringTiles())
 					{
-						reachable = unitReachability.distances[neighbor] <= radius;
+						reachable = unitReachability.distances.at(neighbor) <= radius;
 
 						if(reachable) break;
 					}
@@ -824,7 +824,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
 			for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
 			{
 				bool enemyUnit = false;
-				bool reachable = unitReachability.distances[hex] <= unitSpeed;
+				bool reachable = unitReachability.distances.at(hex) <= unitSpeed;
 
 				if(!reachable && unitReachability.accessibility[hex] == EAccessibility::ALIVE_STACK)
 				{
@@ -836,7 +836,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
 
 						for(BattleHex neighbor : hex.neighbouringTiles())
 						{
-							reachable = unitReachability.distances[neighbor] <= unitSpeed;
+							reachable = unitReachability.distances.at(neighbor) <= unitSpeed;
 
 							if(reachable) break;
 						}

+ 11 - 0
ChangeLog.md

@@ -1,3 +1,14 @@
+# 1.5.6 -> 1.5.7
+
+* Fixed game freeze if player is attacked in online multiplayer game by another player when he has unread dialogs, such as new week notification
+* Fixed heroes on map limit game setting not respected when moving hero from town garrison.
+* Add workaround to fix possible crash on attempt to start previously generated random map that has players without owned heroes or towns
+* Fixed crash on right-clicking spell icon when receiving unlearnable spells from Pandora
+* Fixed possible text overflow in match information box in online lobby
+* Fixed overlapping text in lobby login window
+* Fixed excessive removal of open dialogs such as new week or map events on new turn
+* Fixed objects like Mystical Gardens not resetting their state on new week correctly
+
 # 1.5.5 -> 1.5.6
 
 ### Stability

+ 2 - 2
android/vcmi-app/build.gradle

@@ -26,8 +26,8 @@ android {
 		minSdk = qtMinSdkVersion as Integer
 		targetSdk = qtTargetSdkVersion as Integer // ANDROID_TARGET_SDK_VERSION in the CMake project
 
-		versionCode 1560
-		versionName "1.5.6"
+		versionCode 1570
+		versionName "1.5.7"
 
 		setProperty("archivesBaseName", "vcmi")
 	}

+ 10 - 6
client/CPlayerInterface.cpp

@@ -202,6 +202,11 @@ void CPlayerInterface::playerEndsTurn(PlayerColor player)
 	{
 		makingTurn = false;
 		closeAllDialogs();
+
+		// remove all pending dialogs that do not expect query answer
+		vstd::erase_if(dialogs, [](const std::shared_ptr<CInfoWindow> & window){
+						   return window->ID == QueryID::NONE;
+					   });
 	}
 }
 
@@ -615,9 +620,7 @@ void CPlayerInterface::battleStartBefore(const BattleID & battleID, const CCreat
 {
 	movementController->onBattleStarted();
 
-	//Don't wait for dialogs when we are non-active hot-seat player
-	if (LOCPLINT == this)
-		waitForAllDialogs();
+	waitForAllDialogs();
 }
 
 void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed)
@@ -640,9 +643,7 @@ void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet
 		cb->registerBattleInterface(autofightingAI);
 	}
 
-	//Don't wait for dialogs when we are non-active hot-seat player
-	if (LOCPLINT == this)
-		waitForAllDialogs();
+	waitForAllDialogs();
 
 	BATTLE_EVENT_POSSIBLE_RETURN;
 }
@@ -1825,6 +1826,9 @@ void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
 
 void CPlayerInterface::waitForAllDialogs()
 {
+	if (!makingTurn)
+		return;
+
 	while(!dialogs.empty())
 	{
 		auto unlockInterface = vstd::makeUnlockGuard(GH.interfaceMutex);

+ 3 - 0
client/globalLobby/GlobalLobbyLoginWindow.cpp

@@ -68,7 +68,10 @@ GlobalLobbyLoginWindow::GlobalLobbyLoginWindow()
 		onLoginModeChanged(0); // call it manually to disable widgets - toggleMode will not emit this call if this is currenly selected option
 	}
 	else
+	{
 		toggleMode->setSelected(1);
+		onLoginModeChanged(1);
+	}
 
 	filledBackground->playerColored(PlayerColor(1));
 	inputUsername->setCallback([this](const std::string & text)

+ 1 - 1
client/globalLobby/GlobalLobbyWidget.cpp

@@ -286,5 +286,5 @@ GlobalLobbyMatchCard::GlobalLobbyMatchCard(GlobalLobbyWindow * window, const Glo
 		opponentDescription.replaceNumber(matchDescription.participants.size());
 	}
 
-	labelMatchOpponent = std::make_shared<CLabel>(5, 30, FONT_SMALL, ETextAlignment::CENTERLEFT, Colors::YELLOW, opponentDescription.toString());
+	labelMatchOpponent = std::make_shared<CLabel>(5, 30, FONT_SMALL, ETextAlignment::CENTERLEFT, Colors::YELLOW, opponentDescription.toString(), 120);
 }

+ 2 - 2
client/widgets/CComponent.cpp

@@ -230,7 +230,7 @@ std::string CComponent::getDescription() const
 			return description;
 		}
 		case ComponentType::SPELL:
-			return VLC->spells()->getById(data.subType.as<SpellID>())->getDescriptionTranslated(data.value.value_or(0));
+			return VLC->spells()->getById(data.subType.as<SpellID>())->getDescriptionTranslated(std::max(0, data.value.value_or(0)));
 		case ComponentType::MORALE:
 			return CGI->generaltexth->heroscrn[ 4 - (data.value.value_or(0)>0) + (data.value.value_or(0)<0)];
 		case ComponentType::LUCK:
@@ -290,7 +290,7 @@ std::string CComponent::getSubtitle() const
 			return CGI->artifacts()->getById(data.subType.as<ArtifactID>())->getNameTranslated();
 		case ComponentType::SPELL_SCROLL:
 		case ComponentType::SPELL:
-			if (data.value < 0)
+			if (data.value.value_or(0) < 0)
 				return "{#A9A9A9|" + CGI->spells()->getById(data.subType.as<SpellID>())->getNameTranslated() + "}";
 			else
 				return CGI->spells()->getById(data.subType.as<SpellID>())->getNameTranslated();

+ 1 - 1
cmake_modules/VersionDefinition.cmake

@@ -1,6 +1,6 @@
 set(VCMI_VERSION_MAJOR 1)
 set(VCMI_VERSION_MINOR 5)
-set(VCMI_VERSION_PATCH 6)
+set(VCMI_VERSION_PATCH 7)
 add_definitions(
 	-DVCMI_VERSION_MAJOR=${VCMI_VERSION_MAJOR}
 	-DVCMI_VERSION_MINOR=${VCMI_VERSION_MINOR}

+ 6 - 0
debian/changelog

@@ -1,3 +1,9 @@
+vcmi (1.5.7) jammy; urgency=medium
+
+  * New upstream release
+
+ -- Ivan Savenko <[email protected]>  Fri, 23 Aug 2024 12:00:00 +0200
+
 vcmi (1.5.6) jammy; urgency=medium
 
   * New upstream release

+ 2 - 2
docs/Readme.md

@@ -1,7 +1,7 @@
 [![VCMI](https://github.com/vcmi/vcmi/actions/workflows/github.yml/badge.svg?branch=develop&event=push)](https://github.com/vcmi/vcmi/actions/workflows/github.yml?query=branch%3Adevelop+event%3Apush)
 [![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.0)
-[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.4/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.5)
-[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.5/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.6)
+[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.6/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.6)
+[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.7/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.7)
 [![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/total)](https://github.com/vcmi/vcmi/releases)
 
 # VCMI Project

+ 1 - 0
launcher/eu.vcmi.VCMI.metainfo.xml

@@ -90,6 +90,7 @@
 	</screenshots>
 	<launchable type="desktop-id">vcmilauncher.desktop</launchable>
 	<releases>
+		<release version="1.5.7" date="2024-08-23" type="stable"/>
 		<release version="1.5.6" date="2024-08-04" type="stable"/>
 		<release version="1.5.5" date="2024-07-17" type="stable"/>
 		<release version="1.5.4" date="2024-07-12" type="stable"/>

+ 1 - 1
lib/battle/CBattleInfoCallback.cpp

@@ -1035,7 +1035,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
 		if(isInObstacle(curHex, obstacles, checkParams))
 			continue;
 
-		const int costToNeighbour = ret.distances[curHex.hex] + 1;
+		const int costToNeighbour = ret.distances.at(curHex.hex) + 1;
 		for(BattleHex neighbour : BattleHex::neighbouringTilesCache[curHex.hex])
 		{
 			if(neighbour.isValid())

+ 21 - 20
lib/gameState/CGameState.cpp

@@ -312,6 +312,27 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
 		std::unique_ptr<CMap> randomMap = mapGenerator.generate();
 		progressTracking.exclude(mapGenerator);
 
+		// Update starting options
+		for(int i = 0; i < randomMap->players.size(); ++i)
+		{
+			const auto & playerInfo = randomMap->players[i];
+			if(playerInfo.canAnyonePlay())
+			{
+				PlayerSettings & playerSettings = scenarioOps->playerInfos[PlayerColor(i)];
+				playerSettings.compOnly = !playerInfo.canHumanPlay;
+				playerSettings.castle = playerInfo.defaultCastle();
+				if(playerSettings.isControlledByAI() && playerSettings.name.empty())
+				{
+					playerSettings.name = VLC->generaltexth->allTexts[468];
+				}
+				playerSettings.color = PlayerColor(i);
+			}
+			else
+			{
+				scenarioOps->playerInfos.erase(PlayerColor(i));
+			}
+		}
+
 		if(allowSavingRandomMap)
 		{
 			try
@@ -342,26 +363,6 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
 		}
 
 		map = randomMap.release();
-		// Update starting options
-		for(int i = 0; i < map->players.size(); ++i)
-		{
-			const auto & playerInfo = map->players[i];
-			if(playerInfo.canAnyonePlay())
-			{
-				PlayerSettings & playerSettings = scenarioOps->playerInfos[PlayerColor(i)];
-				playerSettings.compOnly = !playerInfo.canHumanPlay;
-				playerSettings.castle = playerInfo.defaultCastle();
-				if(playerSettings.isControlledByAI() && playerSettings.name.empty())
-				{
-					playerSettings.name = VLC->generaltexth->allTexts[468];
-				}
-				playerSettings.color = PlayerColor(i);
-			}
-			else
-			{
-				scenarioOps->playerInfos.erase(PlayerColor(i));
-			}
-		}
 
 		logGlobal->info("Generated random map in %i ms.", sw.getDiff());
 	}

+ 1 - 0
lib/rewardable/Info.cpp

@@ -338,6 +338,7 @@ void Rewardable::Info::configureRewards(
 void Rewardable::Info::configureObject(Rewardable::Configuration & object, CRandomGenerator & rng, IGameCallback * cb) const
 {
 	object.info.clear();
+	object.variables.values.clear();
 
 	configureVariables(object, rng, cb, parameters["variables"]);
 

+ 4 - 3
server/CGameHandler.cpp

@@ -2696,10 +2696,11 @@ bool CGameHandler::garrisonSwap(ObjectInstanceID tid)
 	}
 	else if (town->garrisonHero && !town->visitingHero) //move hero out of the garrison
 	{
-		//check if moving hero out of town will break 8 wandering heroes limit
-		if (getHeroCount(town->garrisonHero->tempOwner,false) >= 8)
+		int mapCap = VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP);
+		//check if moving hero out of town will break wandering heroes limit
+		if (getHeroCount(town->garrisonHero->tempOwner,false) >= mapCap)
 		{
-			complain("Cannot move hero out of the garrison, there are already 8 wandering heroes!");
+			complain("Cannot move hero out of the garrison, there are already " + std::to_string(mapCap) + " wandering heroes!");
 			return false;
 		}