Browse Source

Merge pull request #2805 from IvanSavenko/bugfixing_beta

Bugfixing for 1.3.2
Ivan Savenko 2 years ago
parent
commit
2fad687691

+ 2 - 0
Mods/vcmi/config/vcmi/ukrainian.json

@@ -173,6 +173,8 @@
 
 	"vcmi.heroWindow.openCommander.hover" : "Відкрити вікно командира",
 	"vcmi.heroWindow.openCommander.help"  : "Показує інформацію про командира героя",
+	"vcmi.heroWindow.openBackpack.hover" : "Відкрити вікно рюкзака з артефактами",
+	"vcmi.heroWindow.openBackpack.help"  : "Відкриває вікно, що дозволяє легше керувати рюкзаком артефактів",
 
 	"vcmi.commanderWindow.artifactMessage" : "Бажаєте передати цей артефакт герою?",
 

+ 22 - 4
client/CServerHandler.cpp

@@ -573,18 +573,36 @@ void CServerHandler::sendRestartGame() const
 	sendLobbyPack(endGame);
 }
 
-void CServerHandler::sendStartGame(bool allowOnlyAI) const
+bool CServerHandler::validateGameStart(bool allowOnlyAI) const
 {
 	try
 	{
 		verifyStateBeforeStart(allowOnlyAI ? true : settings["session"]["onlyai"].Bool());
 	}
-	catch (const std::exception & e)
+	catch(CModHandler::Incompatibility & e)
 	{
+		logGlobal->warn("Incompatibility exception during start scenario: %s", e.what());
+
+		auto errorMsg = CGI->generaltexth->translate("vcmi.server.errors.modsIncompatibility") + '\n';
+		errorMsg += e.what();
+
+		showServerError(errorMsg);
+		return false;
+	}
+	catch(std::exception & e)
+	{
+		logGlobal->error("Exception during startScenario: %s", e.what());
 		showServerError( std::string("Unable to start map! Reason: ") + e.what());
-		return;
+		return false;
 	}
 
+	return true;
+}
+
+void CServerHandler::sendStartGame(bool allowOnlyAI) const
+{
+	verifyStateBeforeStart(allowOnlyAI ? true : settings["session"]["onlyai"].Bool());
+
 	LobbyStartGame lsg;
 	if(client)
 	{
@@ -708,7 +726,7 @@ void CServerHandler::startCampaignScenario(std::shared_ptr<CampaignState> cs)
 	});
 }
 
-void CServerHandler::showServerError(std::string txt) const
+void CServerHandler::showServerError(const std::string & txt) const
 {
 	CInfoWindow::showInfoDialog(txt, {});
 }

+ 4 - 2
client/CServerHandler.h

@@ -148,16 +148,18 @@ public:
 	void sendRestartGame() const override;
 	void sendStartGame(bool allowOnlyAI = false) const override;
 
+	bool validateGameStart(bool allowOnlyAI = false) const;
+	void debugStartTest(std::string filename, bool save = false);
+
 	void startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameState = nullptr);
 	void endGameplay(bool closeConnection = true, bool restart = false);
 	void startCampaignScenario(std::shared_ptr<CampaignState> cs = {});
-	void showServerError(std::string txt) const;
+	void showServerError(const std::string & txt) const;
 
 	// TODO: LobbyState must be updated within game so we should always know how many player interfaces our client handle
 	int howManyPlayerInterfaces();
 	ui8 getLoadMode();
 
-	void debugStartTest(std::string filename, bool save = false);
 	void restoreLastSession();
 
 	void visitForLobby(CPackForLobby & lobbyPack);

+ 4 - 1
client/NetPacksLobbyClient.cpp

@@ -102,7 +102,10 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack)
 	}
 	
 	if(pack.restart)
-		handler.sendStartGame();
+	{
+		if (handler.validateGameStart())
+			handler.sendStartGame();
+	}
 }
 
 void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)

+ 1 - 1
client/adventureMap/AdventureMapShortcuts.cpp

