Преглед на файлове

Merge remote-tracking branch 'vcmi/master' into beta

Ivan Savenko преди 2 години
родител
ревизия
92ce97bbc7

+ 1 - 1
AI/Nullkiller/Behaviors/DefenceBehavior.cpp

@@ -189,7 +189,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 			town->getNameTranslated(),
 			treat.danger,
 			std::to_string(treat.turn),
-			treat.hero->getNameTranslated());
+			treat.hero ? treat.hero->getNameTranslated() : std::string("<no hero>"));
 
 		handleCounterAttack(town, treat, treatNode.maximumDanger, tasks);
 

+ 2 - 0
client/gui/CGuiHandler.cpp

@@ -88,6 +88,8 @@ void CGuiHandler::handleEvents()
 void CGuiHandler::fakeMouseMove()
 {
 	dispatchMainThread([](){
+		assert(CPlayerInterface::pim);
+		boost::unique_lock lock(*CPlayerInterface::pim);
 		GH.events().dispatchMouseMoved(Point(0, 0), GH.getCursorPosition());
 	});
 }

+ 7 - 3
client/lobby/RandomMapTab.cpp

@@ -147,7 +147,6 @@ void RandomMapTab::updateMapInfoByHost()
 	mapInfo->mapHeader->twoLevel = mapGenOptions->getHasTwoLevels();
 
 	// Generate player information
-	mapInfo->mapHeader->players.clear();
 	int playersToGen = PlayerColor::PLAYER_LIMIT_I;
 	if(mapGenOptions->getPlayerCount() != CMapGenOptions::RANDOM_SIZE)
 	{
@@ -157,10 +156,15 @@ void RandomMapTab::updateMapInfoByHost()
 			playersToGen = mapGenOptions->getPlayerCount();
 	}
 
-
 	mapInfo->mapHeader->howManyTeams = playersToGen;
 
 	std::set<TeamID> occupiedTeams;
+	for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
+	{
+		mapInfo->mapHeader->players[i].canComputerPlay = false;
+		mapInfo->mapHeader->players[i].canHumanPlay = false;
+	}
+
 	for(int i = 0; i < playersToGen; ++i)
 	{
 		PlayerInfo player;
@@ -179,7 +183,7 @@ void RandomMapTab::updateMapInfoByHost()
 		occupiedTeams.insert(team);
 		player.hasMainTown = true;
 		player.generateHeroAtMainTown = true;
-		mapInfo->mapHeader->players.push_back(player);
+		mapInfo->mapHeader->players[i] = player;
 	}
 	for(auto & player : mapInfo->mapHeader->players)
 	{

+ 32 - 14
client/windows/CCastleInterface.cpp

@@ -1451,7 +1451,11 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 	auto statusbarBackground = std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26);
 	statusbar = CGStatusBar::create(statusbarBackground);
 
-	name = std::make_shared<CLabel>(197, 30, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, boost::str(boost::format(CGI->generaltexth->hcommands[7]) % building->getNameTranslated()));
+	MetaString nameString;
+	nameString.appendTextID("core.hallinfo.7");
+	nameString.replaceTextID(building->getNameTextID());
+
+	name = std::make_shared<CLabel>(197, 30, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, nameString.toString());
 	description = std::make_shared<CTextBox>(building->getDescriptionTranslated(), Rect(33, 135, 329, 67), 0, FONT_MEDIUM, ETextAlignment::CENTER);
 	stateText = std::make_shared<CTextBox>(getTextForState(state), Rect(33, 216, 329, 67), 0, FONT_SMALL, ETextAlignment::CENTER);
 
@@ -1468,14 +1472,20 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 
 	if(!rightClick)
 	{	//normal window
-		std::string tooltipYes = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->getNameTranslated());
-		std::string tooltipNo  = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->getNameTranslated());
 
-		buy = std::make_shared<CButton>(Point(45, 446), "IBUY30", CButton::tooltip(tooltipYes), [&](){ buyFunc(); }, EShortcut::GLOBAL_ACCEPT);
+		MetaString tooltipYes;
+		tooltipYes.appendTextID("core.genrltxt.595");
+		tooltipYes.replaceTextID(building->getNameTextID());
+
+		MetaString tooltipNo;
+		tooltipNo.appendTextID("core.genrltxt.596");
+		tooltipNo.replaceTextID(building->getNameTextID());
+
+		buy = std::make_shared<CButton>(Point(45, 446), "IBUY30", CButton::tooltip(tooltipYes.toString()), [&](){ buyFunc(); }, EShortcut::GLOBAL_ACCEPT);
 		buy->setBorderColor(Colors::METALLIC_GOLD);
 		buy->block(state!=7 || LOCPLINT->playerID != town->tempOwner);
 
-		cancel = std::make_shared<CButton>(Point(290, 445), "ICANCEL", CButton::tooltip(tooltipNo), [&](){ close();}, EShortcut::GLOBAL_CANCEL);
+		cancel = std::make_shared<CButton>(Point(290, 445), "ICANCEL", CButton::tooltip(tooltipNo.toString()), [&](){ close();}, EShortcut::GLOBAL_CANCEL);
 		cancel->setBorderColor(Colors::METALLIC_GOLD);
 	}
 }