@@ -402,7 +402,7 @@ bool AdventureMapShortcuts::optionCanViewQuests()
 
 bool AdventureMapShortcuts::optionCanToggleLevel()
 {
-	return optionInMapView() && LOCPLINT->cb->getMapSize().z > 1;
+	return optionSidePanelActive() && LOCPLINT->cb->getMapSize().z > 1;
 }
 
 bool AdventureMapShortcuts::optionMapLevelSurface()

+ 1 - 0
client/eventsSDL/InputHandler.cpp

@@ -128,6 +128,7 @@ void InputHandler::preprocessEvent(const SDL_Event & ev)
 #endif
 	else if(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4)
 	{
+		boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
 		Settings full = settings.write["video"]["fullscreen"];
 		full->Bool() = !full->Bool();
 

+ 4 - 1
client/lobby/CBonusSelection.cpp

@@ -343,7 +343,7 @@ void CBonusSelection::updateAfterStateChange()
 	{
 		buttonStart->block(getCampaign()->scenario(CSH->campaignMap).travelOptions.bonusesToChoose.size());
 	}
-	else if(buttonStart->isBlocked())
+	else
 	{
 		buttonStart->block(false);
 	}
@@ -390,6 +390,9 @@ void CBonusSelection::goBack()
 
 void CBonusSelection::startMap()
 {
+	if (!CSH->validateGameStart())
+		return;
+
 	auto showPrologVideo = [=]()
 	{
 		auto exitCb = [=]()

+ 5 - 24
client/lobby/CLobbyScreen.cpp

@@ -88,6 +88,8 @@ CLobbyScreen::CLobbyScreen(ESelectionScreen screenType)
 		break;
 	}
 
+	buttonStart->block(true); // to be unblocked after map list is ready
+
 	buttonBack = std::make_shared<CButton>(Point(581, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], [&]()
 	{
 		CSH->sendClientDisconnecting();
@@ -126,34 +128,11 @@ void CLobbyScreen::startCampaign()
 
 void CLobbyScreen::startScenario(bool allowOnlyAI)
 {
-	try
+	if (CSH->validateGameStart(allowOnlyAI))
 	{
 		CSH->sendStartGame(allowOnlyAI);
 		buttonStart->block(true);
 	}
-	catch(CModHandler::Incompatibility & e)
-	{
-		logGlobal->warn("Incompatibility exception during start scenario: %s", e.what());
-		
-		auto errorMsg = CGI->generaltexth->translate("vcmi.server.errors.modsIncompatibility") + '\n';
-		errorMsg += e.what();
-		
-		CInfoWindow::showInfoDialog(errorMsg, CInfoWindow::TCompsInfo(), PlayerColor(1));
-	}
-	catch(std::exception & e)
-	{
-		logGlobal->error("Exception during startScenario: %s", e.what());
-		
-		if(std::string(e.what()) == "ExceptionNoHuman")
-			CInfoWindow::showInfoDialog(CGI->generaltexth->allTexts[530], CInfoWindow::TCompsInfo(), PlayerColor(1));
-		
-		if(std::string(e.what()) == "ExceptionNoTemplate")
-			CInfoWindow::showInfoDialog(CGI->generaltexth->allTexts[751], CInfoWindow::TCompsInfo(), PlayerColor(1));
-	}
-	catch(...)
-	{
-		logGlobal->error("Unknown exception");
-	}
 }
 
 void CLobbyScreen::toggleMode(bool host)
@@ -192,6 +171,8 @@ void CLobbyScreen::updateAfterStateChange()
 	if(CSH->mi && tabOpt)
 		tabOpt->recreate();
 
+	buttonStart->block(CSH->mi == nullptr || CSH->isGuest());
+
 	card->changeSelection();
 	if (card->iconDifficulty)
 	{

+ 2 - 2
client/mapView/MapRenderer.cpp

@@ -18,6 +18,7 @@
 #include "../render/CAnimation.h"
 #include "../render/Canvas.h"
 #include "../render/IImage.h"
+#include "../render/Colors.h"
 
 #include "../../CCallback.h"
 
@@ -246,7 +247,6 @@ uint8_t MapRendererRoad::checksum(IMapRendererContext & context, const int3 & co
 
 MapRendererBorder::MapRendererBorder()
 {
-	emptyFill = std::make_unique<Canvas>(Point(32,32));
 	animation = std::make_unique<CAnimation>("EDG");
 	animation->preload();
 }
@@ -298,7 +298,7 @@ void MapRendererBorder::renderTile(IMapRendererContext & context, Canvas & targe
 	}
 	else
 	{
-		target.draw(*emptyFill, Point(0,0));
+		target.drawColor(Rect(0,0,32,32), Colors::BLACK);
 	}
 }
 

+ 0 - 1
client/mapView/MapRenderer.h

@@ -90,7 +90,6 @@ public:
 class MapRendererBorder
 {
 	std::unique_ptr<CAnimation> animation;
-	std::unique_ptr<Canvas> emptyFill;
 
 	size_t getIndexForTile(IMapRendererContext & context, const int3 & coordinates);
 

+ 1 - 1
client/windows/CHeroWindow.cpp

@@ -87,7 +87,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 	if(settings["general"]["enableUiEnhancements"].Bool())
 	{
 		questlogButton = std::make_shared<CButton>(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
-		backpackButton = std::make_shared<CButton>(Point(424, 429), "buttons/backpack", CButton::tooltipLocalized("vcmi.heroWindow.Backpack"), [=](){ createBackpackWindow(); }, EShortcut::HERO_BACKPACK);
+		backpackButton = std::make_shared<CButton>(Point(424, 429), "buttons/backpack", CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"), [=](){ createBackpackWindow(); }, EShortcut::HERO_BACKPACK);
 		backpackButton->addOverlay(std::make_shared<CPicture>("buttons/backpackButtonIcon"));
 		dismissButton = std::make_shared<CButton>(Point(534, 429), "hsbtns2.def", CButton::tooltip(heroscrn[28]), [=](){ dismissCurrent(); }, EShortcut::HERO_DISMISS);
 	}

+ 27 - 13
config/widgets/adventureMap.json

@@ -126,7 +126,7 @@
 							"playerColored" : true,
 							"area": { "top" : 0, "left": 0, "width" : 32, "height" : 32 }
 						}
-					],
+					]
 				},
 				{
 					"type": "adventureMapContainer",
@@ -142,7 +142,7 @@
 							"playerColored" : true,
 							"area": { "top" : 0, "left": 0, "width" : 32, "height" : 32 }
 						}
-					],
+					]
 				},
 				{
 					"type": "adventureMapButton",
@@ -507,12 +507,19 @@
 					"area": { "top" : 23, "left": 128, "width" : 60, "height" : 32 }
 				},
 				{
-					"type": "adventureMapButton",
-					"name": "worldViewSurface",
-					"image" : "IAM003.DEF",
-					"hotkey": "adventureToggleMapLevel",
-					"playerColored" : true,
-					"area": { "top" : 79, "left": 343, "width" : 32, "height" : 32 }
+					"type": "adventureMapContainer",
+					"hideWhen" : "mapLayerSurface",
+					"area": { "top" : 343, "left": 79, "width" : 32, "height" : 32 }
+					"items" : [
+						{
+							"type": "adventureMapButton",
+							"name": "worldViewSurface",
+							"image" : "IAM003.DEF",
+							"hotkey": "adventureToggleMapLevel",
+							"playerColored" : true,
+							"area": { "top" : 0, "left": 0, "width" : 32, "height" : 32 }
+						}
+					]
 				},
 				{
 					"type": "adventureMapButton",
@@ -523,12 +530,19 @@
 					"area": { "top" : 343, "left": 5, "width" : 66, "height" : 32 }
 				},
 				{
-					"type": "adventureMapButton",
-					"name": "worldViewUnderground",
-					"image" : "IAM010.DEF",
-					"playerColored" : true,
-					"hotkey": "adventureToggleMapLevel",
+					"type": "adventureMapContainer",
+					"hideWhen" : "mapLayerUnderground",
 					"area": { "top" : 343, "left": 79, "width" : 32, "height" : 32 }
+					"items" : [
+						{
+							"type": "adventureMapButton",
+							"name": "worldViewUnderground",
+							"image" : "IAM010.DEF",
+							"playerColored" : true,
+							"hotkey": "adventureToggleMapLevel",
+							"area": { "top" : 0, "left": 0, "width" : 32, "height" : 32 }
+						}
+					]
 				},
 				{
 					"type": "adventureMapButton",

+ 2 - 2
launcher/modManager/cmodlistview_moc.cpp

@@ -764,10 +764,10 @@ void CModListView::installMods(QStringList archives)
 		enableMod(mod);
 	}
 
+	checkManagerErrors();
+
 	for(QString archive : archives)
 		QFile::remove(archive);
-
-	checkManagerErrors();
 }
 
 void CModListView::on_refreshButton_clicked()

+ 5 - 0
launcher/modManager/cmodmanager.cpp

@@ -39,6 +39,11 @@ QString detectModArchive(QString path, QString modName)
 			}
 		}
 	}
+
+	logGlobal->error("Failed to detect mod path in archive!");
+	logGlobal->debug("List of file in archive:");
+	for(auto file : files)
+		logGlobal->debug("%s", file.c_str());
 	
 	return "";
 }

+ 3 - 3
lib/StartInfo.cpp

@@ -71,7 +71,7 @@ std::string StartInfo::getCampaignName() const
 void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const
 {
 	if(!mi || !mi->mapHeader)
-		throw std::domain_error("There is no map to start!");
+		throw std::domain_error(VLC->generaltexth->translate("core.genrltxt.529"));
 	
 	auto missingMods = CMapService::verifyMapHeaderMods(*mi->mapHeader);
 	CModHandler::Incompatibility::ModList modList;
@@ -88,12 +88,12 @@ void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const
 			break;
 
 	if(i == si->playerInfos.cend() && !ignoreNoHuman)
-		throw std::domain_error("There is no human player on map");
+		throw std::domain_error(VLC->generaltexth->translate("core.genrltxt.530"));
 
 	if(si->mapGenOptions && si->mode == StartInfo::NEW_GAME)
 	{
 		if(!si->mapGenOptions->checkOptions())
-			throw std::domain_error("No random map template found!");
+			throw std::domain_error(VLC->generaltexth->translate("core.genrltxt.751"));
 	}
 }
 