@@ -1841,17 +1851,25 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
 	anim = std::make_shared<CCreatureAnim>(64, 50, creature->animDefName);
 	anim->clipRect(113,125,200,150);
 
-	title = std::make_shared<CLabel>(165, 28, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW,
-				boost::str(boost::format(CGI->generaltexth->allTexts[274]) % creature->getNameSingularTranslated()));
-	costText = std::make_shared<CLabel>(165, 218, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->jktexts[43]);
-	costValue = std::make_shared<CLabel>(165, 292, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE,
-	                std::to_string(aid.toArtifact(CGI->artifacts())->getPrice()));
+	MetaString titleString;
+	titleString.appendTextID("core.genrltxt.274");
+	titleString.replaceTextID(creature->getNameSingularTextID());
 
-	std::string text = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % creature->getNameSingularTranslated());
-	buy = std::make_shared<CButton>(Point(42, 312), "IBUY30.DEF", CButton::tooltip(text), [&](){ close(); }, EShortcut::GLOBAL_ACCEPT);
+	MetaString buyText;
+	buyText.appendTextID("core.genrltxt.595");
+	buyText.replaceTextID(creature->getNameSingularTextID());
 
-	text = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % creature->getNameSingularTranslated());
-	cancel = std::make_shared<CButton>(Point(224, 312), "ICANCEL.DEF", CButton::tooltip(text), [&](){ close(); }, EShortcut::GLOBAL_CANCEL);
+	MetaString cancelText;
+	cancelText.appendTextID("core.genrltxt.596");
+	cancelText.replaceTextID(creature->getNameSingularTextID());
+
+	std::string costString = std::to_string(aid.toArtifact(CGI->artifacts())->getPrice());
+
+	title = std::make_shared<CLabel>(165, 28, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, titleString.toString());
+	costText = std::make_shared<CLabel>(165, 218, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->jktexts[43]);
+	costValue = std::make_shared<CLabel>(165, 292, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, costString);
+	buy = std::make_shared<CButton>(Point(42, 312), "IBUY30.DEF", CButton::tooltip(buyText.toString()), [&](){ close(); }, EShortcut::GLOBAL_ACCEPT);
+	cancel = std::make_shared<CButton>(Point(224, 312), "ICANCEL.DEF", CButton::tooltip(cancelText.toString()), [&](){ close(); }, EShortcut::GLOBAL_CANCEL);
 
 	if(possible)
 		buy->addCallback([=](){ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); });

+ 6 - 0
lib/mapObjects/CGTownInstance.cpp

@@ -996,6 +996,12 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(const BuildingID &
 	std::function<CBuilding::TRequired::Variant(const BuildingID &)> dependTest =
 	[&](const BuildingID & id) -> CBuilding::TRequired::Variant
 	{
+		if (town->buildings.count(id) == 0)
+		{
+			logMod->error("Invalid building ID %d in building dependencies!", id.getNum());
+			return CBuilding::TRequired::OperatorAll();
+		}
+
 		const CBuilding * build = town->buildings.at(id);
 		CBuilding::TRequired::OperatorAll requirements;
 

+ 2 - 0
server/CGameHandler.cpp

@@ -6464,6 +6464,8 @@ void CGameHandler::runBattle()
 
 bool CGameHandler::makeAutomaticAction(const CStack *stack, BattleAction &ba)
 {
+	boost::unique_lock lock(battleActionMutex);
+
 	BattleSetActiveStack bsa;
 	bsa.stack = stack->unitId();
 	bsa.askPlayerInterface = false;

+ 6 - 0
server/NetPacksServer.cpp

@@ -25,6 +25,8 @@
 #include "../lib/spells/ISpellMechanics.h"
 #include "../lib/serializer/Cast.h"
 
+extern boost::recursive_mutex battleActionMutex;
+
 void ApplyGhNetPackVisitor::visitSaveGame(SaveGame & pack)
 {
 	gh.save(pack.fname);
@@ -280,6 +282,8 @@ void ApplyGhNetPackVisitor::visitQueryReply(QueryReply & pack)
 
 void ApplyGhNetPackVisitor::visitMakeAction(MakeAction & pack)
 {
+	boost::unique_lock lock(battleActionMutex);
+
 	const BattleInfo * b = gs.curB;
 	if(!b)
 		gh.throwAndComplain(&pack, "Can not make action - there is no battle ongoing!");
@@ -307,6 +311,8 @@ void ApplyGhNetPackVisitor::visitMakeAction(MakeAction & pack)
 
 void ApplyGhNetPackVisitor::visitMakeCustomAction(MakeCustomAction & pack)
 {
+	boost::unique_lock lock(battleActionMutex);
+
 	const BattleInfo * b = gs.curB;
 	if(!b)
 		gh.throwNotAllowedAction(&pack);