+ 22 - 2
lib/filesystem/CZipLoader.cpp

@@ -157,7 +157,15 @@ std::vector<std::string> ZipArchive::listFiles(const boost::filesystem::path & f
 
 	unzFile file = unzOpen2_64(filename.c_str(), FileStream::GetMinizipFilefunc());
 
-	if (unzGoToFirstFile(file) == UNZ_OK)
+	if (file == nullptr)
+	{
+		logGlobal->error("Failed to open file '%s'! Unable to list files!", filename.string());
+		return {};
+	}
+
+	int result = unzGoToFirstFile(file);
+
+	if (result == UNZ_OK)
 	{
 		do
 		{
@@ -171,9 +179,21 @@ std::vector<std::string> ZipArchive::listFiles(const boost::filesystem::path & f
 			unzGetCurrentFileInfo64(file, &info, zipFilename.data(), static_cast<uLong>(zipFilename.size()), nullptr, 0, nullptr, 0);
 
 			ret.emplace_back(zipFilename.data(), zipFilename.size());
+
+			result = unzGoToNextFile(file);
+		}
+		while (result == UNZ_OK);
+
+		if (result != UNZ_OK && result != UNZ_END_OF_LIST_OF_FILE)
+		{
+			logGlobal->error("Failed to list file from '%s'! Error code %d", filename.string(), result);
 		}
-		while (unzGoToNextFile(file) == UNZ_OK);
 	}
+	else
+	{
+		logGlobal->error("Failed to list files from '%s'! Error code %d", filename.string(), result);
+	}
+
 	unzClose(file);
 
 	return ret;

+ 5 - 0
server/CGameHandler.cpp

@@ -589,6 +589,11 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
 			battleResult.data->exp[0] += 500;
 	}
 
+	// Give 500 exp to winner if a town was conquered during the battle
+	const auto * defendedTown = battleGetDefendedTown();
+	if (defendedTown && battleResult.data->winner == BattleSide::ATTACKER)
+		battleResult.data->exp[BattleSide::ATTACKER] += 500;
+
 	if(heroAttacker)
 		battleResult.data->exp[0] = heroAttacker->calculateXp(battleResult.data->exp[0]);//scholar skill
 	if(heroDefender)